Exemplo n.º 1
1
 private void calculateGridTranslation() {
   if (transformCells.getScaleX() >= SHOW_GRID_MIN_SCALE) {
     @SuppressWarnings("SuspiciousNameCombination")
     double modX = Math.floorMod(round(transformCells.getTranslateX()), cellWidth);
     double modY = Math.floorMod(round(transformCells.getTranslateY()), cellHeight);
     transformGrid.setToTranslation(-cellWidth + modX - 1, -cellHeight + modY - 1);
   }
 }
Exemplo n.º 2
0
  /**
   * Iterates through the Page's Boxes, drawing to the provided Graphics object
   *
   * @see java.awt.print.Printable#print(java.awt.Graphics, java.awt.print.PageFormat, int)
   */
  public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
      throws PrinterException {

    if (pageIndex >= 1) {
      return Printable.NO_SUCH_PAGE;
    }

    Graphics2D graphics2d = (Graphics2D) graphics;

    AffineTransform at = graphics2d.getTransform();
    double dpi = at.getScaleX() * 72;

    if (PrintingPlugin.isDebugging(TRACE_PRINTING)) {
      PrintingPlugin.log("Printing page " + pageIndex, null); // $NON-NLS-1$
      System.out.println("PageFormat: " + pageFormat); // $NON-NLS-1$
      System.out.println("PageFormat height: " + pageFormat.getHeight()); // $NON-NLS-1$
      System.out.println("PageFormat width: " + pageFormat.getWidth()); // $NON-NLS-1$
      System.out.println(
          "PageFormat imageableX,Y "
              + pageFormat.getImageableX()
              + ", "
              + pageFormat.getImageableY()); // $NON-NLS-1$ //$NON-NLS-2$
      System.out.println(
          "PageFormat imageable height: " + pageFormat.getImageableHeight()); // $NON-NLS-1$
      System.out.println(
          "PageFormat imageable width: " + pageFormat.getImageableWidth()); // $NON-NLS-1$
      System.out.println(
          "PageFormat orientation (LANDSCAPE="
              + PageFormat.LANDSCAPE
              + ", PORTRAIT="
              + PageFormat.PORTRAIT
              + "): "
              + pageFormat.getOrientation()); // $NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$

      System.out.println("Graphics: clip bounds: " + graphics2d.getClipBounds()); // $NON-NLS-1$
      System.out.println("Transform: scaleX: " + at.getScaleX()); // $NON-NLS-1$
      System.out.println("Transform: scaleY: " + at.getScaleY()); // $NON-NLS-1$
      System.out.println("DPI?? : " + dpi); // $NON-NLS-1$
    }

    graphics2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());

    Iterator<Box> iter = diagram.getBoxes().iterator();
    while (iter.hasNext()) {

      Box box = iter.next();
      graphics2d =
          (Graphics2D)
              graphics.create(
                  box.getLocation().x,
                  box.getLocation().y,
                  box.getSize().width,
                  box.getSize().height);

      box.getBoxPrinter().draw(graphics2d, monitor);
    }

    return Printable.PAGE_EXISTS;
  }
Exemplo n.º 3
0
  /**
   * @param ls
   * @param at
   * @param generalize
   * @param maxDistance
   */
  public void init(LineString ls, AffineTransform at, boolean generalize, float maxDistance) {
    _init(ls, at, generalize, maxDistance);

    xScale =
        (float) Math.sqrt((at.getScaleX() * at.getScaleX()) + (at.getShearX() * at.getShearX()));
    yScale =
        (float) Math.sqrt((at.getScaleY() * at.getScaleY()) + (at.getShearY() * at.getShearY()));
  }
Exemplo n.º 4
0
  @Override
  public void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2d = ((Graphics2D) g);
    g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
    g2d.setRenderingHint(
        RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
    g2d.setRenderingHint(
        RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
    g2d.setRenderingHint(
        RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
    g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
    g2d.setColor(Color.BLACK);
    g2d.fillRect(0, 0, getWidth(), getHeight());

    if (bufferedImage != null) {
      synchronized (LOCKER) {
        g2d.drawImage(bufferedImage, transformCells, null);
      }
    }
    // draw struct preview
    if (structurePreview != null) {
      Composite composite = g2d.getComposite();
      g2d.setComposite(compositeStructPreview);
      g2d.drawImage(structurePreview, previewTransform, null);
      g2d.setComposite(composite);
    }
    // draw grid
    if (transformCells.getScaleX() > SHOW_GRID_MIN_SCALE) {
      Composite composite = g2d.getComposite();
      g2d.setComposite(compositeGrid);
      g2d.drawImage(bufferedImageGrid, transformGrid, null);
      g2d.setComposite(composite);
    }
    // draw border for preview
    if (structurePreview != null && Math.abs(transformCells.getScaleX()) >= 0.95) {
      Shape shape = new Rectangle(0, 0, structurePreview.getWidth(), structurePreview.getHeight());
      shape = previewTransform.createTransformedShape(shape);
      g2d.setColor(Color.RED);
      g2d.draw(shape);
    }

    // draw border
    double x = transformCells.getTranslateX();
    double y = transformCells.getTranslateY();

    g2d.setColor(BORDER_COLOR);
    g2d.setStroke(new BasicStroke(BORDER_WIDTH));
    g2d.drawRect(
        round(x - BORDER_WIDTH),
        round(y - BORDER_WIDTH),
        round(getAutomatonWidth() * transformCells.getScaleX() + 2 * BORDER_WIDTH),
        round(getAutomatonHeight() * transformCells.getScaleY() + 2 * BORDER_WIDTH));
  }
  TexturePaintContext(ColorModel cm, AffineTransform xform, int bWidth, int bHeight, int maxw) {
    this.colorModel = getInternedColorModel(cm);
    this.bWidth = bWidth;
    this.bHeight = bHeight;
    this.maxWidth = maxw;

    try {
      xform = xform.createInverse();
    } catch (NoninvertibleTransformException e) {
      xform.setToScale(0, 0);
    }
    this.incXAcross = mod(xform.getScaleX(), bWidth);
    this.incYAcross = mod(xform.getShearY(), bHeight);
    this.incXDown = mod(xform.getShearX(), bWidth);
    this.incYDown = mod(xform.getScaleY(), bHeight);
    this.xOrg = xform.getTranslateX();
    this.yOrg = xform.getTranslateY();
    this.colincx = (int) incXAcross;
    this.colincy = (int) incYAcross;
    this.colincxerr = fractAsInt(incXAcross);
    this.colincyerr = fractAsInt(incYAcross);
    this.rowincx = (int) incXDown;
    this.rowincy = (int) incYDown;
    this.rowincxerr = fractAsInt(incXDown);
    this.rowincyerr = fractAsInt(incYDown);
  }
Exemplo n.º 6
0
  /**
   * Cuando soltamos el botón del ratón desplazamos la imagen a la posición de destino calculando el
   * extent nuevamente.
   */
  public void mouseReleased(MouseEvent e) throws BehaviorException {
    if (!isActiveTool()) return;
    if (e.getButton() == MouseEvent.BUTTON1 && isMoveable) {
      FLyrRasterSE lyr = grBehavior.getLayer();
      if (lyr == null) return;

      ViewPort vp = grBehavior.getMapControl().getMapContext().getViewPort();
      ptoFin = vp.toMapPoint(e.getPoint());

      // Asignamos la nueva matriz de transformación a la capa
      AffineTransform atOld = lyr.getAffineTransform();
      AffineTransform atNew = null;

      double distX = ptoFin.getX() - ptoIni.getX();
      double distY = ptoFin.getY() - ptoIni.getY();

      // La nueva matriz de transformación es la vieja más la distancia desplazada
      atNew =
          new AffineTransform(
              atOld.getScaleX(),
              atOld.getShearY(),
              atOld.getShearX(),
              atOld.getScaleY(),
              atOld.getTranslateX() + distX,
              atOld.getTranslateY() + distY);
      lyr.setAffineTransform(atNew);

      grBehavior.getMapControl().getMapContext().invalidate();
      isMoveable = false;
      super.mouseReleased(e);
    }
  }
Exemplo n.º 7
0
  public void init(Graphics2D g, float scale, int width, int height) {
    if (this.METRICS == null) {
      AffineTransform transform = g.getTransform();
      if (Double.compare(transform.getScaleX(), 1) != 0
          || Double.compare(transform.getScaleY(), 1) != 0) {
        throw new IllegalStateException("Illegal Transform");
      }

      this.METRICS = new FontMetrics[FONTS.length];
      Font defaultFont = g.getFont();
      for (int i = 0; i < FONTS.length; i++) {
        g.setFont(FONTS[i]);
        this.METRICS[i] = g.getFontMetrics();
      }
      g.setFont(defaultFont);
    }

    this.g = g;
    this.scale = scale;
    this.screen.width = width;
    this.screen.height = height;
    this.lapList.clear();
    this.fixedLabelMap.clear();

    this.r = (int) (2 / this.scale + 0.5);
    this.r2 = (int) (4 / this.scale + 0.5);
  }
Exemplo n.º 8
0
  /**
   * Applique une translation à la perspective selon le mouvement de la souris par rapport au centre
   * de l'image.
   *
   * @param coordSouris Les coordonnées de la souris.
   */
  public void translate(double[] coordSouris) {

    double largeur;
    double hauteur;

    // Garde en mémoire la transformation courant
    pileTransform.push(new AffineTransform(transformation));

    // Calcul des dimensions après le zoom
    largeur =
        panneauSource.getImagePlus().getWidth()
            * panneauSource.getImagePlus().getPerspective().getTransformation().getScaleX();
    hauteur =
        panneauSource.getImagePlus().getHeight()
            * panneauSource.getImagePlus().getPerspective().getTransformation().getScaleY();

    // Déplacement de la perspective selon la position de la souris.
    transformation.setTransform(
        transformation.getScaleX(),
        0,
        0,
        transformation.getScaleY(),
        coordSouris[0] - (largeur / 2),
        coordSouris[1] - (hauteur / 2));

    setChanged();
    notifyObservers();
  }
Exemplo n.º 9
0
 private Rectangle getScaledRectangle(Rectangle rectangle) {
   final AffineTransform i2mTransform =
       ImageManager.getImageToModelTransform(product.getGeoCoding());
   final double scaleX = i2mTransform.getScaleX();
   final double scaleY = i2mTransform.getScaleY();
   double scaleFactorY = Math.abs(scaleY / scaleX);
   final AffineTransform scaleTransform = AffineTransform.getScaleInstance(1.0, scaleFactorY);
   return scaleTransform.createTransformedShape(rectangle).getBounds();
 }
Exemplo n.º 10
0
 public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
   paintFrame(c, g, x, y);
   if (c != null) {
     int w = getIconWidth();
     int h = getIconHeight();
     AffineTransform tx = ((Graphics2D) g).getTransform();
     w = (int) (w * tx.getScaleX());
     h = (int) (h * tx.getScaleY());
     registerRepaintArea(c, x, y, w, h);
   }
 }
Exemplo n.º 11
0
  /**
   * Synchronize the scrollbar with the image. If the transform is out of range, it will correct it.
   * This function considers only following factors :<b> transform, image size, client area</b>.
   */
  public void syncScrollBars() {
    if (sourceImage == null) {
      redraw();
      return;
    }

    AffineTransform af = transform;
    double sx = af.getScaleX(), sy = af.getScaleY();
    double tx = af.getTranslateX(), ty = af.getTranslateY();
    if (tx > 0) tx = 0;
    if (ty > 0) ty = 0;

    ScrollBar horizontal = getHorizontalBar();
    horizontal.setIncrement((int) (getClientArea().width / 20));
    horizontal.setPageIncrement(getClientArea().width);
    Rectangle imageBound = sourceImage.getBounds();
    int cw = getClientArea().width, ch = getClientArea().height;
    if (imageBound.width * sx > cw) {
        /* image is wider than client area */
      horizontal.setMaximum((int) (imageBound.width * sx));
      horizontal.setEnabled(true);
      if (((int) -tx) > horizontal.getMaximum() - cw) tx = -horizontal.getMaximum() + cw;
    } else {
        /* image is narrower than client area */
      horizontal.setEnabled(false);
      tx = (cw - imageBound.width * sx) / 2; // center if too small.
    }
    horizontal.setSelection((int) (-tx));
    horizontal.setThumb((int) (getClientArea().width));

    ScrollBar vertical = getVerticalBar();
    vertical.setIncrement((int) (getClientArea().height / 20));
    vertical.setPageIncrement((int) (getClientArea().height));
    if (imageBound.height * sy > ch) {
        /* image is higher than client area */
      vertical.setMaximum((int) (imageBound.height * sy));
      vertical.setEnabled(true);
      if (((int) -ty) > vertical.getMaximum() - ch) ty = -vertical.getMaximum() + ch;
    } else {
        /* image is less higher than client area */
      vertical.setEnabled(false);
      ty = (ch - imageBound.height * sy) / 2; // center if too small.
    }
    vertical.setSelection((int) (-ty));
    vertical.setThumb((int) (getClientArea().height));

    /* update transform. */
    af = AffineTransform.getScaleInstance(sx, sy);
    af.preConcatenate(AffineTransform.getTranslateInstance(tx, ty));
    transform = af;

    redraw();
  }
Exemplo n.º 12
0
  private void handleZoom(double zoom) {
    final int scaleFactor = 1;
    final double accelerationFactor = 0.05;
    final double scaleZoom = 0.25;
    final double scaleFactorDown = 0.8;

    zoom = scaleZoom * -zoom;
    zoom += 1;

    transformCells.translate(zoomCenterX, zoomCenterY);
    double newScale = transformCells.getScaleX();

    int acceleration = round(newScale * accelerationFactor);
    if (zoom > 1) {
      if (transformCells.getScaleX() > 0.95) {
        newScale = (newScale + scaleFactor + acceleration) / newScale;
      } else {
        newScale = 1 / scaleFactorDown;
      }
    } else if (zoom < 1) {
      if (transformCells.getScaleX() > 1.05) {
        newScale = (newScale - scaleFactor - acceleration) / newScale;
      } else {
        newScale = scaleFactorDown;
      }
    }

    if (transformCells.getScaleX() * newScale >= MIN_SCALE
        && transformCells.getScaleX() * newScale <= MAX_SCALE) {
      transformCells.scale(newScale, newScale);
    }
    transformCells.translate(-zoomCenterX, -zoomCenterY);

    if (previewTransform != null) {
      calculatePreviewTranslation();
    }

    bufferedImageGrid = createGrid();
    repaint();
  }
Exemplo n.º 13
0
 /** Asigna las coordenadas temporales en el dialogo. */
 public void assignTransformToDialog() {
   AffineTransform atNew = null;
   double distX = ptoFin.getX() - ptoIni.getX();
   double distY = ptoFin.getY() - ptoIni.getY();
   AffineTransform atOld = grBehavior.getLayer().getAffineTransform();
   // La nueva matriz de transformación es la vieja más la distancia desplazada
   atNew =
       new AffineTransform(
           atOld.getScaleX(),
           atOld.getShearY(),
           atOld.getShearX(),
           atOld.getScaleY(),
           atOld.getTranslateX() + distX,
           atOld.getTranslateY() + distY);
   trIO.loadTransform(atNew);
 }
Exemplo n.º 14
0
  public synchronized void paint(Graphics gin) {
    Graphics2D g = (Graphics2D) gin;

    if (im == null) return;

    int height = getHeight();
    int width = getWidth();

    if (fit) {
      t = new AffineTransform();
      double scale = Math.min(((double) width) / im.getWidth(), ((double) height) / im.getHeight());
      // we'll re-center the transform in a moment.
      t.scale(scale, scale);
    }

    // if the image (in either X or Y) is smaller than the view port, then center
    // the image with respect to that axis.
    double mwidth = im.getWidth() * t.getScaleX();
    double mheight = im.getHeight() * t.getScaleY();
    if (mwidth < width)
      t.preConcatenate(
          AffineTransform.getTranslateInstance((width - mwidth) / 2.0 - t.getTranslateX(), 0));
    if (mheight < height)
      t.preConcatenate(
          AffineTransform.getTranslateInstance(0, (height - mheight) / 2.0 - t.getTranslateY()));

    // if we're allowing panning (because only a portion of the image is visible),
    // don't allow translations that show less information that is possible.
    Point2D topleft = t.transform(new Point2D.Double(0, 0), null);
    Point2D bottomright = t.transform(new Point2D.Double(im.getWidth(), im.getHeight()), null);

    if (mwidth > width) {
      if (topleft.getX() > 0)
        t.preConcatenate(AffineTransform.getTranslateInstance(-topleft.getX(), 0));
      if (bottomright.getX() < width)
        t.preConcatenate(AffineTransform.getTranslateInstance(width - bottomright.getX(), 0));
      //		    t.translate(width-bottomright.getX(), 0);
    }
    if (mheight > height) {
      if (topleft.getY() > 0)
        t.preConcatenate(AffineTransform.getTranslateInstance(0, -topleft.getY()));
      if (bottomright.getY() < height)
        t.preConcatenate(AffineTransform.getTranslateInstance(0, height - bottomright.getY()));
    }

    g.drawImage(im, t, null);
  }
Exemplo n.º 15
0
 /**
  * Scales current view point transformation.
  *
  * @param sx Amount to scale by along the x axis.
  * @param sy Amount to scale by along the y axis.
  * @param isLast Flag, indicating that this scale is last in sequence of arbitrary view point
  *     operations.
  * @throws Exception
  */
 public void scaleView(double sx, double sy, boolean isLast) throws Exception {
   recalcViewPoint();
   double targetScaleX = cartesian2Screen.getScaleX() * sx;
   double targetScaleY = cartesian2Screen.getScaleY() * sy;
   if (targetScaleX >= SCALE_MIN_BOUNDARY
       && targetScaleX <= SCALE_MAX_BOUNDARY
       && targetScaleY >= SCALE_MIN_BOUNDARY
       && targetScaleY <= SCALE_MAX_BOUNDARY) {
     cartesian2Screen.scale(sx, sy);
     cache.scaleChanged();
     lightweightCache.scaleChanged();
     if (isLast) {
       invalidate();
       fireViewScaled(sx, sy, aoiToGeoGeometry(), aoiToCartesianGeometry());
     }
   }
 }
Exemplo n.º 16
0
  @Override
  public FGEArea transform(AffineTransform t) {
    // TODO: not valid for AffineTransform containing rotations

    FGEPoint p1 = (new FGEPoint(getX(), getY())).transform(t);
    FGEPoint p2 = (new FGEPoint(getX() + getWidth(), getY() + getHeight())).transform(t);

    // TODO: if transformation contains a rotation, turn into a regular polygon
    // arcwidth,archeight must also be computed according to this rotation

    return new FGERoundRectangle(
        Math.min(p1.x, p2.x),
        Math.min(p1.y, p2.y),
        Math.abs(p1.x - p2.x),
        Math.abs(p1.y - p2.y),
        arcwidth * t.getScaleX(),
        archeight * t.getScaleY(),
        _filling);
  }
Exemplo n.º 17
0
  public void mouseDragged(MouseEvent e) {
    if (e.getModifiers() == modifiers) {
      Point2D pEndScale = e.getPoint();

      double scale = pEndScale.distance(viewOrigin) / pStartScale.distance(viewOrigin);

      AffineTransform transform = super.plot.getTransform();
      transform.setTransform(
          transform.getScaleX() * scale,
          transform.getShearY(),
          transform.getShearX(),
          transform.getScaleY() * scale,
          transform.getTranslateX() * scale,
          transform.getTranslateY() * scale);

      pStartScale = pEndScale;
      super.plot.setTransform(transform);
    }
  }
Exemplo n.º 18
0
  public void draw(Graphics2D g2, float x, float y) {
    AffineTransform transf = g2.getTransform();
    Stroke oldStroke = g2.getStroke();

    final double sx = transf.getScaleX();
    final double sy = transf.getScaleY();
    double s = 1;
    if (sx == sy) {
      // There are rounding problems due to scale factor: lines could have different
      // spacing...
      // So the increment (space+thickness) is done in using integer.
      s = sx;
      AffineTransform t = (AffineTransform) transf.clone();
      t.scale(1 / sx, 1 / sy);
      g2.setTransform(t);
    }

    g2.setStroke(
        new BasicStroke((float) (s * thickness), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
    float th = thickness / 2.f;
    final Line2D.Float line = new Line2D.Float();
    float xx = x + space;
    xx = (float) (xx * s + (space / 2.f) * s);
    final int inc = (int) Math.round((space + thickness) * s);

    for (int i = 0; i < N; i++) {
      line.setLine(xx + th * s, (y - height) * s, xx + th * s, y * s);
      g2.draw(line);
      xx += inc;
    }

    if (strike) {

      line.setLine(
          (x + space) * s, (y - height / 2.f) * s, xx - s * space / 2, (y - height / 2.f) * s);
      g2.draw(line);
    }

    g2.setTransform(transf);
    g2.setStroke(oldStroke);
  }
  void setModelTransformation(final AffineTransform gridToCRS) {
    // See pag 28 of the spec for an explanation
    final double[] modelTransformation = new double[16];
    modelTransformation[0] = gridToCRS.getScaleX();
    modelTransformation[1] = gridToCRS.getShearX();
    modelTransformation[2] = 0;
    modelTransformation[3] = gridToCRS.getTranslateX();
    modelTransformation[4] = gridToCRS.getShearY();
    modelTransformation[5] = gridToCRS.getScaleY();
    modelTransformation[6] = 0;
    modelTransformation[7] = gridToCRS.getTranslateY();
    modelTransformation[8] = 0;
    modelTransformation[9] = 0;
    modelTransformation[10] = 0;
    modelTransformation[11] = 0;
    modelTransformation[12] = 0;
    modelTransformation[13] = 0;
    modelTransformation[14] = 0;
    modelTransformation[15] = 1;

    nTransform = createTiffField(getModelTransformationTag());
    final Node nValues = createTiffDoubles(modelTransformation);
    nTransform.appendChild(nValues);
  }
  /**
   * 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 ctm the transformation matrix
   * @param dBounds device bounds
   * @param pageHeight height of the current page
   */
  public RadialShadingContext(
      PDShadingType3 shading,
      ColorModel colorModel,
      AffineTransform xform,
      Matrix ctm,
      int pageHeight,
      Rectangle dBounds)
      throws IOException {
    super(shading, colorModel, xform, ctm, pageHeight, dBounds);
    this.radialShadingType = shading;
    coords = shading.getCoords().toFloatArray();

    if (ctm != null) {
      // the shading is used in combination with the sh-operator
      // transform the coords from shading to user space
      ctm.createAffineTransform().transform(coords, 0, coords, 0, 1);
      ctm.createAffineTransform().transform(coords, 3, coords, 3, 1);
      // scale radius to user space
      coords[2] *= ctm.getXScale();
      coords[5] *= ctm.getXScale();

      // move the 0,0-reference
      coords[1] = pageHeight - coords[1];
      coords[4] = pageHeight - coords[4];
    } else {
      // the shading is used as pattern colorspace in combination
      // with a fill-, stroke- or showText-operator
      float translateY = (float) xform.getTranslateY();
      // move the 0,0-reference including the y-translation from user to device space
      coords[1] = pageHeight + translateY - coords[1];
      coords[4] = pageHeight + translateY - coords[4];
    }

    // transform the coords from user to device space
    xform.transform(coords, 0, coords, 0, 1);
    xform.transform(coords, 3, coords, 3, 1);

    // scale radius to device space
    coords[2] *= xform.getScaleX();
    coords[5] *= xform.getScaleX();

    // a radius is always positive
    coords[2] = Math.abs(coords[2]);
    coords[5] = Math.abs(coords[5]);

    // domain values
    if (this.radialShadingType.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[3] - coords[0];
    y1y0 = coords[4] - coords[1];
    r1r0 = coords[5] - coords[2];
    x1x0pow2 = Math.pow(x1x0, 2);
    y1y0pow2 = Math.pow(y1y0, 2);
    r0pow2 = Math.pow(coords[2], 2);
    denom = x1x0pow2 + y1y0pow2 - Math.pow(r1r0, 2);
    d1d0 = domain[1] - domain[0];

    // get background values if available
    COSArray bg = shading.getBackground();
    if (bg != null) {
      background = bg.toFloatArray();
      rgbBackground = convertToRGB(background);
    }
    longestDistance = getLongestDis();
    colorTable = calcColorTable();
  }
Exemplo n.º 21
0
  /**
   * Applique un zoom à la perspective selon la direction de la molette.
   *
   * @param facteurZoom La direction de la molette.
   */
  public void zoom(double wheelRotation) {

    /*
     * Pour conserver le zoom centrer, on doit d'abord déplacer le coin
     * supérieur gauche vers le centre, appliquer le zoom, puis revenir
     * vers la position originale. En utilisant la variation de dimension
     * avant et après le zoom, l'image ne reviendra pas exactement à sa
     * position originale, s'ajustant ainsi proportionnellement au zoom
     * appliqué.
     */

    double largeur;
    double hauteur;

    // Garde en mémoire la transformation courant
    pileTransform.push(new AffineTransform(transformation));

    zoom = 1;
    zoom += (.1 * -wheelRotation);

    // Calcul des dimensions avant le zoom
    largeur =
        panneauSource.getImagePlus().getWidth()
            * panneauSource.getImagePlus().getPerspective().getTransformation().getScaleX();
    hauteur =
        panneauSource.getImagePlus().getHeight()
            * panneauSource.getImagePlus().getPerspective().getTransformation().getScaleY();

    /* On translate l'image vers le centre.
    A noter que d'utiliser translate ou setToTranslate ne donne pas le
    résultat escompté en raison du "state" ou du fonctionnement un
    peu anodin du mutateur. */
    transformation.setTransform(
        transformation.getScaleX(),
        0,
        0,
        transformation.getScaleY(),
        transformation.getTranslateX() + largeur / 2,
        transformation.getTranslateY() + hauteur / 2);

    // On applique le zoom
    transformation.scale(zoom, zoom);

    // Calcul des dimensions après le zoom
    largeur =
        panneauSource.getImagePlus().getWidth()
            * panneauSource.getImagePlus().getPerspective().getTransformation().getScaleX();
    hauteur =
        panneauSource.getImagePlus().getHeight()
            * panneauSource.getImagePlus().getPerspective().getTransformation().getScaleY();

    /* On translate l'image vers sa position d'origine.
    A noter que d'utiliser translate ou setToTranslate ne donne pas le
    résultat escompté en raison du "state" ou du fonctionnement un
    peu anodin du mutateur. */
    transformation.setTransform(
        transformation.getScaleX(),
        0,
        0,
        transformation.getScaleY(),
        transformation.getTranslateX() - largeur / 2,
        transformation.getTranslateY() - hauteur / 2);

    setChanged();
    notifyObservers();
  }
Exemplo n.º 22
0
 private Point2D getCellSizeAfterScale() {
   return new Point2D.Double(round(transformCells.getScaleX()), round(transformCells.getScaleY()));
 }
Exemplo n.º 23
0
  /**
   * DOCUMENT ME!
   *
   * @param graphics DOCUMENT ME!
   * @param shape DOCUMENT ME!
   * @param style DOCUMENT ME!
   */
  public static void drawShape(Graphics2D graphics, Shape shape, Style2D style) {
    if (style instanceof MarkStyle2D) {
      // get the point onto the shape has to be painted
      float[] coords = new float[2];
      PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
      iter.currentSegment(coords);

      MarkStyle2D ms2d = (MarkStyle2D) style;
      Shape transformedShape = ms2d.getTransformedShape(coords[0], coords[1]);

      if (transformedShape != null) {
        if (ms2d.getFill() != null) {
          graphics.setPaint(ms2d.getFill());
          graphics.setComposite(ms2d.getFillComposite());
          graphics.fill(transformedShape);
        }

        if (ms2d.getContour() != null) {
          graphics.setPaint(ms2d.getContour());
          graphics.setStroke(ms2d.getStroke());
          graphics.setComposite(ms2d.getContourComposite());
          graphics.draw(transformedShape);
        }
      }
    } else if (style instanceof GraphicStyle2D) {
      // get the point onto the shape has to be painted
      float[] coords = new float[2];
      PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
      iter.currentSegment(coords);

      GraphicStyle2D gs2d = (GraphicStyle2D) style;

      renderImage(
          graphics,
          coords[0],
          coords[1],
          (Image) gs2d.getImage(),
          gs2d.getRotation(),
          gs2d.getOpacity());
    } else if (style instanceof TextStyle2D) {
      // get the point onto the shape has to be painted
      float[] coords = new float[2];
      PathIterator iter = shape.getPathIterator(IDENTITY_TRANSFORM);
      iter.currentSegment(coords);

      AffineTransform old = graphics.getTransform();
      AffineTransform temp = new AffineTransform(old);
      TextStyle2D ts2d = (TextStyle2D) style;
      GlyphVector textGv = ts2d.getTextGlyphVector(graphics);
      Rectangle2D bounds = textGv.getVisualBounds();

      temp.translate(coords[0], coords[1]);

      double x = 0;
      double y = 0;

      x = (ts2d.getAnchorX() * (-bounds.getWidth())) + ts2d.getDisplacementX();
      y = (ts2d.getAnchorY() * (bounds.getHeight())) + ts2d.getDisplacementY();

      temp.rotate(ts2d.getRotation());
      temp.translate(x, y);

      graphics.setTransform(temp);

      if (ts2d.getHaloFill() != null) {
        float radious = ts2d.getHaloRadius();

        // graphics.translate(radious, -radious);
        graphics.setPaint(ts2d.getHaloFill());
        graphics.setComposite(ts2d.getHaloComposite());
        graphics.fill(ts2d.getHaloShape(graphics));

        // graphics.translate(radious, radious);
      }

      if (ts2d.getFill() != null) {
        graphics.setPaint(ts2d.getFill());
        graphics.setComposite(ts2d.getComposite());
        graphics.drawGlyphVector(textGv, 0, 0);
      }

      graphics.setTransform(old);
    } else {
      // if the style is a polygon one, process it even if the polyline is
      // not
      // closed (by SLD specification)
      if (style instanceof PolygonStyle2D) {
        PolygonStyle2D ps2d = (PolygonStyle2D) style;

        if (ps2d.getFill() != null) {
          Paint paint = ps2d.getFill();

          if (paint instanceof TexturePaint) {
            TexturePaint tp = (TexturePaint) paint;
            BufferedImage image = tp.getImage();
            Rectangle2D rect = tp.getAnchorRect();
            AffineTransform at = graphics.getTransform();
            double width = rect.getWidth() * at.getScaleX();
            double height = rect.getHeight() * at.getScaleY();
            Rectangle2D scaledRect = new Rectangle2D.Double(0, 0, width, height);
            paint = new TexturePaint(image, scaledRect);
          }

          graphics.setPaint(paint);
          graphics.setComposite(ps2d.getFillComposite());
          graphics.fill(shape);
        }
      }

      if (style instanceof LineStyle2D) {
        LineStyle2D ls2d = (LineStyle2D) style;

        if (ls2d.getStroke() != null) {
          // see if a graphic stroke is to be used, the drawing method
          // is completely
          // different in this case
          Paint paint = ls2d.getContour();

          if (paint instanceof TexturePaint) {
            TexturePaint tp = (TexturePaint) paint;
            BufferedImage image = tp.getImage();
            Rectangle2D rect = tp.getAnchorRect();
            AffineTransform at = graphics.getTransform();
            double width = rect.getWidth() * at.getScaleX();
            double height = rect.getHeight() * at.getScaleY();
            Rectangle2D scaledRect = new Rectangle2D.Double(0, 0, width, height);
            paint = new TexturePaint(image, scaledRect);
          }

          graphics.setPaint(paint);
          graphics.setStroke(ls2d.getStroke());
          graphics.setComposite(ls2d.getContourComposite());
          graphics.draw(shape);
        }
      }
    }
  }
Exemplo n.º 24
0
 public int getCollisionRadius() {
   return (int) (scale.getScaleX() * getRadius());
 }
Exemplo n.º 25
0
  /**
   * Invoked automatically when a polyline is about to be draw. This implementation paints the
   * polyline according to the rendered style
   *
   * @param graphics The graphics in which to draw.
   * @param shape The polygon to draw.
   * @param style The style to apply, or <code>null</code> if none.
   * @param scale The scale denominator for the current zoom level
   * @throws FactoryException
   * @throws TransformException
   */
  public void paint(
      final Graphics2D graphics,
      final LiteShape2 shape,
      final Style2D style,
      final double scale,
      boolean isLabelObstacle) {
    if (style == null) {
      // TODO: what's going on? Should not be reached...
      LOGGER.severe("ShapePainter has been asked to paint a null style!!");

      return;
    }

    // Is the current scale within the style scale range?
    if (!style.isScaleInRange(scale)) {
      LOGGER.fine("Out of scale");
      return;
    }

    if (style instanceof IconStyle2D) {
      AffineTransform temp = graphics.getTransform();
      try {
        IconStyle2D icoStyle = (IconStyle2D) style;
        Icon icon = icoStyle.getIcon();
        graphics.setComposite(icoStyle.getComposite());

        // the displacement to be applied to all points, centers the icon and applies the
        // Graphic displacement as well
        float dx = icoStyle.getDisplacementX();
        float dy = icoStyle.getDisplacementY();

        // iterate over all points
        float[] coords = new float[2];
        PathIterator citer = getPathIterator(shape);
        AffineTransform at = new AffineTransform(temp);
        while (!(citer.isDone())) {
          if (citer.currentSegment(coords) != PathIterator.SEG_MOVETO) {
            at.setTransform(temp);

            double x = coords[0] + dx;
            double y = coords[1] + dy;
            at.translate(x, y);
            at.rotate(icoStyle.getRotation());
            at.translate(
                -(icon.getIconWidth() * icoStyle.getAnchorPointX()),
                (icon.getIconHeight() * (icoStyle.getAnchorPointY() - 1)));
            graphics.setTransform(at);

            icon.paintIcon(null, graphics, 0, 0);

            if (isLabelObstacle) {
              // TODO: rotation?
              labelCache.put(
                  new Rectangle2D.Double(x, y, icon.getIconWidth(), icon.getIconHeight()));
            }
          }
          citer.next();
        }
      } finally {
        graphics.setTransform(temp);
      }
    } else if (style instanceof MarkStyle2D) {
      PathIterator citer = getPathIterator(shape);

      // get the point onto the shape has to be painted
      float[] coords = new float[2];
      MarkStyle2D ms2d = (MarkStyle2D) style;

      Shape transformedShape;
      while (!(citer.isDone())) {
        if (citer.currentSegment(coords) != PathIterator.SEG_MOVETO) {
          transformedShape = ms2d.getTransformedShape(coords[0], coords[1]);
          if (transformedShape != null) {
            if (ms2d.getFill() != null) {
              graphics.setPaint(ms2d.getFill());
              graphics.setComposite(ms2d.getFillComposite());
              graphics.fill(transformedShape);
            }

            if (ms2d.getContour() != null) {
              graphics.setPaint(ms2d.getContour());
              graphics.setStroke(ms2d.getStroke());
              graphics.setComposite(ms2d.getContourComposite());
              graphics.draw(transformedShape);
            }

            if (isLabelObstacle) {
              labelCache.put(transformedShape.getBounds2D());
            }
          }
        }
        citer.next();
      }
    } else if (style instanceof GraphicStyle2D) {
      float[] coords = new float[2];
      PathIterator iter = getPathIterator(shape);
      iter.currentSegment(coords);

      GraphicStyle2D gs2d = (GraphicStyle2D) style;

      BufferedImage image = gs2d.getImage();
      double dx = gs2d.getDisplacementX() - gs2d.getAnchorPointX() * image.getWidth();
      double dy = gs2d.getDisplacementY() - ((1 - gs2d.getAnchorPointY()) * image.getHeight());
      while (!(iter.isDone())) {
        if (iter.currentSegment(coords) != PathIterator.SEG_MOVETO) {
          renderImage(
              graphics,
              coords[0],
              coords[1],
              dx,
              dy,
              image,
              gs2d.getRotation(),
              gs2d.getComposite(),
              isLabelObstacle);
        }
        iter.next();
      }
    } else {
      if (isLabelObstacle) {
        labelCache.put(shape.getBounds2D());
      }
      // if the style is a polygon one, process it even if the polyline is
      // not closed (by SLD specification)
      if (style instanceof PolygonStyle2D) {
        PolygonStyle2D ps2d = (PolygonStyle2D) style;

        if (ps2d.getFill() != null) {
          Paint paint = ps2d.getFill();

          if (paint instanceof TexturePaint) {
            TexturePaint tp = (TexturePaint) paint;
            BufferedImage image = tp.getImage();
            Rectangle2D cornerRect = tp.getAnchorRect();
            Point2D anchorPoint = (Point2D) graphics.getRenderingHint(TEXTURE_ANCHOR_HINT_KEY);
            Rectangle2D alignedRect = null;
            if (anchorPoint != null) {
              alignedRect =
                  new Rectangle2D.Double(
                      Math.round(anchorPoint.getX()),
                      Math.round(anchorPoint.getY()),
                      cornerRect.getWidth(),
                      cornerRect.getHeight());
            } else {
              alignedRect =
                  new Rectangle2D.Double(0.0, 0.0, cornerRect.getWidth(), cornerRect.getHeight());
            }
            paint = new TexturePaint(image, alignedRect);
          }

          graphics.setPaint(paint);
          graphics.setComposite(ps2d.getFillComposite());
          fillLiteShape(graphics, shape);
        }
        if (ps2d.getGraphicFill() != null) {
          Shape oldClip = graphics.getClip();
          try {
            paintGraphicFill(graphics, shape, ps2d.getGraphicFill(), scale);
          } finally {
            graphics.setClip(oldClip);
          }
        }
      }

      if (style instanceof LineStyle2D) {
        LineStyle2D ls2d = (LineStyle2D) style;

        if (ls2d.getStroke() != null) {
          // see if a graphic stroke is to be used, the drawing method
          // is completely
          // different in this case
          if (ls2d.getGraphicStroke() != null) {
            drawWithGraphicsStroke(
                graphics,
                dashShape(shape, ls2d.getStroke()),
                ls2d.getGraphicStroke(),
                isLabelObstacle);
          } else {
            Paint paint = ls2d.getContour();

            if (paint instanceof TexturePaint) {
              TexturePaint tp = (TexturePaint) paint;
              BufferedImage image = tp.getImage();
              Rectangle2D rect = tp.getAnchorRect();
              AffineTransform at = graphics.getTransform();
              double width = rect.getWidth() * at.getScaleX();
              double height = rect.getHeight() * at.getScaleY();
              Rectangle2D scaledRect = new Rectangle2D.Double(0, 0, width, height);
              paint = new TexturePaint(image, scaledRect);
            }

            // debugShape(shape);
            Stroke stroke = ls2d.getStroke();
            if (graphics.getRenderingHint(RenderingHints.KEY_ANTIALIASING)
                == RenderingHints.VALUE_ANTIALIAS_ON) {
              if (stroke instanceof BasicStroke) {
                BasicStroke bs = (BasicStroke) stroke;
                stroke =
                    new BasicStroke(
                        bs.getLineWidth() + 0.5f,
                        bs.getEndCap(),
                        bs.getLineJoin(),
                        bs.getMiterLimit(),
                        bs.getDashArray(),
                        bs.getDashPhase());
              }
            }

            graphics.setPaint(paint);
            graphics.setStroke(stroke);
            graphics.setComposite(ls2d.getContourComposite());
            graphics.draw(shape);
          }
        }
      }
    }
  }
Exemplo n.º 26
0
 public int getCollisionBoxWidth() {
   return (int) (scale.getScaleX() * getWidth());
 }
  /**
   * Ipp filter.
   *
   * @param src the src.
   * @param dst the dst.
   * @param imageType the image type.
   * @return the int.
   */
  @SuppressWarnings("unused")
  private int ippFilter(Raster src, WritableRaster dst, int imageType) {
    int srcStride, dstStride;
    boolean skipChannel = false;
    int channels;
    int offsets[] = null;

    switch (imageType) {
      case BufferedImage.TYPE_INT_RGB:
      case BufferedImage.TYPE_INT_BGR:
        {
          channels = 4;
          srcStride = src.getWidth() * 4;
          dstStride = dst.getWidth() * 4;
          skipChannel = true;
          break;
        }

      case BufferedImage.TYPE_INT_ARGB:
      case BufferedImage.TYPE_INT_ARGB_PRE:
      case BufferedImage.TYPE_4BYTE_ABGR:
      case BufferedImage.TYPE_4BYTE_ABGR_PRE:
        {
          channels = 4;
          srcStride = src.getWidth() * 4;
          dstStride = dst.getWidth() * 4;
          break;
        }

      case BufferedImage.TYPE_BYTE_GRAY:
      case BufferedImage.TYPE_BYTE_INDEXED:
        {
          channels = 1;
          srcStride = src.getWidth();
          dstStride = dst.getWidth();
          break;
        }

      case BufferedImage.TYPE_3BYTE_BGR:
        {
          channels = 3;
          srcStride = src.getWidth() * 3;
          dstStride = dst.getWidth() * 3;
          break;
        }

      case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in
        // native code?
      case BufferedImage.TYPE_USHORT_565_RGB:
      case BufferedImage.TYPE_USHORT_555_RGB:
      case BufferedImage.TYPE_BYTE_BINARY:
        {
          return slowFilter(src, dst);
        }

      default:
        {
          SampleModel srcSM = src.getSampleModel();
          SampleModel dstSM = dst.getSampleModel();

          if (srcSM instanceof PixelInterleavedSampleModel
              && dstSM instanceof PixelInterleavedSampleModel) {
            // Check PixelInterleavedSampleModel
            if (srcSM.getDataType() != DataBuffer.TYPE_BYTE
                || dstSM.getDataType() != DataBuffer.TYPE_BYTE) {
              return slowFilter(src, dst);
            }

            channels = srcSM.getNumBands(); // Have IPP functions for 1,
            // 3 and 4 channels
            if (channels != 1 && channels != 3 && channels != 4) {
              return slowFilter(src, dst);
            }

            int dataTypeSize = DataBuffer.getDataTypeSize(srcSM.getDataType()) / 8;

            srcStride = ((ComponentSampleModel) srcSM).getScanlineStride() * dataTypeSize;
            dstStride = ((ComponentSampleModel) dstSM).getScanlineStride() * dataTypeSize;
          } else if (srcSM instanceof SinglePixelPackedSampleModel
              && dstSM instanceof SinglePixelPackedSampleModel) {
            // Check SinglePixelPackedSampleModel
            SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel) srcSM;
            SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel) dstSM;

            // No IPP function for this type
            if (sppsm1.getDataType() == DataBuffer.TYPE_USHORT) {
              return slowFilter(src, dst);
            }

            channels = sppsm1.getNumBands();
            // Have IPP functions for 1, 3 and 4 channels
            if (channels != 1 && channels != 3 && channels != 4) {
              return slowFilter(src, dst);
            }

            // Check compatibility of sample models
            if (sppsm1.getDataType() != sppsm2.getDataType()
                || !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets())
                || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) {
              return slowFilter(src, dst);
            }

            for (int i = 0; i < channels; i++) {
              if (sppsm1.getSampleSize(i) != 8) {
                return slowFilter(src, dst);
              }
            }

            if (channels == 3) {
              channels = 4;
            }

            int dataTypeSize = DataBuffer.getDataTypeSize(sppsm1.getDataType()) / 8;

            srcStride = sppsm1.getScanlineStride() * dataTypeSize;
            dstStride = sppsm2.getScanlineStride() * dataTypeSize;
          } else {
            return slowFilter(src, dst);
          }

          // Fill offsets if there's a child raster
          if (src.getParent() != null || dst.getParent() != null) {
            if (src.getSampleModelTranslateX() != 0
                || src.getSampleModelTranslateY() != 0
                || dst.getSampleModelTranslateX() != 0
                || dst.getSampleModelTranslateY() != 0) {
              offsets = new int[4];
              offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
              offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
              offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
              offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
            }
          }
        }
    }

    double m00 = at.getScaleX();
    double m01 = at.getShearX();
    double m02 = at.getTranslateX();
    double m10 = at.getShearY();
    double m11 = at.getScaleY();
    double m12 = at.getTranslateY();

    Object srcData, dstData;
    AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
    try {
      srcData = dbAccess.getData(src.getDataBuffer());
      dstData = dbAccess.getData(dst.getDataBuffer());
    } catch (IllegalArgumentException e) {
      return -1; // Unknown data buffer type
    }

    return ippAffineTransform(
        m00,
        m01,
        m02,
        m10,
        m11,
        m12,
        srcData,
        src.getWidth(),
        src.getHeight(),
        srcStride,
        dstData,
        dst.getWidth(),
        dst.getHeight(),
        dstStride,
        iType,
        channels,
        skipChannel,
        offsets);
  }
Exemplo n.º 28
0
  /**
   * Load a specified a raster as a portion of the granule describe by this {@link
   * GranuleDescriptor}.
   *
   * @param imageReadParameters the {@link ImageReadParam} to use for reading.
   * @param index the index to use for the {@link ImageReader}.
   * @param cropBBox the bbox to use for cropping.
   * @param mosaicWorldToGrid the cropping grid to world transform.
   * @param request the incoming request to satisfy.
   * @param hints {@link Hints} to be used for creating this raster.
   * @return a specified a raster as a portion of the granule describe by this {@link
   *     GranuleDescriptor}.
   * @throws IOException in case an error occurs.
   */
  public GranuleLoadingResult loadRaster(
      final ImageReadParam imageReadParameters,
      final int index,
      final ReferencedEnvelope cropBBox,
      final MathTransform2D mosaicWorldToGrid,
      final RasterLayerRequest request,
      final Hints hints)
      throws IOException {

    if (LOGGER.isLoggable(java.util.logging.Level.FINER)) {
      final String name = Thread.currentThread().getName();
      LOGGER.finer(
          "Thread:" + name + " Loading raster data for granuleDescriptor " + this.toString());
    }
    ImageReadParam readParameters = null;
    int imageIndex;
    final ReferencedEnvelope bbox =
        inclusionGeometry != null
            ? new ReferencedEnvelope(
                granuleBBOX.intersection(inclusionGeometry.getEnvelopeInternal()),
                granuleBBOX.getCoordinateReferenceSystem())
            : granuleBBOX;
    boolean doFiltering = false;
    if (filterMe) {
      doFiltering = Utils.areaIsDifferent(inclusionGeometry, baseGridToWorld, granuleBBOX);
    }

    // intersection of this tile bound with the current crop bbox
    final ReferencedEnvelope intersection =
        new ReferencedEnvelope(
            bbox.intersection(cropBBox), cropBBox.getCoordinateReferenceSystem());
    if (intersection.isEmpty()) {
      if (LOGGER.isLoggable(java.util.logging.Level.FINE)) {
        LOGGER.fine(
            new StringBuilder("Got empty intersection for granule ")
                .append(this.toString())
                .append(" with request ")
                .append(request.toString())
                .append(" Resulting in no granule loaded: Empty result")
                .toString());
      }
      return null;
    }

    ImageInputStream inStream = null;
    ImageReader reader = null;
    try {
      //
      // get info about the raster we have to read
      //

      // get a stream
      assert cachedStreamSPI != null : "no cachedStreamSPI available!";
      inStream =
          cachedStreamSPI.createInputStreamInstance(
              granuleUrl, ImageIO.getUseCache(), ImageIO.getCacheDirectory());
      if (inStream == null) return null;

      // get a reader and try to cache the relevant SPI
      if (cachedReaderSPI == null) {
        reader = ImageIOExt.getImageioReader(inStream);
        if (reader != null) cachedReaderSPI = reader.getOriginatingProvider();
      } else reader = cachedReaderSPI.createReaderInstance();
      if (reader == null) {
        if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) {
          LOGGER.warning(
              new StringBuilder("Unable to get s reader for granuleDescriptor ")
                  .append(this.toString())
                  .append(" with request ")
                  .append(request.toString())
                  .append(" Resulting in no granule loaded: Empty result")
                  .toString());
        }
        return null;
      }
      // set input
      reader.setInput(inStream);

      // Checking for heterogeneous granules
      if (request.isHeterogeneousGranules()) {
        // create read parameters
        readParameters = new ImageReadParam();

        // override the overviews controller for the base layer
        imageIndex =
            ReadParamsController.setReadParams(
                request.getRequestedResolution(),
                request.getOverviewPolicy(),
                request.getDecimationPolicy(),
                readParameters,
                request.rasterManager,
                overviewsController);
      } else {
        imageIndex = index;
        readParameters = imageReadParameters;
      }

      // get selected level and base level dimensions
      final GranuleOverviewLevelDescriptor selectedlevel = getLevel(imageIndex, reader);

      // now create the crop grid to world which can be used to decide
      // which source area we need to crop in the selected level taking
      // into account the scale factors imposed by the selection of this
      // level together with the base level grid to world transformation
      AffineTransform2D cropWorldToGrid =
          new AffineTransform2D(selectedlevel.gridToWorldTransformCorner);
      cropWorldToGrid = (AffineTransform2D) cropWorldToGrid.inverse();
      // computing the crop source area which lives into the
      // selected level raster space, NOTICE that at the end we need to
      // take into account the fact that we might also decimate therefore
      // we cannot just use the crop grid to world but we need to correct
      // it.
      final Rectangle sourceArea =
          CRS.transform(cropWorldToGrid, intersection).toRectangle2D().getBounds();
      // gutter
      if (selectedlevel.baseToLevelTransform.isIdentity()) sourceArea.grow(2, 2);
      XRectangle2D.intersect(
          sourceArea,
          selectedlevel.rasterDimensions,
          sourceArea); // make sure roundings don't bother us
      // is it empty??
      if (sourceArea.isEmpty()) {
        if (LOGGER.isLoggable(java.util.logging.Level.FINE)) {
          LOGGER.fine(
              "Got empty area for granuleDescriptor "
                  + this.toString()
                  + " with request "
                  + request.toString()
                  + " Resulting in no granule loaded: Empty result");
        }
        return null;

      } else if (LOGGER.isLoggable(java.util.logging.Level.FINER)) {
        LOGGER.finer(
            "Loading level "
                + imageIndex
                + " with source region: "
                + sourceArea
                + " subsampling: "
                + readParameters.getSourceXSubsampling()
                + ","
                + readParameters.getSourceYSubsampling()
                + " for granule:"
                + granuleUrl);
      }

      // Setting subsampling
      int newSubSamplingFactor = 0;
      final String pluginName = cachedReaderSPI.getPluginClassName();
      if (pluginName != null && pluginName.equals(ImageUtilities.DIRECT_KAKADU_PLUGIN)) {
        final int ssx = readParameters.getSourceXSubsampling();
        final int ssy = readParameters.getSourceYSubsampling();
        newSubSamplingFactor = ImageIOUtilities.getSubSamplingFactor2(ssx, ssy);
        if (newSubSamplingFactor != 0) {
          if (newSubSamplingFactor > maxDecimationFactor && maxDecimationFactor != -1) {
            newSubSamplingFactor = maxDecimationFactor;
          }
          readParameters.setSourceSubsampling(newSubSamplingFactor, newSubSamplingFactor, 0, 0);
        }
      }

      // set the source region
      readParameters.setSourceRegion(sourceArea);
      final RenderedImage raster;
      try {
        // read
        raster =
            request
                .getReadType()
                .read(
                    readParameters,
                    imageIndex,
                    granuleUrl,
                    selectedlevel.rasterDimensions,
                    reader,
                    hints,
                    false);

      } catch (Throwable e) {
        if (LOGGER.isLoggable(java.util.logging.Level.FINE)) {
          LOGGER.log(
              java.util.logging.Level.FINE,
              "Unable to load raster for granuleDescriptor "
                  + this.toString()
                  + " with request "
                  + request.toString()
                  + " Resulting in no granule loaded: Empty result",
              e);
        }
        return null;
      }

      // use fixed source area
      sourceArea.setRect(readParameters.getSourceRegion());

      //
      // setting new coefficients to define a new affineTransformation
      // to be applied to the grid to world transformation
      // -----------------------------------------------------------------------------------
      //
      // With respect to the original envelope, the obtained planarImage
      // needs to be rescaled. The scaling factors are computed as the
      // ratio between the cropped source region sizes and the read
      // image sizes.
      //
      // place it in the mosaic using the coords created above;
      double decimationScaleX = ((1.0 * sourceArea.width) / raster.getWidth());
      double decimationScaleY = ((1.0 * sourceArea.height) / raster.getHeight());
      final AffineTransform decimationScaleTranform =
          XAffineTransform.getScaleInstance(decimationScaleX, decimationScaleY);

      // keep into account translation  to work into the selected level raster space
      final AffineTransform afterDecimationTranslateTranform =
          XAffineTransform.getTranslateInstance(sourceArea.x, sourceArea.y);

      // now we need to go back to the base level raster space
      final AffineTransform backToBaseLevelScaleTransform = selectedlevel.baseToLevelTransform;

      // now create the overall transform
      final AffineTransform finalRaster2Model = new AffineTransform(baseGridToWorld);
      finalRaster2Model.concatenate(CoverageUtilities.CENTER_TO_CORNER);
      final double x = finalRaster2Model.getTranslateX();
      final double y = finalRaster2Model.getTranslateY();

      if (!XAffineTransform.isIdentity(backToBaseLevelScaleTransform, Utils.AFFINE_IDENTITY_EPS))
        finalRaster2Model.concatenate(backToBaseLevelScaleTransform);
      if (!XAffineTransform.isIdentity(afterDecimationTranslateTranform, Utils.AFFINE_IDENTITY_EPS))
        finalRaster2Model.concatenate(afterDecimationTranslateTranform);
      if (!XAffineTransform.isIdentity(decimationScaleTranform, Utils.AFFINE_IDENTITY_EPS))
        finalRaster2Model.concatenate(decimationScaleTranform);

      // keep into account translation factors to place this tile
      finalRaster2Model.preConcatenate((AffineTransform) mosaicWorldToGrid);
      final Interpolation interpolation = request.getInterpolation();
      // paranoiac check to avoid that JAI freaks out when computing its internal layouT on images
      // that are too small
      Rectangle2D finalLayout =
          ImageUtilities.layoutHelper(
              raster,
              (float) finalRaster2Model.getScaleX(),
              (float) finalRaster2Model.getScaleY(),
              (float) finalRaster2Model.getTranslateX(),
              (float) finalRaster2Model.getTranslateY(),
              interpolation);
      if (finalLayout.isEmpty()) {
        if (LOGGER.isLoggable(java.util.logging.Level.INFO))
          LOGGER.info(
              "Unable to create a granuleDescriptor "
                  + this.toString()
                  + " due to jai scale bug creating a null source area");
        return null;
      }
      ROI granuleLoadingShape = null;
      if (granuleROIShape != null) {

        final Point2D translate =
            mosaicWorldToGrid.transform(new DirectPosition2D(x, y), (Point2D) null);
        AffineTransform tx2 = new AffineTransform();
        tx2.preConcatenate(
            AffineTransform.getScaleInstance(
                ((AffineTransform) mosaicWorldToGrid).getScaleX(),
                -((AffineTransform) mosaicWorldToGrid).getScaleY()));
        tx2.preConcatenate(
            AffineTransform.getScaleInstance(
                ((AffineTransform) baseGridToWorld).getScaleX(),
                -((AffineTransform) baseGridToWorld).getScaleY()));
        tx2.preConcatenate(
            AffineTransform.getTranslateInstance(translate.getX(), translate.getY()));
        granuleLoadingShape = (ROI) granuleROIShape.transform(tx2);
      }
      // apply the affine transform  conserving indexed color model
      final RenderingHints localHints =
          new RenderingHints(
              JAI.KEY_REPLACE_INDEX_COLOR_MODEL,
              interpolation instanceof InterpolationNearest ? Boolean.FALSE : Boolean.TRUE);
      if (XAffineTransform.isIdentity(finalRaster2Model, Utils.AFFINE_IDENTITY_EPS)) {
        return new GranuleLoadingResult(raster, granuleLoadingShape, granuleUrl, doFiltering);
      } else {
        //
        // In case we are asked to use certain tile dimensions we tile
        // also at this stage in case the read type is Direct since
        // buffered images comes up untiled and this can affect the
        // performances of the subsequent affine operation.
        //
        final Dimension tileDimensions = request.getTileDimensions();
        if (tileDimensions != null && request.getReadType().equals(ReadType.DIRECT_READ)) {
          final ImageLayout layout = new ImageLayout();
          layout.setTileHeight(tileDimensions.width).setTileWidth(tileDimensions.height);
          localHints.add(new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout));
        } else {
          if (hints != null && hints.containsKey(JAI.KEY_IMAGE_LAYOUT)) {
            final Object layout = hints.get(JAI.KEY_IMAGE_LAYOUT);
            if (layout != null && layout instanceof ImageLayout) {
              localHints.add(
                  new RenderingHints(JAI.KEY_IMAGE_LAYOUT, ((ImageLayout) layout).clone()));
            }
          }
        }
        if (hints != null && hints.containsKey(JAI.KEY_TILE_CACHE)) {
          final Object cache = hints.get(JAI.KEY_TILE_CACHE);
          if (cache != null && cache instanceof TileCache)
            localHints.add(new RenderingHints(JAI.KEY_TILE_CACHE, (TileCache) cache));
        }
        if (hints != null && hints.containsKey(JAI.KEY_TILE_SCHEDULER)) {
          final Object scheduler = hints.get(JAI.KEY_TILE_SCHEDULER);
          if (scheduler != null && scheduler instanceof TileScheduler)
            localHints.add(new RenderingHints(JAI.KEY_TILE_SCHEDULER, (TileScheduler) scheduler));
        }
        boolean addBorderExtender = true;
        if (hints != null && hints.containsKey(JAI.KEY_BORDER_EXTENDER)) {
          final Object extender = hints.get(JAI.KEY_BORDER_EXTENDER);
          if (extender != null && extender instanceof BorderExtender) {
            localHints.add(new RenderingHints(JAI.KEY_BORDER_EXTENDER, (BorderExtender) extender));
            addBorderExtender = false;
          }
        }
        // border extender
        if (addBorderExtender) {
          localHints.add(ImageUtilities.BORDER_EXTENDER_HINTS);
        }
        //                boolean hasScaleX=!(Math.abs(finalRaster2Model.getScaleX()-1) <
        // 1E-2/(raster.getWidth()+1-raster.getMinX()));
        //                boolean hasScaleY=!(Math.abs(finalRaster2Model.getScaleY()-1) <
        // 1E-2/(raster.getHeight()+1-raster.getMinY()));
        //                boolean hasShearX=!(finalRaster2Model.getShearX() == 0.0);
        //                boolean hasShearY=!(finalRaster2Model.getShearY() == 0.0);
        //                boolean hasTranslateX=!(Math.abs(finalRaster2Model.getTranslateX()) <
        // 0.01F);
        //                boolean hasTranslateY=!(Math.abs(finalRaster2Model.getTranslateY()) <
        // 0.01F);
        //                boolean isTranslateXInt=!(Math.abs(finalRaster2Model.getTranslateX() -
        // (int) finalRaster2Model.getTranslateX()) <  0.01F);
        //                boolean isTranslateYInt=!(Math.abs(finalRaster2Model.getTranslateY() -
        // (int) finalRaster2Model.getTranslateY()) <  0.01F);
        //
        //                boolean isIdentity = finalRaster2Model.isIdentity() &&
        // !hasScaleX&&!hasScaleY &&!hasTranslateX&&!hasTranslateY;

        //                // TODO how can we check that the a skew is harmelss????
        //                if(isIdentity){
        //                    // TODO check if we are missing anything like tiling or such that
        // comes from hints
        //                    return new GranuleLoadingResult(raster, granuleLoadingShape,
        // granuleUrl, doFiltering);
        //                }
        //
        //                // TOLERANCE ON PIXELS SIZE
        //
        //                // Check and see if the affine transform is in fact doing
        //                // a Translate operation. That is a scale by 1 and no rotation.
        //                // In which case call translate. Note that only integer translate
        //                // is applicable. For non-integer translate we'll have to do the
        //                // affine.
        //                // If the hints contain an ImageLayout hint, we can't use
        //                // TranslateIntOpImage since it isn't capable of dealing with that.
        //                // Get ImageLayout from renderHints if any.
        //                ImageLayout layout = RIFUtil.getImageLayoutHint(localHints);
        //                if ( !hasScaleX &&
        //                     !hasScaleY  &&
        //                      !hasShearX&&
        //                      !hasShearY&&
        //                      isTranslateXInt&&
        //                      isTranslateYInt&&
        //                    layout == null) {
        //                    // It's a integer translate
        //                    return new GranuleLoadingResult(new TranslateIntOpImage(raster,
        //                                                    localHints,
        //                                                   (int) finalRaster2Model.getShearX(),
        //                                                   (int)
        // finalRaster2Model.getShearY()),granuleLoadingShape, granuleUrl, doFiltering);
        //                }

        ImageWorker iw = new ImageWorker(raster);
        iw.setRenderingHints(localHints);
        iw.affine(finalRaster2Model, interpolation, request.getBackgroundValues());
        return new GranuleLoadingResult(
            iw.getRenderedImage(), granuleLoadingShape, granuleUrl, doFiltering);
      }

    } catch (IllegalStateException e) {
      if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) {
        LOGGER.log(
            java.util.logging.Level.WARNING,
            new StringBuilder("Unable to load raster for granuleDescriptor ")
                .append(this.toString())
                .append(" with request ")
                .append(request.toString())
                .append(" Resulting in no granule loaded: Empty result")
                .toString(),
            e);
      }
      return null;
    } catch (org.opengis.referencing.operation.NoninvertibleTransformException e) {
      if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) {
        LOGGER.log(
            java.util.logging.Level.WARNING,
            new StringBuilder("Unable to load raster for granuleDescriptor ")
                .append(this.toString())
                .append(" with request ")
                .append(request.toString())
                .append(" Resulting in no granule loaded: Empty result")
                .toString(),
            e);
      }
      return null;
    } catch (TransformException e) {
      if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) {
        LOGGER.log(
            java.util.logging.Level.WARNING,
            new StringBuilder("Unable to load raster for granuleDescriptor ")
                .append(this.toString())
                .append(" with request ")
                .append(request.toString())
                .append(" Resulting in no granule loaded: Empty result")
                .toString(),
            e);
      }
      return null;

    } finally {
      try {
        if (request.getReadType() != ReadType.JAI_IMAGEREAD && inStream != null) {
          inStream.close();
        }
      } finally {
        if (request.getReadType() != ReadType.JAI_IMAGEREAD && reader != null) {
          reader.dispose();
        }
      }
    }
  }
Exemplo n.º 29
0
  @DescribeResult(name = "result", description = "The contours feature collection")
  public SimpleFeatureCollection execute(
      @DescribeParameter(name = "data", description = "The raster to be used as the source")
          GridCoverage2D gc2d,
      @DescribeParameter(
              name = "band",
              description = "The source image band to process",
              min = 0,
              max = 1)
          Integer band,
      @DescribeParameter(name = "levels", description = "Values for which to generate contours")
          double[] levels,
      @DescribeParameter(
              name = "interval",
              description = "Interval between contour values (ignored if levels arg is supplied)",
              min = 0)
          Double interval,
      @DescribeParameter(
              name = "simplify",
              description = "Values for which to generate contours",
              min = 0)
          Boolean simplify,
      @DescribeParameter(
              name = "smooth",
              description = "Values for which to generate contours",
              min = 0)
          Boolean smooth,
      @DescribeParameter(
              name = "roi",
              description = "The geometry used to delineate the area of interest in model space",
              min = 0)
          Geometry roi,
      ProgressListener progressListener)
      throws ProcessException {

    //
    // initial checks
    //
    if (gc2d == null) {
      throw new ProcessException("Invalid input, source grid coverage should be not null");
    }
    if (band != null && (band < 0 || band >= gc2d.getNumSampleDimensions())) {
      throw new ProcessException("Invalid input, invalid band number:" + band);
    }
    boolean hasValues = !(levels == null || levels.length == 0);
    if (!hasValues && interval == null) {
      throw new ProcessException("One between interval and values must be valid");
    }

    // switch to geophisics if necessary
    gc2d = gc2d.view(ViewType.GEOPHYSICS);

    //
    // GRID TO WORLD preparation
    //
    final AffineTransform mt2D =
        (AffineTransform) gc2d.getGridGeometry().getGridToCRS2D(PixelOrientation.CENTER);

    // get the list of nodata, if any
    List<Object> noDataList = new ArrayList<Object>();
    for (GridSampleDimension sd : gc2d.getSampleDimensions()) {
      // grab all the explicit nodata
      final double[] sdNoData = sd.getNoDataValues();
      if (sdNoData != null) {
        for (double nodata : sdNoData) {
          noDataList.add(nodata);
        }
      }

      // handle also readers setting up nodata in a category with a specific name
      if (sd.getCategories() != null) {
        for (Category cat : sd.getCategories()) {
          if (cat.getName().equals(NO_DATA)) {
            final NumberRange<? extends Number> catRange = cat.getRange();
            if (catRange.getMinimum() == catRange.getMaximum()) {
              noDataList.add(catRange.getMinimum());
            } else {
              Range<Double> noData =
                  new Range<Double>(
                      catRange.getMinimum(),
                      catRange.isMinIncluded(),
                      catRange.getMaximum(),
                      catRange.isMaxIncluded());
              noDataList.add(noData);
            }
          }
        }
      }
    }

    // get the rendered image
    final RenderedImage raster = gc2d.getRenderedImage();

    // perform jai operation
    ParameterBlockJAI pb = new ParameterBlockJAI("Contour");
    pb.setSource("source0", raster);

    if (roi != null) {
      pb.setParameter("roi", CoverageUtilities.prepareROI(roi, mt2D));
    }
    if (band != null) {
      pb.setParameter("band", band);
    }
    if (interval != null) {
      pb.setParameter("interval", interval);
    } else {
      final ArrayList<Double> elements = new ArrayList<Double>(levels.length);
      for (double level : levels) elements.add(level);
      pb.setParameter("levels", elements);
    }
    if (simplify != null) {
      pb.setParameter("simplify", simplify);
    }
    if (smooth != null) {
      pb.setParameter("smooth", smooth);
    }
    if (noDataList != null) {
      pb.setParameter("nodata", noDataList);
    }

    final RenderedOp dest = JAI.create("Contour", pb);
    @SuppressWarnings("unchecked")
    final Collection<LineString> prop =
        (Collection<LineString>) dest.getProperty(ContourDescriptor.CONTOUR_PROPERTY_NAME);

    // wrap as a feature collection and return
    final SimpleFeatureType schema = CoverageUtilities.createFeatureType(gc2d, LineString.class);
    final SimpleFeatureBuilder builder = new SimpleFeatureBuilder(schema);
    int i = 0;
    final ListFeatureCollection featureCollection = new ListFeatureCollection(schema);
    final AffineTransformation jtsTransformation =
        new AffineTransformation(
            mt2D.getScaleX(),
            mt2D.getShearX(),
            mt2D.getTranslateX(),
            mt2D.getShearY(),
            mt2D.getScaleY(),
            mt2D.getTranslateY());
    for (LineString line : prop) {

      // get value
      Double value = (Double) line.getUserData();
      line.setUserData(null);
      // filter coordinates in place
      line.apply(jtsTransformation);

      // create feature and add to list
      builder.set("the_geom", line);
      builder.set("value", value);

      featureCollection.add(builder.buildFeature(String.valueOf(i++)));
    }

    // return value

    return featureCollection;
  }
  /**
   * Executes the raster to vector process.
   *
   * @param coverage the input grid coverage
   * @param band the coverage band to process; defaults to 0 if {@code null}
   * @param insideEdges whether boundaries between raster regions with data values (ie. not NODATA)
   *     should be returned; defaults to {@code true} if {@code null}
   * @param roi optional polygonal {@code Geometry} to define a sub-area within which vectorizing
   *     will be done
   * @param noDataValues optional list of values to treat as NODATA; regions with these values will
   *     not be represented in the returned features; if {@code null}, 0 is used as the single
   *     NODATA value; ignored if {@code classificationRanges} is provided
   * @param classificationRanges optional list of {@code Range} objects to pre-classify the input
   *     coverage prior to vectorizing; values not included in the list will be treated as NODATA;
   *     values in the first {@code Range} are classified to 1, those in the second {@code Range} to
   *     2 etc.
   * @param progressListener an optional listener
   * @return a feature collection where each feature has a {@code Polygon} ("the_geom") and an
   *     attribute "value" with value of the corresponding region in either {@code coverage} or the
   *     classified coverage (when {@code classificationRanges} is used)
   * @throws ProcessException
   */
  @DescribeResult(name = "result", description = "The polygon feature collection")
  public SimpleFeatureCollection execute(
      @DescribeParameter(name = "data", description = "The raster to be used as the source")
          GridCoverage2D coverage,
      @DescribeParameter(
              name = "band",
              description = "(Integer, default=0) the source image band to process",
              min = 0)
          Integer band,
      @DescribeParameter(
              name = "insideEdges",
              description =
                  "(Boolean, default=true) whether to vectorize boundaries between adjacent regions with non-outside values",
              min = 0)
          Boolean insideEdges,
      @DescribeParameter(
              name = "roi",
              description = "The geometry used to delineate the area of interest in model space",
              min = 0)
          Geometry roi,
      @DescribeParameter(
              name = "nodata",
              description = "Collection<Number>, default={0}) values to treat as NODATA",
              collectionType = Number.class,
              min = 0)
          Collection<Number> noDataValues,
      @DescribeParameter(
              name = "ranges",
              description =
                  "The list of ranges to be applied. \n"
                      + "Each range is expressed as 'OPEN START ; END CLOSE'\n"
                      + "where 'OPEN:=(|[, CLOSE=)|]',\n "
                      + "START is the low value, or nothing to imply -INF,\n"
                      + "CLOSE is the biggest value, or nothing to imply +INF",
              collectionType = Range.class,
              min = 0)
          List<Range> classificationRanges,
      ProgressListener progressListener)
      throws ProcessException {

    //
    // initial checks
    //
    if (coverage == null) {
      throw new ProcessException("Invalid input, source grid coverage should be not null");
    }

    if (band == null) {
      band = 0;
    } else if (band < 0 || band >= coverage.getNumSampleDimensions()) {
      throw new ProcessException("Invalid input, invalid band number:" + band);
    }

    // do we have classification ranges?
    boolean hasClassificationRanges =
        classificationRanges != null && classificationRanges.size() > 0;

    // apply the classification by setting 0 as the default value and using 1, ..., numClasses for
    // the other classes.
    // we use 0 also as the noData for the resulting coverage.
    if (hasClassificationRanges) {

      final RangeLookupProcess lookup = new RangeLookupProcess();
      coverage = lookup.execute(coverage, band, classificationRanges, progressListener);
    }

    // Use noDataValues to set the "outsideValues" parameter of the Vectorize
    // operation unless classificationRanges are in use, in which case the
    // noDataValues arg is ignored.
    List<Number> outsideValues = new ArrayList<Number>();
    if (noDataValues != null && !hasClassificationRanges) {
      outsideValues.addAll(noDataValues);
    } else {
      outsideValues.add(0);
    }

    //
    // GRID TO WORLD preparation
    //
    final AffineTransform mt2D =
        (AffineTransform) coverage.getGridGeometry().getGridToCRS2D(PixelOrientation.UPPER_LEFT);

    // get the rendered image
    final RenderedImage raster = coverage.getRenderedImage();

    // perform jai operation
    ParameterBlockJAI pb = new ParameterBlockJAI("Vectorize");
    pb.setSource("source0", raster);

    if (roi != null) {
      pb.setParameter("roi", CoverageUtilities.prepareROI(roi, mt2D));
    }
    pb.setParameter("band", band);
    pb.setParameter("outsideValues", outsideValues);
    if (insideEdges != null) {
      pb.setParameter("insideEdges", insideEdges);
    }
    // pb.setParameter("removeCollinear", false);

    final RenderedOp dest = JAI.create("Vectorize", pb);
    @SuppressWarnings("unchecked")
    final Collection<Polygon> prop =
        (Collection<Polygon>) dest.getProperty(VectorizeDescriptor.VECTOR_PROPERTY_NAME);

    // wrap as a feature collection and return
    final SimpleFeatureType featureType =
        CoverageUtilities.createFeatureType(coverage, Polygon.class);
    final SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType);
    int i = 0;
    final ListFeatureCollection featureCollection = new ListFeatureCollection(featureType);
    final AffineTransformation jtsTransformation =
        new AffineTransformation(
            mt2D.getScaleX(),
            mt2D.getShearX(),
            mt2D.getTranslateX(),
            mt2D.getShearY(),
            mt2D.getScaleY(),
            mt2D.getTranslateY());
    for (Polygon polygon : prop) {
      // get value
      Double value = (Double) polygon.getUserData();
      polygon.setUserData(null);
      // filter coordinates in place
      polygon.apply(jtsTransformation);

      // create feature and add to list
      builder.set("the_geom", polygon);
      builder.set("value", value);

      featureCollection.add(builder.buildFeature(String.valueOf(i++)));
    }

    // return value
    return featureCollection;
  }