Beispiel #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);
   }
 }
  protected boolean drawPdfScript(final RenderNode box) {
    final Object attribute =
        box.getAttributes()
            .getAttribute(AttributeNames.Pdf.NAMESPACE, AttributeNames.Pdf.SCRIPT_ACTION);
    if (attribute == null) {
      return false;
    }

    final String attributeText = String.valueOf(attribute);
    final PdfAction action = PdfAction.javaScript(attributeText, writer, false);

    final AffineTransform affineTransform = getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    final float leftX = translateX + (float) (StrictGeomUtility.toExternalValue(box.getX()));
    final float rightX =
        translateX + (float) (StrictGeomUtility.toExternalValue(box.getX() + box.getWidth()));
    final float lowerY =
        (float) (globalHeight - StrictGeomUtility.toExternalValue(box.getY() + box.getHeight()));
    final float upperY = (float) (globalHeight - StrictGeomUtility.toExternalValue(box.getY()));
    final PdfAnnotation annotation =
        new PdfAnnotation(writer, leftX, lowerY, rightX, upperY, action);
    writer.addAnnotation(annotation);
    return true;
  }
  protected void drawHyperlink(
      final RenderNode box, final String target, final String window, final String title) {
    if (box.isNodeVisible(getDrawArea()) == false) {
      return;
    }

    final PdfAction action = createActionForLink(target);

    final AffineTransform affineTransform = getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    final float leftX = translateX + (float) (StrictGeomUtility.toExternalValue(box.getX()));
    final float rightX =
        translateX + (float) (StrictGeomUtility.toExternalValue(box.getX() + box.getWidth()));
    final float lowerY =
        (float) (globalHeight - StrictGeomUtility.toExternalValue(box.getY() + box.getHeight()));
    final float upperY = (float) (globalHeight - StrictGeomUtility.toExternalValue(box.getY()));

    if (action != null) {
      final PdfAnnotation annotation =
          new PdfAnnotation(writer, leftX, lowerY, rightX, upperY, action);
      writer.addAnnotation(annotation);
    } else if (StringUtils.isEmpty(title) == false) {
      final Rectangle rect = new Rectangle(leftX, lowerY, rightX, upperY);
      final PdfAnnotation commentAnnotation =
          PdfAnnotation.createText(writer, rect, "Tooltip", title, false, null);
      commentAnnotation.setAppearance(
          PdfAnnotation.APPEARANCE_NORMAL,
          writer.getDirectContent().createAppearance(rect.getWidth(), rect.getHeight()));
      writer.addAnnotation(commentAnnotation);
    }
  }
  protected void drawImageMap(final RenderableReplacedContentBox content) {
    if (version < '6') {
      return;
    }

    final ImageMap imageMap = RenderUtility.extractImageMap(content);
    // only generate a image map, if the user does not specify their own onw via the override.
    // Of course, they would have to provide the map by other means as well.

    if (imageMap == null) {
      return;
    }

    final ImageMapEntry[] imageMapEntries = imageMap.getMapEntries();
    for (int i = 0; i < imageMapEntries.length; i++) {
      final ImageMapEntry imageMapEntry = imageMapEntries[i];
      final String link = imageMapEntry.getAttribute(LibXmlInfo.XHTML_NAMESPACE, "href");
      final String tooltip = imageMapEntry.getAttribute(LibXmlInfo.XHTML_NAMESPACE, "title");
      if (StringUtils.isEmpty(tooltip)) {
        continue;
      }

      final AffineTransform affineTransform = getGraphics().getTransform();
      final float translateX = (float) affineTransform.getTranslateX();
      final int x = (int) (translateX + StrictGeomUtility.toExternalValue(content.getX()));
      final int y = (int) StrictGeomUtility.toExternalValue(content.getY());
      final float[] translatedCoords =
          translateCoordinates(imageMapEntry.getAreaCoordinates(), x, y);

      final PolygonAnnotation polygonAnnotation = new PolygonAnnotation(writer, translatedCoords);
      polygonAnnotation.put(PdfName.CONTENTS, new PdfString(tooltip, PdfObject.TEXT_UNICODE));
      writer.addAnnotation(polygonAnnotation);
    }
  }
  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);
  }
Beispiel #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);
    }
  }
Beispiel #7
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));
  }
Beispiel #8
0
  /* Scroll horizontally */
  private void scrollHorizontally(ScrollBar scrollBar) {
    if (sourceImage == null) return;

    AffineTransform af = transform;
    double tx = af.getTranslateX();
    double select = -scrollBar.getSelection();
    af.preConcatenate(AffineTransform.getTranslateInstance(select - tx, 0));
    transform = af;
    syncScrollBars();
  }
Beispiel #9
0
 @Override
 protected void basicTextShowGlyphs(PDGlyphs glyphs, float advance) {
   AffineTransform tx;
   tx = (AffineTransform) getDeviceTransform().clone();
   tx.concatenate(textState.globalTransform);
   lastStartX = tx.getTranslateX();
   lastStartY = tx.getTranslateY();
   // get the transformed character bounding box
   double glyphAscent = glyphs.getAscent();
   double glyphDescent = glyphs.getDescent();
   double ascent = (textState.fontSize * glyphAscent) / THOUSAND;
   double descent = (textState.fontSize * glyphDescent) / THOUSAND;
   if (descent > 0) {
     descent = -descent;
   }
   double[] pts = {0, descent, advance, ascent};
   tx.deltaTransform(pts, 0, pts, 0, 2);
   //
   float x = (float) lastStartX;
   float y = (float) (lastStartY + pts[1]);
   float width = (float) pts[2];
   float height = (float) (pts[3] - pts[1]);
   if (width < 0) {
     x += width;
     width = -width;
   }
   if (height < 0) {
     y += height;
     height = -height;
   }
   Rectangle2D charRect = new Rectangle2D.Float(x, y, width, height);
   if (getBounds() == null || getBounds().intersects(charRect)) {
     onCharacterFound(glyphs, charRect);
   }
   // advance text matrix and store position for reference
   super.basicTextShowGlyphs(glyphs, advance);
   tx = (AffineTransform) getDeviceTransform().clone();
   tx.concatenate(textState.globalTransform);
   lastStopX = tx.getTranslateX();
   lastStopY = tx.getTranslateY();
 }
Beispiel #10
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();
  }
Beispiel #11
0
 /**
  * @param target the location the new origin, may be <code>null</code>
  * @return the world coordinate of the origin of the geo referenced raster.
  */
 public double[] getOrigin(OriginLocation target) {
   double[] result = new double[2];
   if (target != null && target != location) {
     if (location == CENTER) {
       result = getWorldCoordinate(0, 0);
     } else {
       result = getWorldCoordinate(+0.5, +0.5);
     }
   } else {
     result[0] = transform.getTranslateX();
     result[1] = transform.getTranslateY();
   }
   return result;
 }
Beispiel #12
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);
 }
Beispiel #13
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);
  }
  protected void drawBookmark(final RenderNode box, final String bookmark) {
    if (box.isNodeVisible(getDrawArea()) == false) {
      return;
    }
    final PdfOutline root = writer.getDirectContent().getRootOutline();

    final AffineTransform affineTransform = getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    final float upperY =
        translateX + (float) (globalHeight - StrictGeomUtility.toExternalValue(box.getY()));
    final float leftX = (float) (StrictGeomUtility.toExternalValue(box.getX()));
    final PdfDestination dest = new PdfDestination(PdfDestination.FIT, leftX, upperY, 0);
    new PdfOutline(root, dest, bookmark);
    // destination will always point to the 'current' page
    // todo: Make this a hierarchy ..
  }
  protected void drawAnchor(final RenderNode content) {
    if (content.isNodeVisible(getDrawArea()) == false) {
      return;
    }
    final String anchorName =
        (String) content.getStyleSheet().getStyleProperty(ElementStyleKeys.ANCHOR_NAME);
    if (anchorName == null) {
      return;
    }
    final AffineTransform affineTransform = getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    final float upperY =
        translateX + (float) (globalHeight - StrictGeomUtility.toExternalValue(content.getY()));
    final float leftX = (float) (StrictGeomUtility.toExternalValue(content.getX()));
    final PdfDestination dest = new PdfDestination(PdfDestination.FIT, leftX, upperY, 0);
    writer.getDirectContent().localDestination(anchorName, dest);
  }
Beispiel #16
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);
    }
  }
  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);
  }
  /**
   * 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;
  }
Beispiel #19
0
  /*
   * This method is only called in those circumstances where the
   * operation has a non-null secondary transform specfied.  Its
   * role is to check for various optimizations based on the types
   * of both the secondary and SG2D transforms and to do some
   * quick calculations to avoid having to combine the transforms
   * and/or to call a more generalized method.
   */
  protected void transformImage(
      SunGraphics2D sg, Image img, int x, int y, AffineTransform extraAT, int interpType) {
    int txtype = extraAT.getType();
    int imgw = img.getWidth(null);
    int imgh = img.getHeight(null);
    boolean checkfinalxform;

    if (sg.transformState <= sg.TRANSFORM_ANY_TRANSLATE
        && (txtype == AffineTransform.TYPE_IDENTITY
            || txtype == AffineTransform.TYPE_TRANSLATION)) {
      // First optimization - both are some kind of translate

      // Combine the translations and check if interpolation is necessary.
      double tx = extraAT.getTranslateX();
      double ty = extraAT.getTranslateY();
      tx += sg.transform.getTranslateX();
      ty += sg.transform.getTranslateY();
      int itx = (int) Math.floor(tx + 0.5);
      int ity = (int) Math.floor(ty + 0.5);
      if (interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR
          || (closeToInteger(itx, tx) && closeToInteger(ity, ty))) {
        renderImageCopy(sg, img, null, x + itx, y + ity, 0, 0, imgw, imgh);
        return;
      }
      checkfinalxform = false;
    } else if (sg.transformState <= sg.TRANSFORM_TRANSLATESCALE
        && ((txtype
                & (AffineTransform.TYPE_FLIP
                    | AffineTransform.TYPE_MASK_ROTATION
                    | AffineTransform.TYPE_GENERAL_TRANSFORM))
            == 0)) {
      // Second optimization - both are some kind of translate or scale

      // Combine the scales and check if interpolation is necessary.

      // Transform source bounds by extraAT,
      // then translate the bounds again by x, y
      // then transform the bounds again by sg.transform
      double coords[] =
          new double[] {
            0, 0, imgw, imgh,
          };
      extraAT.transform(coords, 0, coords, 0, 2);
      coords[0] += x;
      coords[1] += y;
      coords[2] += x;
      coords[3] += y;
      sg.transform.transform(coords, 0, coords, 0, 2);

      if (tryCopyOrScale(sg, img, 0, 0, imgw, imgh, null, interpType, coords)) {
        return;
      }
      checkfinalxform = false;
    } else {
      checkfinalxform = true;
    }

    // Begin Transform
    AffineTransform tx = new AffineTransform(sg.transform);
    tx.translate(x, y);
    tx.concatenate(extraAT);

    // Do not try any more optimizations if either of the cases
    // above was tried as we have already verified that the
    // resulting transform will not simplify.
    if (checkfinalxform) {
      // In this case neither of the above simple transform
      // pairs was found so we will do some final tests on
      // the final rendering transform which may be the
      // simple product of two complex transforms.
      transformImage(sg, img, tx, interpType, 0, 0, imgw, imgh, null);
    } else {
      renderImageXform(sg, img, tx, interpType, 0, 0, imgw, imgh, null);
    }
  }
Beispiel #20
0
 /**
  * Formats a transformation matrix in millipoints with values as points.
  *
  * @param transform the transformation matrix in millipoints
  * @return the formatted matrix in points
  */
 public static String formatAffineTransformMptToPt(AffineTransform transform) {
   AffineTransform scaled = new AffineTransform(transform);
   scaled.setToTranslation(transform.getTranslateX() / 1000, transform.getTranslateY() / 1000);
   return IFUtil.toString(scaled);
 }
  /**
   * This method is responsible fro creating a world file to georeference an image given the image
   * bounding box and the image geometry. The name of the file is composed by the name of the image
   * file with a proper extension, depending on the format (see WorldImageFormat). The projection is
   * in the world file.
   *
   * @param imageFile
   * @param baseFile Basename and path for this image.
   * @param ext
   * @throws IOException In case we cannot create the world file.
   * @throws TransformException
   */
  private void createWorldFile(
      final AffineTransform transform, final String ext, final String baseFile) throws IOException {

    // /////////////////////////////////////////////////////////////////////
    //
    // CRS information
    //
    // ////////////////////////////////////////////////////////////////////
    // final AffineTransform gridToWorld = (AffineTransform)
    // gc.getGridGeometry ().getGridToCRS ();
    final boolean lonFirst = (XAffineTransform.getSwapXY(transform) != -1);

    // /////////////////////////////////////////////////////////////////////
    //
    // World File values
    // It is worthwhile to note that we have to keep into account the fact
    // that the axis could be swapped (LAT,lon) therefore when getting
    // xPixSize and yPixSize we need to look for it a the right place
    // inside the grid to world transform.
    //
    // ////////////////////////////////////////////////////////////////////
    final double xPixelSize = (lonFirst) ? transform.getScaleX() : transform.getShearY();
    final double rotation1 = (lonFirst) ? transform.getShearX() : transform.getScaleX();
    final double rotation2 = (lonFirst) ? transform.getShearY() : transform.getScaleY();
    final double yPixelSize = (lonFirst) ? transform.getScaleY() : transform.getShearX();
    final double xLoc = transform.getTranslateX();
    final double yLoc = transform.getTranslateY();

    // /////////////////////////////////////////////////////////////////////
    //
    // writing world file
    //
    // ////////////////////////////////////////////////////////////////////
    final StringBuffer buff = new StringBuffer(baseFile);
    // looking for another extension
    if (ext.substring(0, 4).equalsIgnoreCase(".tif")) {
      buff.append(".tfw");
    } else if (ext.substring(0, 4).equalsIgnoreCase(".png")) {
      buff.append(".pgw");
    } else if (ext.substring(0, 4).equalsIgnoreCase(".jpg")
        || ext.substring(0, 4).equalsIgnoreCase("jpeg")) {
      buff.append(".jpw");
    } else if (ext.substring(0, 4).equalsIgnoreCase(".gif")) {
      buff.append(".gfw");
    } else if (ext.substring(0, 4).equalsIgnoreCase(".bmp")) {
      buff.append(".bpw");
    } else {
      buff.append(".tffw");
    }
    final File worldFile = new File(buff.toString());

    LOG.debug("Writing world file: " + worldFile);

    final PrintWriter out = new PrintWriter(new FileOutputStream(worldFile));
    try {
      out.println(xPixelSize);
      out.println(rotation1);
      out.println(rotation2);
      out.println(yPixelSize);
      out.println(xLoc);
      out.println(yLoc);
      out.flush();
    } finally {
      out.close();
    }
  }
  protected void drawText(final RenderableText renderableText, final long contentX2) {
    if (renderableText.getLength() == 0) {
      return;
    }

    final long posX = renderableText.getX();
    final long posY = renderableText.getY();
    final float x1 = (float) (StrictGeomUtility.toExternalValue(posX));

    final PdfContentByte cb;
    PdfTextSpec textSpec = (PdfTextSpec) getTextSpec();
    if (textSpec == null) {
      final StyleSheet layoutContext = renderableText.getStyleSheet();

      // The code below may be weird, but at least it is predictable weird.
      final String fontName =
          getMetaData()
              .getNormalizedFontFamilyName(
                  (String) layoutContext.getStyleProperty(TextStyleKeys.FONT));
      final String encoding = (String) layoutContext.getStyleProperty(TextStyleKeys.FONTENCODING);
      final float fontSize =
          (float) layoutContext.getDoubleStyleProperty(TextStyleKeys.FONTSIZE, 10);

      final boolean embed =
          globalEmbed || layoutContext.getBooleanStyleProperty(TextStyleKeys.EMBEDDED_FONT);
      final boolean bold = layoutContext.getBooleanStyleProperty(TextStyleKeys.BOLD);
      final boolean italics = layoutContext.getBooleanStyleProperty(TextStyleKeys.ITALIC);

      final BaseFontFontMetrics fontMetrics =
          getMetaData()
              .getBaseFontFontMetrics(fontName, fontSize, bold, italics, encoding, embed, false);

      final PdfGraphics2D g2 = (PdfGraphics2D) getGraphics();
      final Color cssColor = (Color) layoutContext.getStyleProperty(ElementStyleKeys.PAINT);
      g2.setPaint(cssColor);
      g2.setFillPaint();
      g2.setStrokePaint();
      // final float translateY = (float) affineTransform.getTranslateY();

      cb = g2.getRawContentByte();

      textSpec = new PdfTextSpec(layoutContext, getMetaData(), g2, fontMetrics, cb);
      setTextSpec(textSpec);

      cb.beginText();
      cb.setFontAndSize(fontMetrics.getBaseFont(), fontSize);
    } else {
      cb = textSpec.getContentByte();
    }

    final BaseFontFontMetrics baseFontRecord = textSpec.getFontMetrics();
    final BaseFont baseFont = baseFontRecord.getBaseFont();
    final float ascent = baseFont.getFontDescriptor(BaseFont.BBOXURY, textSpec.getFontSize());
    final float y2 = (float) (StrictGeomUtility.toExternalValue(posY) + ascent);
    final float y = globalHeight - y2;

    final AffineTransform affineTransform = textSpec.getGraphics().getTransform();
    final float translateX = (float) affineTransform.getTranslateX();

    final FontNativeContext nativeContext = baseFontRecord.getNativeContext();
    if (baseFontRecord.isTrueTypeFont()
        && textSpec.isBold()
        && nativeContext.isNativeBold() == false) {
      final float strokeWidth = textSpec.getFontSize() / 30.0f; // right from iText ...
      if (strokeWidth == 1) {
        cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
      } else {
        cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
        cb.setLineWidth(strokeWidth);
      }
    } else {
      cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
    }

    // if the font does not declare to be italics already, emulate it ..
    if (baseFontRecord.isTrueTypeFont()
        && textSpec.isItalics()
        && nativeContext.isNativeItalics() == false) {
      final float italicAngle =
          baseFont.getFontDescriptor(BaseFont.ITALICANGLE, textSpec.getFontSize());
      if (italicAngle == 0) {
        // italics requested, but the font itself does not supply italics gylphs.
        cb.setTextMatrix(1, 0, PdfLogicalPageDrawable.ITALIC_ANGLE, 1, x1 + translateX, y);
      } else {
        cb.setTextMatrix(x1 + translateX, y);
      }
    } else {
      cb.setTextMatrix(x1 + translateX, y);
    }

    final OutputProcessorMetaData metaData = getMetaData();
    final GlyphList gs = renderableText.getGlyphs();
    final int offset = renderableText.getOffset();

    final CodePointBuffer codePointBuffer = getCodePointBuffer();
    if (metaData.isFeatureSupported(OutputProcessorFeature.FAST_FONTRENDERING)
        && isNormalTextSpacing(renderableText)) {
      final int maxLength = renderableText.computeMaximumTextSize(contentX2);
      final String text = gs.getText(renderableText.getOffset(), maxLength, codePointBuffer);

      cb.showText(text);
    } else {
      final PdfTextArray textArray = new PdfTextArray();
      final StringBuilder buffer = new StringBuilder(gs.getSize());
      final int maxPos = offset + renderableText.computeMaximumTextSize(contentX2);

      for (int i = offset; i < maxPos; i++) {
        final Glyph g = gs.getGlyph(i);
        final Spacing spacing = g.getSpacing();
        if (i != offset) {
          final float optimum = (float) StrictGeomUtility.toFontMetricsValue(spacing.getMinimum());
          if (optimum != 0) {
            textArray.add(buffer.toString());
            textArray.add(-optimum / textSpec.getFontSize());
            buffer.setLength(0);
          }
        }

        final String text = gs.getGlyphAsString(i, codePointBuffer);
        buffer.append(text);
      }
      if (buffer.length() > 0) {
        textArray.add(buffer.toString());
      }
      cb.showText(textArray);
    }
  }
  @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;
  }
  /**
   * 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);
  }
Beispiel #25
0
 /**
  * returns the x and y, rounded up
  *
  * @return
  */
 private String getLocationString() {
   return new BigDecimal(translation.getTranslateX()).setScale(2, RoundingMode.HALF_EVEN)
       + ", "
       + new BigDecimal(translation.getTranslateY()).setScale(2, RoundingMode.HALF_EVEN);
 }
  /**
   * 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();
  }
Beispiel #27
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();
        }
      }
    }
  }