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 2020/09/24 14:44:52 UTC
[sis] branch geoapi-4.0 updated (3dff7c6 -> dceffce)
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 3dff7c6 Add a `GridOrientation` argument to `GridGeometry(GridExtent, Envelope)` constructor. The intent is to make this constructor more useful for expressing "desired" geometry, as opposed to geometry of preexisting data.
new 246dc01 API change: rename GridOrientation.HOMOTHETIC as HOMOTHETY. Add an argument in `GridExtent.cornerToCRS(…) for axis order.
new dceffce Add a `DISPLAY` enumeration value in `GridOrientation`.
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/GridCoverage2D.java | 2 +-
.../org/apache/sis/coverage/grid/GridExtent.java | 16 +++---
.../org/apache/sis/coverage/grid/GridGeometry.java | 57 +++++++++++++++++++---
.../apache/sis/coverage/grid/GridOrientation.java | 37 +++++++++++---
.../sis/coverage/grid/GridCoverageBuilderTest.java | 4 +-
.../apache/sis/coverage/grid/GridExtentTest.java | 16 ++++--
.../apache/sis/coverage/grid/GridGeometryTest.java | 37 +++++++++++++-
.../coverage/grid/ResampledGridCoverageTest.java | 2 +-
.../sis/internal/referencing/AxisDirections.java | 24 ++++-----
.../internal/referencing/AxisDirectionsTest.java | 38 ++++++++++++++-
.../sis/storage/geotiff/GridGeometryBuilder.java | 2 +-
11 files changed, 192 insertions(+), 43 deletions(-)
[sis] 01/02: API change: rename GridOrientation.HOMOTHETIC as HOMOTHETY. Add an argument in `GridExtent.cornerToCRS(…) for axis order.
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 246dc017438c8caaff197f5d9ff14c627ceab643
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Sep 24 11:11:54 2020 +0200
API change: rename GridOrientation.HOMOTHETIC as HOMOTHETY.
Add an argument in `GridExtent.cornerToCRS(…) for axis order.
---
.../org/apache/sis/coverage/grid/GridCoverage2D.java | 2 +-
.../java/org/apache/sis/coverage/grid/GridExtent.java | 18 ++++++++++--------
.../org/apache/sis/coverage/grid/GridGeometry.java | 4 ++--
.../org/apache/sis/coverage/grid/GridOrientation.java | 8 ++++----
.../sis/coverage/grid/GridCoverageBuilderTest.java | 4 ++--
.../org/apache/sis/coverage/grid/GridExtentTest.java | 6 +++---
.../org/apache/sis/coverage/grid/GridGeometryTest.java | 2 +-
.../sis/coverage/grid/ResampledGridCoverageTest.java | 2 +-
.../sis/storage/geotiff/GridGeometryBuilder.java | 2 +-
9 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java
index fe5df02..f846d48 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridCoverage2D.java
@@ -304,7 +304,7 @@ public class GridCoverage2D extends GridCoverage {
} catch (TransformException e) {
throw new IllegalGridGeometryException(e); // Should never happen.
} else {
- domain = new GridGeometry(extent, domain.envelope, GridOrientation.HOMOTHETIC);
+ domain = new GridGeometry(extent, domain.envelope, GridOrientation.HOMOTHETY);
}
}
}
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 503fff0..6b8f174 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
@@ -1348,24 +1348,26 @@ public class GridExtent implements GridEnvelope, LenientComparable, Serializable
* This method assumes that all axes are in the same order (no axis swapping) and there is no flipping of
* axis direction except for those specified in the {@code flips} bitmask. The transform maps cell corners.
*
- * @param env the target envelope. Despite this method name, the envelope CRS is ignored.
- * @param flips bitmask of axes to flip.
+ * @param env the target envelope. Despite this method name, the envelope CRS is ignored.
+ * @param flips bitmask of target axes to flip (0 if none).
+ * @param sourceDimensions source dimension for each target dimension, or {@code null} if dimensions are the same.
* @return an affine transform from this grid extent to the given envelope, expressed as a matrix.
*/
- final MatrixSIS cornerToCRS(final Envelope env, final long flips) {
+ final MatrixSIS cornerToCRS(final Envelope env, final long flips, final int[] sourceDimensions) {
final int srcDim = getDimension();
final int tgtDim = env.getDimension();
final MatrixSIS affine = Matrices.create(tgtDim + 1, srcDim + 1, ExtendedPrecisionMatrix.ZERO);
final DoubleDouble scale = new DoubleDouble();
final DoubleDouble offset = new DoubleDouble();
for (int j=0; j<tgtDim; j++) {
- if (j < srcDim) {
+ final int i = (sourceDimensions != null) ? sourceDimensions[j] : j;
+ if (i < srcDim) {
final boolean flip = (flips & Numerics.bitmask(j)) != 0;
- offset.set(coordinates[j]);
- scale.set(coordinates[j + srcDim]);
+ offset.set(coordinates[i]);
+ scale.set(coordinates[i + srcDim]);
scale.subtract(offset);
scale.add(1); // == getSize(j) but without overflow.
- scale.inverseDivideGuessError(env.getSpan(j)); // == (envelope span) / (grid size).
+ scale.inverseDivideGuessError(env.getSpan(i)); // == (envelope span) / (grid size).
if (flip) scale.negate();
if (!offset.isZero()) { // Use `if` for keeping the value if scale is NaN.
offset.multiply(scale);
@@ -1377,7 +1379,7 @@ public class GridExtent implements GridEnvelope, LenientComparable, Serializable
scale.value = Double.NaN;
scale.error = Double.NaN;
}
- affine.setNumber(j, j, scale);
+ affine.setNumber(j, i, scale);
}
affine.setElement(tgtDim, srcDim, 1);
return affine;
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 fb91cf6..5ae3434 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
@@ -571,7 +571,7 @@ public class GridGeometry implements LenientComparable, Serializable {
*/
@Deprecated
public GridGeometry(final GridExtent extent, final Envelope envelope) {
- this(extent, envelope, GridOrientation.HOMOTHETIC);
+ this(extent, envelope, GridOrientation.HOMOTHETY);
}
/**
@@ -620,7 +620,7 @@ public class GridGeometry implements LenientComparable, Serializable {
* matrix multiplication. Use double-double arithmetic everywhere.
*/
ArgumentChecks.ensureNonNull("orientation", orientation);
- final MatrixSIS affine = extent.cornerToCRS(env, orientation.flip);
+ final MatrixSIS affine = extent.cornerToCRS(env, orientation.flip, null);
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.
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 02b2bd1..cff41ae 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
@@ -54,15 +54,15 @@ public enum GridOrientation {
* <var>S<sub>y</sub></var> > 0 and
* <var>S<sub>z</sub></var> > 0.
*/
- HOMOTHETIC(0),
+ HOMOTHETY(0),
/**
* 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 #HOMOTHETIC} except that the <var>S<sub>y</sub></var> term in
+ * 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>.
*
* <p>{@code REFLECTION_Y} is commonly used when the grid is a {@link java.awt.image.RenderedImage}.
- * By contrast, an {@link #HOMOTHETIC} transform often results in <var>y</var> axis oriented toward up,
+ * 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>
*/
@@ -74,7 +74,7 @@ public enum GridOrientation {
/**
* Bitmask of axes to flip.
- * This is the argument to give in calls to {@link GridExtent#cornerToCRS(Envelope, long)}.
+ * This is the argument to give in calls to {@link GridExtent#cornerToCRS(Envelope, long, int[])}.
*/
final int flip;
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverageBuilderTest.java b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverageBuilderTest.java
index cd5e839..74137f2 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverageBuilderTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridCoverageBuilderTest.java
@@ -139,7 +139,7 @@ public final strictfp class GridCoverageBuilderTest extends TestCase {
final GeneralEnvelope env = new GeneralEnvelope(HardCodedCRS.WGS84);
env.setRange(0, 0, 10); // Scale factor of 2 for grid size of 10.
env.setRange(1, 0, 4); // Scale factor of ½ for grid size of 8.
- GridGeometry grid = new GridGeometry(new GridExtent(8, 5), env, GridOrientation.HOMOTHETIC);
+ GridGeometry grid = new GridGeometry(new GridExtent(8, 5), env, GridOrientation.HOMOTHETY);
assertSame(builder, builder.setDomain(grid));
try {
builder.build();
@@ -147,7 +147,7 @@ public final strictfp class GridCoverageBuilderTest extends TestCase {
} catch (IllegalStateException ex) {
assertNotNull(ex.getMessage());
}
- grid = new GridGeometry(new GridExtent(width, height), env, GridOrientation.HOMOTHETIC);
+ grid = new GridGeometry(new GridExtent(width, height), env, GridOrientation.HOMOTHETY);
assertSame(builder, builder.setDomain(grid));
return builder.build();
}
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
index a87ffe1..1a67174 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
@@ -269,7 +269,7 @@ public final strictfp class GridExtentTest extends TestCase {
}
/**
- * Tests {@link GridExtent#cornerToCRS(Envelope, long)}.
+ * Tests {@link GridExtent#cornerToCRS(Envelope, long, int[])}.
*/
@Test
public void testCornerToCRS() {
@@ -286,7 +286,7 @@ public final strictfp class GridExtentTest extends TestCase {
assertMatrixEquals("cornerToCRS", new Matrix3(
0.5, 0, 50,
0, 2, 40,
- 0, 0, 1), extent.cornerToCRS(aoi, 0), STRICT);
+ 0, 0, 1), extent.cornerToCRS(aoi, 0, null), STRICT);
/*
* Y axis flip.
* Verification: y = −2 × −25 + 20 = 70 (the maximum value declared in envelope).
@@ -294,7 +294,7 @@ public final strictfp class GridExtentTest extends TestCase {
assertMatrixEquals("cornerToCRS", new Matrix3(
0.5, 0, 50,
0, -2, 20,
- 0, 0, 1), extent.cornerToCRS(aoi, 2), STRICT);
+ 0, 0, 1), extent.cornerToCRS(aoi, 2, null), STRICT);
}
/**
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 8ea4d2d..42acf36 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
@@ -343,7 +343,7 @@ public final strictfp class GridGeometryTest extends TestCase {
* Simplest case: no axis flip.
* Verification: y = 2 × −25 + 40 = −10 (the minimum value declared in envelope).
*/
- GridGeometry grid = new GridGeometry(extent, aoi, GridOrientation.HOMOTHETIC);
+ GridGeometry grid = new GridGeometry(extent, aoi, GridOrientation.HOMOTHETY);
Matrix matrix = MathTransforms.getMatrix(grid.getGridToCRS(PixelInCell.CELL_CORNER));
assertMatrixEquals("cornerToCRS", new Matrix3(
0.5, 0, 50,
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
index 7fe355e..fb15991 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/ResampledGridCoverageTest.java
@@ -105,7 +105,7 @@ public final strictfp class ResampledGridCoverageTest extends TestCase {
final int y = random.nextInt(32) - 10;
final GridGeometry gg = new GridGeometry(
new GridExtent(null, new long[] {x, y}, new long[] {x+width, y+height}, false),
- new Envelope2D(HardCodedCRS.WGS84, 20, 15, 60, 62), GridOrientation.HOMOTHETIC);
+ new Envelope2D(HardCodedCRS.WGS84, 20, 15, 60, 62), GridOrientation.HOMOTHETY);
return new GridCoverage2D(gg, null, image);
}
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GridGeometryBuilder.java b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GridGeometryBuilder.java
index a45aec1..3a6973f 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GridGeometryBuilder.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GridGeometryBuilder.java
@@ -335,7 +335,7 @@ final class GridGeometryBuilder {
envelope = new GeneralEnvelope(crs);
envelope.setToNaN();
}
- gridGeometry = new GridGeometry(extent, envelope, GridOrientation.HOMOTHETIC);
+ gridGeometry = new GridGeometry(extent, envelope, GridOrientation.HOMOTHETY);
canNotCreate(e);
/*
* Note: we catch TransformExceptions because they may be caused by erroneous data in the GeoTIFF file,
[sis] 02/02: Add a `DISPLAY` enumeration value in `GridOrientation`.
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 dceffce01b58f1901345ca9ca6bb112726b3c02a
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Sep 24 16:44:23 2020 +0200
Add a `DISPLAY` enumeration value in `GridOrientation`.
---
.../org/apache/sis/coverage/grid/GridExtent.java | 2 +-
.../org/apache/sis/coverage/grid/GridGeometry.java | 55 +++++++++++++++++++---
.../apache/sis/coverage/grid/GridOrientation.java | 29 ++++++++++--
.../apache/sis/coverage/grid/GridExtentTest.java | 10 ++++
.../apache/sis/coverage/grid/GridGeometryTest.java | 35 ++++++++++++++
.../sis/internal/referencing/AxisDirections.java | 24 +++++-----
.../internal/referencing/AxisDirectionsTest.java | 38 ++++++++++++++-
7 files changed, 170 insertions(+), 23 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 6b8f174..51177bc 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
@@ -1367,7 +1367,7 @@ public class GridExtent implements GridEnvelope, LenientComparable, Serializable
scale.set(coordinates[i + srcDim]);
scale.subtract(offset);
scale.add(1); // == getSize(j) but without overflow.
- scale.inverseDivideGuessError(env.getSpan(i)); // == (envelope span) / (grid size).
+ scale.inverseDivideGuessError(env.getSpan(j)); // == (envelope span) / (grid size).
if (flip) scale.negate();
if (!offset.isZero()) { // Use `if` for keeping the value if scale is NaN.
offset.multiply(scale);
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 5ae3434..d5c52e1 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
@@ -45,6 +45,8 @@ import org.apache.sis.geometry.Envelopes;
import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.geometry.ImmutableEnvelope;
import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
+import org.apache.sis.referencing.crs.AbstractCRS;
+import org.apache.sis.referencing.cs.AxesConvention;
import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.referencing.operation.matrix.MatrixSIS;
@@ -52,6 +54,7 @@ import org.apache.sis.referencing.operation.transform.MathTransforms;
import org.apache.sis.referencing.operation.transform.PassThroughTransform;
import org.apache.sis.internal.referencing.DirectPositionView;
import org.apache.sis.internal.referencing.TemporalAccessor;
+import org.apache.sis.internal.referencing.AxisDirections;
import org.apache.sis.internal.metadata.ReferencingServices;
import org.apache.sis.internal.system.Modules;
import org.apache.sis.internal.feature.Resources;
@@ -586,6 +589,11 @@ public class GridGeometry implements LenientComparable, Serializable {
* For grid geometries describing preexisting data, it is safer and more flexible to use one of
* the constructors expecting a {@link MathTransform} argument.</p>
*
+ * <h4>Dimension order</h4>
+ * The given envelope shall always declare dimensions in same order than the given extent.
+ * This constructor may reorder CRS axes if {@code orientation} is {@link GridOrientation#DISPLAY},
+ * but in such case this constructor will derive itself an envelope and CRS with the reordered axes.
+ *
* @param extent the valid extent of grid coordinates, or {@code null} if unknown.
* @param envelope the envelope together with CRS of the "real world" coordinates, or {@code null} if unknown.
* @param orientation high-level description of desired characteristics of the {@code gridToCRS} transform.
@@ -599,19 +607,53 @@ public class GridGeometry implements LenientComparable, Serializable {
this.extent = extent;
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
+ * AxisConvention.DISPLAY_ORIENTED.
+ */
+ 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 AbstractCRS sourceCRS = AbstractCRS.castOrCopy(envelope.getCoordinateReferenceSystem());
+ if (sourceCRS != null) {
+ final AbstractCRS targetCRS = sourceCRS.forConvention(AxesConvention.DISPLAY_ORIENTED);
+ if (targetCRS != sourceCRS) {
+ final CoordinateSystem sourceCS = sourceCRS.getCoordinateSystem();
+ final CoordinateSystem targetCS = targetCRS.getCoordinateSystem();
+ sourceDimensions = AxisDirections.indicesOfColinear(sourceCS, targetCS);
+ if (sourceDimensions != null) {
+ final double[] lowerCorner = new double[sourceDimensions.length];
+ final double[] upperCorner = new double[sourceDimensions.length];
+ for (int i=0; i < sourceDimensions.length; i++) {
+ final int s = sourceDimensions[i];
+ lowerCorner[i] = envelope.getMinimum(s);
+ upperCorner[i] = envelope.getMaximum(s);
+ if (sourceCS.getAxis(s).getDirection() != targetCS.getAxis(i).getDirection()) {
+ flip |= Numerics.bitmask(i);
+ }
+ }
+ target = new ImmutableEnvelope(lowerCorner, upperCorner, targetCRS);
+ }
+ }
+ }
+ }
+ if (target == null) {
+ target = ImmutableEnvelope.castOrCopy(envelope);
+ }
+ /*
* If the envelope contains no useful information, then the grid extent is mandatory.
* We do that for forcing grid geometries to contain at least one information.
*/
boolean nilEnvelope = true;
- final ImmutableEnvelope env = ImmutableEnvelope.castOrCopy(envelope);
- if (env == null || ((nilEnvelope = env.isAllNaN()) && env.getCoordinateReferenceSystem() == null)) {
- if (env != null && nilEnvelope) {
+ if (target == null || ((nilEnvelope = target.isAllNaN()) && target.getCoordinateReferenceSystem() == null)) {
+ if (target != null && nilEnvelope) {
throw new NullArgumentException(Errors.format(Errors.Keys.UnspecifiedCRS));
}
ArgumentChecks.ensureNonNull("extent", extent);
this.envelope = null;
} else {
- this.envelope = env;
+ this.envelope = target;
if (extent != null && !nilEnvelope) {
/*
* If we have both the extent and an envelope with at least one non-NaN coordinates,
@@ -620,13 +662,14 @@ public class GridGeometry implements LenientComparable, Serializable {
* matrix multiplication. Use double-double arithmetic everywhere.
*/
ArgumentChecks.ensureNonNull("orientation", orientation);
- final MatrixSIS affine = extent.cornerToCRS(env, orientation.flip, null);
+ 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 DoubleDouble scale = (DoubleDouble) affine.getNumber(j, 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);
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 cff41ae..3d10a4d 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
@@ -18,6 +18,7 @@ package org.apache.sis.coverage.grid;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.datum.PixelInCell;
+import org.apache.sis.referencing.cs.AxesConvention;
/**
@@ -29,7 +30,10 @@ import org.opengis.referencing.datum.PixelInCell;
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.1
- * @since 1.1
+ *
+ * @see GridGeometry#GridGeometry(GridExtent, Envelope, GridOrientation)
+ *
+ * @since 1.1
* @module
*/
public enum GridOrientation {
@@ -66,11 +70,28 @@ public enum GridOrientation {
* instead of down as commonly expected with rendered images.
* This {@code REFLECTION_Y} value matches the common usage for grids backed by images.</p>
*/
- REFLECTION_Y(2);
+ REFLECTION_Y(2),
- /*
- * TODO: add DISPLAY. The difference compared to REFLECTION_Y is that it may change CRS axes.
+ /**
+ * 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):
+ *
+ * {@preformat math
+ * ┌ ┐
+ * │ 0 Sx 0 Tx │
+ * │ −Sy 0 0 Ty │
+ * │ 0 0 Sz Tz │
+ * │ 0 0 0 1 │
+ * └ ┘
+ * }
+ *
+ * @see AxesConvention#DISPLAY_ORIENTED
*/
+ DISPLAY(2);
/**
* Bitmask of axes to flip.
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
index 1a67174..b1cc369 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
@@ -295,6 +295,16 @@ public final strictfp class GridExtentTest extends TestCase {
0.5, 0, 50,
0, -2, 20,
0, 0, 1), extent.cornerToCRS(aoi, 2, null), STRICT);
+ /*
+ * Swap axis order. The {1,0} indices apply to grid dimensions, not to CRS dimensions.
+ * Verification: x = 0.375 × −25 + 49.375 = 40 (the minimum value declared in envelope).
+ * y = 2.667 × −20 + 43.333 ≈ −10 (idem).
+ */
+ assertMatrixEquals("cornerToCRS", new Matrix3(
+ 0, 0.375, 49.375,
+ 2.6666666666666667, 0, 43.333333333333333,
+ 0, 0, 1),
+ extent.cornerToCRS(aoi, 0, new int[] {1,0}), 1E-15);
}
/**
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 42acf36..07ebd7e 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
@@ -369,6 +369,41 @@ public final strictfp class GridGeometryTest extends TestCase {
assertArrayEquals("resolution", new double[] {0.5, 2}, grid.getResolution(false), STRICT);
assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
verifyGridToCRS(grid);
+ /*
+ * The use of `DISPLAY` mode in this particular case should be equivalent ro `REFLECTION_Y`.
+ */
+ assertEquals(grid, new GridGeometry(extent, aoi, GridOrientation.DISPLAY));
+ }
+
+ /**
+ * Tests the construction from a geospatial envelope and an extent with reordering of axes
+ * for matching display convention.
+ *
+ * @see GridExtentTest#testCornerToCRS()
+ */
+ @Test
+ public void testFromExtentAndDisplayEnvelope() {
+ final GeneralEnvelope aoi = new GeneralEnvelope(HardCodedCRS.WGS84_φλ);
+ aoi.setRange(1, 40, 55);
+ aoi.setRange(0, -10, 70);
+ final GridExtent extent = new GridExtent(null,
+ new long[] {-25, -20},
+ new long[] { 15, 10}, false);
+ /*
+ * Same case than the one tested by `testFromExtentAndEnvelope()`,
+ * but with axis order swapped.
+ */
+ GridGeometry grid = new GridGeometry(extent, aoi, GridOrientation.DISPLAY);
+ Matrix matrix = MathTransforms.getMatrix(grid.getGridToCRS(PixelInCell.CELL_CORNER));
+ assertMatrixEquals("cornerToCRS", new Matrix3(
+ 0, 0.5, 50,
+ -2, 0, 20,
+ 0, 0, 1), matrix, STRICT);
+
+ // Verify other computed properties.
+ assertArrayEquals("resolution", new double[] {0.5, 2}, grid.getResolution(false), STRICT);
+ assertTrue("isConversionLinear", grid.isConversionLinear(0, 1));
+ verifyGridToCRS(grid);
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
index dfbdeb4..9f512dc 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
@@ -29,6 +29,7 @@ import org.apache.sis.internal.metadata.NameToIdentifier;
import org.apache.sis.util.ComparisonMode;
import org.apache.sis.util.Characters;
import org.apache.sis.util.Utilities;
+import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.Static;
import org.apache.sis.util.iso.Types;
import org.apache.sis.measure.Units;
@@ -492,10 +493,10 @@ public final class AxisDirections extends Static {
* <li>Otherwise if a sequence of {@code cs} axes have similar names than the {@code subCS} axes (as determined
* by {@linkplain org.apache.sis.referencing.IdentifiedObjects#isHeuristicMatchForName heuristic match},
* that sequence has precedence.</li>
- * <li>Otherwise the index of the first sequence if returned, regardless axis names.</li>
+ * <li>Otherwise the index of the first sequence is returned, regardless axis names.</li>
* </ol>
*
- * Note that colinear axes are normally not allowed, except if the case of {@link org.opengis.referencing.crs.TemporalCRS}
+ * Note that colinear axes are normally not allowed, except in the case of {@link org.opengis.referencing.crs.TemporalCRS}
* when one time axis is the runtime (the date where a numerical model has been executed) and the other time axis is the
* forecast time (the date at which a prevision is made).
*
@@ -551,20 +552,21 @@ next: for (int i=0; i <= limit; i++) {
*
* @param cs the coordinate system which contains all axes, or {@code null}.
* @param subCS the coordinate system to search into {@code cs}.
- * @return the sequence of axes colinear with {@code subCS} axes, or {@code null} if none.
+ * @return indices in {@code cs} of axes colinear with {@code subCS} axes in the order they appear in {@code subCS},
+ * or {@code null} if at least one {@code subCS} axis can not be mapped to a {@code cs} axis.
*
* @since 1.1
*/
public static int[] indicesOfColinear(final CoordinateSystem cs, final CoordinateSystem subCS) {
- final int[] indices = new int[subCS.getDimension()];
+ final int dim = subCS.getDimension();
final int index = indexOfColinear(cs, subCS); // More robust than fallback below.
- for (int i=0; i<indices.length; i++) {
- if (index >= 0) {
- indices[i] = index + i;
- } else {
- if ((indices[i] = indexOfColinear(cs, subCS.getAxis(i).getDirection())) < 0) {
- return null;
- }
+ if (index >= 0) {
+ return ArraysExt.range(index, index + dim);
+ }
+ final int[] indices = new int[dim];
+ for (int i=0; i<dim; i++) {
+ if ((indices[i] = indexOfColinear(cs, subCS.getAxis(i).getDirection())) < 0) {
+ return null;
}
}
return indices;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
index c711d32..5df9414 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
@@ -43,7 +43,7 @@ import static org.apache.sis.internal.referencing.AxisDirections.COUNTER_CLOCKWI
* {@code sis-referencing} module because those tests use {@link HardCodedAxes} constants.</p>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
* @since 0.4
* @module
*/
@@ -421,6 +421,42 @@ public final strictfp class AxisDirectionsTest extends TestCase {
}
/**
+ * Tests {@link AxisDirections#indicesOfColinear(CoordinateSystem, CoordinateSystem)}.
+ *
+ * @since 1.1
+ */
+ @Test
+ public void testIndicesOfColinear() {
+ assertArrayEquals(new int[] {0, 1}, AxisDirections.indicesOfColinear(
+ HardCodedCS.GEODETIC_3D,
+ HardCodedCS.GEODETIC_2D));
+
+ assertArrayEquals(new int[] {1, 0}, AxisDirections.indicesOfColinear(
+ HardCodedCS.GEODETIC_φλ,
+ HardCodedCS.GEODETIC_2D));
+
+ assertArrayEquals(new int[] {1, 0}, AxisDirections.indicesOfColinear(
+ HardCodedCS.GEODETIC_3D,
+ HardCodedCS.GEODETIC_φλ));
+
+ assertArrayEquals(new int[] {2}, AxisDirections.indicesOfColinear(
+ HardCodedCS.GEODETIC_3D,
+ HardCodedCS.ELLIPSOIDAL_HEIGHT));
+
+ assertArrayEquals(new int[] {2}, AxisDirections.indicesOfColinear(
+ HardCodedCS.GEODETIC_3D,
+ HardCodedCS.DEPTH));
+
+ assertArrayEquals(null, AxisDirections.indicesOfColinear(
+ HardCodedCS.GEODETIC_3D,
+ HardCodedCS.DAYS));
+
+ assertArrayEquals(null, AxisDirections.indicesOfColinear(
+ HardCodedCS.GEODETIC_2D,
+ HardCodedCS.GEODETIC_3D));
+ }
+
+ /**
* Tests {@link AxisDirections#suggestAbbreviation(String, AxisDirection, Unit)}.
*
* @since 0.6