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 8bb0edb Make a better effort to take the `gridToCRS` transform in
account when determining a CRS for a GridExtent.
8bb0edb is described below
commit 8bb0edb2cc89ff406f5a473c0d5ed410bd886597
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Apr 15 12:21:12 2020 +0200
Make a better effort to take the `gridToCRS` transform in account when
determining a CRS for a GridExtent.
---
.../org/apache/sis/coverage/grid/GridExtent.java | 8 +-
.../apache/sis/coverage/grid/GridExtentCRS.java | 136 +++++++++++++++------
.../apache/sis/coverage/grid/GridExtentTest.java | 39 +++++-
3 files changed, 145 insertions(+), 38 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 a0806cf..a13b529 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
@@ -96,6 +96,8 @@ public class GridExtent implements GridEnvelope,
LenientComparable, Serializable
* This map contains only the "positive" axis directions.
*
* @todo Verify if there is more directions to add as of ISO 19111:2018.
+ *
+ * @see #typeFromAxes(CoordinateReferenceSystem, int)
*/
private static final Map<AxisDirection,DimensionNameType> AXIS_DIRECTIONS;
static {
@@ -317,6 +319,7 @@ public class GridExtent implements GridEnvelope,
LenientComparable, Serializable
/**
* Infers the axis types from the given coordinate reference system.
+ * This method is the converse of {@link GridExtentCRS}.
*
* @param crs the coordinate reference system, or {@code null}.
* @param dimension number of name type to infer. Shall not be greater
than the CRS dimension.
@@ -851,8 +854,9 @@ public class GridExtent implements GridEnvelope,
LenientComparable, Serializable
public GeneralEnvelope toEnvelope(final MathTransform cornerToCRS) throws
TransformException {
ArgumentChecks.ensureNonNull("cornerToCRS", cornerToCRS);
final GeneralEnvelope envelope = toCRS(cornerToCRS, cornerToCRS, null);
- if (cornerToCRS.isIdentity()) try {
-
envelope.setCoordinateReferenceSystem(GridExtentCRS.build(getDimension(),
types, null));
+ final Matrix gridToCRS = MathTransforms.getMatrix(cornerToCRS);
+ if (gridToCRS != null && Matrices.isAffine(gridToCRS)) try {
+
envelope.setCoordinateReferenceSystem(GridExtentCRS.build(gridToCRS, (types !=
null) ? types : DEFAULT_TYPES, null));
} catch (FactoryException e) {
throw new TransformException(e);
}
diff --git
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtentCRS.java
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtentCRS.java
index 2e4d1c5..597e7b8 100644
---
a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtentCRS.java
+++
b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtentCRS.java
@@ -27,18 +27,24 @@ import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.opengis.referencing.crs.CRSFactory;
import org.opengis.referencing.crs.EngineeringCRS;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.datum.EngineeringDatum;
+import org.opengis.referencing.operation.Matrix;
import org.apache.sis.referencing.cs.AbstractCS;
import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.referencing.AxisDirections;
import org.apache.sis.util.resources.Vocabulary;
import org.apache.sis.util.iso.Types;
import org.apache.sis.measure.Units;
import org.apache.sis.referencing.datum.DefaultEngineeringDatum;
+import org.apache.sis.util.Characters;
/**
- * Builds the coordinate reference system of a {@link GridExtent}.
- * This is used only in the rare case where we need to represent an extent as
an envelope.
+ * Builds the engineering coordinate reference system of a {@link GridExtent}.
+ * This is used only in the rare cases where we need to represent an extent as
an envelope.
+ * This class converts {@link DimensionNameType} codes into axis names,
abbreviations and directions.
+ * It is the converse of {@link
GridExtent#typeFromAxes(CoordinateReferenceSystem, int)}.
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @version 1.1
@@ -74,53 +80,113 @@ final class GridExtentCRS {
}
/**
- * Builds a coordinate reference system of the given number of dimensions
for the given axis types.
+ * Returns a default axis abbreviation for the given dimension.
*/
- static EngineeringCRS build(final int dimension, final DimensionNameType[]
types, final Locale locale)
+ private static String abbreviation(final int dimension) {
+ final StringBuilder b = new
StringBuilder(4).append('x').append(dimension);
+ for (int i=b.length(); --i >= 1;) {
+ b.setCharAt(i, Characters.toSuperScript(b.charAt(i)));
+ }
+ return b.toString();
+ }
+
+ /**
+ * Builds a coordinate reference system for the given axis types.
+ *
+ * @param gridToCRS matrix of the transform used for converting grid
cell indices to envelope coordinates.
+ * It does not matter whether it maps pixel center or corner
(translation coefficients are ignored).
+ * @param types the value of {@link GridExtent#types} or a default
value (shall not be {@code null}).
+ * @param locale locale to use for axis names, or {@code null} for
default.
+ * @return CRS for the grid, or {@code null}.
+ *
+ * @see GridExtent#typeFromAxes(CoordinateReferenceSystem, int)
+ */
+ static EngineeringCRS build(final Matrix gridToCRS, final
DimensionNameType[] types, final Locale locale)
throws FactoryException
{
+ final int tgtDim = gridToCRS.getNumRow() - 1;
+ final int srcDim = Math.min(gridToCRS.getNumCol() - 1, types.length);
+ final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[tgtDim];
final CSFactory csFactory =
DefaultFactories.forBuildin(CSFactory.class);
- final CoordinateSystemAxis[] axes = new
CoordinateSystemAxis[dimension];
- if (types != null) {
-skip: for (int i=0; i<dimension; i++) {
- final DimensionNameType type = types[i];
- if (type != null) {
- final String abbreviation;
- final AxisDirection direction;
- if (type == DimensionNameType.ROW || type ==
DimensionNameType.LINE) {
- abbreviation = "y"; direction =
AxisDirection.ROW_POSITIVE;
- } else if (type == DimensionNameType.COLUMN || type ==
DimensionNameType.SAMPLE) {
- abbreviation = "x"; direction =
AxisDirection.COLUMN_POSITIVE;
- } else if (type == DimensionNameType.VERTICAL) {
- abbreviation = "z"; direction = AxisDirection.UP;
- } else if (type == DimensionNameType.TIME) {
- abbreviation = "t"; direction = AxisDirection.FUTURE;
- } else {
- abbreviation = "d" + dimension;
- direction = AxisDirection.OTHER;
+ for (int i=0; i<srcDim; i++) {
+ final DimensionNameType type = types[i];
+ if (type != null) {
+ /*
+ * Try to locate the CRS dimension corresponding to grid
dimension j.
+ * We expect a one-to-one matching; if it is not the case,
return null.
+ * Current version does not accept scale factors, but we could
revisit
+ * in a future version if there is a need for it.
+ */
+ int target = -1;
+ double scale = 0;
+ for (int j=0; j<tgtDim; j++) {
+ final double m = gridToCRS.getElement(j, i);
+ if (m != 0) {
+ if (target >= 0 || axes[j] != null || Math.abs(m) !=
1) {
+ return null;
+ }
+ target = j;
+ scale = m;
}
- // Verify that no other axis has the same direction.
- for (int j=i; --j >= 0;) {
- final CoordinateSystemAxis previous = axes[j];
- if (previous != null &&
direction.equals(previous.getDirection())) {
- continue skip;
+ }
+ if (target < 0) {
+ return null;
+ }
+ /*
+ * This hard-coded set of axis directions is the converse of
+ * GridExtent.AXIS_DIRECTIONS map.
+ */
+ String abbreviation;
+ AxisDirection direction;
+ if (type == DimensionNameType.COLUMN || type ==
DimensionNameType.SAMPLE) {
+ abbreviation = "x"; direction =
AxisDirection.COLUMN_POSITIVE;
+ } else if (type == DimensionNameType.ROW || type ==
DimensionNameType.LINE) {
+ abbreviation = "y"; direction = AxisDirection.ROW_POSITIVE;
+ } else if (type == DimensionNameType.VERTICAL) {
+ abbreviation = "z"; direction = AxisDirection.UP;
+ } else if (type == DimensionNameType.TIME) {
+ abbreviation = "t"; direction = AxisDirection.FUTURE;
+ } else {
+ abbreviation = abbreviation(target);
+ direction = AxisDirection.OTHER;
+ }
+ /*
+ * Verify that no other axis has the same direction and
abbreviation. If duplicated
+ * values are found, keep only the first occurrence in grid
axis order (may not be
+ * the CRS axis order).
+ */
+ for (int k = tgtDim; --k >= 0;) {
+ final CoordinateSystemAxis previous = axes[k];
+ if (previous != null) {
+ if
(direction.equals(AxisDirections.absolute(previous.getDirection()))) {
+ direction = AxisDirection.OTHER;
+ }
+ if (abbreviation.equals(previous.getAbbreviation())) {
+ abbreviation = abbreviation(target);
}
}
- final String name =
Types.toString(Types.getCodeTitle(type), locale);
- axes[i] = axis(csFactory, name, abbreviation, direction);
}
+ if (scale < 0) {
+ direction = AxisDirections.opposite(direction);
+ }
+ final String name = Types.toString(Types.getCodeTitle(type),
locale);
+ axes[target] = axis(csFactory, name, abbreviation, direction);
}
}
- for (int i=0; i<dimension; i++) {
- if (axes[i] == null) {
- final String name =
Vocabulary.getResources(locale).getString(Vocabulary.Keys.Dimension_1, i);
- final String abbreviation = "d" + dimension;
- axes[i] = axis(csFactory, name, abbreviation,
AxisDirection.OTHER);
+ /*
+ * Search for axes that have not been created in above loop.
+ * It happens when some axes have no associated `DimensionNameType`
code.
+ */
+ for (int j=0; j<tgtDim; j++) {
+ if (axes[j] == null) {
+ final String name =
Vocabulary.getResources(locale).getString(Vocabulary.Keys.Dimension_1, j);
+ final String abbreviation = abbreviation(j);
+ axes[j] = axis(csFactory, name, abbreviation,
AxisDirection.OTHER);
}
}
final Map<String,?> properties = properties("Grid extent");
final CoordinateSystem cs;
- switch (dimension) {
+ switch (tgtDim) {
case 2: cs = csFactory.createAffineCS(properties, axes[0],
axes[1]); break;
case 3: cs = csFactory.createAffineCS(properties, axes[0],
axes[1], axes[2]); break;
default: cs = new AbstractCS(properties, axes); break;
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 88fd556..b0cb727 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
@@ -22,17 +22,22 @@ import org.opengis.geometry.Envelope;
import org.opengis.geometry.DirectPosition;
import org.opengis.metadata.spatial.DimensionNameType;
import org.opengis.coverage.PointOutsideCoverageException;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.AxisDirection;
import org.apache.sis.geometry.AbstractEnvelope;
import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.geometry.GeneralDirectPosition;
import org.apache.sis.coverage.SubspaceNotSpecifiedException;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.referencing.operation.matrix.Matrix3;
import org.apache.sis.referencing.crs.HardCodedCRS;
import org.apache.sis.util.resources.Vocabulary;
import org.apache.sis.test.TestCase;
import org.junit.Test;
-import static org.apache.sis.test.Assert.*;
+import static org.apache.sis.test.ReferencingAssert.*;
/**
@@ -263,6 +268,38 @@ public final strictfp class GridExtentTest extends
TestCase {
}
/**
+ * Tests {@link GridExtent#toEnvelope(MathTransform)}.
+ *
+ * @throws TransformException if an error occurred while transforming to
an envelope.
+ */
+ @Test
+ public void testToEnvelope() throws TransformException {
+ final GridExtent extent = new GridExtent(new DimensionNameType[] {
+ DimensionNameType.ROW,
+ DimensionNameType.TIME,
+ DimensionNameType.COLUMN,
+ DimensionNameType.VERTICAL
+ }, new long[] {100, 5, 200, 40}, new long[] {500, 7, 800, 50}, false);
+ final GeneralEnvelope envelope =
extent.toEnvelope(MathTransforms.linear(Matrices.create(5, 5, new double[] {
+ 0, 0, 1, 0, 0,
+ -1, 0, 0, 0, 0,
+ 0, 0, 0, -1, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 1})));
+
+ assertEnvelopeEquals(new GeneralEnvelope(
+ new double[] {200, -500, -50, 5},
+ new double[] {800, -100, -40, 7}), envelope);
+
+ final CoordinateSystem cs =
envelope.getCoordinateReferenceSystem().getCoordinateSystem();
+ assertAxisDirectionsEqual("toEnvelope", cs,
+ AxisDirection.COLUMN_POSITIVE,
+ AxisDirection.ROW_NEGATIVE,
+ AxisDirection.DOWN,
+ AxisDirection.FUTURE);
+ }
+
+ /**
* Tests {@link GridExtent#toString()}.
* Note that the string representation may change in any future SIS
version.
*