Package org.nlogo.render

Source Code of org.nlogo.render.CachedShape

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

package org.nlogo.render;

import org.nlogo.api.Graphics2DWrapper;
import org.nlogo.api.GraphicsInterface;
import org.nlogo.shape.VectorShape;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

// A lot of the code in this file is for the turtle shape cache.  The
// purpose of the cache is to speed up rendering of turtles.  We need
// to draw the same turtle shapes over and over again.  Instead of
// re-rendering the shape from scratch every time, we render it once,
// ahead of time, to a small offscreen buffer, and then when we need
// to draw it again, we can just copy the buffer to the screen.  The
// more complicated the shape is, the bigger the speedup this gets us.

// The whole caching thing gets a bit complicated because we can't
// cache an unlimited amount of bitmaps.  So we need to expire old
// entries, we only cache certain turtle sizes, etc.

public strictfp class TurtleShapeManager {
  // only cache this many pixels.  this is arbitrary.  it's a speed
  // vs. memory usage tradeoff.
  private static final int MAX_CACHE_PIXELS = 1024 * 1024 * 2;

  // this determines to what extent we ignore small changes in angle.
  // (It's a ratio because the bigger the patch size, the finer distinctions
  // will be visible.)
  private static final int ANGLE_STEP_RATIO = 30;

  private final java.util.Queue<CacheKey> cacheQueue =
      new LinkedList<CacheKey>();
  private final Map<CacheKey, CachedShape> shapeCache =
      new HashMap<CacheKey, CachedShape>();
  final org.nlogo.api.ShapeList shapeList;

  private int cellSize;
  private int pixelCount = 0// measured in pixels
  private int angleStep;
  private int numAngleSteps;

  TurtleShapeManager(org.nlogo.api.ShapeList shapeList) {
    this.shapeList = shapeList;
  }

  public int cacheSize() {
    return shapeCache.size();
  }

  public String getCacheReport() {
    return "shapes " + shapeCache.size() + " pixels " + pixelCount + " angleStep " + angleStep;
  }

  void resetCache(double patchSize) {
    shapeCache.clear();
    cacheQueue.clear();
    pixelCount = 0;
    cellSize = (int) StrictMath.floor(patchSize);
    if (cellSize == 0) {
      angleStep = 1;
    } else {
      angleStep = ANGLE_STEP_RATIO / cellSize;
      if (angleStep == 0) {
        angleStep = 1;
      }
    }
    numAngleSteps = 360 / angleStep;
  }

  boolean useCache(org.nlogo.api.Turtle turtle, double patchSize) {
    // ideally we'd be smart enough to cache
    // any size, but for now let's just cache
    // a few frequently used sizes - ST 1/6/05
    double turtleSize = turtle.size();
    return patchSize == cellSize &&
        (turtleSize == 1.0 ||
            turtleSize == 1.5 ||
            turtleSize == 2.0) &&
        turtle.lineThickness() == 0.0;
  }

  VectorShape getShape(org.nlogo.api.Turtle turtle) {
    return (VectorShape) shapeList.shape(turtle.shape());
  }

  CachedShape getCachedShape(VectorShape shape, java.awt.Color color,
                             double angle, double size) {
    int angleIndex;

    if (shape.isRotatable()) {
      angleIndex = (int) StrictMath.rint(angle / angleStep);
      if (angleIndex == numAngleSteps) {
        angleIndex = 0;
      }
      angle = angleIndex * angleStep;
    } else {
      angleIndex = 0;
      angle = 0.0;
    }
    CacheKey key = new CacheKey(color.getRGB(), angleIndex, shape, size);
    CachedShape cached = shapeCache.get(key);
    if (cached != null) {
      return cached;
    }
    // remove the oldest item in cache so the size stays constant
    while (pixelCount >= MAX_CACHE_PIXELS) {
      discardOldestShape();
    }
    CachedShape newShape =
        new CachedShape(shape, cellSize, (int) angle, size, color);
    shapeCache.put(key, newShape);
    cacheQueue.add(key);
    pixelCount += newShape.getPixelCount();
    return newShape;
  }

  private void discardOldestShape() {
    CacheKey oldKey = cacheQueue.remove();
    pixelCount -= shapeCache.get(oldKey).getPixelCount();
    shapeCache.remove(oldKey);
  }
}

// this might be temporary I'm going to try to make VectorShape a Drawable
// we'll see.
class VectorShapeDrawable
    implements Drawable {
  private final VectorShape shape;
  private final int heading;
  private final double lineThickness;
  private final double patchSize;
  private final java.awt.Color color;
  private final double turtleSize;

  VectorShapeDrawable(VectorShape shape, java.awt.Color color, double patchSize, int heading,
                      double lineThickness, double turtleSize) {
    this.shape = shape;
    this.heading = heading;
    this.lineThickness = lineThickness;
    this.patchSize = patchSize;
    this.color = color;
    this.turtleSize = turtleSize;
  }

  public void draw(GraphicsInterface g, double size) {
    shape.paint
        (g, color, 0, 0, turtleSize, patchSize, heading, lineThickness);
  }

  public double adjustSize(double turtleSize, double patchSize) {
    return 0;
  }
}

strictfp class CachedShape
    implements Drawable {
  private final java.awt.image.BufferedImage image;
  private final int imageSize; // in pixels, e.g. 5 if 5x5 (note 5 not 25)

  CachedShape(VectorShape shape, int cellSize, int angle,
              double turtleSize, java.awt.Color color) {
    imageSize = (cellSize * (int) StrictMath.ceil(turtleSize));

    image = new java.awt.image.BufferedImage
        (imageSize, imageSize,
            java.awt.image.BufferedImage.TYPE_INT_ARGB);
    Graphics2DWrapper g = new Graphics2DWrapper((java.awt.Graphics2D) image.getGraphics());
    g.antiAliasing(true);
    try {
      shape.paint(g, color, 0, 0, turtleSize, cellSize, angle, 0.0);
    } finally {
      g.dispose();
    }
  }

  public void draw(GraphicsInterface g, double size) {
    g.drawImage(image);
  }

  public double adjustSize(double turtleSize, double patchSize) {
    return 0;
  }

  int getPixelCount() {
    return imageSize * imageSize;
  }
}
TOP

Related Classes of org.nlogo.render.CachedShape

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.