sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: In a call to `GridGeometry.reduce(…)`, the number of CRS dimensions is not necessarily the same than the number of grid dimensions.
Date Mon, 09 Mar 2020 11:47:27 GMT
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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 8011fe0  In a call to `GridGeometry.reduce(…)`, the number of CRS dimensions is
not necessarily the same than the number of grid dimensions.
8011fe0 is described below

commit 8011fe07876d03c00249a98384ffb86995833841
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Mon Mar 9 12:46:11 2020 +0100

    In a call to `GridGeometry.reduce(…)`, the number of CRS dimensions is not necessarily
the same than the number of grid dimensions.
---
 .../apache/sis/coverage/grid/GridDerivation.java   |  3 +-
 .../org/apache/sis/coverage/grid/GridGeometry.java | 24 ++++++----
 .../apache/sis/coverage/grid/GridGeometryTest.java | 25 +++++++++-
 .../operation/transform/TransformSeparator.java    |  4 +-
 .../transform/TransformSeparatorTest.java          | 53 +++++++++++++++++++++-
 5 files changed, 95 insertions(+), 14 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
index cb67ca5..0d03081 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridDerivation.java
@@ -295,7 +295,7 @@ public class GridDerivation {
      * instead of CRS coordinates space.
      *
      * @param  extent  the grid extent to set as a result of the given scale, or {@code null}
for computing it automatically.
-     *                 In non-null, then this given extent is used <i>as-is</i>
without checking intersection with the base
+     *                 If non-null, then this given extent is used <i>as-is</i>
without checking intersection with the base
      *                 grid geometry.
      * @param  scales  the scale factors to apply on grid indices. If the length of this
array is smaller than the number of
      *                 grid dimension, then a scale of 1 is assumed for all missing dimensions.
@@ -306,6 +306,7 @@ public class GridDerivation {
      * @see #subsample(int...)
      * @see GridExtent#resize(long...)
      */
+    @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
     public GridDerivation resize(GridExtent extent, double... scales) {
         ArgumentChecks.ensureNonNull("scales", scales);
         ensureSubgridNotSet();
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
index 9247e58..0950629 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.coverage.grid;
 
-import java.util.Arrays;
 import java.util.Objects;
 import java.util.Locale;
 import java.util.Optional;
@@ -68,7 +67,6 @@ import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.CharSequences;
-import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.Debug;
 import org.apache.sis.io.TableAppender;
@@ -611,37 +609,45 @@ public class GridGeometry implements Serializable {
      * Creates a new grid geometry over the specified dimensions of the given grid geometry.
      *
      * @param  other       the grid geometry to copy.
-     * @param  dimensions  the dimensions to select, in strictly increasing order (this may
not be verified).
+     * @param  dimensions  the grid (not CRS) dimensions to select, in strictly increasing
order.
      * @throws FactoryException if an error occurred while separating the "grid to CRS" transform.
      *
      * @see #reduce(int...)
      */
     private GridGeometry(final GridGeometry other, int[] dimensions) throws FactoryException
{
         extent = (other.extent != null) ? other.extent.reduce(dimensions) : null;
-        final int n = dimensions.length;
+        /*
+         * If a `gridToCRS` transform is available, retain the source dimensions specified
by `dimensions`.
+         * We work on source dimensions because they are the grid dimensions. But after this
reduction, we
+         * will work in CRS dimensions for the rest of this method. The CRS dimensions to
retain are often
+         * the same than the grid dimensions, but not necessarily.
+         */
         if (other.gridToCRS != null) {
             final int[] sources = dimensions;
             TransformSeparator sep = new TransformSeparator(other.gridToCRS);
             sep.addSourceDimensions(sources);
             gridToCRS  = sep.separate();
             dimensions = sep.getTargetDimensions();
-            assert dimensions.length == n : Arrays.toString(dimensions);
-            if (!ArraysExt.isSorted(dimensions, true)) {
-                throw new IllegalGridGeometryException(Resources.format(Resources.Keys.IllegalGridGeometryComponent_1,
"dimensions"));
-            }
             /*
              * We redo a separation for `cornerToCRS` instead than applying a translation
of the `gridToCRS`
              * computed above because we don't know which of `gridToCRS` and `cornerToCRS`
has less NaN values.
+             * We require however the exact same sequence of target dimensions.
              */
             sep = new TransformSeparator(other.cornerToCRS);
             sep.addSourceDimensions(sources);
             sep.addTargetDimensions(dimensions);
             cornerToCRS = sep.separate();
-            assert Arrays.equals(sep.getSourceDimensions(), dimensions) : Arrays.toString(dimensions);
         } else {
             gridToCRS   = null;
             cornerToCRS = null;
         }
+        /*
+         * At this point, `dimensions` gives CRS dimensions. It is usually the same sequence
than grid dimensions
+         * but not always. In particular it may have more elements if `TransformSeparator`
detected that dropping
+         * a grid dimension does not force us to drop the corresponding CRS dimension, for
example because it has
+         * a constant value.
+         */
+        final int n = dimensions.length;
         final ImmutableEnvelope env = other.envelope;
         if (env != null) {
             CoordinateReferenceSystem crs = env.getCoordinateReferenceSystem();
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
index b43eac0..357d1c1 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
@@ -39,7 +39,7 @@ import static org.apache.sis.test.ReferencingAssert.*;
  * Tests the {@link GridGeometry} implementation.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.0
+ * @version 1.1
  * @since   1.0
  * @module
  */
@@ -319,4 +319,27 @@ public final strictfp class GridGeometryTest extends TestCase {
                   2, 3,
                   0, 1), MathTransforms.getMatrix(reduced.getGridToCRS(PixelInCell.CELL_CORNER)),
STRICT);
     }
+
+    /**
+     * Tests {@link GridGeometry#reduce(int...)} with a {@code gridToCRS} transform having
a constant value
+     * in one dimension.
+     */
+    @Test
+    public void testReduceScalelessDimension() {
+        final GridGeometry grid = new GridGeometry(
+                new GridExtent(null, new long[] {336, 20, 4}, new long[] {401, 419, 10},
true),
+                PixelInCell.CELL_CORNER, MathTransforms.linear(new Matrix4(
+                        0,   0.5, 0,  -90,
+                        0.5, 0,   0, -180,
+                        0,   0,   0,    3,   // All scale coefficients set to 0.
+                        0,   0,   0,    1)), HardCodedCRS.GEOID_3D);
+
+        GridGeometry reduced = grid.reduce(0, 1);
+        MathTransform tr = reduced.getGridToCRS(PixelInCell.CELL_CORNER);
+        assertMatrixEquals("gridToCRS", Matrices.create(4, 3, new double[] {
+                        0,   0.5, -90,
+                        0.5, 0,  -180,
+                        0,   0,     3,   // All scale coefficients set to 0.
+                        0,   0,     1}), MathTransforms.getMatrix(tr), STRICT);
+    }
 }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java
index 592e1e3..3e26722 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/TransformSeparator.java
@@ -158,7 +158,7 @@ public class TransformSeparator {
 
     /**
      * Adds the specified {@code dimensions} to the specified sequence.
-     * Values must be given in strictly increasing order.
+     * Values must be given in strictly increasing order (this will be verified by this method).
      *
      * @param  sequence    the {@link #sourceDimensions} or {@link #targetDimensions} sequence
to update.
      * @param  dimensions  the user-supplied dimensions to add to the given sequence.
@@ -167,7 +167,7 @@ public class TransformSeparator {
      */
     private static int[] add(int[] sequence, final int[] dimensions, final int max) throws
IllegalArgumentException {
         int offset = 0;
-        int previous = -1;  // This initial value will ensure that we have no negative value.
+        int previous = -1;                          // This initial value will ensure that
we have no negative value.
         if (sequence != null && (offset = sequence.length) != 0) {
             previous = sequence[offset - 1];
             sequence = Arrays.copyOf(sequence, offset + dimensions.length);
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
index 6793ab5..806ecfb 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
@@ -45,7 +45,7 @@ import static org.opengis.test.Assert.*;
  * Tests {@link TransformSeparator}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
  * @since   0.7
  * @module
  */
@@ -189,6 +189,57 @@ public final strictfp class TransformSeparatorTest extends TestCase {
     }
 
     /**
+     * Tests separation of a linear transform where a row contains zero values for all terms
except translation.
+     *
+     * @throws FactoryException if an error occurred while creating a new transform.
+     */
+    @Test
+    public void testScalelessDimension() throws FactoryException {
+        Matrix matrix = new Matrix4(
+            2, 0, 0, 7,
+            0, 4, 0, 6,
+            0, 0, 0, 5,                 // All scale factors are zero.
+            0, 0, 0, 1);
+
+        MathTransform tr = new ProjectiveTransform(matrix);
+        TransformSeparator s = new TransformSeparator(tr);
+        /*
+         * The usually expected case, where the [0 0 0 5] row is dropped. But here, that
row has been dropped
+         * because we explicitly requested so. We test the usual case first before to test
the less intuitive
+         * case in next step.
+         */
+        s.addSourceDimensions(0, 1);
+        s.addTargetDimensions(0, 1);
+        matrix = new Matrix3(           // Expected result.
+            2, 0, 7,
+            0, 4, 6,
+            0, 0, 1);
+
+        tr = s.separate();
+        assertArrayEquals("sourceDimensions", new int[] {0, 1}, s.getSourceDimensions());
+        assertArrayEquals("targetDimensions", new int[] {0, 1}, s.getTargetDimensions());
+        assertMatrixEquals("transform", matrix, ((LinearTransform) tr).getMatrix(), STRICT);
+        /*
+         * Below is the less intuitive case. When asking for the first two dimensions, we
usually expect the
+         * third dimension to be dropped. But if that third dimension is a constant (all
scale factors at 0),
+         * it does not depend on the source dimensions and can be kept. The result is a non-square
matrix
+         * with 2 dimensions in input and still 3 dimensions in output.
+         */
+        s.clear();
+        s.addSourceDimensions(0, 1);
+        matrix = Matrices.create(4, 3, new double[] {
+            2, 0, 7,
+            0, 4, 6,
+            0, 0, 5,                    // All scale factors are zero.
+            0, 0, 1});
+
+        tr = s.separate();
+        assertArrayEquals("sourceDimensions", new int[] {0, 1   }, s.getSourceDimensions());
+        assertArrayEquals("targetDimensions", new int[] {0, 1, 2}, s.getTargetDimensions());
+        assertMatrixEquals("transform", matrix, ((LinearTransform) tr).getMatrix(), STRICT);
+    }
+
+    /**
      * Tests separation of a linear transform containing {@link Double#NaN} values.
      *
      * @throws FactoryException if an error occurred while creating a new transform.


Mime
View raw message