Example #1
0
  /**
   * Performs a translation using the "Resample" operation.
   *
   * @param grid the {@link GridCoverage2D} to apply the translation on.
   * @throws NoninvertibleTransformException If a "grid to CRS" transform is not invertible.
   */
  private void doTranslation(GridCoverage2D grid) throws NoninvertibleTransformException {
    final int transX = -253;
    final int transY = -456;
    final double scaleX = 0.04;
    final double scaleY = -0.04;
    final ParameterBlock block =
        new ParameterBlock()
            .addSource(grid.getRenderedImage())
            .add((float) transX)
            .add((float) transY);
    RenderedImage image = JAI.create("Translate", block);
    assertEquals("Incorrect X translation", transX, image.getMinX());
    assertEquals("Incorrect Y translation", transY, image.getMinY());

    /*
     * Create a grid coverage from the translated image but with the same envelope.
     * Consequently, the 'gridToCoordinateSystem' should be translated by the same
     * amount, with the opposite sign.
     */
    AffineTransform expected = getAffineTransform(grid);
    assertNotNull(expected);
    expected = new AffineTransform(expected); // Get a mutable instance.
    final GridCoverageFactory factory = CoverageFactoryFinder.getGridCoverageFactory(null);
    grid =
        factory.create(
            "Translated",
            image,
            grid.getEnvelope(),
            grid.getSampleDimensions(),
            new GridCoverage2D[] {grid},
            grid.getProperties());
    expected.translate(-transX, -transY);
    assertTransformEquals(expected, getAffineTransform(grid));

    /*
     * Apply the "Resample" operation with a specific 'gridToCoordinateSystem' transform.
     * The envelope is left unchanged. The "Resample" operation should compute automatically
     * new image bounds.
     */
    final AffineTransform at = AffineTransform.getScaleInstance(scaleX, scaleY);
    final MathTransform tr = ProjectiveTransform.create(at);
    // account for the half pixel correction between the two spaces since we are talking raster here
    // but the resample will talk model!
    final MathTransform correctedTransform =
        PixelTranslation.translate(tr, PixelInCell.CELL_CORNER, PixelInCell.CELL_CENTER);
    final GridGeometry2D geometry = new GridGeometry2D(null, correctedTransform, null);
    final GridCoverage2D newGrid =
        (GridCoverage2D)
            Operations.DEFAULT.resample(grid, grid.getCoordinateReferenceSystem(), geometry, null);
    assertEquals(correctedTransform, getAffineTransform(newGrid));
    image = newGrid.getRenderedImage();
    expected.preConcatenate(at.createInverse());
    final Point point = new Point(transX, transY);
    assertSame(point, expected.transform(point, point)); // Round toward neareast integer
  }
Example #2
0
  @Test
  public void testDomainSubsetRxRy() throws Exception {
    // get base  coverage
    final GridCoverage baseCoverage =
        catalog.getCoverageByName(TASMANIA_BM.getLocalPart()).getGridCoverage(null, null);
    final AffineTransform2D expectedTx =
        (AffineTransform2D) baseCoverage.getGridGeometry().getGridToCRS();
    final GeneralEnvelope originalEnvelope = (GeneralEnvelope) baseCoverage.getEnvelope();
    final GeneralEnvelope newEnvelope = new GeneralEnvelope(originalEnvelope);
    newEnvelope.setEnvelope(
        originalEnvelope.getMinimum(0),
        originalEnvelope.getMaximum(1) - originalEnvelope.getSpan(1) / 2,
        originalEnvelope.getMinimum(0) + originalEnvelope.getSpan(0) / 2,
        originalEnvelope.getMaximum(1));

    final MathTransform cornerWorldToGrid =
        PixelTranslation.translate(expectedTx, PixelInCell.CELL_CENTER, PixelInCell.CELL_CORNER);
    final GeneralGridEnvelope expectedGridEnvelope =
        new GeneralGridEnvelope(
            CRS.transform(cornerWorldToGrid.inverse(), newEnvelope),
            PixelInCell.CELL_CORNER,
            false);
    final StringBuilder envelopeBuilder = new StringBuilder();
    envelopeBuilder.append(newEnvelope.getMinimum(0)).append(",");
    envelopeBuilder.append(newEnvelope.getMinimum(1)).append(",");
    envelopeBuilder.append(newEnvelope.getMaximum(0)).append(",");
    envelopeBuilder.append(newEnvelope.getMaximum(1));

    Map<String, Object> raw = baseMap();
    final String layerID = getLayerId(TASMANIA_BM);
    raw.put("sourcecoverage", layerID);
    raw.put("version", "1.0.0");
    raw.put("format", "image/geotiff");
    raw.put("BBox", envelopeBuilder.toString());
    raw.put("crs", "EPSG:4326");
    raw.put("resx", Double.toString(expectedTx.getScaleX()));
    raw.put("resy", Double.toString(Math.abs(expectedTx.getScaleY())));

    final GridCoverage[] coverages = executeGetCoverageKvp(raw);
    final GridCoverage2D result = (GridCoverage2D) coverages[0];
    assertTrue(coverages.length == 1);
    final AffineTransform2D tx = (AffineTransform2D) result.getGridGeometry().getGridToCRS();
    assertEquals("resx", expectedTx.getScaleX(), tx.getScaleX(), 1E-6);
    assertEquals("resx", Math.abs(expectedTx.getScaleY()), Math.abs(tx.getScaleY()), 1E-6);

    final GridEnvelope gridEnvelope = result.getGridGeometry().getGridRange();
    assertEquals("w", 180, gridEnvelope.getSpan(0));
    assertEquals("h", 180, gridEnvelope.getSpan(1));
    assertEquals("grid envelope", expectedGridEnvelope, gridEnvelope);

    // dispose
    CoverageCleanerCallback.disposeCoverage(baseCoverage);
    CoverageCleanerCallback.disposeCoverage(coverages[0]);
  }
  private void inspectCoordinateReferenceSystems() throws DataSourceException {
    // get the crs for the requested bbox
    requestCRS = CRS.getHorizontalCRS(requestedBBox.getCoordinateReferenceSystem());

    //
    // Check if the request CRS is different from the coverage native CRS
    //
    if (!CRS.equalsIgnoreMetadata(requestCRS, coverageProperties.crs2D))
      try {
        destinationToSourceTransform =
            CRS.findMathTransform(requestCRS, coverageProperties.crs2D, true);
      } catch (FactoryException e) {
        throw new DataSourceException("Unable to inspect request CRS", e);
      }
    // now transform the requested envelope to source crs
    if (destinationToSourceTransform != null && destinationToSourceTransform.isIdentity()) {
      destinationToSourceTransform = null; // the CRS is basically the same
    } else if (destinationToSourceTransform instanceof AffineTransform) {
      needsReprojection = true;
      //
      // k, the transformation between the various CRS is not null or the
      // Identity, let's see if it is an affine transform, which case we
      // can incorporate it into the requested grid to world
      //
      // we should not have any problems with regards to BBOX reprojection
      // update the requested grid to world transformation by pre concatenating the destination to
      // source transform
      AffineTransform mutableTransform = (AffineTransform) requestedGridToWorld.clone();
      mutableTransform.preConcatenate((AffineTransform) destinationToSourceTransform);

      // update the requested envelope
      try {
        final MathTransform tempTransform =
            PixelTranslation.translate(
                ProjectiveTransform.create(mutableTransform),
                PixelInCell.CELL_CENTER,
                PixelInCell.CELL_CORNER);
        requestedBBox =
            new ReferencedEnvelope(
                CRS.transform(tempTransform, new GeneralEnvelope(requestedRasterArea)));

      } catch (MismatchedDimensionException e) {
        throw new DataSourceException("Unable to inspect request CRS", e);
      } catch (TransformException e) {
        throw new DataSourceException("Unable to inspect request CRS", e);
      }

      // now clean up all the traces of the transformations
      destinationToSourceTransform = null;
    }
  }
  /**
   * Checks whether a world file is associated with the data source. If found, set a proper
   * envelope.
   *
   * @throws IllegalStateException
   * @throws IOException
   */
  protected void parseWorldFile() {
    final String worldFilePath =
        new StringBuffer(this.parentPath)
            .append(GridCoverageUtilities.SEPARATOR)
            .append(coverageName)
            .toString();

    File file2Parse = null;
    boolean worldFileExists = false;
    // //
    //
    // Check for a world file with the format specific extension
    //
    // //
    if (worldFileExt != null && worldFileExt.length() > 0) {
      file2Parse = new File(worldFilePath + worldFileExt);
      worldFileExists = file2Parse.exists();
    }

    // //
    //
    // Check for a world file with the default extension
    //
    // //
    if (!worldFileExists) {
      file2Parse = new File(worldFilePath + GridCoverageUtilities.DEFAULT_WORLDFILE_EXT);
      worldFileExists = file2Parse.exists();
    }

    if (worldFileExists) {

      try {
        final WorldFileReader reader = new WorldFileReader(file2Parse);
        raster2Model = reader.getTransform();

        // //
        //
        // In case we read from a real world file we have together the
        // envelope. World file transformation assumes to work in the
        // CELL_CENTER condition
        //
        // //
        MathTransform tempTransform =
            PixelTranslation.translate(
                raster2Model, PixelInCell.CELL_CENTER, PixelInCell.CELL_CORNER);
        final Envelope gridRange = new GeneralEnvelope((GridEnvelope2D) originalGridRange);
        final GeneralEnvelope coverageEnvelope = CRS.transform(tempTransform, gridRange);
        originalEnvelope = coverageEnvelope;
        return;
      } catch (TransformException e) {
        if (LOGGER.isLoggable(Level.WARNING)) {
          LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
        }
      } catch (IllegalStateException e) {
        if (LOGGER.isLoggable(Level.WARNING)) {
          LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
        }
      } catch (IOException e) {
        if (LOGGER.isLoggable(Level.WARNING)) {
          LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
        }
      }
    }
    // if we got here we did not find a suitable transform
    raster2Model = null;
  }
  /**
   * Return a crop region from a specified envelope, leveraging on the grid to world transformation.
   *
   * @param refinedRequestedBBox the crop envelope
   * @return a {@code Rectangle} representing the crop region.
   * @throws TransformException in case a problem occurs when going back to raster space.
   * @throws DataSourceException
   */
  private void computeCropRasterArea() throws DataSourceException {

    // we have nothing to crop
    if (cropBBox == null) {
      destinationRasterArea = null;
      return;
    }

    //
    // We need to invert the requested gridToWorld and then adjust the requested raster area are
    // accordingly
    //

    // invert the requested grid to world keeping into account the fact that it is related to cell
    // center
    // while the raster is related to cell corner
    MathTransform2D requestedWorldToGrid;
    try {
      requestedWorldToGrid =
          (MathTransform2D)
              PixelTranslation.translate(
                      ProjectiveTransform.create(requestedGridToWorld),
                      PixelInCell.CELL_CENTER,
                      PixelInCell.CELL_CORNER)
                  .inverse();
    } catch (NoninvertibleTransformException e) {
      throw new DataSourceException(e);
    }

    if (destinationToSourceTransform == null || destinationToSourceTransform.isIdentity()) {

      // now get the requested bbox which have been already adjusted and project it back to raster
      // space
      try {
        destinationRasterArea =
            new GeneralGridEnvelope(
                    CRS.transform(requestedWorldToGrid, new GeneralEnvelope(cropBBox)),
                    PixelInCell.CELL_CORNER,
                    false)
                .toRectangle();
      } catch (IllegalStateException e) {
        throw new DataSourceException(e);
      } catch (TransformException e) {
        throw new DataSourceException(e);
      }
    } else {
      //
      // reproject the crop bbox back and then crop, notice that we are imposing
      //
      try {
        final GeneralEnvelope cropBBOXInRequestCRS =
            CRS.transform(cropBBox, requestedBBox.getCoordinateReferenceSystem());
        cropBBOXInRequestCRS.setCoordinateReferenceSystem(
            requestedBBox.getCoordinateReferenceSystem());
        // make sure it falls within the requested envelope
        cropBBOXInRequestCRS.intersect(requestedBBox);

        // now go back to raster space
        destinationRasterArea =
            new GeneralGridEnvelope(
                    CRS.transform(requestedWorldToGrid, cropBBOXInRequestCRS),
                    PixelInCell.CELL_CORNER,
                    false)
                .toRectangle();
        // intersect with the original requested raster space to be sure that we stay within the
        // requested raster area
        XRectangle2D.intersect(destinationRasterArea, requestedRasterArea, destinationRasterArea);
      } catch (NoninvertibleTransformException e) {
        throw new DataSourceException(e);
      } catch (TransformException e) {
        throw new DataSourceException(e);
      }
    }
    // is it empty??
    if (destinationRasterArea.isEmpty()) {
      if (LOGGER.isLoggable(Level.FINE))
        LOGGER.log(
            Level.FINE,
            "Requested envelope too small resulting in empty cropped raster region. cropBbox:"
                + cropBBox);
      // TODO: Future versions may define a 1x1 rectangle starting
      // from the lower coordinate
      empty = true;
      return;
    }
  }