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 2022/01/19 13:55:04 UTC
[sis] branch geoapi-4.0 updated (ecee3c9 -> 031330c)
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 ecee3c9 Build configuration: upgrade Maven dependencies.
new a7dc22f Resolve more issues with the use of axis direction such as "South along 90° East". It fixes some exceptions that were thrown when using Polar Stereographic projection.
new 031330c Adopt "colinear" as a valid spelling. While "collinear" seems more widely used, "colinear" is the spelling used by Java2D and is used in current SIS public API.
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/DimensionReducer.java | 2 +-
.../org/apache/sis/coverage/grid/GridGeometry.java | 2 +-
.../sis/coverage/grid/GridDerivationTest.java | 27 ++++
.../sis/internal/referencing/AxesMapper.java | 160 +++++++++++++++++++++
.../sis/internal/referencing/AxisDirections.java | 73 ++++------
.../sis/referencing/cs/CoordinateSystems.java | 26 +++-
.../sis/referencing/cs/DirectionAlongMeridian.java | 15 +-
.../apache/sis/referencing/cs/package-info.java | 2 +-
.../sis/internal/referencing/AxesMapperTest.java | 97 +++++++++++++
.../internal/referencing/AxisDirectionsTest.java | 27 ++--
.../sis/test/suite/ReferencingTestSuite.java | 1 +
ide-project/NetBeans/nbproject/genfiles.properties | 2 +-
ide-project/NetBeans/nbproject/project.xml | 3 +
.../org/apache/sis/internal/netcdf/Linearizer.java | 43 ++----
14 files changed, 378 insertions(+), 102 deletions(-)
create mode 100644 core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxesMapper.java
create mode 100644 core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxesMapperTest.java
[sis] 01/02: Resolve more issues with the use of axis direction such as "South along 90° East". It fixes some exceptions that were thrown when using Polar Stereographic projection.
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 a7dc22f9c4d2273b331dd3abb399752c9805d21f
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Jan 19 14:16:32 2022 +0100
Resolve more issues with the use of axis direction such as "South along 90° East".
It fixes some exceptions that were thrown when using Polar Stereographic projection.
---
.../apache/sis/coverage/grid/DimensionReducer.java | 2 +-
.../org/apache/sis/coverage/grid/GridGeometry.java | 2 +-
.../sis/coverage/grid/GridDerivationTest.java | 27 ++++
.../sis/internal/referencing/AxesMapper.java | 160 +++++++++++++++++++++
.../sis/internal/referencing/AxisDirections.java | 73 ++++------
.../sis/referencing/cs/CoordinateSystems.java | 26 +++-
.../sis/referencing/cs/DirectionAlongMeridian.java | 15 +-
.../apache/sis/referencing/cs/package-info.java | 2 +-
.../sis/internal/referencing/AxesMapperTest.java | 97 +++++++++++++
.../internal/referencing/AxisDirectionsTest.java | 27 ++--
.../sis/test/suite/ReferencingTestSuite.java | 1 +
ide-project/NetBeans/nbproject/genfiles.properties | 2 +-
ide-project/NetBeans/nbproject/project.xml | 2 +
.../org/apache/sis/internal/netcdf/Linearizer.java | 43 ++----
14 files changed, 377 insertions(+), 102 deletions(-)
diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DimensionReducer.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DimensionReducer.java
index 884380d..568cd1c 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DimensionReducer.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/DimensionReducer.java
@@ -63,7 +63,7 @@ final class DimensionReducer {
final CoordinateSystem sourceCS = sourceCRS.getCoordinateSystem();
final CoordinateSystem targetCS = targetCRS.getCoordinateSystem();
if (sourceCS.getDimension() < targetCS.getDimension()) {
- dimensions = AxisDirections.indicesOfColinear(targetCS, sourceCS);
+ dimensions = AxisDirections.indicesOfLenientMapping(targetCS, sourceCS);
if (dimensions != null) {
Arrays.sort(dimensions);
reducedCRS = CRS.reduce(targetCRS, dimensions);
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 d635d13..79ae461 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
@@ -625,7 +625,7 @@ public class GridGeometry implements LenientComparable, Serializable {
if (targetCRS != sourceCRS) {
final CoordinateSystem sourceCS = sourceCRS.getCoordinateSystem();
final CoordinateSystem targetCS = targetCRS.getCoordinateSystem();
- sourceDimensions = AxisDirections.indicesOfColinear(sourceCS, targetCS);
+ sourceDimensions = AxisDirections.indicesOfLenientMapping(sourceCS, targetCS);
if (sourceDimensions != null) {
final double[] lowerCorner = new double[sourceDimensions.length];
final double[] upperCorner = new double[sourceDimensions.length];
diff --git a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java
index a4ab028..f322466 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/coverage/grid/GridDerivationTest.java
@@ -32,6 +32,7 @@ import org.apache.sis.geometry.DirectPosition2D;
import org.apache.sis.geometry.GeneralDirectPosition;
import org.apache.sis.internal.referencing.Formulas;
import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
+import org.apache.sis.referencing.CommonCRS;
import org.apache.sis.referencing.cs.AxesConvention;
import org.apache.sis.referencing.crs.DefaultCompoundCRS;
import org.apache.sis.referencing.operation.matrix.Matrices;
@@ -305,6 +306,32 @@ public final strictfp class GridDerivationTest extends TestCase {
}
/**
+ * Tests {@link GridDerivation#subgrid(Envelope, double...)} on a grid using a polar projection.
+ * The test also uses a geographic envelope with more dimensions than the source grid geometry.
+ * The difficulty is that axis directions do not match directly: the source grid has directions
+ * such as "South along 90° meridian".
+ */
+ @Test
+ public void testSubgridOnPolarProjection() {
+ GeneralEnvelope envelope = new GeneralEnvelope(CommonCRS.WGS84.universal(90, 0));
+ envelope.setRange(0, -1000, 1500);
+ envelope.setRange(1, -2000, 1800);
+ GridGeometry grid = new GridGeometry(new GridExtent(500, 400), envelope, GridOrientation.HOMOTHETY);
+
+ envelope = new GeneralEnvelope(HardCodedCRS.WGS84_WITH_TIME);
+ envelope.setRange(0, -45, -44);
+ envelope.setRange(1, 64, 65);
+ envelope.setRange(2, 20, 40);
+ final GridDerivation derivation = grid.derive();
+ grid = derivation.subgrid(envelope, 0.002, 0.001).build();
+ /*
+ * The main test is to check that we reach this point without an exception being thrown.
+ * We add a small arbitrary test below as a matter of principle.
+ */
+ assertTrue(envelope.subEnvelope(0, 2).intersects(grid.getEnvelope()));
+ }
+
+ /**
* Tests {@link GridDerivation#subgrid(GridExtent, int...)}
* with an integer amount of tiles, operating only on extents.
*/
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxesMapper.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxesMapper.java
new file mode 100644
index 0000000..462526f
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxesMapper.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.referencing;
+
+import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.apache.sis.referencing.cs.CoordinateSystems;
+import org.apache.sis.internal.util.Numerics;
+
+import static java.lang.Long.numberOfTrailingZeros;
+
+
+/**
+ * Maps coordinate axes for a "sub-coordinate system" to the axes of a coordinate systems with more dimensions.
+ * This enumeration contains the criterion to apply for matching axes, in priority order.
+ *
+ * <p>In current implementation, the enumeration values are used only internally.
+ * The useful method is {@link #indices(CoordinateSystem, CoordinateSystem)}.</p>
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.2
+ * @since 1.2
+ * @module
+ */
+enum AxesMapper {
+ /**
+ * Match axes having the exact same direction.
+ */
+ SAME,
+
+ /**
+ * Match axes having opposite direction.
+ */
+ OPPOSITE,
+
+ /**
+ * Match axes of the kind "South along 90° East".
+ */
+ POLAR;
+
+ /**
+ * Bitmask for axis direction handled in a special way.
+ * They are the substitute for directions like "South along 90° East".
+ * We arbitrarily replace the first direction by East and the second direction by North.
+ */
+ private static final int EAST = 1, NORTH = 2;
+
+ /**
+ * Returns the indices in {@code cs} of axes presumed covariant with the {@code subCS} axes.
+ * Directions such as "South along 90°E" are arbitrarily handled as if they were covariant with East and North.
+ *
+ * <h4>Limitations</h4>
+ * Current implementation considers only the first 64 dimensions.
+ * If there is more dimensions, the extra ones are silently ignored.
+ *
+ * @param cs the coordinate system which contains all axes, or {@code null}.
+ * @param subCS the coordinate system to search into {@code cs}.
+ * @return indices in {@code cs} of axes covariant 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.
+ */
+ public static int[] indices(final CoordinateSystem cs, final CoordinateSystem subCS) {
+ final int[] indices = new int[subCS.getDimension()];
+ long axesToSearch = Numerics.bitmask(indices.length) - 1; // Bit mask of `subCS` axes not yet used.
+ long availableAxes = Numerics.bitmask(cs.getDimension()) - 1; // Bit mask of `cs` axes not yet used.
+ int directionUsed = 0;
+ for (final AxesMapper comparisonMode : values()) {
+ /*
+ * We will do 3 attempts to match axes, with matching criteria relaxed on each iteration:
+ *
+ * 1) Matches axes having the same direction.
+ * 2) Matches axes having opposite directions.
+ * 3) Matches axes of the kind "South along 90° East".
+ *
+ * On each `comparisonMode` iteration, we iterate over all `subCS` axes which have not be selected in
+ * a previous iteration. The `iterSubCS` bitmask has a bit set to 1 for each remaining axes to visit.
+ */
+ long iterSubCS = axesToSearch, clearSubCS;
+ for (int dimSubCS; hasMore(dimSubCS = numberOfTrailingZeros(iterSubCS)); iterSubCS &= clearSubCS) {
+ clearSubCS = clearMask(dimSubCS);
+ AxisDirection search = subCS.getAxis(dimSubCS).getDirection();
+ switch (comparisonMode) {
+ case OPPOSITE: {
+ if (search == (search = AxisDirections.opposite(search)) || search == null) {
+ continue; // Axis already examined in previous iteration.
+ }
+ break;
+ }
+ case POLAR: {
+ if (CoordinateSystems.isAlongMeridian(search)) {
+ switch (directionUsed) {
+ case 0: // For first axis, fallback on EAST.
+ case NORTH: search = AxisDirection.EAST; break;
+ case EAST: search = AxisDirection.NORTH; break;
+ default: return null; // Too many such axes.
+ }
+ }
+ }
+ }
+ /*
+ * At this point we got the axis direction to search adjusted for the comparison mode.
+ * Now iterate over all `cs` dimensions in search for an axis having a compatible direction.
+ */
+ long iterCS = availableAxes, clearCS;
+ for (int dimCS; hasMore(dimCS = numberOfTrailingZeros(iterCS)); iterCS &= clearCS) {
+ clearCS = clearMask(dimCS);
+ AxisDirection candidate = cs.getAxis(dimCS).getDirection();
+ if (comparisonMode == POLAR && CoordinateSystems.isAlongMeridian(candidate)) {
+ switch (directionUsed) {
+ case 0: // For first axis, fallback on EAST.
+ case NORTH: candidate = AxisDirection.EAST; break;
+ case EAST: candidate = AxisDirection.NORTH; break;
+ default: return null; // Too many such axes.
+ }
+ }
+ if (search.equals(candidate)) {
+ if (search.equals(AxisDirection.EAST)) directionUsed |= EAST;
+ if (search.equals(AxisDirection.NORTH)) directionUsed |= NORTH;
+ indices[dimSubCS] = dimCS;
+ availableAxes &= clearCS;
+ axesToSearch &= clearSubCS;
+ if (axesToSearch == 0) {
+ return indices;
+ }
+ break; // Move to next `subCS` axis.
+ }
+ }
+ }
+ }
+ return (axesToSearch == 0) ? indices : null;
+ }
+
+ /**
+ * Returns {@code true} if the given value computed by {@link Long#numberOfTrailingZeros(long)}
+ * means that there is at least one more dimension to process. This is used for stopping iterations.
+ */
+ private static boolean hasMore(final int numBits) {
+ return (numBits & ~(Long.SIZE - 1)) == 0;
+ }
+
+ /**
+ * Returns a mask for clearing the bit associated to the given coordinate system dimension.
+ */
+ private static long clearMask(final int dim) {
+ return ~(1L << dim);
+ }
+}
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 2dd092b..2102cd0 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
@@ -70,6 +70,8 @@ public final class AxisDirections extends Static {
/**
* Ordinal of the last element in the {@link AxisDirection} code list.
* This is used for differentiating the standard codes from the user-defined ones.
+ *
+ * @see #isUserDefined(AxisDirection)
*/
private static final int LAST_ORDINAL = DISPLAY_DOWN.ordinal();
@@ -265,22 +267,6 @@ public final class AxisDirections extends Static {
}
/**
- * Returns {@code true} if the given axis is such as "South along 90°E".
- *
- * <p><b>This is a temporary method to be removed!</b>
- * Latest ISO 19111 revision uses another mechanism for declaring such axis direction.
- * This method will be removed after we upgraded the API accordingly.
- *
- * @param dir the axis to test, or {@code null}.
- * @return {@code true} if the given axis is such as "South along 90°E".
- *
- * @since 1.2
- */
- public static boolean isAlongMeridian(final AxisDirection dir) {
- return (dir != null) && !isCompass(dir);
- }
-
- /**
* Returns {@code true} if the given direction is {@code UP} or {@code DOWN}.
*
* @param dir the direction to test, or {@code null}.
@@ -558,37 +544,6 @@ next: for (int i=0; i <= limit; i++) {
}
/**
- * Returns the indices in {@code cs} of axes colinear with the {@code subCS} axes.
- * If many axes have the same direction (should not happen except for temporal axes),
- * this method gives precedence to a sequence of consecutive indices.
- *
- * <p>This method is similar to {@link #indexOfColinear(CoordinateSystem, CoordinateSystem)} except that it
- * enumerates the indices instead of returning only the first index. If {@code indexOfColinear(…)} can not
- * find consecutive indices, then this method fallbacks on a sequence of indices regardless their order.</p>
- *
- * @param cs the coordinate system which contains all axes, or {@code null}.
- * @param subCS the coordinate system to search into {@code cs}.
- * @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 dim = subCS.getDimension();
- final int index = indexOfColinear(cs, subCS); // More robust than fallback below.
- 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;
- }
-
- /**
* Returns whether the second axis is colinear with the first axis. This method returns {@code true}
* if the {@linkplain #absolute absolute} direction of the given directions are equal.
* For example "down" is considered colinear with "up".
@@ -602,6 +557,30 @@ next: for (int i=0; i <= limit; i++) {
}
/**
+ * Returns the indices of {@code cs} axes presumed covariant with {@code subCS} axes.
+ * The mapping is based on axis directions only, with collinear axes mapped in priority.
+ * If some axes can not be mapped using collinearity criterion, then directions from poles
+ * (e.g. <cite>"South along 90°E"</cite>) are arbitrarily handled as if they were covariant
+ * with East and North directions, in that order.
+ *
+ * @param cs the coordinate system which contains all axes, or {@code null}.
+ * @param subCS the coordinate system for which to search axes into {@code cs}.
+ * @return indices in {@code cs} of axes covariant 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.
+ *
+ * @see #indexOfColinear(CoordinateSystem, CoordinateSystem)
+ *
+ * @since 1.2
+ */
+ public static int[] indicesOfLenientMapping(final CoordinateSystem cs, final CoordinateSystem subCS) {
+ final int index = indexOfColinear(cs, subCS); // More robust than fallback below.
+ if (index >= 0) {
+ return ArraysExt.range(index, index + subCS.getDimension());
+ }
+ return AxesMapper.indices(cs, subCS);
+ }
+
+ /**
* Searches for an axis direction having the given name in the specified list of directions.
* This method compares the given name with the name of each {@code AxisDirection} in a lenient way:
*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
index 4ad1b6f..3df656a 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
@@ -57,7 +57,7 @@ import org.apache.sis.referencing.operation.matrix.MatrixSIS;
* between two coordinate systems.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.2
* @since 0.4
* @module
*/
@@ -138,6 +138,30 @@ public final class CoordinateSystems extends Static {
}
/**
+ * Returns {@code true} if the given axis direction seems to be a direction along a meridian.
+ *
+ * <table class="sis">
+ * <caption>Examples</caption>
+ * <tr><th>Axis name</th> <th>Return value</th></tr>
+ * <tr><td>North along 90 deg East</td> <td>{@code true}</td></tr>
+ * <tr><td>South along 90 deg East</td> <td>{@code true}</td></tr>
+ * <tr><td>South</td> <td>{@code false}</td></tr>
+ * <tr><td>East</td> <td>{@code false}</td></tr>
+ * </table>
+ *
+ * Note that {@code true} is not a guarantee that {@link #parseAxisDirection(String)} will succeed.
+ * But it means that there is reasonable chances of success based on brief inspection of axis name.
+ *
+ * @param direction the direction to test. Can be null.
+ * @return if the given direction is non-null and seems to be a direction along a meridian.
+ *
+ * @since 1.2
+ */
+ public static boolean isAlongMeridian(final AxisDirection direction) {
+ return AxisDirections.isUserDefined(direction) && DirectionAlongMeridian.matches(direction.name());
+ }
+
+ /**
* Returns the arithmetic (counterclockwise) angle from the first axis direction to the second direction.
* This method returns a value between -180° and +180°, or {@code null} if no angle can be computed.
*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DirectionAlongMeridian.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DirectionAlongMeridian.java
index e106ef9..9265f6c 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DirectionAlongMeridian.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DirectionAlongMeridian.java
@@ -43,11 +43,8 @@ import org.apache.sis.util.resources.Errors;
* that contains (through its coordinate system) the axes having those directions. This is consistent with
* ISO 19162:2015 §7.5.4(iv) - WKT 2 formatting.
*
- * <h2>Immutability and thread safety</h2>
- * This final class is immutable and thus inherently thread-safe.
- *
* @author Martin Desruisseaux (IRD)
- * @version 0.8
+ * @version 1.2
* @since 0.4
* @module
*/
@@ -108,6 +105,14 @@ final class DirectionAlongMeridian extends FormattableObject implements Comparab
}
/**
+ * Returns {@code true} if the given direction is non-null
+ * and has a name which seems to be a direction along meridian.
+ */
+ public static boolean matches(final String direction) {
+ return (direction != null) && EPSG.matcher(direction).matches();
+ }
+
+ /**
* Returns the direction along meridian for the specified axis direction, or {@code null} if none.
*
* <p>TIP: caller can check {@link AxisDirections#isUserDefined(AxisDirection)} before to invoke this method
@@ -282,7 +287,7 @@ final class DirectionAlongMeridian extends FormattableObject implements Comparab
buffer.append(meridian < 0 ? 'W' : 'E');
}
name = buffer.toString();
- assert EPSG.matcher(name).matches() : name;
+ assert matches(name) : name;
return name;
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/package-info.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/package-info.java
index 2b24494..955e459 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/package-info.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/package-info.java
@@ -33,7 +33,7 @@
* and units between two coordinate systems, or filtering axes.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.2
* @since 0.4
* @module
*/
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxesMapperTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxesMapperTest.java
new file mode 100644
index 0000000..ca70c23
--- /dev/null
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxesMapperTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.referencing;
+
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.cs.HardCodedCS;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Tests the {@link AxesMapper} class.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.2
+ * @since 1.2
+ * @module
+ */
+public final strictfp class AxesMapperTest extends TestCase {
+ /**
+ * Tests with axes having same direction in same order.
+ */
+ @Test
+ public void testSameDirections() {
+ assertArrayEquals(new int[] {0, 1}, AxesMapper.indices(
+ HardCodedCS.GEODETIC_3D,
+ HardCodedCS.GEODETIC_2D));
+ }
+
+ /**
+ * Tests with axes having same direction but different order.
+ */
+ @Test
+ public void testAxisOrderChange() {
+ assertArrayEquals(new int[] {1, 0}, AxesMapper.indices(
+ HardCodedCS.GEODETIC_φλ,
+ HardCodedCS.GEODETIC_2D));
+
+ assertArrayEquals(new int[] {1, 0}, AxesMapper.indices(
+ HardCodedCS.GEODETIC_3D,
+ HardCodedCS.GEODETIC_φλ));
+ }
+
+ /**
+ * Tests selection of vertical axis, including opposite direction.
+ */
+ @Test
+ public void testVerticalAxis() {
+ assertArrayEquals(new int[] {2}, AxesMapper.indices(
+ HardCodedCS.GEODETIC_3D,
+ HardCodedCS.ELLIPSOIDAL_HEIGHT));
+
+ assertArrayEquals(new int[] {2}, AxesMapper.indices(
+ HardCodedCS.GEODETIC_3D,
+ HardCodedCS.DEPTH));
+ }
+
+ /**
+ * Tests the search of axes that do not exist in source coordinate system.
+ */
+ @Test
+ public void testNotFound() {
+ assertNull(AxesMapper.indices(
+ HardCodedCS.GEODETIC_3D,
+ HardCodedCS.DAYS));
+
+ assertNull(AxesMapper.indices(
+ HardCodedCS.GEODETIC_2D,
+ HardCodedCS.GEODETIC_3D));
+ }
+
+ /**
+ * Tests with directions such as "South along 90° East".
+ */
+ @Test
+ public void testDirectionsFromPole() {
+ assertArrayEquals(new int[] {1,0}, AxesMapper.indices(
+ HardCodedCS.GEODETIC_φλ,
+ CommonCRS.WGS84.universal(90, 0).getCoordinateSystem()));
+ }
+}
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 5df9414..25352ce 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
@@ -25,6 +25,7 @@ import org.apache.sis.referencing.cs.HardCodedAxes;
import org.apache.sis.referencing.cs.HardCodedCS;
import org.apache.sis.measure.Units;
import org.apache.sis.test.DependsOnMethod;
+import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
import org.junit.Test;
@@ -39,14 +40,12 @@ import static org.apache.sis.internal.referencing.AxisDirections.COUNTER_CLOCKWI
/**
* Tests the {@link AxisDirections} class.
*
- * <p>The {@code AxisDirections} class is defined in the {@code sis-metadata} module, but tested in the
- * {@code sis-referencing} module because those tests use {@link HardCodedAxes} constants.</p>
- *
* @author Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.2
* @since 0.4
* @module
*/
+@DependsOn(AxesMapperTest.class)
public final strictfp class AxisDirectionsTest extends TestCase {
/**
* Tests {@link AxisDirections#absolute(AxisDirection)}.
@@ -421,37 +420,37 @@ public final strictfp class AxisDirectionsTest extends TestCase {
}
/**
- * Tests {@link AxisDirections#indicesOfColinear(CoordinateSystem, CoordinateSystem)}.
+ * Tests {@link AxisDirections#indicesOfLenientMapping(CoordinateSystem, CoordinateSystem)}.
*
- * @since 1.1
+ * @see AxesMapperTest
*/
@Test
- public void testIndicesOfColinear() {
- assertArrayEquals(new int[] {0, 1}, AxisDirections.indicesOfColinear(
+ public void testIndicesOfLenientMapping() {
+ assertArrayEquals(new int[] {0, 1}, AxisDirections.indicesOfLenientMapping(
HardCodedCS.GEODETIC_3D,
HardCodedCS.GEODETIC_2D));
- assertArrayEquals(new int[] {1, 0}, AxisDirections.indicesOfColinear(
+ assertArrayEquals(new int[] {1, 0}, AxisDirections.indicesOfLenientMapping(
HardCodedCS.GEODETIC_φλ,
HardCodedCS.GEODETIC_2D));
- assertArrayEquals(new int[] {1, 0}, AxisDirections.indicesOfColinear(
+ assertArrayEquals(new int[] {1, 0}, AxisDirections.indicesOfLenientMapping(
HardCodedCS.GEODETIC_3D,
HardCodedCS.GEODETIC_φλ));
- assertArrayEquals(new int[] {2}, AxisDirections.indicesOfColinear(
+ assertArrayEquals(new int[] {2}, AxisDirections.indicesOfLenientMapping(
HardCodedCS.GEODETIC_3D,
HardCodedCS.ELLIPSOIDAL_HEIGHT));
- assertArrayEquals(new int[] {2}, AxisDirections.indicesOfColinear(
+ assertArrayEquals(new int[] {2}, AxisDirections.indicesOfLenientMapping(
HardCodedCS.GEODETIC_3D,
HardCodedCS.DEPTH));
- assertArrayEquals(null, AxisDirections.indicesOfColinear(
+ assertArrayEquals(null, AxisDirections.indicesOfLenientMapping(
HardCodedCS.GEODETIC_3D,
HardCodedCS.DAYS));
- assertArrayEquals(null, AxisDirections.indicesOfColinear(
+ assertArrayEquals(null, AxisDirections.indicesOfLenientMapping(
HardCodedCS.GEODETIC_2D,
HardCodedCS.GEODETIC_3D));
}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java b/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
index 261adfd..42130b8 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
@@ -34,6 +34,7 @@ import org.junit.BeforeClass;
org.apache.sis.internal.referencing.FormulasTest.class,
org.apache.sis.internal.referencing.j2d.AbstractShapeTest.class,
org.apache.sis.internal.referencing.j2d.ShapeUtilitiesTest.class,
+ org.apache.sis.internal.referencing.AxesMapperTest.class,
org.apache.sis.internal.referencing.AxisDirectionsTest.class,
org.apache.sis.internal.referencing.VerticalDatumTypesTest.class,
org.apache.sis.internal.referencing.PositionalAccuracyConstantTest.class,
diff --git a/ide-project/NetBeans/nbproject/genfiles.properties b/ide-project/NetBeans/nbproject/genfiles.properties
index 26927a9..72e6bc5 100644
--- a/ide-project/NetBeans/nbproject/genfiles.properties
+++ b/ide-project/NetBeans/nbproject/genfiles.properties
@@ -3,6 +3,6 @@
build.xml.data.CRC32=58e6b21c
build.xml.script.CRC32=462eaba0
build.xml.stylesheet.CRC32=28e38971@1.53.1.46
-nbproject/build-impl.xml.data.CRC32=d3e84221
+nbproject/build-impl.xml.data.CRC32=f92ba43e
nbproject/build-impl.xml.script.CRC32=6b1e829a
nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.101.0.48
diff --git a/ide-project/NetBeans/nbproject/project.xml b/ide-project/NetBeans/nbproject/project.xml
index 00659e4..e45ea3e 100644
--- a/ide-project/NetBeans/nbproject/project.xml
+++ b/ide-project/NetBeans/nbproject/project.xml
@@ -86,7 +86,9 @@
<word>classname</word>
<word>classnames</word>
<word>classpath</word>
+ <word>collinearity</word>
<word>complexify</word>
+ <word>covariant</word>
<word>deserialization</word>
<word>deserialized</word>
<word>endianness</word>
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Linearizer.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Linearizer.java
index d02505b..4a4f6a0 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Linearizer.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Linearizer.java
@@ -100,7 +100,7 @@ public final class Linearizer {
* </ul>
*
* <div class="note"><b>Rational:</b>
- * the intend is to increase the chances to get the Polar Stereographic projection for images close to pole.
+ * the intent is to increase the chances to get the Polar Stereographic projection for images close to pole.
* This is necessary because longitude values may become far from central meridian at latitudes such as 88°,
* causing the Transverse Mercator projection to produce NaN numbers.</div>
*/
@@ -112,34 +112,6 @@ public final class Linearizer {
* 60° is the limit of the domain of validity of Polar Stereographic methods.
*/
static final int POLAR_THRESHOLD = 60;
-
- /**
- * Returns a coordinate system containing the axes to search and replace in order to build
- * a "CRS after linearization" from a "CRS before linearization". The caller will use only
- * the axis directions (not the names) of the returned coordinate system.
- *
- * <h4>Rational</h4>
- * Usually, the source CRS is geographic and the target CRS is projected.
- * We can generally associate a source axis to a target axis by looking at their directions.
- * For example the "Longitude" source axis is approximately colinear with the "Easting" target axis.
- * {@link org.opengis.referencing.cs.AxisDirection#EAST} can be used as a criterion for mapping them.
- * Note however that axis names can not be used, because they differ in geographic and projected CRS.
- *
- * <p>However there is an exception where target axis directions will not work neither.
- * If the projection is a polar projection with axis directions such as "South along 90°E",
- * then {@link AxisDirections#indicesOfColinear(CoordinateSystem, CoordinateSystem)} will
- * not find a match. We can workaround by using arbitrary (East, North) directions instead.</p>
- *
- * @param targetCS coordinate system of {@link Linearizer#targetCRS}.
- */
- final CoordinateSystem getAxisReplacement(final CoordinateSystem targetCS) {
- for (int i = targetCS.getDimension(); --i >= 0;) {
- if (AxisDirections.isAlongMeridian(targetCS.getAxis(i).getDirection())) {
- return CommonCRS.defaultGeographic().getCoordinateSystem();
- }
- }
- return targetCS;
- }
}
/**
@@ -364,11 +336,20 @@ public final class Linearizer {
Matrix original = null;
search: for (final GridCacheValue replacement : replacements) {
final SingleCRS targetCRS = replacement.linearizationTarget;
- final CoordinateSystem targetCS = replacement.linearizationType.getAxisReplacement(targetCRS.getCoordinateSystem());
+ final CoordinateSystem targetCS = targetCRS.getCoordinateSystem();
int firstDimension = 0;
for (int i=0; i < components.length; i++) {
final SingleCRS sourceCRS = components[i];
- final int[] r = AxisDirections.indicesOfColinear(sourceCRS.getCoordinateSystem(), targetCS);
+ /*
+ * In the most typical cases, the source CRS is geographic and the target CRS is projected.
+ * We can generally associate a source axis to a target axis by looking at their directions.
+ * For example the "Longitude" source axis is approximately colinear with the "Easting" target axis.
+ * However there is a use case where target axis directions can not be matched directly to source:
+ * if the projection is a polar projection with target axis directions such as "South along 90°E",
+ * then `AxisDirections.indexOfColinear(CoordinateSystem, CoordinateSystem)} will not find a match.
+ * We need the more flexible `indicesOfLenientMapping(…)` method.
+ */
+ final int[] r = AxisDirections.indicesOfLenientMapping(sourceCRS.getCoordinateSystem(), targetCS);
if (r != null) {
components[i] = targetCRS;
if (replacement.axisSwap) {
[sis] 02/02: Adopt "colinear" as a valid spelling. While "collinear" seems more widely used, "colinear" is the spelling used by Java2D and is used in current SIS public API.
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 031330cce06447feaf9ddace63e2906fdd180668
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Jan 19 14:53:51 2022 +0100
Adopt "colinear" as a valid spelling. While "collinear" seems more widely used,
"colinear" is the spelling used by Java2D and is used in current SIS public API.
---
.../main/java/org/apache/sis/internal/referencing/AxisDirections.java | 2 +-
ide-project/NetBeans/nbproject/genfiles.properties | 2 +-
ide-project/NetBeans/nbproject/project.xml | 1 +
3 files changed, 3 insertions(+), 2 deletions(-)
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 2102cd0..b162bdf 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
@@ -558,7 +558,7 @@ next: for (int i=0; i <= limit; i++) {
/**
* Returns the indices of {@code cs} axes presumed covariant with {@code subCS} axes.
- * The mapping is based on axis directions only, with collinear axes mapped in priority.
+ * The mapping is based on axis directions only, with colinear axes mapped in priority.
* If some axes can not be mapped using collinearity criterion, then directions from poles
* (e.g. <cite>"South along 90°E"</cite>) are arbitrarily handled as if they were covariant
* with East and North directions, in that order.
diff --git a/ide-project/NetBeans/nbproject/genfiles.properties b/ide-project/NetBeans/nbproject/genfiles.properties
index 72e6bc5..fde32dd 100644
--- a/ide-project/NetBeans/nbproject/genfiles.properties
+++ b/ide-project/NetBeans/nbproject/genfiles.properties
@@ -3,6 +3,6 @@
build.xml.data.CRC32=58e6b21c
build.xml.script.CRC32=462eaba0
build.xml.stylesheet.CRC32=28e38971@1.53.1.46
-nbproject/build-impl.xml.data.CRC32=f92ba43e
+nbproject/build-impl.xml.data.CRC32=f706d4ab
nbproject/build-impl.xml.script.CRC32=6b1e829a
nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.101.0.48
diff --git a/ide-project/NetBeans/nbproject/project.xml b/ide-project/NetBeans/nbproject/project.xml
index e45ea3e..e247d6f 100644
--- a/ide-project/NetBeans/nbproject/project.xml
+++ b/ide-project/NetBeans/nbproject/project.xml
@@ -86,6 +86,7 @@
<word>classname</word>
<word>classnames</word>
<word>classpath</word>
+ <word>colinear</word>
<word>collinearity</word>
<word>complexify</word>
<word>covariant</word>