예제 #1
0
 /**
  * Creates the map's bounding box in real world coordinates.
  *
  * @param worldToScreen a transform which converts World coordinates to screen pixel coordinates.
  *     No assumptions are done on axis order as this is assumed to be pre-calculated. The affine
  *     transform may specify an rotation, in case the envelope will encompass the complete
  *     (rotated) world polygon.
  * @param paintArea the size of the rendering output area
  * @return the envelope in world coordinates corresponding to the screen rectangle.
  */
 public static Envelope createMapEnvelope(Rectangle paintArea, AffineTransform worldToScreen)
     throws NoninvertibleTransformException {
   //
   // (X1,Y1) (X2,Y1)
   //
   // (X1,Y2) (X2,Y2)
   double[] pts = new double[8];
   pts[0] = paintArea.getMinX();
   pts[1] = paintArea.getMinY();
   pts[2] = paintArea.getMaxX();
   pts[3] = paintArea.getMinY();
   pts[4] = paintArea.getMaxX();
   pts[5] = paintArea.getMaxY();
   pts[6] = paintArea.getMinX();
   pts[7] = paintArea.getMaxY();
   worldToScreen.inverseTransform(pts, 0, pts, 0, 4);
   double xMin = Double.MAX_VALUE;
   double yMin = Double.MAX_VALUE;
   double xMax = -Double.MAX_VALUE;
   double yMax = -Double.MAX_VALUE;
   for (int i = 0; i < 4; i++) {
     xMin = Math.min(xMin, pts[2 * i]);
     yMin = Math.min(yMin, pts[2 * i + 1]);
     xMax = Math.max(xMax, pts[2 * i]);
     yMax = Math.max(yMax, pts[2 * i + 1]);
   }
   return new Envelope(xMin, xMax, yMin, yMax);
 }
  /**
   * Clears the area of the tile on the graphics
   *
   * @param graphics graphics to draw onto
   * @param style raster symbolizer
   * @throws FactoryException
   * @throws TransformException
   * @throws RenderException
   */
  private void renderBlankTile(Graphics2D graphics, WMTTile tile, WMTRenderJob renderJob)
      throws Exception {

    if (tile == null) {
      return;
    }

    // get the bounds of the tile and convert to necessary viewport projection
    Envelope bnds = renderJob.projectTileToMapCrs(tile.getExtent());

    // determine screen coordinates of tiles
    Point upperLeft = getContext().worldToPixel(new Coordinate(bnds.getMinX(), bnds.getMinY()));
    Point bottomRight = getContext().worldToPixel(new Coordinate(bnds.getMaxX(), bnds.getMaxY()));
    Rectangle tileSize = new Rectangle(upperLeft);
    tileSize.add(bottomRight);

    // render
    try {
      graphics.setBackground(new Color(255, 255, 255, 0)); // set the tile transparent for now
      graphics.clearRect(tileSize.x, tileSize.y, tileSize.width, tileSize.height);

      if (TESTING) {
        /* for testing draw border around tiles */
        graphics.setColor(Color.BLACK);
        graphics.drawLine(
            (int) tileSize.getMinX(),
            (int) tileSize.getMinY(),
            (int) tileSize.getMinX(),
            (int) tileSize.getMaxY());
        graphics.drawLine(
            (int) tileSize.getMinX(),
            (int) tileSize.getMinY(),
            (int) tileSize.getMaxX(),
            (int) tileSize.getMinY());
        graphics.drawLine(
            (int) tileSize.getMaxX(),
            (int) tileSize.getMinY(),
            (int) tileSize.getMaxX(),
            (int) tileSize.getMaxY());
        graphics.drawLine(
            (int) tileSize.getMinX(),
            (int) tileSize.getMaxY(),
            (int) tileSize.getMaxX(),
            (int) tileSize.getMaxY());
      }
    } catch (Throwable t) {
      WMTPlugin.log("Error Rendering Blank tile. Painting Tile: " + tile.getId(), t); // $NON-NLS-1$
    }
  }
예제 #3
0
  public void paintEntityLayer(final int layer, final long timestamp, final Graphics g) {
    final int w = getWidth();
    final int h = getHeight();
    Rectangle gClip = g.getClipBounds();
    TRectangle wClip =
        new TRectangle(
            centerX + (gClip.getMinX() - w / 2) / scale,
            centerY + (gClip.getMinY() - h / 2) / scale,
            gClip.getWidth() / scale,
            gClip.getHeight() / scale);
    plane.eachEntity(
        wClip,
        layer << 1,
        (~layer << 1) & (0x7 << 1),
        new Iterated() {
          /** Position buffer */
          double[] pbuf = new double[3];

          @Override
          public void item(Object o) {
            AWTDrawableEntity e = (AWTDrawableEntity) o;
            e.getPosition(timestamp, pbuf);
            e.draw(
                (Graphics2D) g,
                (float) ((pbuf[0] - centerX) * scale + w / 2),
                (float) ((pbuf[1] - centerY) * scale + h / 2),
                (float) scale,
                (float) e.getRotation(timestamp),
                timestamp,
                layer);
          }
        });
  }
  public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
    int cellSize = world.getCellSize();
    double scrollPos = 0;
    if (orientation == SwingConstants.HORIZONTAL) {
      // scrolling left
      if (direction < 0) {
        scrollPos = visibleRect.getMinX();

      }
      // scrolling right
      else if (direction > 0) {
        scrollPos = visibleRect.getMaxX();
      }
    } else {
      // scrolling up
      if (direction < 0) {
        scrollPos = visibleRect.getMinY();
      }
      // scrolling down
      else if (direction > 0) {
        scrollPos = visibleRect.getMaxY();
      }
    }
    int increment = Math.abs((int) Math.IEEEremainder(scrollPos, cellSize));
    if (increment == 0) {
      increment = cellSize;
    }

    return increment;
  }
예제 #5
0
  public void mouseWheelMoved(MouseWheelEvent e) {
    if (isOSX) {
      return;
    }
    int notches = e.getWheelRotation();

    if (false) {
      if (notches < 0) {
        child.zoomToCursor(child.getPctZoom() * 21 / 20, e.getPoint());
      } else {
        child.zoomToCursor(child.getPctZoom() * 20 / 21, e.getPoint());
      }

      Component comp = container.getParent().getParent();
      if (comp instanceof MainPanel) ((MainPanel) comp).updateZoomCombo();
    }

    boolean horizontalScroll =
        ((e.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK)
            || ((e.getModifiers() & ActionEvent.META_MASK) == ActionEvent.META_MASK);

    Rectangle r = container.getViewport().getViewRect();
    int newx = Math.min((int) r.getMinX() + (horizontalScroll ? notches : 0), 0);
    int newy = Math.min((int) r.getMinY() + (horizontalScroll ? 0 : notches), 0);
    scrollTo(newx, newy);
  }
예제 #6
0
  public void paint(Graphics2D g, ChartFrame cf, Rectangle bounds) {
    Dataset ls = visibleDataset(cf, LS);

    if (ls != null) {
      Range range = cf.getSplitPanel().getChartPanel().getRange();

      g.setColor(properties.getColor());
      g.setStroke(properties.getStroke());

      double y = cf.getChartData().getY(range.getLowerBound(), bounds, range, false);
      g.draw(new Line2D.Double(bounds.getMinX(), y, bounds.getMaxX(), y));

      for (int i = 0; i < ls.getItemsCount(); i++) {
        if (ls.getDataItem(i) != null) {
          double x = cf.getChartData().getX(i, bounds);
          double y1 = cf.getChartData().getY(range.getLowerBound(), bounds, range, false);
          double y2 = cf.getChartData().getY(range.getUpperBound(), bounds, range, false);
          double w = cf.getChartProperties().getBarWidth();

          g.draw(new Line2D.Double(x - w / 2, y1, x, y2));
          g.draw(new Line2D.Double(x + w / 2, y1, x, y2));
        }
      }
    }
  }
예제 #7
0
  @Override
  public void mouseMoved(MouseEvent e) {

    if (this.selecting) {
      this.disable();
      if (e.getX() > selected.getMaxX() - 5
          && e.getX() < selected.getMaxX() + 5
          && e.getY() > selected.getMaxY() - 5
          && e.getY() < selected.getMaxY() + 5) {
        e.getComponent().setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
        curDir = DIR_SE;

      } else if (e.getX() == selected.getMinX()
          && (e.getY() < selected.getMaxY() && e.getY() > selected.getMinY())) {
        e.getComponent().setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
        curDir = DIR_W;
      } else if (e.getX() == selected.getMaxX()
          && (e.getY() < selected.getMaxY() && e.getY() > selected.getMinY())) {
        e.getComponent().setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
        curDir = DIR_E;
      } else if (e.getY() < selected.getMaxY() + 5
          && e.getY() > selected.getMaxY() - 5
          && (e.getX() < selected.getMaxX() && e.getX() > selected.getMinX())) {
        e.getComponent().setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));
        curDir = DIR_S;
      } else if (e.getY() == selected.getMinY()
          && (e.getX() < selected.getMaxX() && e.getX() > selected.getMinX())) {
        curDir = DIR_N;
        e.getComponent().setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
      } else if (e.getY() < selected.getCenterY() + 10
          && e.getY() > selected.getCenterY() - 10
          && (e.getX() < (selected.getCenterX() + 10) && e.getX() > selected.getCenterX() - 10)) {
        e.getComponent().setCursor(new Cursor(Cursor.MOVE_CURSOR));
        this.enable();

        curDir = NOP;
      } else {
        e.getComponent().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
        curDir = NOP;
      }
    } else {
      e.getComponent().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
      curDir = NOP;
    }
  }
  /**
   * Constructor creates an instance to be used for fill operations.
   *
   * @param shading the shading type to be used
   * @param colorModel the color model to be used
   * @param xform transformation for user to device space
   * @param matrix the pattern matrix concatenated with that of the parent content stream
   * @param deviceBounds the bounds of the area to paint, in device units
   * @throws IOException if there is an error getting the color space or doing color conversion.
   */
  public AxialShadingContext(
      PDShadingType2 shading,
      ColorModel colorModel,
      AffineTransform xform,
      Matrix matrix,
      Rectangle deviceBounds)
      throws IOException {
    super(shading, colorModel, xform, matrix);
    this.axialShadingType = shading;
    coords = shading.getCoords().toFloatArray();

    // domain values
    if (shading.getDomain() != null) {
      domain = shading.getDomain().toFloatArray();
    } else {
      // set default values
      domain = new float[] {0, 1};
    }
    // extend values
    COSArray extendValues = shading.getExtend();
    if (shading.getExtend() != null) {
      extend = new boolean[2];
      extend[0] = ((COSBoolean) extendValues.get(0)).getValue();
      extend[1] = ((COSBoolean) extendValues.get(1)).getValue();
    } else {
      // set default values
      extend = new boolean[] {false, false};
    }
    // calculate some constants to be used in getRaster
    x1x0 = coords[2] - coords[0];
    y1y0 = coords[3] - coords[1];
    d1d0 = domain[1] - domain[0];
    denom = Math.pow(x1x0, 2) + Math.pow(y1y0, 2);

    try {
      // get inverse transform to be independent of current user / device space
      // when handling actual pixels in getRaster()
      rat = matrix.createAffineTransform().createInverse();
      rat.concatenate(xform.createInverse());
    } catch (NoninvertibleTransformException ex) {
      LOG.error(ex, ex);
    }

    // shading space -> device space
    AffineTransform shadingToDevice = (AffineTransform) xform.clone();
    shadingToDevice.concatenate(matrix.createAffineTransform());

    // worst case for the number of steps is opposite diagonal corners, so use that
    double dist =
        Math.sqrt(
            Math.pow(deviceBounds.getMaxX() - deviceBounds.getMinX(), 2)
                + Math.pow(deviceBounds.getMaxY() - deviceBounds.getMinY(), 2));
    factor = (int) Math.ceil(dist);

    // build the color table for the given number of steps
    colorTable = calcColorTable();
  }
예제 #9
0
 public void mouseDragged(MouseEvent e) {
   Rectangle r = container.getViewport().getViewRect();
   final int stepSize = 10;
   int newx = (int) r.getMinX();
   int newy = (int) r.getMinY();
   // scroll when dragging out of view
   if (e.getX() > r.getMaxX()) {
     newx += stepSize;
   }
   if (e.getX() < r.getMinX()) {
     newx = Math.max(newx - stepSize, 0);
   }
   if (e.getY() > r.getMaxY()) {
     newy += stepSize;
   }
   if (e.getY() < r.getMinY()) {
     newy = Math.max(newy - stepSize, 0);
   }
   scrollTo(newx, newy);
   child.mouseMove(new SwingMouseEvent(e));
 }
예제 #10
0
파일: Timeline.java 프로젝트: emu1729/ows
  public void paint(Graphics g, Rectangle grid, int max) {
    g.setColor(getColor());

    double divisionSize = (double) grid.getWidth() / getSize();
    double currentLocation = grid.getMinX();
    Point formerLocation = new Point(0, 0);

    for (Integer point : timeline) {
      double x = currentLocation;
      double y = grid.getMaxY() - (double) (point) / max * grid.getHeight();

      g.fillOval(
          (int) (x - circleRadius), (int) (y - circleRadius), 2 * circleRadius, 2 * circleRadius);
      if (currentLocation != (int) grid.getMinX()) {
        g.drawLine((int) formerLocation.getX(), (int) formerLocation.getY(), (int) x, (int) y);
      }

      formerLocation.setLocation(x, y);
      currentLocation += divisionSize;
    }
  }
예제 #11
0
  private Point2D.Double checkInBounds(double newX, double newY) {

    if (!bounds.contains(newX, newY)) {
      if (bounds.getMinX() > newX) {
        newX = bounds.getMinX();
        newY = adjustBunnyWhenHit(180, newX, newY).getY();
      } else if (bounds.getMaxX() < newX) {
        newX = bounds.getMaxX();
        newY = adjustBunnyWhenHit(0, newX, newY).getY();
      }

      if (bounds.getMinY() > newY) {
        newY = bounds.getMinY();
        newX = adjustBunnyWhenHit(270, newX, newY).getX();
      } else if (bounds.getMaxY() < newY) {
        newY = bounds.getMaxY();
        newX = adjustBunnyWhenHit(90, newX, newY).getX();
      }
      orientation = fixOrientation(tempOrientation);
    }

    return (new Point2D.Double(newX, newY));
  }
예제 #12
0
  /**
   * Compute the bounding screen extent of a rotated rectangle.
   *
   * @param rect Rectangle to rotate.
   * @param x X coordinate of the rotation point.
   * @param y Y coordinate of the rotation point.
   * @param rotation Rotation angle.
   * @return The smallest rectangle that completely contains {@code rect} when rotated by the
   *     specified angle.
   */
  protected Rectangle computeRotatedScreenExtent(Rectangle rect, int x, int y, Angle rotation) {
    Rectangle r = new Rectangle(rect);

    // Translate the rectangle to the rotation point.
    r.translate(-x, -y);

    // Compute corner points
    Vec4[] corners = {
      new Vec4(r.getMaxX(), r.getMaxY()),
      new Vec4(r.getMaxX(), r.getMinY()),
      new Vec4(r.getMinX(), r.getMaxY()),
      new Vec4(r.getMinX(), r.getMinY())
    };

    // Rotate the rectangle
    Matrix rotationMatrix = Matrix.fromRotationZ(rotation);
    for (int i = 0; i < corners.length; i++) {
      corners[i] = corners[i].transformBy3(rotationMatrix);
    }

    // Find the bounding rectangle of rotated points.
    int minX = Integer.MAX_VALUE;
    int minY = Integer.MAX_VALUE;
    int maxX = -Integer.MAX_VALUE;
    int maxY = -Integer.MAX_VALUE;

    for (Vec4 v : corners) {
      if (v.x > maxX) maxX = (int) v.x;

      if (v.x < minX) minX = (int) v.x;

      if (v.y > maxY) maxY = (int) v.y;

      if (v.y < minY) minY = (int) v.y;
    }

    // Set bounds and translate the rectangle back to where it started.
    r.setBounds(minX, minY, maxX - minX, maxY - minY);
    r.translate(x, y);

    return r;
  }
예제 #13
0
  /**
   * Returns true if the specified region is visible in the specified {@link Graphics} object.<br>
   * Internally use the {@link Graphics} clip area to determine if region is visible.
   */
  public static boolean isVisible(Graphics g, Rectangle region) {
    if ((g == null) || (region == null)) return false;

    final Rectangle clipRegion = g.getClipBounds();

    // no clip region --> return true
    if (clipRegion == null) return true;

    if (region.width == 0) {
      // special case of single point region
      if (region.height == 0) return clipRegion.contains(region.x, region.y);
      else
        // special case of null width region
        return clipRegion.contains(region.x, region.getMinY())
            || clipRegion.contains(region.x, region.getMaxY());

    } else if (region.height == 0)
      // special case of null height region
      return clipRegion.contains(region.getMinX(), region.y)
          || clipRegion.contains(region.getMaxX(), region.y);
    else return clipRegion.intersects(region);
  }
예제 #14
0
  public void drawCollapsedMarker(int x, int y, int width, int height) {
    // rectangle
    int rectangleWidth = MARKER_WIDTH;
    int rectangleHeight = MARKER_WIDTH;
    Rectangle rect =
        new Rectangle(
            x + (width - rectangleWidth) / 2,
            y + height - rectangleHeight - 3,
            rectangleWidth,
            rectangleHeight);
    g.draw(rect);

    // plus inside rectangle
    Line2D.Double line =
        new Line2D.Double(
            rect.getCenterX(), rect.getY() + 2, rect.getCenterX(), rect.getMaxY() - 2);
    g.draw(line);
    line =
        new Line2D.Double(
            rect.getMinX() + 2, rect.getCenterY(), rect.getMaxX() - 2, rect.getCenterY());
    g.draw(line);
  }
예제 #15
0
  /**
   * Creates a master shape of the letter.
   *
   * @param shape
   * @return the master shape
   */
  private final Master createMaster(RenderContext ctx, Shape shape, double ascent) {
    final Area area = new Area(shape);
    final double scale = MASTER_HEIGHT / ascent;

    area.transform(AffineTransform.getScaleInstance(scale, scale));
    final Rectangle bounds = area.getBounds();
    // System.out.println("createMaster bounds " + bounds);
    // area.transform(AffineTransform.getTranslateInstance(-bounds.getMinX(),
    // -bounds.getMinY()));
    // bounds = area.getBounds();

    final int minX = (int) (bounds.getMinX() - 0.5);
    final int maxX = (int) (bounds.getMaxX() + 0.5);
    final int minY = (int) (bounds.getMinY() - 0.5);
    final int maxY = (int) (bounds.getMaxY() + 0.5);
    final int width = maxX - minX;
    final int height = maxY - minY;

    BitSet bits = (BitSet) ctx.getObject(BITS_NAME);
    if (bits == null) {
      bits = new BitSet(width * height);
      ctx.setObject(BITS_NAME, bits);
    } else {
      bits.clear();
    }
    int ofs = 0;
    for (int y = maxY; y > minY; y--) {
      for (int x = minX; x < maxX; x++) {
        if (area.contains(x, y)) {
          bits.set(ofs);
        }
        ofs++;
      }
    }

    return new Master(bits, width, height, minX, minY);
  }
예제 #16
0
 /**
  * Add a new rectangle to the collection. This includes adding its top and bottom coordinates to
  * the horizontal projection collection and its left and right coordinates to the vertical
  * projection collection, and adding the rectangle itself to every rectangle list between its
  * starting and ending coordinates.
  *
  * @param r the rectangle to add
  */
 public void add(Rectangle r) {
   this.vAllRect.addElement(r);
   this.treeHoriz = addRect(r, r.getMinY(), r.getMinY() + r.getHeight(), this.treeHoriz);
   this.treeVert = addRect(r, r.getMinX(), r.getMinX() + r.getWidth(), this.treeVert);
 }
  /*
   * (non-Javadoc)
   *
   * @see org.jvnet.flamingo.ribbon.ui.BasicRibbonUI#paintTaskArea(java.awt.
   * Graphics , int, int, int, int)
   */
  @Override
  protected void paintTaskArea(Graphics g, int x, int y, int width, int height) {
    if (this.ribbon.getTaskCount() == 0) return;

    Graphics2D g2d = (Graphics2D) g.create();

    RibbonTask selectedTask = this.ribbon.getSelectedTask();
    JRibbonTaskToggleButton selectedTaskButton = this.taskToggleButtons.get(selectedTask);
    Rectangle selectedTaskButtonBounds = selectedTaskButton.getBounds();
    Point converted =
        SwingUtilities.convertPoint(
            selectedTaskButton.getParent(), selectedTaskButtonBounds.getLocation(), this.ribbon);
    float radius =
        SubstanceSizeUtils.getClassicButtonCornerRadius(
            SubstanceSizeUtils.getComponentFontSize(this.ribbon));

    float borderDelta = SubstanceSizeUtils.getBorderStrokeWidth() / 2.0f;

    SubstanceBorderPainter borderPainter = SubstanceCoreUtilities.getBorderPainter(this.ribbon);
    float borderThickness = SubstanceSizeUtils.getBorderStrokeWidth();

    AbstractRibbonBand band = (selectedTask.getBandCount() == 0) ? null : selectedTask.getBand(0);
    SubstanceColorScheme borderScheme =
        SubstanceColorSchemeUtilities.getColorScheme(
            band, ColorSchemeAssociationKind.BORDER, ComponentState.ENABLED);

    Rectangle taskToggleButtonsViewportBounds =
        taskToggleButtonsScrollablePanel.getView().getParent().getBounds();
    taskToggleButtonsViewportBounds.setLocation(
        SwingUtilities.convertPoint(
            taskToggleButtonsScrollablePanel,
            taskToggleButtonsViewportBounds.getLocation(),
            this.ribbon));
    int startSelectedX = Math.max(converted.x + 1, (int) taskToggleButtonsViewportBounds.getMinX());
    startSelectedX = Math.min(startSelectedX, (int) taskToggleButtonsViewportBounds.getMaxX());
    int endSelectedX =
        Math.min(
            converted.x + selectedTaskButtonBounds.width - 1,
            (int) taskToggleButtonsViewportBounds.getMaxX());
    endSelectedX = Math.max(endSelectedX, (int) taskToggleButtonsViewportBounds.getMinX());

    Shape outerContour =
        RibbonBorderShaper.getRibbonBorderOutline(
            this.ribbon,
            x + borderDelta,
            x + width - borderDelta,
            startSelectedX - borderThickness,
            endSelectedX + borderThickness,
            converted.y + borderDelta,
            y + borderDelta,
            y + height - borderDelta,
            radius);

    Shape innerContour =
        RibbonBorderShaper.getRibbonBorderOutline(
            this.ribbon,
            x + borderDelta + borderThickness,
            x + width - borderThickness - borderDelta,
            startSelectedX - borderThickness,
            endSelectedX + borderThickness,
            converted.y + borderDelta + borderThickness,
            y + borderDelta + borderThickness,
            y + height - borderThickness - borderDelta,
            radius);

    g2d.setColor(
        SubstanceColorSchemeUtilities.getColorScheme(band, ComponentState.ENABLED)
            .getBackgroundFillColor());
    g2d.clipRect(x, y, width, height + 2);
    g2d.fill(outerContour);

    // g2d.setColor(Color.red);
    // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    // RenderingHints.VALUE_ANTIALIAS_ON);
    // g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
    // RenderingHints.VALUE_STROKE_PURE);
    // g2d.setStroke(new BasicStroke(0.5f));
    // g2d.draw(outerContour);
    // g2d.setColor(Color.blue);
    // g2d.draw(innerContour);
    borderPainter.paintBorder(
        g2d,
        this.ribbon,
        width,
        height + selectedTaskButtonBounds.height + 1,
        outerContour,
        innerContour,
        borderScheme);

    // check whether the currently selected task is a contextual task
    RibbonTask selected = selectedTask;
    RibbonContextualTaskGroup contextualGroup = selected.getContextualGroup();
    if (contextualGroup != null) {
      // paint a small gradient directly below the task area
      Insets ins = this.ribbon.getInsets();
      int topY = ins.top + getTaskbarHeight();
      int bottomY = topY + 5;
      Color hueColor = contextualGroup.getHueColor();
      Paint paint =
          new GradientPaint(
              0,
              topY,
              FlamingoUtilities.getAlphaColor(
                  hueColor, (int) (255 * RibbonContextualTaskGroup.HUE_ALPHA)),
              0,
              bottomY,
              FlamingoUtilities.getAlphaColor(hueColor, 0));
      g2d.setPaint(paint);
      g2d.clip(outerContour);
      g2d.fillRect(0, topY, width, bottomY - topY + 1);
    }

    // paint outlines of the contextual task groups
    // paintContextualTaskGroupsOutlines(g);

    g2d.dispose();
  }
  /**
   * Returns the specified property.
   *
   * @param name Property name.
   * @param opNode Operation node.
   */
  public Object getProperty(String name, Object opNode) {
    validate(name, opNode);

    if (opNode instanceof RenderedOp && name.equalsIgnoreCase("roi")) {
      RenderedOp op = (RenderedOp) opNode;

      ParameterBlock pb = op.getParameterBlock();

      // Retrieve the rendered source image and its ROI.
      RenderedImage src = pb.getRenderedSource(0);
      Object property = src.getProperty("ROI");
      if (property == null
          || property.equals(java.awt.Image.UndefinedProperty)
          || !(property instanceof ROI)) {
        return java.awt.Image.UndefinedProperty;
      }

      // Return undefined also if source ROI is empty.
      ROI srcROI = (ROI) property;
      if (srcROI.getBounds().isEmpty()) {
        return java.awt.Image.UndefinedProperty;
      }

      // Retrieve the Interpolation object.
      Interpolation interp = (Interpolation) pb.getObjectParameter(1);

      // Determine the effective source bounds.
      Rectangle srcBounds = null;
      PlanarImage dst = op.getRendering();
      if (dst instanceof GeometricOpImage && ((GeometricOpImage) dst).getBorderExtender() == null) {
        srcBounds =
            new Rectangle(
                src.getMinX() + interp.getLeftPadding(),
                src.getMinY() + interp.getTopPadding(),
                src.getWidth() - interp.getWidth() + 1,
                src.getHeight() - interp.getHeight() + 1);
      } else {
        srcBounds = new Rectangle(src.getMinX(), src.getMinY(), src.getWidth(), src.getHeight());
      }

      // If necessary, clip the ROI to the effective source bounds.
      if (!srcBounds.contains(srcROI.getBounds())) {
        srcROI = srcROI.intersect(new ROIShape(srcBounds));
      }

      // Retrieve the Warp object.
      Warp warp = (Warp) pb.getObjectParameter(0);

      // Setting constant image to be warped as a ROI
      Rectangle dstBounds = op.getBounds();

      // Setting layout of the constant image
      ImageLayout2 layout = new ImageLayout2();
      int minx = (int) srcBounds.getMinX();
      int miny = (int) srcBounds.getMinY();
      int w = (int) srcBounds.getWidth();
      int h = (int) srcBounds.getHeight();
      layout.setMinX(minx);
      layout.setMinY(miny);
      layout.setWidth(w);
      layout.setHeight(h);
      RenderingHints hints = op.getRenderingHints();
      hints.add(new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout));

      final PlanarImage constantImage =
          ConstantDescriptor.create(new Float(w), new Float(h), new Byte[] {(byte) 255}, hints);

      PlanarImage roiImage = null;

      // Make sure to specify tileCache, tileScheduler, tileRecyclier, by cloning hints.
      RenderingHints warpingHints = op.getRenderingHints();
      warpingHints.remove(JAI.KEY_IMAGE_LAYOUT);

      // Creating warped roi by the same way (Warp, Interpolation, source ROI) we warped the
      // input image.
      final ParameterBlock paramBlk = new ParameterBlock();
      paramBlk.addSource(constantImage);
      paramBlk.add(warp);
      paramBlk.add(interp);
      paramBlk.add(null);
      paramBlk.add(srcROI);

      // force in the image layout, this way we get exactly the same
      // as the affine we're eliminating
      Hints localHints = new Hints(op.getRenderingHints());
      localHints.remove(JAI.KEY_IMAGE_LAYOUT);
      ImageLayout il = new ImageLayout();
      il.setMinX(dstBounds.x);
      il.setMinY(dstBounds.y);
      il.setWidth(dstBounds.width);
      il.setHeight(dstBounds.height);
      localHints.put(JAI.KEY_IMAGE_LAYOUT, il);
      roiImage = JAI.create("Warp", paramBlk, localHints);
      ROI dstROI = new ROI(roiImage, 1);

      // If necessary, clip the warped ROI to the destination bounds.
      if (!dstBounds.contains(dstROI.getBounds())) {
        dstROI = dstROI.intersect(new ROIShape(dstBounds));
      }

      // Return the warped and possibly clipped ROI.
      return dstROI;
    }

    return java.awt.Image.UndefinedProperty;
  }
예제 #19
0
 /**
  * Hamming distance between two rectangles.
  *
  * @param r1 rectangle 1
  * @param r2 rectangle 2
  * @return Hamming distance between the top-left corner of the rectangles.
  */
 public double distance(Rectangle r1, Rectangle r2) {
   return Math.abs(r1.getMinY() - r2.getMinY()) + Math.abs(r1.getMinX() - r2.getMinX());
 }
예제 #20
0
  /**
   * Applies the band select operation to a grid coverage.
   *
   * @param cropEnvelope the target envelope; always not null
   * @param cropROI the target ROI shape; nullable
   * @param roiTolerance; as read from op's params
   * @param sourceCoverage is the source {@link GridCoverage2D} that we want to crop.
   * @param hints A set of rendering hints, or {@code null} if none.
   * @param sourceGridToWorldTransform is the 2d grid-to-world transform for the source coverage.
   * @return The result as a grid coverage.
   */
  private static GridCoverage2D buildResult(
      final GeneralEnvelope cropEnvelope,
      final Geometry cropROI,
      final double roiTolerance,
      final boolean forceMosaic,
      final Hints hints,
      final GridCoverage2D sourceCoverage,
      final AffineTransform sourceGridToWorldTransform) {

    //
    // Getting the source coverage and its child geolocation objects
    //
    final RenderedImage sourceImage = sourceCoverage.getRenderedImage();
    final GridGeometry2D sourceGridGeometry = ((GridGeometry2D) sourceCoverage.getGridGeometry());
    final GridEnvelope2D sourceGridRange = sourceGridGeometry.getGridRange2D();

    //
    // Now we try to understand if we have a simple scale and translate or a
    // more elaborated grid-to-world transformation n which case a simple
    // crop could not be enough, but we may need a more elaborated chain of
    // operation in order to do a good job. As an instance if we
    // have a rotation which is not multiple of PI/2 we have to use
    // the mosaic with a ROI
    //
    final boolean isSimpleTransform =
        CoverageUtilities.isSimpleGridToWorldTransform(sourceGridToWorldTransform, EPS);

    // Do we need to explode the Palette to RGB(A)?
    //
    int actionTaken = 0;

    // //
    //
    // Layout
    //
    // //
    final RenderingHints targetHints = new RenderingHints(null);
    if (hints != null) targetHints.add(hints);
    final ImageLayout layout = initLayout(sourceImage, targetHints);
    targetHints.put(JAI.KEY_IMAGE_LAYOUT, layout);

    //
    // prepare the processor to use for this operation
    //
    final JAI processor = OperationJAI.getJAI(targetHints);
    final boolean useProvidedProcessor = !processor.equals(JAI.getDefaultInstance());

    try {

      if (cropROI != null) {
        // replace the cropEnvelope with the envelope of the intersection
        // of the ROI and the cropEnvelope.
        // Remember that envelope(intersection(roi,cropEnvelope)) != intersection(cropEnvelope,
        // envelope(roi))
        final Polygon modelSpaceROI = FeatureUtilities.getPolygon(cropEnvelope, GFACTORY);
        Geometry intersection = IntersectUtils.intersection(cropROI, modelSpaceROI);
        Envelope2D e2d =
            JTS.getEnvelope2D(
                intersection.getEnvelopeInternal(), cropEnvelope.getCoordinateReferenceSystem());
        GeneralEnvelope ge = new GeneralEnvelope((org.opengis.geometry.Envelope) e2d);
        cropEnvelope.setEnvelope(ge);
      }

      // //
      //
      // Build the new range by keeping into
      // account translation of grid geometry constructor for respecting
      // OGC PIXEL-IS-CENTER ImageDatum assumption.
      //
      // //
      final AffineTransform sourceWorldToGridTransform = sourceGridToWorldTransform.createInverse();

      // //
      //
      // finalRasterArea will hold the smallest rectangular integer raster area that contains the
      // floating point raster
      // area which we obtain when applying the world-to-grid transform to the cropEnvelope. Note
      // that we need to intersect
      // such an area with the area covered by the source coverage in order to be sure we do not try
      // to crop outside the
      // bounds of the source raster.
      //
      // //
      final Rectangle2D finalRasterAreaDouble =
          XAffineTransform.transform(
              sourceWorldToGridTransform, cropEnvelope.toRectangle2D(), null);
      final Rectangle finalRasterArea = finalRasterAreaDouble.getBounds();

      // intersection with the original range in order to not try to crop outside the image bounds
      Rectangle.intersect(finalRasterArea, sourceGridRange, finalRasterArea);
      if (finalRasterArea.isEmpty())
        throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP));

      // //
      //
      // It is worth to point out that doing a crop the G2W transform
      // should not change while the envelope might change as
      // a consequence of the rounding of the underlying image datum
      // which uses integer factors or in case the G2W is very
      // complex. Note that we will always strive to
      // conserve the original grid-to-world transform.
      //
      // //

      // we do not have to crop in this case (should not really happen at
      // this time)
      if (finalRasterArea.equals(sourceGridRange) && isSimpleTransform && cropROI == null)
        return sourceCoverage;

      // //
      //
      // if I get here I have something to crop
      // using the world-to-grid transform for going from envelope to the
      // new grid range.
      //
      // //
      final double minX = finalRasterArea.getMinX();
      final double minY = finalRasterArea.getMinY();
      final double width = finalRasterArea.getWidth();
      final double height = finalRasterArea.getHeight();

      // //
      //
      // Check if we need to use mosaic or crop
      //
      // //
      final PlanarImage croppedImage;
      final ParameterBlock pbj = new ParameterBlock();
      pbj.addSource(sourceImage);
      java.awt.Polygon rasterSpaceROI = null;
      String operatioName = null;
      if (!isSimpleTransform || cropROI != null) {
        // /////////////////////////////////////////////////////////////////////
        //
        // We don't have a simple scale and translate transform, JAI
        // crop MAY NOT suffice. Let's decide whether or not we'll use
        // the Mosaic.
        //
        // /////////////////////////////////////////////////////////////////////
        Polygon modelSpaceROI = FeatureUtilities.getPolygon(cropEnvelope, GFACTORY);

        // //
        //
        // Now convert this polygon back into a shape for the source
        // raster space.
        //
        // //
        final List<Point2D> points = new ArrayList<Point2D>(5);
        rasterSpaceROI =
            FeatureUtilities.convertPolygonToPointArray(
                modelSpaceROI, ProjectiveTransform.create(sourceWorldToGridTransform), points);
        if (rasterSpaceROI == null || rasterSpaceROI.getBounds().isEmpty())
          if (finalRasterArea.isEmpty())
            throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP));
        final boolean doMosaic =
            forceMosaic
                ? true
                : decideJAIOperation(roiTolerance, rasterSpaceROI.getBounds2D(), points);
        if (doMosaic || cropROI != null) {
          // prepare the params for the mosaic
          final ROI[] roiarr;
          try {
            if (cropROI != null) {
              final LiteShape2 cropRoiLS2 =
                  new LiteShape2(
                      cropROI, ProjectiveTransform.create(sourceWorldToGridTransform), null, false);
              ROI cropRS = new ROIShape(cropRoiLS2);
              Rectangle2D rt = cropRoiLS2.getBounds2D();
              if (!hasIntegerBounds(rt)) {
                // Approximate Geometry
                Geometry geo = (Geometry) cropRoiLS2.getGeometry().clone();
                transformGeometry(geo);
                cropRS = new ROIShape(new LiteShape2(geo, null, null, false));
              }
              roiarr = new ROI[] {cropRS};
            } else {
              final ROIShape roi = new ROIShape(rasterSpaceROI);
              roiarr = new ROI[] {roi};
            }
          } catch (FactoryException ex) {
            throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP), ex);
          }
          pbj.add(MosaicDescriptor.MOSAIC_TYPE_OVERLAY);
          pbj.add(null);
          pbj.add(roiarr);
          pbj.add(null);
          pbj.add(CoverageUtilities.getBackgroundValues(sourceCoverage));

          // prepare the final layout
          final Rectangle bounds = rasterSpaceROI.getBounds2D().getBounds();
          Rectangle.intersect(bounds, sourceGridRange, bounds);
          if (bounds.isEmpty()) throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP));

          // we do not have to crop in this case (should not really happen at
          // this time)
          if (!doMosaic && bounds.getBounds().equals(sourceGridRange) && isSimpleTransform)
            return sourceCoverage;

          // nice trick, we use the layout to do the actual crop
          final Rectangle boundsInt = bounds.getBounds();
          layout.setMinX(boundsInt.x);
          layout.setWidth(boundsInt.width);
          layout.setMinY(boundsInt.y);
          layout.setHeight(boundsInt.height);
          operatioName = "Mosaic";
        }
      }

      // do we still have to set the operation name? If so that means we have to go for crop.
      if (operatioName == null) {
        // executing the crop
        pbj.add((float) minX);
        pbj.add((float) minY);
        pbj.add((float) width);
        pbj.add((float) height);
        operatioName = "GTCrop";
      }
      // //
      //
      // Apply operation
      //
      // //
      if (!useProvidedProcessor) {
        croppedImage = JAI.create(operatioName, pbj, targetHints);
      } else {
        croppedImage = processor.createNS(operatioName, pbj, targetHints);
      }

      // conserve the input grid to world transformation
      Map sourceProperties = sourceCoverage.getProperties();
      Map properties = null;
      if (sourceProperties != null && !sourceProperties.isEmpty()) {
        properties = new HashMap(sourceProperties);
      }
      if (rasterSpaceROI != null) {
        if (properties != null) {
          properties.put("GC_ROI", rasterSpaceROI);
        } else {
          properties = Collections.singletonMap("GC_ROI", rasterSpaceROI);
        }
      }

      return new GridCoverageFactory(hints)
          .create(
              sourceCoverage.getName(),
              croppedImage,
              new GridGeometry2D(
                  new GridEnvelope2D(croppedImage.getBounds()),
                  sourceGridGeometry.getGridToCRS2D(PixelOrientation.CENTER),
                  sourceCoverage.getCoordinateReferenceSystem()),
              (GridSampleDimension[])
                  (actionTaken == 1 ? null : sourceCoverage.getSampleDimensions().clone()),
              new GridCoverage[] {sourceCoverage},
              properties);

    } catch (TransformException e) {
      throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP), e);
    } catch (NoninvertibleTransformException e) {
      throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP), e);
    }
  }
예제 #21
0
  /**
   * Calculates an approximation of the tiles that are making up the building. Sets these tiles
   * values to the corresponding collision values.
   *
   * @param collsionMatrix The collision matrix that is modified
   */
  public void calculateCollision(int[][] collisionMatrix) {
    Rectangle rect = p.getBounds();
    int maxX, maxY, minX, minY;
    maxX = (int) rect.getMaxX();
    maxY = (int) rect.getMaxY();
    minX = (int) rect.getMinX();
    minY = (int) rect.getMinY();

    // If building is a building used for education - find the center of it and add an EDUCATION
    // node
    if (tag.equals(OSM_Reader.EDUCATION)) {
      createEducationCenter(collisionMatrix, (maxX - minX) / 2 + minX, (maxY - minY) / 2 + minY);
    }

    double distance;
    double[] minDistances = new double[targetsInside.size()];
    Arrays.fill(minDistances, Double.MAX_VALUE);
    LinkedList<int[]> closestNodes = new LinkedList<int[]>();
    // Initiate vector with edge points (closest to respective target point)
    for (int i = 0; i < targetsInside.size(); i++) {
      int[] temp = new int[2];
      closestNodes.add(temp);
    }

    // Go through each line of the building
    for (int y = minY; y <= maxY; y++) {
      // Are we inside of map bounds (y)
      if (Math.round(OSM_Reader.scaleCollision * y) >= 0
          && Math.round(OSM_Reader.scaleCollision * y) < collisionMatrix.length) {
        for (int x = minX; x <= maxX; x++) {
          // Are we inside of map bounds (x)
          if (Math.round(OSM_Reader.scaleCollision * x) >= 0
              && Math.round(OSM_Reader.scaleCollision * x) < collisionMatrix.length) {
            // Is this point inside of the building? (and has no previous cost value)
            if (p.contains(x, y)
                && collisionMatrix[Math.round(OSM_Reader.scaleCollision * x)][
                        Math.round(OSM_Reader.scaleCollision * y)]
                    == 0) {
              collisionMatrix[Math.round(OSM_Reader.scaleCollision * x)][
                      Math.round(OSM_Reader.scaleCollision * y)] =
                  cost;

              // On the edge of the building
              if (!p.contains(x - 1, y) || !p.contains(x + 1, y)) {
                Node node;
                // Go through all targets that are inside of the building
                for (int i = 0; i < targetsInside.size(); i++) {
                  node = targetsInside.get(i);

                  // Calculate the Euclidean distance from target to edge
                  distance =
                      Math.sqrt(Math.pow(node.getXPos() - x, 2) + Math.pow(node.getYPos() - y, 2));

                  // Check if target is closer to this edge point
                  if (minDistances[i] > distance) {
                    minDistances[i] = distance;
                    closestNodes.get(i)[0] = x;
                    closestNodes.get(i)[1] = y;
                  }
                }
              }
            }
          }
        }
      }
    }
    createEntranceWays(collisionMatrix, closestNodes);
  }
  /**
   * @see net.refractions.udig.render.internal.wmsc.basic#renderTile(Graphics2D graphics, WMTTile
   *     tile, CoordinateReferenceSystem crs, RasterSymbolizer style)
   * @param graphics
   * @param tile
   * @param style
   * @throws FactoryException
   * @throws TransformException
   * @throws RenderException
   */
  private void renderTile(
      Graphics2D graphics, WMTTile tile, RasterSymbolizer style, WMTRenderJob renderJob)
      throws Exception {

    if (tile == null || tile.getBufferedImage() == null) {
      return;
    }

    // create a gridcoverage from the tile image
    GridCoverageFactory factory = new GridCoverageFactory();

    // get the tile bounds in the CRS the tiles were drawn in
    ReferencedEnvelope tileBndsMercatorRef =
        renderJob.projectTileToTileProjectedCrs(tile.getExtent());

    GridCoverage2D coverage =
        (GridCoverage2D)
            factory.create(
                "GridCoverage", tile.getBufferedImage(), tileBndsMercatorRef); // $NON-NLS-1$

    Envelope2D coveragebounds = coverage.getEnvelope2D();

    // bounds of tile
    ReferencedEnvelope bnds =
        new ReferencedEnvelope(
            coveragebounds.getMinX(),
            coveragebounds.getMaxX(),
            coveragebounds.getMinY(),
            coveragebounds.getMaxY(),
            renderJob.getCrsTilesProjected());

    // reproject tile bounds to map CRS
    bnds = renderJob.projectTileProjectedToMapCrs(bnds);

    // determine screen coordinates of tiles
    Point upperLeft = getContext().worldToPixel(new Coordinate(bnds.getMinX(), bnds.getMinY()));
    Point bottomRight = getContext().worldToPixel(new Coordinate(bnds.getMaxX(), bnds.getMaxY()));
    Rectangle tileSize = new Rectangle(upperLeft);
    tileSize.add(bottomRight);

    // render
    try {
      CoordinateReferenceSystem crs = getContext().getCRS();
      AffineTransform worldToScreen = RendererUtilities.worldToScreenTransform(bnds, tileSize, crs);
      GridCoverageRenderer paint = new GridCoverageRenderer(crs, bnds, tileSize, worldToScreen);

      paint.paint(graphics, coverage, style);

      if (TESTING) {
        //            if(true){
        /* for testing draw border around tiles */
        graphics.setColor(Color.BLACK);
        graphics.drawLine(
            (int) tileSize.getMinX(),
            (int) tileSize.getMinY(),
            (int) tileSize.getMinX(),
            (int) tileSize.getMaxY());
        graphics.drawLine(
            (int) tileSize.getMinX(),
            (int) tileSize.getMinY(),
            (int) tileSize.getMaxX(),
            (int) tileSize.getMinY());
        graphics.drawLine(
            (int) tileSize.getMaxX(),
            (int) tileSize.getMinY(),
            (int) tileSize.getMaxX(),
            (int) tileSize.getMaxY());
        graphics.drawLine(
            (int) tileSize.getMinX(),
            (int) tileSize.getMaxY(),
            (int) tileSize.getMaxX(),
            (int) tileSize.getMaxY());
        graphics.drawString(
            tile.getId(), ((int) tileSize.getMaxX() - 113), ((int) tileSize.getMaxY() - 113));
      }
    } catch (Throwable t) {
      WMTPlugin.log("Error Rendering tile. Painting Tile " + tile.getId(), t); // $NON-NLS-1$
    }
  }
예제 #23
0
  /** Resets the annotations appearance stream. */
  public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) {

    matrix = new AffineTransform();
    shapes = new Shapes();

    // setup the AP stream.
    setModifiedDate(PDate.formatDateTime(new Date()));
    // refresh rectangle
    rectangle = getUserSpaceRectangle().getBounds();
    entries.put(Annotation.RECTANGLE_KEY, PRectangle.getPRectangleVector(rectangle));
    userSpaceRectangle =
        new Rectangle2D.Float(
            (float) rectangle.getX(), (float) rectangle.getY(),
            (float) rectangle.getWidth(), (float) rectangle.getHeight());

    int strokeWidth = (int) borderStyle.getStrokeWidth();
    Rectangle rectangleToDraw =
        new Rectangle(
            (int) rectangle.getX() + strokeWidth,
            (int) rectangle.getY() + strokeWidth,
            (int) rectangle.getWidth() - strokeWidth * 2,
            (int) rectangle.getHeight() - strokeWidth * 2);

    // setup the space for the AP content stream.
    AffineTransform af = new AffineTransform();
    af.scale(1, -1);
    af.translate(-this.bbox.getMinX(), -this.bbox.getMaxY());

    BasicStroke stroke;
    if (borderStyle.isStyleDashed()) {
      stroke =
          new BasicStroke(
              borderStyle.getStrokeWidth(),
              BasicStroke.CAP_BUTT,
              BasicStroke.JOIN_MITER,
              borderStyle.getStrokeWidth() * 2.0f,
              borderStyle.getDashArray(),
              0.0f);
    } else {
      stroke = new BasicStroke(borderStyle.getStrokeWidth());
    }

    Ellipse2D.Double circle =
        new Ellipse2D.Double(
            rectangleToDraw.getMinX(),
            rectangleToDraw.getMinY(),
            rectangleToDraw.getWidth(),
            rectangleToDraw.getHeight());

    shapes.add(new TransformDrawCmd(af));
    shapes.add(new StrokeDrawCmd(stroke));
    shapes.add(new ShapeDrawCmd(circle));
    if (isFillColor) {
      shapes.add(new ColorDrawCmd(fillColor));
      shapes.add(new FillDrawCmd());
    }
    if (borderStyle.getStrokeWidth() > 0) {
      shapes.add(new ColorDrawCmd(color));
      shapes.add(new DrawDrawCmd());
    }

    // update the appearance stream
    // create/update the appearance stream of the xObject.
    StateManager stateManager = library.getStateManager();
    Form form;
    if (hasAppearanceStream()) {
      form = (Form) getAppearanceStream();
      // else a stream, we won't support this for annotations.
    } else {
      // create a new xobject/form object
      HashMap formEntries = new HashMap();
      formEntries.put(Form.TYPE_KEY, Form.TYPE_VALUE);
      formEntries.put(Form.SUBTYPE_KEY, Form.SUB_TYPE_VALUE);
      form = new Form(library, formEntries, null);
      form.setPObjectReference(stateManager.getNewReferencNumber());
      library.addObject(form, form.getPObjectReference());
    }

    if (form != null) {
      Rectangle2D formBbox =
          new Rectangle2D.Float(0, 0, (float) bbox.getWidth(), (float) bbox.getHeight());
      form.setAppearance(shapes, matrix, formBbox);
      stateManager.addChange(new PObject(form, form.getPObjectReference()));
      // update the AP's stream bytes so contents can be written out
      form.setRawBytes(PostScriptEncoder.generatePostScript(shapes.getShapes()));
      HashMap appearanceRefs = new HashMap();
      appearanceRefs.put(APPEARANCE_STREAM_NORMAL_KEY, form.getPObjectReference());
      entries.put(APPEARANCE_STREAM_KEY, appearanceRefs);

      // compress the form object stream.
      if (compressAppearanceStream) {
        form.getEntries().put(Stream.FILTER_KEY, new Name("FlateDecode"));
      } else {
        form.getEntries().remove(Stream.FILTER_KEY);
      }
    }
  }
  /**
   * Method to update cells according to the changes that have been applied. Cells are drawn in
   * respect to the centre point.
   */
  public void updateDrawings() {
    // re-create graphical display, as a dynamic display
    display = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
    graphicsDisplay = (Graphics2D) display.createGraphics();
    graphicsDisplay.setPaint(Color.white);
    graphicsDisplay.fillRect(0, 0, display.getWidth(), display.getHeight());

    Point2D.Double robotDrawPos =
        getVisualLoc(
            new Point2D.Double(
                robotPos.getX(),
                robotPos.getY())); // get robot's position to determine origin or draw later
    if (followRobot
        == true) // if the display is following the robot, draw the robot in the centre of the
                 // display
    {
      shiftX = (int) (Math.round((displayCentre.getX() - robotDrawPos.getX()) / 10) * 10);
      shiftY = (int) (Math.round((displayCentre.getY() - robotDrawPos.getY()) / 10) * 10);
      robotDrawPos =
          displayCentre; // change robot drawing position to the centre point of the display
    } else {
      // otherwise no shifts
      shiftX = 0;
      shiftY = 0;
    }
    // update cell graphics
    Map<Point2D.Double, Cell> cells = mapLink.getCells();
    Iterator<Point2D.Double> i = cells.keySet().iterator();
    if (enabledSelection) {
      selectedCellKeys.clear();
    }
    while (i.hasNext()) {
      Point2D.Double key = i.next(); // obtain the next cell key
      Cell cell = cells.get(key); // obtain the cell
      boolean hasChanged = false;
      boolean newCell = false;
      CellGraphic cellWob;
      try {
        cellWob = cellDrawings.get(key); // try to obtain the current drawing
      } catch (
          NullPointerException
              e) // if no drawing has been assigned, ensure the graphic is set to null
      {
        cellWob = null;
        newCell = true; // set flag to indicate that this is a  new cell
      }

      if (cellWob == null) {
        newCell = true;
      }
      switch (cell
          .getState()) // compare the actual cell state with what cell state is being displayed
      {
        case CLEAN: // if the actual cell is clean and either the cell is incorrectly displayed or
                    // has no graphic
          {
            if (newCell == true || !(cellWob instanceof CleanCellGfx)) {
              cellWob = new CleanCellGfx(this);
              hasChanged = true;
            }
            break;
          }
        case UNCLEAN: // if the actual cell is unclean and either the cell is incorrectly displayed
                      // or has no graphic
          {
            if (newCell == true || !(cellWob instanceof UncleanCellGfx)) {
              cellWob = new UncleanCellGfx(this);
              hasChanged = true;
            }
            break;
          }
        case HALFCLEAN: // if the actual cell is half-clean and either the cell is incorrectly
                        // displayed or has no graphic
          {
            if (newCell == true || !(cellWob instanceof HalfCleanCellGfx)) {
              cellWob = new HalfCleanCellGfx(this);
              hasChanged = true;
            }
            break;
          }
        case CLOSED: // if the actual cell is closed and either the cell is incorrectly displayed or
                     // has no graphic
          {
            if (newCell == true || !(cellWob instanceof ClosedCellGfx)) {
              cellWob = new ClosedCellGfx(this);
              hasChanged = true;
            }
            break;
          }
      }

      // if the cell is new or it has changed state
      if (newCell == true || hasChanged == true) {
        cellDrawings.put(key, cellWob); // place or update the graphic in the hashmap
      }

      if (enabledSelection
          && cell.getState() != CellState.CLOSED
          && cellWob.getX() >= selectedRegion.getMinX()
          && cellWob.getX() <= selectedRegion.getMaxX()
          && cellWob.getY() >= selectedRegion.getMinY()
          && cellWob.getY() <= selectedRegion.getMaxY()) {
        cellWob.toggleSelected(true);
        selectedCellKeys.add(key);
      } else {
        cellWob.toggleSelected(false);
      }
      Point2D.Double graphPos = getVisualLoc(new Point2D.Double(cell.getXVal(), cell.getYVal()));
      // set x and y values, already tested casting to int in getPixelLoc
      int x = (int) graphPos.getX();
      int y = (int) graphPos.getY();
      cellWob.setLocation(x + shiftX, y + shiftY); // assign location of the graphic
      cellWob.paint(graphicsDisplay);
    }
    // update robot drawing, on top of cells
    graphicsDisplay.drawImage(
        robotWob,
        (int) robotDrawPos.getX(),
        (int) robotDrawPos.getY(),
        (int) cellUnitWidth,
        (int) cellUnitHeight,
        this);

    graphicsDisplay.dispose();
  }