Package org.nlogo.render

Source Code of org.nlogo.render.TrailDrawer

// (C) Uri Wilensky. https://github.com/NetLogo/NetLogo

package org.nlogo.render;

import org.nlogo.api.Dump;
import org.nlogo.api.Graphics2DWrapper;

public strictfp class TrailDrawer
    implements org.nlogo.api.TrailDrawerInterface,
    org.nlogo.api.ViewSettings {
  private final org.nlogo.api.World world;
  private java.awt.image.BufferedImage drawingImage = null;
  private int width;
  private int height;
  int[] colors = null;
  public TopologyRenderer topology;
  private final TurtleDrawer turtleDrawer;
  private final LinkDrawer linkDrawer;

  public TrailDrawer(org.nlogo.api.World world, TurtleDrawer turtleDrawer, LinkDrawer linkDrawer) {
    this.world = world;
    this.turtleDrawer = turtleDrawer;
    this.linkDrawer = linkDrawer;
  }

  // for rendering drawing in 3D view
  boolean drawingDirty = false;
  boolean drawingBlank = true;

  public int[] colors() {
    if (drawingDirty) {
      if (colors == null) {
        colors = new int[width * height * 4];
      }
      java.awt.image.Raster raster = drawingImage.getRaster();
      // note that the docs say the output array should be allocated
      // by getDataElements if it is null, my experience is it doesn't. ev 9/21/05
      raster.getDataElements(0, 0, width, height, colors);
    }

    return colors;
  }

  public void setTopology(TopologyRenderer topology) {
    this.topology = topology;
  }

  public boolean sendPixels() {
    return sendPixels;
  }

  public void sendPixels(boolean dirty) {
    sendPixels = dirty;
  }

  private boolean sendPixels = false;

  public boolean isDirty() {
    return drawingDirty;
  }

  public boolean isBlank() {
    return drawingBlank;
  }

  public int getWidth() {
    return width;
  }

  public int getHeight() {
    return height;
  }

  public void markDirty() {
    drawingBlank = false;
    drawingDirty = true;
  }

  public void markClean() {
    drawingDirty = false;
  }

  private void setUpDrawingImage() {
    width = (int) StrictMath.round(world.patchSize() * world.worldWidth());
    height = (int) StrictMath.round(world.patchSize() * world.worldHeight());

    if (width > 0 && height > 0) {
      drawingImage =
          new java.awt.image.BufferedImage
              (width, height,
                  java.awt.image.BufferedImage.TYPE_INT_ARGB);
      colors = null;
    } else {
      drawingImage = null;
    }

    drawingBlank = true;
  }

  public void rescaleDrawing() {
    java.awt.image.BufferedImage oldImage = drawingImage;

    setUpDrawingImage();

    if (oldImage != null && drawingImage != null) {
      java.awt.Graphics2D graphics = drawingImage.createGraphics();

      graphics.drawImage(oldImage, 0, 0, width, height, null);

      drawingDirty = true;
    }
  }


  // sometimes we want to make sure that a drawing is created
  // (like for the api method getDrawing)
  // and sometimes we only want to get the drawing if it has already
  // been created (like for the 3D view or hubnet view mirroring)
  // in which case it's ok to return null.
  // getAndCreateDrawing is the only method available from the api
  // ev 7/31/06
  public java.awt.image.BufferedImage getAndCreateDrawing(boolean dirty) {
    if (drawingImage == null) {
      setUpDrawingImage();
    }
    if (dirty) {
      drawingBlank = false;
      drawingDirty = true;
    }

    return drawingImage;
  }

  public Object getDrawing() {
    return drawingImage;
  }

  // for hubnet client
  public void readImage(java.io.InputStream is)
      throws java.io.IOException {
    setUpDrawingImage();

    java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(is);

    java.awt.Graphics2D dg = drawingImage.createGraphics();

    dg.drawImage(image, 0, 0, null);

    drawingBlank = false;
    drawingDirty = true;
  }

  public void importDrawing(java.io.InputStream is)
      throws java.io.IOException {
    if (drawingImage == null) {
      setUpDrawingImage();
    }
    if (drawingImage != null) {

      java.awt.image.BufferedImage image;

      image = javax.imageio.ImageIO.read(is);

      if (image == null) {
        throw new javax.imageio.IIOException("Unsupported image format.");
      }
      float scalex = (float) getWidth() / (float) image.getWidth();
      float scaley = (float) getHeight() / (float) image.getHeight();
      float scale = scalex < scaley ? scalex : scaley;
      java.awt.image.BufferedImage scaledImage = null;

      if (scale != 1) {

        final java.awt.image.AffineTransformOp trans =
            new java.awt.image.AffineTransformOp(java.awt.geom.AffineTransform.getScaleInstance(scale, scale),
                java.awt.image.AffineTransformOp.TYPE_BILINEAR);

        // To workaround a java bug, if our image was read
        // into a grayscale color space BufferedImage, than we
        // want to make sure we scale to the same color model
        // so that the colors don't get brightened.  However,
        // we can't do this for image buffers with alpha
        // values, or the scaling gets hosed too.  A curse
        // upon all "open source" languages with closed source
        // implementations. -- CLB
        if (image.getColorModel().getColorSpace().getType() == java.awt.color.ColorSpace.TYPE_GRAY
            && !image.getColorModel().hasAlpha()) {
          scaledImage = trans.createCompatibleDestImage(image, image.getColorModel());
          trans.filter(image, scaledImage);
        } else {
          scaledImage = trans.filter(image, null);
        }

      } else {
        scaledImage = image;
      }

      final int xOffset = (getWidth() - scaledImage.getWidth()) / 2;
      final int yOffset = (getHeight() - scaledImage.getHeight()) / 2;
      drawingImage.createGraphics().drawImage(scaledImage, xOffset, yOffset, null);
      markDirty();

    }
    sendPixels = true;
  }

  public void importDrawing(org.nlogo.api.File file)
      throws java.io.IOException {
    try {
      importDrawing(file.getInputStream());
    }
    catch (javax.imageio.IIOException ex) {
      throw new javax.imageio.IIOException("Unsupported image format: " + file.getPath(), ex);
    }
  }

  public void exportDrawingToCSV(java.io.PrintWriter writer) {
    if (!drawingBlank) {
      writer.println(Dump.csv().encode("DRAWING"));

      writer.println(Dump.csv().encode(Double.toString(world.patchSize())));

      String colorString = org.nlogo.util.HexString.toHexString(colors());

      Dump.csv().stringToCSV(writer, colorString);
    }
    writer.println();
  }

  public void setColors(int[] colors) {
    setUpDrawingImage();

    // rather than directly setting the values in the drawing buffer
    // make a temporary one and copy the image.  otherwise on OS 10.4
    // the drawing disappears when we try and draw to it again.
    // I expect has to do with the accessing the pixels directly
    // v. through the graphics object problem. ev 6/22/05

    java.awt.image.BufferedImage image =
        new java.awt.image.BufferedImage
            (width, height,
                java.awt.image.BufferedImage.TYPE_INT_ARGB);

    image.setRGB(0, 0, width, height,
        colors, 0, width);

    java.awt.Graphics2D dg = drawingImage.createGraphics();

    dg.drawImage(image, 0, 0, null);

    drawingBlank = false;
    drawingDirty = true;
    sendPixels = true;
  }

  public void clearDrawing() {
    if (drawingImage != null) {
      setUpDrawingImage();
    }
  }

  public void stamp(org.nlogo.api.Agent agent, boolean erase) {
    Graphics2DWrapper tg = new Graphics2DWrapper(getAndCreateDrawing(false).createGraphics());
    tg.antiAliasing(true);
    tg.setComposite(erase ? java.awt.AlphaComposite.Clear : java.awt.AlphaComposite.SrcOver);

    topology.prepareToPaint(this, width, height);

    // we use world.patchSize here because the drawing does not
    // change resolution due to zooming. ev 4/2/08
    if (agent instanceof org.nlogo.api.Turtle) {
      turtleDrawer.drawTurtleShape
          (tg, topology, (org.nlogo.api.Turtle) agent, world.patchSize());
    } else if (agent instanceof org.nlogo.api.Link) {
      linkDrawer.drawLink
          (tg, topology, (org.nlogo.api.Link) agent, world.patchSize(), false);
    }
    tg.antiAliasing(false);

    markDirty();
  }

  public void drawLine(double x1, double y1, double x2, double y2,
                       Object penColor, double penSize, String penMode) {

    if (drawingImage == null) {
      setUpDrawingImage();
    }

    if (drawingImage != null) {
      Graphics2DWrapper tg = new Graphics2DWrapper((java.awt.Graphics2D) drawingImage.getGraphics());

      tg.setPenWidth(penSize);

      if (penMode.equals("erase")) {
        tg.setComposite(java.awt.AlphaComposite.Clear);

        drawWrappedLine(tg, x1, y1, x2, y2, penSize);

        tg.setComposite(java.awt.AlphaComposite.SrcOver);
      } else {
        tg.antiAliasing(true);

        tg.setColor(org.nlogo.api.Color.getColor(penColor));

        drawWrappedLine(tg, x1, y1, x2, y2, penSize);

        tg.antiAliasing(false);
      }
    }
  }

  private void drawWrappedLine(Graphics2DWrapper tg,
                               double x1, double y1, double x2, double y2,
                               double penSize) {
    double startX = x1;
    double startY = y1;
    double endX = x1;
    double endY = y1;
    double temp;
    if (endX < startX) {
      temp = endX;
      endX = startX;
      startX = temp;
    }
    if (endY < startY) {
      temp = endY;
      endY = startY;
      startY = temp;
    }

    double xdiff = x2 - x1;
    double ydiff = y2 - y1;
    double distX = x2 - x1;
    double distY = y2 - y1;
    double newStartX = 0;
    double newStartY = 0;
    double maxy = world.maxPycor() + 0.4999999;
    double maxx = world.maxPxcor() + 0.4999999;
    double miny = world.minPycor() - 0.5;
    double minx = world.minPxcor() - 0.5;
    double pixelSize = 1 / world.patchSize();

    do {
      endX = startX + distX;
      endY = startY + distY;

      if (endY < miny) {
        endX = (miny - startY) * xdiff / ydiff + startX;
        endY = miny;
        newStartY = maxy;
        newStartX = endX;
        if (newStartX == minx) {
          newStartX = maxx;
        } else if (newStartX == maxx) {
          newStartX = minx;
        }
      }
      if (endY > maxy) {
        endX = startX + ((maxy - startY) * xdiff / ydiff);
        endY = maxy;
        newStartX = endX;
        newStartY = miny;
        if (newStartX == minx) {
          newStartX = maxx;
        } else if (newStartX == maxx) {
          newStartX = minx;
        }
      }
      if (endX < minx) {
        endX = minx;
        endY = (ydiff * (endX - startX)) / xdiff + startY;
        newStartX = maxx;
        newStartY = endY;
        if (newStartY == miny) {
          newStartY = maxy;
        } else if (newStartY == maxy) {
          newStartY = miny;
        }
      }
      if (endX > maxx) {
        endX = maxx;
        endY = (ydiff * (endX - startX)) / xdiff + startY;
        newStartX = minx;
        newStartY = endY;
        if (newStartY == miny) {
          newStartY = maxy;
        } else if (newStartY == maxy) {
          newStartY = miny;
        }
      }

      topology.drawLine(tg, startX, startY, endX, endY, penSize);

      distX -= (endX - startX);
      distY -= (endY - startY);

      startX = newStartX;
      startY = newStartY;

    } while (StrictMath.abs(distY) >= pixelSize || StrictMath.abs(distX) >= pixelSize);

    markDirty();
  }

  // View settings
  public int fontSize() {
    throw new UnsupportedOperationException();
  }

  public double patchSize() {
    return world.patchSize();
  }

  public double viewWidth() {
    return world.worldWidth();
  }

  public double viewHeight() {
    return world.worldHeight();
  }

  public org.nlogo.api.Perspective perspective() {
    throw new UnsupportedOperationException();
  }

  public double viewOffsetX() {
    throw new UnsupportedOperationException();
  }

  public double viewOffsetY() {
    throw new UnsupportedOperationException();
  }

  public boolean drawSpotlight() {
    throw new UnsupportedOperationException();
  }

  public boolean renderPerspective() {
    return false;
  }

  public boolean isHeadless() {
    throw new UnsupportedOperationException();
  }
}
TOP

Related Classes of org.nlogo.render.TrailDrawer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.