This is an automated email from the ASF dual-hosted git repository. jsorel pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 5c209b019ae4dbf2442ded906ea087cf1e35a324 Author: jsorel <[email protected]> AuthorDate: Thu Nov 14 15:07:46 2019 +0100 Coverage : first implementation of evaluate method for GridCoverage2D --- .../sis/internal/coverage/GridCoverage2D.java | 135 +++++++++++++++++++-- .../sis/internal/coverage/GridCoverage2DTest.java | 3 +- 2 files changed, 129 insertions(+), 9 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/GridCoverage2D.java b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/GridCoverage2D.java index 842ca9d..5f8d76f 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/GridCoverage2D.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/GridCoverage2D.java @@ -16,6 +16,7 @@ */ package org.apache.sis.internal.coverage; +import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.RenderedImage; @@ -25,8 +26,17 @@ import org.apache.sis.coverage.SampleDimension; import org.apache.sis.coverage.grid.GridCoverage; import org.apache.sis.coverage.grid.GridExtent; import org.apache.sis.coverage.grid.GridGeometry; +import org.apache.sis.referencing.CRS; +import org.apache.sis.referencing.operation.transform.MathTransforms; import org.apache.sis.util.ArgumentChecks; import org.opengis.coverage.CannotEvaluateException; +import org.opengis.coverage.PointOutsideCoverageException; +import org.opengis.geometry.DirectPosition; +import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.datum.PixelInCell; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.TransformException; +import org.opengis.util.FactoryException; /** * A {@link GridCoverage} with data stored in a {@link RenderedImage}. @@ -36,11 +46,13 @@ import org.opengis.coverage.CannotEvaluateException; * @since 2.0 * @module */ -public class GridCoverage2D extends GridCoverage { +public final class GridCoverage2D extends GridCoverage { /** * The sample values, stored as a RenderedImage. */ - protected final RenderedImage image; + private final RenderedImage image; + private final int[] imageAxes; + private final CoordinateReferenceSystem crs2d; /** * Result of the call to {@link #forConvertedValues(boolean)}, created when first needed. @@ -48,15 +60,32 @@ public class GridCoverage2D extends GridCoverage { private GridCoverage converted; /** + * The given RenderedImage may not start at 0,0, so does the gridExtent of the grid geometry. + * Image minX/MinY coordinate is expected to be located grid extent lower corner. + * * * @param grid the grid extent, CRS and conversion from cell indices to CRS. * @param bands sample dimensions for each image band. * @param image the sample values as a RenderedImage, potentially multi-banded in packed view. */ - public GridCoverage2D(final GridGeometry grid, final Collection<? extends SampleDimension> bands, final RenderedImage image) { + public GridCoverage2D(final GridGeometry grid, final Collection<? extends SampleDimension> bands, final RenderedImage image) throws FactoryException { super(grid, bands); this.image = image; ArgumentChecks.ensureNonNull("image", image); + + //extract the 2D Coordinater + GridExtent extent = grid.getExtent(); + imageAxes = extent.getSubspaceDimensions(2); + crs2d = CRS.reduce(grid.getCoordinateReferenceSystem(), imageAxes); + + //check image is coherent with grid geometry + if (image.getWidth() != extent.getSize(imageAxes[0])) { + throw new IllegalArgumentException("Image width " + image.getWidth() + "does not match grid extent width "+ extent.getSize(imageAxes[0])); + } + if (image.getHeight()!= extent.getSize(imageAxes[1])) { + throw new IllegalArgumentException("Image height " + image.getHeight()+ "does not match grid extent height "+ extent.getSize(imageAxes[1])); + } + } /** @@ -94,11 +123,10 @@ public class GridCoverage2D extends GridCoverage { if (sliceExtent == null || sliceExtent.equals(getGridGeometry().getExtent())) { return image; } else { - final int[] imgAxes = sliceExtent.getSubspaceDimensions(2); - final int subX = Math.toIntExact(sliceExtent.getLow(imgAxes[0])); - final int subY = Math.toIntExact(sliceExtent.getLow(imgAxes[1])); - final int subWidth = Math.toIntExact(Math.round(sliceExtent.getSize(imgAxes[0]))); - final int subHeight = Math.toIntExact(Math.round(sliceExtent.getSize(imgAxes[1]))); + final int subX = Math.toIntExact(sliceExtent.getLow(imageAxes[0])); + final int subY = Math.toIntExact(sliceExtent.getLow(imageAxes[1])); + final int subWidth = Math.toIntExact(Math.round(sliceExtent.getSize(imageAxes[0]))); + final int subHeight = Math.toIntExact(Math.round(sliceExtent.getSize(imageAxes[1]))); if (image instanceof BufferedImage) { final BufferedImage bi = (BufferedImage) image; @@ -114,4 +142,95 @@ public class GridCoverage2D extends GridCoverage { } } + public double[] evaluate(DirectPosition position, double[] pixel) throws CannotEvaluateException { + + try { + position = toGridCoord(position); + + int x = 0; + int y = 0; + for (int i = 0, n = position.getDimension(); i < n; i++) { + final double dv = position.getOrdinate(i); + if (Double.isFinite(dv)) { + throw new PointOutsideCoverageException("Position outside coverage, axis " + i + " value " + dv); + } + + final int v = Math.toIntExact(Math.round(dv)); + if (i == imageAxes[0]) { + x = v; + } else if (i == imageAxes[1]) { + y = v; + } else if (v != 0) { + //coverage is a slice, all other indices must be zero, otherwise we are outside coverage + throw new PointOutsideCoverageException("Position outside coverage, axis " + i + " value " + v); + } + } + + if (getBounds().contains(x,y)) { + return image.getTile(XToTileX(x), YToTileY(y)).getPixel(x, y, pixel); + } + throw new PointOutsideCoverageException(""); + } catch (FactoryException | TransformException ex) { + throw new CannotEvaluateException(ex.getMessage(), ex); + } + } + + /** + * Converts the specified point to grid coordinate. + * @param point point to transform to grid coordinate + * @return point in grid coordinate + * @throws org.opengis.util.FactoryException if creating transformation fails + * @throws org.opengis.referencing.operation.TransformException if transformation fails + */ + protected DirectPosition toGridCoord(final DirectPosition point) + throws FactoryException, TransformException + { + final CoordinateReferenceSystem sourceCRS = point.getCoordinateReferenceSystem(); + final MathTransform trs; + if (sourceCRS != null) { + MathTransform toCrs = CRS.findOperation(sourceCRS, getCoordinateReferenceSystem(), null).getMathTransform(); + trs = MathTransforms.concatenate(toCrs, getGridGeometry().getGridToCRS(PixelInCell.CELL_CENTER).inverse()); + } else { + trs = getGridGeometry().getGridToCRS(PixelInCell.CELL_CENTER); + } + + return trs.transform(point, null); + } + + /** + * Utility method to convert image bounds as {@link java.awt.Rectangle}. + * @return {@link java.awt.Rectangle} bounds. + */ + private Rectangle getBounds() { + return new Rectangle(image.getMinX(), image.getMinY(), image.getWidth(), image.getHeight()); + } + + /** + * Converts a pixel's X coordinate into a horizontal tile index. + * @param x pixel x coordinate + * @return tile x coordinate + */ + private int XToTileX(int x) { + int tileWidth = image.getTileWidth(); + x -= image.getTileGridXOffset(); + if (x < 0) { + x += 1 - tileWidth; + } + return x/tileWidth; + } + + /** + * Converts a pixel's Y coordinate into a vertical tile index. + * @param y pixel x coordinate + * @return tile y coordinate + */ + private int YToTileY(int y) { + int tileHeight = image.getTileHeight(); + y -= image.getTileGridYOffset(); + if (y < 0) { + y += 1 - tileHeight; + } + return y/tileHeight; + } + } diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/GridCoverage2DTest.java b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/GridCoverage2DTest.java index ed6d759..d1de1eb 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/GridCoverage2DTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/GridCoverage2DTest.java @@ -40,6 +40,7 @@ import org.junit.Assert; import org.junit.Test; import org.opengis.referencing.datum.PixelInCell; import org.opengis.referencing.operation.MathTransform1D; +import org.opengis.util.FactoryException; /** @@ -55,7 +56,7 @@ public class GridCoverage2DTest extends TestCase { * Tests with a two-dimensional coverage. */ @Test - public void testCoverage2D() { + public void testCoverage2D() throws FactoryException { /* * Create coverage of 2×2 pixels with an identity "grid to CRS" transform. * The range of sample values will be [-10 … +10]°C.
