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: Add a GridOrientation.DISPLAY_GRID enumeration value.
Date Fri, 25 Sep 2020 12:49:09 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 fe1437a  Add a GridOrientation.DISPLAY_GRID enumeration value.
fe1437a is described below

commit fe1437a80ec0dce6d460ff6717c853b199c3fd32
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Fri Sep 25 14:14:23 2020 +0200

    Add a GridOrientation.DISPLAY_GRID enumeration value.
---
 .../org/apache/sis/coverage/grid/GridExtent.java   | 13 ++--
 .../org/apache/sis/coverage/grid/GridGeometry.java | 69 +++++++++++--------
 .../apache/sis/coverage/grid/GridOrientation.java  | 80 +++++++++++++++++-----
 .../apache/sis/coverage/grid/GridGeometryTest.java | 23 +++++++
 4 files changed, 134 insertions(+), 51 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
index 51177bc..f0288b5 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
@@ -1206,11 +1206,16 @@ public class GridExtent implements GridEnvelope, LenientComparable,
Serializable
      * @see GridGeometry#reduce(int...)
      */
     public GridExtent reduce(int... dimensions) {
+        dimensions = verifyDimensions(dimensions, getDimension());
+        return (dimensions != null) ? reorder(dimensions) : this;
+    }
+
+    /**
+     * Changes axis order or reduces the number of dimensions.
+     * It is caller responsibility to ensure that the given dimensions are valid.
+     */
+    final GridExtent reorder(final int[] dimensions) {
         final int sd = getDimension();
-        dimensions = verifyDimensions(dimensions, sd);
-        if (dimensions == null) {
-            return this;
-        }
         final int td = dimensions.length;
         DimensionNameType[] tt = null;
         if (types != null) {
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 d5c52e1..6b8a98b 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
@@ -72,6 +72,7 @@ import org.apache.sis.util.LenientComparable;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.Debug;
@@ -578,7 +579,7 @@ public class GridGeometry implements LenientComparable, Serializable {
     }
 
     /**
-     * Creates a grid geometry with an extent and an envelope.
+     * Creates an axis-aligned grid geometry with an extent and an envelope.
      * This constructor can be used when the <cite>grid to CRS</cite> transform
is unknown.
      * If only the coordinate reference system is known, then the envelope coordinates can
be
      * {@linkplain GeneralEnvelope#isAllNaN() all NaN}.
@@ -601,11 +602,12 @@ public class GridGeometry implements LenientComparable, Serializable
{
      * @throws NullPointerException if {@code extent} and {@code envelope} arguments are
both null,
      *         or if only the {@code orientation} argument is null.
      *
+     * @see <a href="https://en.wikipedia.org/wiki/Axis-aligned_object">Axis-aligned
object on Wikipedia</a>
+     *
      * @since 1.1
      */
-    public GridGeometry(final GridExtent extent, final Envelope envelope, final GridOrientation
orientation) {
-        this.extent = extent;
-        nonLinears  = 0;
+    public GridGeometry(GridExtent extent, final Envelope envelope, final GridOrientation
orientation) {
+        nonLinears = 0;
         /*
          * Potentially change axis order and orientation according the given `GridOrientation`
(which may be null).
          * Current code assumes that units of measurement are unchanged, which should be
true for CRSs built using
@@ -614,7 +616,8 @@ public class GridGeometry implements LenientComparable, Serializable {
         long flip = 0;                      // Bitmask specifying whether to reverse axis
in each dimension.
         ImmutableEnvelope target = null;    // May have different axis order than the specified
`envelope` CRS.
         int[] sourceDimensions = null;      // Indices in source envelope of axes colinear
with the target envelope.
-        if (envelope != null && orientation == GridOrientation.DISPLAY) {
+        final boolean reorderExtent = (orientation == GridOrientation.DISPLAY_GRID);
+        if (envelope != null && (reorderExtent || orientation == GridOrientation.DISPLAY))
{
             final AbstractCRS sourceCRS = AbstractCRS.castOrCopy(envelope.getCoordinateReferenceSystem());
             if (sourceCRS != null) {
                 final AbstractCRS targetCRS = sourceCRS.forConvention(AxesConvention.DISPLAY_ORIENTED);
@@ -654,32 +657,42 @@ public class GridGeometry implements LenientComparable, Serializable
{
             this.envelope = null;
         } else {
             this.envelope = target;
-            if (extent != null && !nilEnvelope) {
-                /*
-                 * If we have both the extent and an envelope with at least one non-NaN coordinates,
-                 * create the `cornerToCRS` transform. The `gridToCRS` calculation uses the
knowledge
-                 * that all scale factors are on diagonal, which allows simpler calculation
than full
-                 * matrix multiplication. Use double-double arithmetic everywhere.
-                 */
-                ArgumentChecks.ensureNonNull("orientation", orientation);
-                final MatrixSIS affine = extent.cornerToCRS(target, orientation.flip ^ flip,
sourceDimensions);
-                cornerToCRS = MathTransforms.linear(affine);
-                final int srcDim = cornerToCRS.getSourceDimensions();       // Translation
column in matrix.
-                final int tgtDim = cornerToCRS.getTargetDimensions();       // Number of
matrix rows before last row.
-                resolution = new double[tgtDim];
-                for (int j=0; j<tgtDim; j++) {
-                    final int i = (sourceDimensions != null) ? sourceDimensions[j] : j;
-                    final DoubleDouble scale  = (DoubleDouble) affine.getNumber(j, i);
-                    final DoubleDouble offset = (DoubleDouble) affine.getNumber(j, srcDim);
-                    resolution[j] = Math.abs(scale.doubleValue());
-                    scale.multiply(0.5);
-                    offset.add(scale);
-                    affine.setNumber(j, srcDim, offset);
+            if (extent != null) {
+                if (reorderExtent) {
+                    if (!ArraysExt.isRange(0, sourceDimensions)) {
+                        extent = extent.reorder(sourceDimensions);
+                    }
+                    sourceDimensions = null;
+                }
+                if (!nilEnvelope) {
+                    /*
+                     * If we have both the extent and an envelope with at least one non-NaN
coordinates,
+                     * create the `cornerToCRS` transform. The `gridToCRS` calculation uses
the knowledge
+                     * that all scale factors are on diagonal, which allows simpler calculation
than full
+                     * matrix multiplication. Use double-double arithmetic everywhere.
+                     */
+                    ArgumentChecks.ensureNonNull("orientation", orientation);
+                    final MatrixSIS affine = extent.cornerToCRS(target, orientation.flip
^ flip, sourceDimensions);
+                    cornerToCRS = MathTransforms.linear(affine);
+                    final int srcDim = cornerToCRS.getSourceDimensions();       // Translation
column in matrix.
+                    final int tgtDim = cornerToCRS.getTargetDimensions();       // Number
of matrix rows before last row.
+                    resolution = new double[tgtDim];
+                    for (int j=0; j<tgtDim; j++) {
+                        final int i = (sourceDimensions != null) ? sourceDimensions[j] :
j;
+                        final DoubleDouble scale  = (DoubleDouble) affine.getNumber(j, i);
+                        final DoubleDouble offset = (DoubleDouble) affine.getNumber(j, srcDim);
+                        resolution[j] = Math.abs(scale.doubleValue());
+                        scale.multiply(0.5);
+                        offset.add(scale);
+                        affine.setNumber(j, srcDim, offset);
+                    }
+                    gridToCRS = MathTransforms.linear(affine);
+                    this.extent = extent;
+                    return;
                 }
-                gridToCRS = MathTransforms.linear(affine);
-                return;
             }
         }
+        this.extent = extent;
         gridToCRS   = null;
         cornerToCRS = null;
         resolution  = null;
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridOrientation.java
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridOrientation.java
index 3d10a4d..9f92f1b 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridOrientation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridOrientation.java
@@ -26,7 +26,8 @@ import org.apache.sis.referencing.cs.AxesConvention;
  * This is determined by the {@linkplain GridGeometry#getGridToCRS(PixelInCell) grid to CRS}
transform.
  * For example conversion from grid coordinates to CRS coordinates may flip the <var>y</var>
axis
  * (grid coordinates increasing toward down on screen), or may swap <var>x</var>
and <var>y</var> axes, <i>etc.</i>
- * The possibilities are infinite; this enumeration covers only a few common types.
+ * The possibilities are infinite; this enumeration covers only a few common types where
the grid is
+ * <a href="https://en.wikipedia.org/wiki/Axis-aligned_object">axis-aligned</a>
with the CRS.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.1
@@ -40,8 +41,8 @@ public enum GridOrientation {
     /**
      * The {@code gridToCRS} transform applies only scales and translations (no axis flip
or swap).
      * Moving along the grid axis in dimension <var>i</var> causes a displacement
along the CRS axis
-     * in the same dimension <var>i</var>. In matrix terms all coefficients on
the diagonal are positives
-     * (restricted to 1 on the last row), the translation terms can be anything, and all
other terms are zero.
+     * in the same dimension <var>i</var>.
+     * In matrix terms all non-zero coefficients are on the diagonal or in the translation
column.
      * For example in the three-dimensional case:
      *
      * {@preformat math
@@ -63,35 +64,76 @@ public enum GridOrientation {
     /**
      * The {@code gridToCRS} transform applies scales and translations with a flip of the
second axis (<var>y</var>).
      * This is the same kind of conversion than {@link #HOMOTHETY} except that the <var>S<sub>y</sub></var>
term in
-     * the matrix is replaced by −<var>S<sub>y</sub></var>.
+     * the matrix is replaced by −<var>S<sub>y</sub></var> and
the <var>T<sub>y</sub></var> term has a different value.
+     * For example in the three-dimensional case, the {@code gridToCRS} transform is:
      *
-     * <p>{@code REFLECTION_Y} is commonly used when the grid is a {@link java.awt.image.RenderedImage}.
+     * {@preformat math
+     *   ┌                 ┐
+     *   │ Sx  0   0   Tx  │
+     *   │ 0  −Sy  0   Ty′ │
+     *   │ 0   0   Sz  Tz  │
+     *   │ 0   0   0   1   │
+     *   └                 ┘
+     * }
+     *
+     * {@code REFLECTION_Y} is commonly used when the grid is a {@link java.awt.image.RenderedImage}.
      * By contrast, an {@link #HOMOTHETY} transform often results in <var>y</var>
axis oriented toward up,
      * instead of down as commonly expected with rendered images.
-     * This {@code REFLECTION_Y} value matches the common usage for grids backed by images.</p>
+     * This {@code REFLECTION_Y} value matches the common usage for grids backed by images.
      */
     REFLECTION_Y(2),
 
     /**
      * CRS axes are reordered and oriented toward directions commonly used for displaying
purpose.
-     * This orientation can be used for deriving a coordinate reference system with the
-     * <i>(<var>longitude</var>, <var>latitude</var>)</i>
or <i>(<var>x</var>,<var>y</var>)</i> axis order.
-     * Grid axes order is unchanged.
-     * An example of {@code gridToCRS} transform obtained by this orientation is as below
-     * (the exact matrix depends on the CRS axes):
+     * {@link GridGeometry}s created with this orientation have properties computed as below:
+     *
+     * <ul>
+     *   <li>The {@link GridExtent} specified by user (never modified).</li>
+     *   <li>An envelope initialized to user-specified envelope (potentially modified
below).</li>
+     *   <li>A {@code gridToCRS} initialized to {@link #REFLECTION_Y} (potentially
modified below).</li>
+     *   <li>The {@linkplain AxesConvention#DISPLAY_ORIENTED display oriented} variant
of the CRS specified by user.</li>
+     *   <li>If above CRS variant is same as user-specified CRS, we are done. Otherwise:
+     *     <ul>
+     *       <li>Envelope dimensions are reordered to match axis order in above CRS
variant
+     *           Those changes are applied on a copy of user-specified envelope.</li>
+     *       <li>The {@code gridToCRS} transform is amended with the same reordering
(applied on columns)
+     *           as for envelope.</li>
+     *     </ul>
+     *   </li>
+     * </ul>
+     *
+     * Below is an example of {@code gridToCRS} transform obtained when the display-oriented
CRS variant
+     * is different than the user-specified CRS (if those CRSs are equal, then the transform
is rather
+     * like the one shown in {@link #REFLECTION_Y}):
      *
      * {@preformat math
-     *   ┌                 ┐
-     *   │  0   Sx  0   Tx │
-     *   │ −Sy  0   0   Ty │
-     *   │  0   0   Sz  Tz │
-     *   │  0   0   0   1  │
-     *   └                 ┘
+     *   ┌                  ┐
+     *   │  0   Sx  0   Tx  │
+     *   │ −Sy  0   0   Ty′ │
+     *   │  0   0   Sz  Tz  │
+     *   │  0   0   0   1   │
+     *   └                  ┘
      * }
      *
+     * This orientation can be used for deriving a coordinate reference system with the
+     * <i>(<var>longitude</var>, <var>latitude</var>)</i>
or <i>(<var>x</var>,<var>y</var>)</i> axis order,
+     * but without altering grid axes order.
+     *
      * @see AxesConvention#DISPLAY_ORIENTED
      */
-    DISPLAY(2);
+    DISPLAY(2),
+
+    /**
+     * CRS and grid axes are reordered and oriented toward directions commonly used for displaying
purpose.
+     * This is similar to {@link #DISPLAY} except that {@link GridExtent} axes get the same
reordering than CRS axes.
+     * Consequently the {@code gridToCRS} transform always has the form shown in {@link #REFLECTION_Y}.
+     *
+     * <p>This orientation can be used for deriving a coordinate reference system with
the
+     * <i>(<var>longitude</var>, <var>latitude</var>)</i>
or <i>(<var>x</var>,<var>y</var>)</i> axis order,
+     * and modify grid cell layout (i.e. replace the {@link GridExtent} instance)
+     * in way that allows {@link java.awt.image.RenderedImage} to appear with expected orientation.</p>
+     */
+    DISPLAY_GRID(2);
 
     /**
      * Bitmask of axes to flip.
@@ -100,7 +142,7 @@ public enum GridOrientation {
     final int flip;
 
     /**
-     * Creates a new enumeration.
+     * Creates a new enumeration value.
      */
     private GridOrientation(final int flip) {
         this.flip = flip;
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 07ebd7e..68763d4 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
@@ -353,6 +353,7 @@ public final strictfp class GridGeometryTest extends TestCase {
         // Verify other computed properties.
         assertArrayEquals("resolution", new double[] {0.5, 2}, grid.getResolution(false),
STRICT);
         assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
+        assertSame("extent", extent, grid.getExtent());
         verifyGridToCRS(grid);
         /*
          * Same envelope and extent, but flip Y axis.
@@ -368,6 +369,7 @@ public final strictfp class GridGeometryTest extends TestCase {
         // Verify other computed properties.
         assertArrayEquals("resolution", new double[] {0.5, 2}, grid.getResolution(false),
STRICT);
         assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
+        assertSame("extent", extent, grid.getExtent());
         verifyGridToCRS(grid);
         /*
          * The use of `DISPLAY` mode in this particular case should be equivalent ro `REFLECTION_Y`.
@@ -403,6 +405,27 @@ public final strictfp class GridGeometryTest extends TestCase {
         // Verify other computed properties.
         assertArrayEquals("resolution", new double[] {0.5, 2}, grid.getResolution(false),
STRICT);
         assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
+        assertSame("extent", extent, grid.getExtent());
+        verifyGridToCRS(grid);
+        /*
+         * Same extent and envelope, but reordering extend dimensions
+         * instead than `gridToCRS` columns.
+         */
+        grid = new GridGeometry(extent, aoi, GridOrientation.DISPLAY_GRID);
+        matrix = MathTransforms.getMatrix(grid.getGridToCRS(PixelInCell.CELL_CORNER));
+        assertMatrixEquals("cornerToCRS", new Matrix3(
+                0.5,  0,   50,
+                0,   -2,   20,
+                0,    0,    1), matrix, STRICT);
+
+        assertExtentEquals(
+                new long[] {-20, -25},
+                new long[] {  9,  14}, grid.getExtent());
+
+        // Verify other computed properties.
+        assertArrayEquals("resolution", new double[] {0.5, 2}, grid.getResolution(false),
STRICT);
+        assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
+        assertNotSame("extent", extent, grid.getExtent());
         verifyGridToCRS(grid);
     }
 


Mime
View raw message