You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2019/04/04 14:47:20 UTC

[sis] branch geoapi-4.0 updated (77172ed -> da98b1f)

This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a change to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git.


    from 77172ed  Fix a NullPointerException when the envelope do not contains an horizontal component.
     new 5617967  fix(raster): Ensure wrap-around trick is applied on grid geometry slicing.
     new da98b1f  chore(raster): Add tests for grid derivation: slicing on a corner, slicing with wrap-around.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../apache/sis/coverage/grid/GridDerivation.java   |  47 +++++++---
 .../sis/coverage/grid/GridDerivationTest.java      | 102 +++++++++++++++++++++
 .../internal/referencing/WraparoundAdjustment.java |   6 +-
 3 files changed, 138 insertions(+), 17 deletions(-)


[sis] 02/02: chore(raster): Add tests for grid derivation: slicing on a corner, slicing with wrap-around.

Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit da98b1fc8a431ef8ab2c53ba629f57d738e7e32b
Author: Alexis Manin <al...@gmail.com>
AuthorDate: Thu Apr 4 11:37:15 2019 +0200

    chore(raster): Add tests for grid derivation: slicing on a corner, slicing with wrap-around.
---
 .../sis/coverage/grid/GridDerivationTest.java      | 102 +++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java b/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java
index 87bb0a5..9c57c9d 100644
--- a/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java
+++ b/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java
@@ -16,6 +16,13 @@
  */
 package org.apache.sis.coverage.grid;
 
+import org.apache.sis.geometry.Envelope2D;
+import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.crs.DefaultCompoundCRS;
+import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.junit.Assert;
+import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.Envelope;
 import org.opengis.metadata.spatial.DimensionNameType;
 import org.opengis.referencing.datum.PixelInCell;
@@ -33,6 +40,10 @@ import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
+import java.util.Collections;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+
 import static org.apache.sis.test.ReferencingAssert.*;
 import static org.apache.sis.coverage.grid.GridGeometryTest.assertExtentEquals;
 
@@ -253,6 +264,97 @@ public final strictfp class GridDerivationTest extends TestCase {
     }
 
     /**
+     * Check that wrap-around is well applied when using {@link GridDerivation#slice(DirectPosition)}.
+     */
+    @Test
+    public void testSliceWrapAround() {
+        final GridGeometry base = new GridGeometry(
+                PixelInCell.CELL_CORNER,
+                new AffineTransform2D(-0.02, 0, 0, 0.1, 55, 172),
+                new Envelope2D(CommonCRS.WGS84.geographic(), 42, 172, 13, 51),
+                GridRoundingMode.NEAREST
+        );
+
+        final GridGeometry expectedResult = base.derive()
+                .slice(new DirectPosition2D(51, 187))
+                .build();
+
+        final GridGeometry fromWrapAround = base.derive()
+                .slice(new DirectPosition2D(51, -173))
+                .build();
+
+        Assert.assertEquals("Slice with wrap-around", expectedResult, fromWrapAround);
+        assertBetween(
+                "Wrapped Y coordinate",
+                base.envelope.getMinimum(1),
+                base.envelope.getMaximum(1),
+                fromWrapAround.envelope.getMedian(1)
+        );
+    }
+
+    /**
+     * Ensure that slicing on a corner point does not fail, but gives back a geometry centered on a pixel corner.
+     * @throws TransformException If we cannot build our test point.
+     */
+    @Test
+    public void testSliceCorner() throws TransformException {
+        GridGeometry base = grid(-132, 327, 986, 597, 2, 3);
+
+        // First of all, we'll try by focusing on the last pixel.
+        final DirectPosition2D gridUpperCorner = new DirectPosition2D(
+                base.extent.getHigh(0),
+                base.extent.getLow(1)
+        );
+
+        final DirectPosition geoUpperCorner = base.getGridToCRS(PixelInCell.CELL_CENTER)
+                .transform(gridUpperCorner, null);
+
+        GridGeometry slice = base.derive()
+                .slice(geoUpperCorner)
+                .build();
+
+        long[] expectedGridPoint = {(long) gridUpperCorner.x, (long) gridUpperCorner.y};
+        assertExtentEquals(expectedGridPoint, expectedGridPoint, slice.extent);
+
+        /* We will now try to focus on a point near the envelope edge. Note that slicing ensures to return a valid grid
+         * for any point INSIDE the envelope, it's non-deterministic about points perfectly aligned on the edge. So,
+         * here we will test a point very near to the envelope edge, but still into it.
+         */
+        final GeneralEnvelope grid3d = new GeneralEnvelope(3);
+        grid3d.setEnvelope(0, 0, 0, 1920, 1080, 4);
+
+        final DefaultCompoundCRS crs3d = new DefaultCompoundCRS(
+                Collections.singletonMap("name", "geo3d"),
+                CommonCRS.defaultGeographic(),
+                CommonCRS.Temporal.JULIAN.crs()
+        );
+        final GeneralEnvelope geo3d = new GeneralEnvelope(crs3d);
+        geo3d.setEnvelope(-180, -90, 1865.128, 180, 90, 1865.256);
+        base = new GridGeometry(
+                PixelInCell.CELL_CORNER,
+                MathTransforms.linear(Matrices.createTransform(grid3d, geo3d)),
+                geo3d,
+                GridRoundingMode.NEAREST
+        );
+
+        final GeneralDirectPosition geo3dUpperCorner = new GeneralDirectPosition(geo3d.getUpperCorner());
+        IntStream.range(0, geo3dUpperCorner.getDimension())
+                .forEach(idx -> geo3dUpperCorner.ordinates[idx] -= 1e-7);
+
+        slice = base.derive()
+                .slice(geo3dUpperCorner)
+                .build();
+
+        // Build expected grid point focused after slicing. We expect it to be upper corner.
+        expectedGridPoint = DoubleStream.of(grid3d.getUpperCorner().getCoordinate())
+                .mapToLong(value -> (long) value)
+                .map(exclusiveValue -> exclusiveValue -1)// Exclusive to inclusive
+                .toArray();
+
+        assertExtentEquals(expectedGridPoint, expectedGridPoint, slice.extent);
+    }
+
+    /**
      * Tests deriving a grid geometry with an envelope crossing the antimeridian.
      */
     @Test


[sis] 01/02: fix(raster): Ensure wrap-around trick is applied on grid geometry slicing.

Posted by de...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 5617967a85673b3e5b77986a3163d2e4d93788f8
Author: Alexis Manin <al...@gmail.com>
AuthorDate: Wed Apr 3 19:49:06 2019 +0200

    fix(raster): Ensure wrap-around trick is applied on grid geometry slicing.
---
 .../apache/sis/coverage/grid/GridDerivation.java   | 47 +++++++++++++++-------
 .../internal/referencing/WraparoundAdjustment.java |  6 ++-
 2 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
index f43c008..a0172e5 100644
--- a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
+++ b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
@@ -504,9 +504,9 @@ public class GridDerivation {
             dimension = baseExtent.getDimension();      // Non-null since 'base.requireGridToCRS()' succeed.
             GeneralEnvelope indices = null;
             if (areaOfInterest != null) {
-                final WraparoundAdjustment adj = new WraparoundAdjustment(areaOfInterest);
-                adj.shiftInto(base.envelope, (baseToAOI != null) ? baseToAOI.getMathTransform() : null);
-                indices = adj.result(cornerToCRS.inverse());
+                indices = new WraparoundAdjustment(areaOfInterest)
+                        .shiftInto(base.envelope, (baseToAOI != null) ? baseToAOI.getMathTransform() : null)
+                        .result(cornerToCRS.inverse());
                 clipExtent(indices);
             }
             if (indices == null || indices.getDimension() != dimension) {
@@ -723,9 +723,13 @@ public class GridDerivation {
      *       For dimensionality reduction, see {@link GridGeometry#reduce(int...)}.</li>
      * </ul>
      *
-     * @param  slicePoint   the coordinates where to get a slice.
+     * @param  slicePoint   the coordinates where to get a slice. If no coordinate reference system is attached to it,
+     *                      we consider it's the same as base grid geometry.
      * @return {@code this} for method call chaining.
-     * @throws IncompleteGridGeometryException if the base grid geometry has no extent or no "grid to CRS" transform.
+     * @throws IncompleteGridGeometryException if the base grid geometry has no extent, no "grid to CRS" transform, or
+     * if its coordinate reference system is unknown while input point one is (in which case we're unable to find a
+     * transform between base CRS and input point CRS). Note that if you're sure that your point is expressed in base
+     * CRS, you can give a point without any CRS, to avoid this check.
      * @throws IllegalGridGeometryException if an error occurred while converting the point coordinates to grid coordinates.
      * @throws PointOutsideCoverageException if the given point is outside the grid extent.
      */
@@ -737,23 +741,36 @@ public class GridDerivation {
             if (toBase != null) {
                 gridToCRS = MathTransforms.concatenate(toBase, gridToCRS);
             }
-            if (base.envelope != null) {
-                final CoordinateReferenceSystem sourceCRS = base.envelope.getCoordinateReferenceSystem();
-                if (sourceCRS != null) {
-                    final CoordinateReferenceSystem targetCRS = slicePoint.getCoordinateReferenceSystem();
-                    if (targetCRS != null) {
-                        final CoordinateOperation operation = CRS.findOperation(sourceCRS, targetCRS, null);
-                        gridToCRS = MathTransforms.concatenate(gridToCRS, operation.getMathTransform());
-                    }
-                }
+
+            /* We'll try to find a link between base coordinate system and input point one. Note that we allow unknown
+             * CRS on slice point, in which case we consider it to be expressed in base geometry system. However, if the
+             * point CRS is known, but base geometry one is not, too much ambiguity resides, and we'll throw an error.
+             */
+            final MathTransform baseToSlice;
+            final CoordinateReferenceSystem targetCRS = slicePoint.getCoordinateReferenceSystem();
+            if (targetCRS != null) {
+                final CoordinateReferenceSystem sourceCRS = base.getCoordinateReferenceSystem();
+                baseToSlice = CRS.findOperation(sourceCRS, targetCRS, null)
+                        .getMathTransform();
+                gridToCRS = MathTransforms.concatenate(gridToCRS, baseToSlice);
+            } else {
+                baseToSlice = null;
             }
+
             final int dimension = gridToCRS.getTargetDimensions();
             ArgumentChecks.ensureDimensionMatches("slicePoint", dimension, slicePoint);
             gridToCRS = dropUnusedDimensions(gridToCRS, dimension);
-            DirectPosition gridPoint = gridToCRS.inverse().transform(slicePoint, null);
+
+            GeneralEnvelope sliceEnvelope = new GeneralEnvelope(slicePoint, slicePoint);
+            sliceEnvelope = new WraparoundAdjustment(sliceEnvelope)
+                    .shiftInto(base.envelope, baseToSlice)
+                    .result(gridToCRS.inverse());
+            DirectPosition gridPoint = sliceEnvelope.getMedian();
             if (scaledExtent != null) {
                 scaledExtent = scaledExtent.slice(gridPoint, modifiedDimensions);
             }
+
+            // Rebuild the extent without scaling
             if (toBase != null) {
                 gridPoint = toBase.transform(gridPoint, gridPoint);
             }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WraparoundAdjustment.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WraparoundAdjustment.java
index 96568f2..fb66213 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WraparoundAdjustment.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WraparoundAdjustment.java
@@ -117,16 +117,17 @@ public final class WraparoundAdjustment {
      * @param  validToAOI        if the envelopes do not use the same CRS, the transformation from {@code domainOfValidity}
      *                           to {@code areaOfInterest}. Otherwise {@code null}. This method does not check by itself if
      *                           a coordinate operation is needed; it must be supplied.
+     * @return this object, allowing to chain {@link #result(MathTransform)} operation.
      * @throws TransformException if an envelope transformation was required but failed.
      *
      * @see GeneralEnvelope#simplify()
      */
-    public void shiftInto(Envelope domainOfValidity, MathTransform validToAOI) throws TransformException {
+    public WraparoundAdjustment shiftInto(Envelope domainOfValidity, MathTransform validToAOI) throws TransformException {
         CoordinateReferenceSystem crs = areaOfInterest.getCoordinateReferenceSystem();
         if (crs == null) {
             crs = domainOfValidity.getCoordinateReferenceSystem();      // Assumed to apply to AOI too.
             if (crs == null) {
-                return;
+                return this;
             }
         }
         /*
@@ -301,6 +302,7 @@ public final class WraparoundAdjustment {
                 }
             }
         }
+        return this;
     }
 
     /**