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 2b1ed5b6c5 Find a coordinate operation path between two CRS when a
step requires a change from spherical coordinates to geodetic coordinates.
Note: when the spherical coordinates are two-dimensional, current version
assumes a radius of zero, which is incorrect. The missing radius problem will
be adressed in a separated commit.
2b1ed5b6c5 is described below
commit 2b1ed5b6c5a55cd03dababda10a9ce49eb75106f
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sun Jun 1 21:57:41 2025 +0200
Find a coordinate operation path between two CRS when a step requires a
change from spherical coordinates to geodetic coordinates.
Note: when the spherical coordinates are two-dimensional, current version
assumes a radius of zero, which is incorrect.
The missing radius problem will be adressed in a separated commit.
---
.../sis/referencing/cs/CoordinateSystems.java | 63 +++++++++++++++-------
.../sis/referencing/cs/DefaultCompoundCS.java | 7 ++-
.../operation/MathTransformContext.java | 2 +-
.../operation/matrix/GeneralMatrix.java | 22 ++++----
.../operation/provider/AbstractProvider.java | 12 ++++-
.../GeocentricAffineBetweenGeographic.java | 2 +-
.../operation/provider/GeocentricToGeographic.java | 4 +-
.../operation/provider/GeographicToGeocentric.java | 32 +++++++++--
.../CoordinateSystemTransformBuilder.java | 45 ++++------------
.../transform/EllipsoidToCentricTransform.java | 42 +++++++++++----
.../operation/CoordinateOperationFinderTest.java | 50 +++++++++++++++++
.../provider/GeocentricTranslationTest.java | 4 +-
.../transform/EllipsoidToCentricTransformTest.java | 4 +-
.../EllipsoidToSphericalTransformTest.java | 2 +-
14 files changed, 196 insertions(+), 95 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/CoordinateSystems.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/CoordinateSystems.java
index 8a5743bd7e..61f84e9ee0 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/CoordinateSystems.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/CoordinateSystems.java
@@ -56,7 +56,7 @@ import org.apache.sis.referencing.operation.matrix.MatrixSIS;
* between two coordinate systems.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.4
+ * @version 1.5
* @since 0.4
*/
public final class CoordinateSystems extends Static {
@@ -74,6 +74,7 @@ public final class CoordinateSystems extends Static {
* @param cs the coordinate system to test (can be {@code null}).
* @return whether the given coordinate system can be associated to a
geodetic CRS.
*
+ * @see #getSingleComponents(CoordinateSystem)
* @since 1.3
*/
public static boolean isGeodetic(final CoordinateSystem cs) {
@@ -280,20 +281,6 @@ public final class CoordinateSystems extends Static {
return null;
}
- /**
- * Adds all single coordinate systems in the given list.
- * This method is used for decomposing a coordinate systems into its
components.
- */
- private static void components(final CoordinateSystem cs, final
List<CoordinateSystem> addTo) {
- if (cs instanceof DefaultCompoundCS) {
- for (final CoordinateSystem c : ((DefaultCompoundCS)
cs).getComponents()) {
- components(c, addTo);
- }
- } else {
- addTo.add(cs);
- }
- }
-
/**
* Returns {@code true} if all {@code CoordinateSystem} interfaces of
{@code targetCS} have a counterpart in
* {@code sourceCS}. This method is equivalent to {@link
Classes#implementSameInterfaces(Class, Class, Class)}
@@ -307,10 +294,8 @@ public final class CoordinateSystems extends Static {
* then this method returns {@code false}.
*/
static boolean hasAllTargetTypes(final CoordinateSystem sourceCS, final
CoordinateSystem targetCS) {
- final List<CoordinateSystem> sources = new
ArrayList<>(sourceCS.getDimension());
- final List<CoordinateSystem> targets = new
ArrayList<>(targetCS.getDimension());
- components(sourceCS, sources);
- components(targetCS, targets);
+ final List<CoordinateSystem> sources = getSingleComponents(sourceCS);
+ final List<CoordinateSystem> targets = getSingleComponents(targetCS);
next: for (final CoordinateSystem cs : targets) {
for (int i=0; i<sources.size(); i++) {
if (Classes.implementSameInterfaces(sources.get(i).getClass(),
cs.getClass(), CoordinateSystem.class)) {
@@ -551,6 +536,46 @@ next: for (final CoordinateSystem cs : targets) {
});
}
+ /**
+ * Returns all components of the given coordinate system.
+ * If the given coordinate system (<abbr>CS</abbr>) is null, then this
method returns an empty list.
+ * Otherwise, if the given <abbr>CS</abbr> is <em>not</em> an instance of
{@link DefaultCompoundCS},
+ * then this method adds that <abbr>CS</abbr> as the singleton element of
the returned list.
+ * Otherwise, this method returns all {@linkplain
DefaultCompoundCS#getComponents() components}.
+ * If a component is itself a {@link DefaultCompoundCS}, its is
recursively decomposed into its
+ * singleton component.
+ *
+ * <h4>Implementation note</h4>
+ * This method always returns a modifiable list.
+ * Callers can freely modify that list without impacting the coordinate
system.
+ *
+ * @param cs the coordinate system to decompose into singleton
components, or {@code null}.
+ * @return the components, or an empty list if {@code cs} is null.
+ *
+ * @see #isGeodetic(CoordinateSystem)
+ * @since 1.5
+ */
+ public static List<CoordinateSystem> getSingleComponents(final
CoordinateSystem cs) {
+ final var addTo = new ArrayList<CoordinateSystem>(3);
+ getSingleComponents(cs, addTo);
+ return addTo;
+ }
+
+ /**
+ * Recursively adds all single coordinate systems in the given list.
+ */
+ private static void getSingleComponents(final CoordinateSystem cs, final
List<CoordinateSystem> addTo) {
+ if (cs != null) {
+ if (cs instanceof DefaultCompoundCS) {
+ for (final CoordinateSystem c : ((DefaultCompoundCS)
cs).getComponents()) {
+ getSingleComponents(c, addTo);
+ }
+ } else {
+ addTo.add(cs);
+ }
+ }
+ }
+
/**
* Returns the axis directions for the specified coordinate system.
* This method guarantees that the returned array is non-null and does not
contain any null direction.
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/DefaultCompoundCS.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/DefaultCompoundCS.java
index 5ccec08324..b77b1d65eb 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/DefaultCompoundCS.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/DefaultCompoundCS.java
@@ -103,6 +103,7 @@ public class DefaultCompoundCS extends AbstractCS {
public DefaultCompoundCS(final Map<String,?> properties,
CoordinateSystem... components) {
super(properties, getAxes(components = clone(components)));
this.components = UnmodifiableArrayList.wrap(components);
+ // TODO: replace by List.of(components) after RFE #4093999.
}
/**
@@ -112,6 +113,7 @@ public class DefaultCompoundCS extends AbstractCS {
private DefaultCompoundCS(final DefaultCompoundCS original, final
CoordinateSystem[] components) {
super(original, null, getAxes(components));
this.components = UnmodifiableArrayList.wrap(components);
+ // TODO: replace by List.of(components) after RFE #4093999.
}
/**
@@ -134,6 +136,7 @@ public class DefaultCompoundCS extends AbstractCS {
private DefaultCompoundCS(final CoordinateSystem[] components, final
CoordinateSystemAxis[] axes) {
super(Map.of(NAME_KEY, AxisDirections.appendTo(new
StringBuilder(60).append("Compound CS"), axes)), axes);
this.components = UnmodifiableArrayList.wrap(components);
+ // TODO: replace by List.of(components) after RFE #4093999.
}
/**
@@ -156,7 +159,7 @@ public class DefaultCompoundCS extends AbstractCS {
for (int i=0; i<components.length; i++) {
count += components[i].getDimension();
}
- final CoordinateSystemAxis[] axis = new CoordinateSystemAxis[count];
+ final var axis = new CoordinateSystemAxis[count];
count = 0;
for (final CoordinateSystem c : components) {
final int dim = c.getDimension();
@@ -191,7 +194,7 @@ public class DefaultCompoundCS extends AbstractCS {
if (cs == null) {
cs = this;
boolean changed = false;
- final CoordinateSystem[] newComponents = new
CoordinateSystem[components.size()];
+ final var newComponents = new
CoordinateSystem[components.size()];
for (int i=0; i<newComponents.length; i++) {
CoordinateSystem component = components.get(i);
AbstractCS m = castOrCopy(component);
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/MathTransformContext.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/MathTransformContext.java
index d1c5bdf710..bac42900d7 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/MathTransformContext.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/MathTransformContext.java
@@ -130,7 +130,7 @@ final class MathTransformContext extends
ParameterizedTransformBuilder {
MatrixSIS cm = MatrixSIS.castOrCopy(matrix);
if (CartesianCS.class.isAssignableFrom(userCS)) {
rotation = Math.toRadians(rotation);
- final Matrix4 rot = new Matrix4();
+ final var rot = new Matrix4();
rot.m00 = rot.m11 = Math.cos(rotation);
rot.m01 = -(rot.m10 = Math.sin(rotation));
if (inverse) {
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
index 70b6055ea5..cbd4c57b8d 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
@@ -153,8 +153,8 @@ class GeneralMatrix extends MatrixSIS implements
ExtendedPrecisionMatrix {
* @throws NullPointerException if the {@link #elements} array is null.
*/
private boolean isValid() {
- final int numRow = this.numRow;
- final int numCol = this.numCol;
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ final int numRow = this.numRow, numCol = this.numCol; //
Protection against accidental changes.
final int length = elements.length;
int i = numRow * numCol; // Cannot overflow.
if ((numRow | numCol) < 0 || (length != i) ||
@@ -320,8 +320,8 @@ class GeneralMatrix extends MatrixSIS implements
ExtendedPrecisionMatrix {
* @param square {@code true} if the matrix must be square, or {@code
false} for allowing non-square matrices.
*/
final boolean isAffine(final boolean square) {
- final int numRow = this.numRow; // Protection
against accidental changes.
- final int numCol = this.numCol;
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ final int numRow = this.numRow, numCol = this.numCol; //
Protection against accidental changes.
if (numRow == numCol || !square) {
int i = numRow * numCol;
if (Arithmetic.isOne(elements[--i])) {
@@ -342,8 +342,8 @@ class GeneralMatrix extends MatrixSIS implements
ExtendedPrecisionMatrix {
*/
@Override
public final boolean isIdentity() {
- final int numRow = this.numRow; // Protection against
accidental changes.
- final int numCol = this.numCol;
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ final int numRow = this.numRow, numCol = this.numCol; //
Protection against accidental changes.
if (numRow != numCol) {
return false;
}
@@ -370,8 +370,8 @@ class GeneralMatrix extends MatrixSIS implements
ExtendedPrecisionMatrix {
*/
@Override
public void transpose() {
- final int numRow = this.numRow; //
Protection against accidental changes.
- final int numCol = this.numCol;
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ final int numRow = this.numRow, numCol = this.numCol; //
Protection against accidental changes.
for (int j=0; j<numRow; j++) {
for (int i=0; i<j; i++) {
final int lo = j*numCol + i;
@@ -386,8 +386,8 @@ class GeneralMatrix extends MatrixSIS implements
ExtendedPrecisionMatrix {
* The matrix sizes much match - this is not verified unless assertions
are enabled.
*/
final void setToProduct(final Matrix A, final Matrix B) {
- final int numRow = this.numRow; // Protection against
accidental changes.
- final int numCol = this.numCol;
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ final int numRow = this.numRow, numCol = this.numCol; //
Protection against accidental changes.
final int nc = A.getNumCol();
assert B.getNumRow() == nc;
assert numRow == A.getNumRow() && numCol == B.getNumCol();
@@ -435,7 +435,7 @@ class GeneralMatrix extends MatrixSIS implements
ExtendedPrecisionMatrix {
@Override
public final boolean equals(final Object object) {
if (object instanceof GeneralMatrix) {
- final GeneralMatrix that = (GeneralMatrix) object;
+ final var that = (GeneralMatrix) object;
return numRow == that.numRow &&
numCol == that.numCol &&
Arrays.equals(elements, that.elements);
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
index d322c0631a..e97912cf4a 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
@@ -69,8 +69,16 @@ public abstract class AbstractProvider extends
DefaultOperationMethod implements
private final Class<? extends SingleOperation> operationType;
/**
- * The base interface of the coordinate system of source/target
coordinates.
- * This is used for resolving some ambiguities at WKT parsing time.
+ * The base interface of the coordinate system of source coordinates.
+ * This is used for resolving some ambiguities at <abbr>WKT</abbr> parsing
time.
+ *
+ * <h4>Deprecation</h4>
+ * This field is not formally annotated as deprecated, but should be
considered as such.
+ * The coordinate system type can be specified by the {@code context}
argument given in
+ * calls to the {@code create(…)} method. In particular, {@link
GeographicToGeocentric}
+ * accepts Cartesian and spherical coordinate systems. In such cases, this
field should
+ * be set to the type expected in Well-Known Text (<abbr>WKT</abbr>)
definitions.
+ * This is not necessarily the only type accepted by this operation method.
*/
public final Class<? extends CoordinateSystem> sourceCSType, targetCSType;
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeocentricAffineBetweenGeographic.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeocentricAffineBetweenGeographic.java
index fd561617da..f648f99548 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeocentricAffineBetweenGeographic.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeocentricAffineBetweenGeographic.java
@@ -40,7 +40,7 @@ import org.apache.sis.measure.Units;
*
* <h2>Default values to verify</h2>
* This class assumes the following default values.
- * Subclasses should verify if those default values are suitable from them:
+ * Subclasses should verify if those default values are suitable for them:
*
* <ul>
* <li>{@link #getOperationType()} defaults to {@link
org.opengis.referencing.operation.Transformation}.</li>
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeocentricToGeographic.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeocentricToGeographic.java
index e546342c0a..c89250e67d 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeocentricToGeographic.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeocentricToGeographic.java
@@ -61,7 +61,7 @@ public final class GeocentricToGeographic extends
AbstractProvider {
*/
public GeocentricToGeographic() {
super(Conversion.class, PARAMETERS,
- CartesianCS.class, false,
+ CartesianCS.class, false, // Type expected in WKT, but not
the only type accepted by this operation.
EllipsoidalCS.class, true,
(byte) 3);
}
@@ -75,7 +75,7 @@ public final class GeocentricToGeographic extends
AbstractProvider {
*/
@Override
public MathTransform createMathTransform(final Context context) throws
FactoryException {
- MathTransform tr = GeographicToGeocentric.create(context,
context.getTargetDimensions());
+ MathTransform tr = GeographicToGeocentric.create(context,
context.getTargetDimensions(), context.getSourceCSType());
try {
tr = tr.inverse();
} catch (NoninvertibleTransformException e) {
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeographicToGeocentric.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeographicToGeocentric.java
index cdaaf291bb..0f1e21e7e4 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeographicToGeocentric.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/GeographicToGeocentric.java
@@ -22,11 +22,14 @@ import javax.measure.quantity.Length;
import org.opengis.util.FactoryException;
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import
org.apache.sis.referencing.operation.transform.EllipsoidToCentricTransform;
+import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
+import org.apache.sis.referencing.internal.Resources;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.parameter.Parameters;
import org.apache.sis.util.privy.Constants;
@@ -71,7 +74,7 @@ public final class GeographicToGeocentric extends
AbstractProvider {
public GeographicToGeocentric() {
super(Conversion.class, PARAMETERS,
EllipsoidalCS.class, true,
- CartesianCS.class, false,
+ CartesianCS.class, false, // Type expected in WKT, but not
the only type accepted by this operation.
(byte) 2);
}
@@ -108,18 +111,37 @@ public final class GeographicToGeocentric extends
AbstractProvider {
*/
@Override
public MathTransform createMathTransform(final Context context) throws
FactoryException {
- return create(context, context.getSourceDimensions());
+ return create(context, context.getSourceDimensions(),
context.getTargetCSType());
}
/**
* Implementation of {@link #createMathTransform(Context)} shared with
{@link GeocentricToGeographic}.
+ * This method creates the "geographic to geocentric" operation. Callers
is responsible to invert the
+ * transform if the "geocentric to geographic" operation is desired.
+ *
+ * @param context the parameter values together with its context.
+ * @param dimension the number of dimension of the geographic
<abbr>CRS</abbr>.
+ * @param geocentric the coordinate system type of the geocentric
<abbr>CRS</abbr>.
+ * @return the conversion from geographic to geocentric coordinates.
+ * @throws FactoryException if an error occurred while creating a
transform.
*/
- static MathTransform create(final Context context, final OptionalInt
dimension) throws FactoryException {
+ static MathTransform create(final Context context, final OptionalInt
dimension,
+ final Class<? extends CoordinateSystem>
geocentric)
+ throws FactoryException
+ {
final Parameters values =
Parameters.castOrWrap(context.getCompletedParameters());
final ParameterValue<?> semiMajor =
values.parameter(Constants.SEMI_MAJOR);
final Unit<Length> unit = semiMajor.getUnit().asType(Length.class);
+ final EllipsoidToCentricTransform.TargetType type;
+ if (geocentric == CoordinateSystem.class) {
+ type = EllipsoidToCentricTransform.TargetType.CARTESIAN; //
Default value.
+ } else try {
+ type = EllipsoidToCentricTransform.TargetType.of(geocentric);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidGeodeticParameterException(
+
Resources.format(Resources.Keys.IncompatibleCoordinateSystemTypes), e);
+ }
return
EllipsoidToCentricTransform.createGeodeticConversion(context.getFactory(),
semiMajor.doubleValue(),
- values.parameter(Constants.SEMI_MINOR).doubleValue(unit),
unit, dimension.orElse(3) >= 3,
- EllipsoidToCentricTransform.TargetType.CARTESIAN);
+ values.parameter(Constants.SEMI_MINOR).doubleValue(unit),
unit, dimension.orElse(3) >= 3, type);
}
}
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransformBuilder.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransformBuilder.java
index 3229427266..1476165cc0 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransformBuilder.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransformBuilder.java
@@ -17,7 +17,6 @@
package org.apache.sis.referencing.operation.transform;
import java.util.List;
-import java.util.ArrayList;
import javax.measure.IncommensurableException;
import org.opengis.util.FactoryException;
import org.opengis.parameter.ParameterValueGroup;
@@ -33,7 +32,6 @@ import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.OperationNotFoundException;
import org.apache.sis.referencing.cs.AxesConvention;
import org.apache.sis.referencing.cs.CoordinateSystems;
-import org.apache.sis.referencing.cs.DefaultCompoundCS;
import org.apache.sis.referencing.internal.Resources;
import org.apache.sis.referencing.operation.provider.GeocentricToGeographic;
import org.apache.sis.referencing.operation.provider.GeographicToGeocentric;
@@ -106,19 +104,6 @@ final class CoordinateSystemTransformBuilder extends
MathTransformBuilder {
throw new
IllegalStateException(Errors.format(Errors.Keys.MissingValueForProperty_1,
"method"));
}
- /**
- * Adds the components of the given coordinate system in the specified
list.
- * This method may invoke itself recursively if there is nested compound
CS.
- * The returned list is always a copy and can be safely modified.
- */
- private static void getComponents(final CoordinateSystem cs, final
List<CoordinateSystem> addTo) {
- if (cs instanceof DefaultCompoundCS) {
- addTo.addAll(((DefaultCompoundCS) cs).getComponents());
- } else {
- addTo.add(cs);
- }
- }
-
/**
* Creates the change of coordinate system.
*
@@ -134,31 +119,19 @@ final class CoordinateSystemTransformBuilder extends
MathTransformBuilder {
Errors.Keys.MissingValueForProperty_1,
(source == null) ? "source" : "target"));
}
- if (ellipsoid != null) {
+ final List<CoordinateSystem> sources =
CoordinateSystems.getSingleComponents(source);
+ final List<CoordinateSystem> targets =
CoordinateSystems.getSingleComponents(target);
+ final int count = sources.size();
+ if (ellipsoid != null && (count | targets.size()) == 1) {
final boolean isEllipsoidalSource = (source instanceof
EllipsoidalCS);
if (isEllipsoidalSource != (target instanceof EllipsoidalCS)) {
- /*
- * For now we support only conversion between EllipsoidalCS
and CartesianCS.
- * But future Apache SIS versions could add support for
conversions between
- * EllipsoidalCS and SphericalCS or other coordinate systems.
- */
- if ((isEllipsoidalSource ? target : source) instanceof
CartesianCS) {
- final var context = factory.builder(isEllipsoidalSource ?
GeographicToGeocentric.NAME
- :
GeocentricToGeographic.NAME);
- if (isEllipsoidalSource) {
- context.setSourceAxes(source, ellipsoid);
- context.setTargetAxes(target, null);
- } else {
- context.setSourceAxes(source, null);
- context.setTargetAxes(target, ellipsoid);
- }
- return context.create();
- }
+ final var context = factory.builder(isEllipsoidalSource ?
GeographicToGeocentric.NAME
+ :
GeocentricToGeographic.NAME);
+ context.setSourceAxes(source, isEllipsoidalSource? ellipsoid :
null);
+ context.setTargetAxes(target, isEllipsoidalSource ? null :
ellipsoid);
+ return context.create();
}
}
- final var sources = new ArrayList<CoordinateSystem>(3);
getComponents(source, sources);
- final var targets = new ArrayList<CoordinateSystem>(3);
getComponents(target, targets);
- final int count = sources.size();
/*
* Current implementation expects the same number of components, in
the same order
* and with the same number of dimensions in each component. A future
version will
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
index 1fe9a70238..e2960d274f 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
@@ -36,6 +36,9 @@ import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.TransformException;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.SphericalCS;
import org.apache.sis.util.Debug;
import org.apache.sis.util.ComparisonMode;
import org.apache.sis.util.ArgumentChecks;
@@ -61,6 +64,7 @@ import static
org.apache.sis.referencing.operation.provider.MapProjection.SEMI_M
import static
org.apache.sis.referencing.operation.provider.MapProjection.SEMI_MINOR;
import static
org.apache.sis.referencing.operation.provider.MapProjection.ECCENTRICITY;
import static
org.apache.sis.referencing.operation.provider.GeocentricAffineBetweenGeographic.DIMENSION;
+import org.apache.sis.util.resources.Errors;
/**
@@ -154,7 +158,23 @@ public class EllipsoidToCentricTransform extends
AbstractMathTransform implement
*
* @since 1.5
*/
- SPHERICAL
+ SPHERICAL;
+
+ /**
+ * Returns the enumeration value for the given type of coordinate
system.
+ * The {@code cs} argument should be {@code CartesianCS.class}, {@code
SphericalCS.class}
+ * or a subclass of those types.
+ *
+ * @param cs the coordinate system type.
+ * @return enumeration value associated to the given type.
+ * @throws IllegalArgumentException if the given {@code cs} is not one
of the above-documented types.
+ * @since 1.5
+ */
+ public static TargetType of(final Class<? extends CoordinateSystem>
cs) {
+ if (CartesianCS.class.isAssignableFrom(cs)) return CARTESIAN;
+ if (SphericalCS.class.isAssignableFrom(cs)) return SPHERICAL;
+ throw new
IllegalArgumentException(Errors.format(Errors.Keys.UnsupportedType_1, cs));
+ }
}
/**
@@ -310,17 +330,17 @@ public class EllipsoidToCentricTransform extends
AbstractMathTransform implement
* @param unit the unit of measurement for the semi-axes and the
ellipsoidal height.
* @param withHeight {@code true} if source geographic coordinates
include an ellipsoidal height
* (i.e. are 3-D), or {@code false} if they are only
2-D.
- * @param target whether the target coordinate system shall be
Cartesian or spherical.
+ * @param csType whether the target coordinate system shall be
Cartesian or spherical.
*
* @see #createGeodeticConversion(MathTransformFactory, double, double,
Unit, boolean, TargetType)
*/
public EllipsoidToCentricTransform(final double semiMajor, final double
semiMinor,
- final Unit<Length> unit, final boolean withHeight, final
TargetType target)
+ final Unit<Length> unit, final boolean withHeight, final
TargetType csType)
{
ArgumentChecks.ensureStrictlyPositive("semiMajor", semiMajor);
ArgumentChecks.ensureStrictlyPositive("semiMinor", semiMinor);
- ArgumentChecks.ensureNonNull("target", target);
- toSphericalCS = (target == TargetType.SPHERICAL);
+ ArgumentChecks.ensureNonNull("csType", csType);
+ toSphericalCS = (csType == TargetType.SPHERICAL);
axisRatio = semiMinor / semiMajor;
eccentricitySquared = 1 - (axisRatio * axisRatio);
useIterations = (eccentricitySquared >= ECCENTRICITY_THRESHOLD *
ECCENTRICITY_THRESHOLD);
@@ -494,7 +514,7 @@ public class EllipsoidToCentricTransform extends
AbstractMathTransform implement
public ParameterValueGroup getParameterValues() {
final Parameters pg =
Parameters.castOrWrap(getParameterDescriptors().createValue());
pg.getOrCreate(ECCENTRICITY).setValue(sqrt(eccentricitySquared));
- pg.parameter("target").setValue(getTargetType());
+ pg.parameter("csType").setValue(getTargetType());
pg.getOrCreate(DIMENSION).setValue(getSourceDimensions());
return pg;
}
@@ -512,7 +532,7 @@ public class EllipsoidToCentricTransform extends
AbstractMathTransform implement
if (DESCRIPTOR == null) {
final ParameterBuilder builder = new
ParameterBuilder().setCodeSpace(Citations.SIS, Constants.SIS);
final ParameterDescriptor<TargetType> target =
builder.setRequired(true)
- .addName("target").create(TargetType.class,
TargetType.CARTESIAN);
+ .addName("csType").create(TargetType.class,
TargetType.CARTESIAN);
DESCRIPTOR = builder.addName("Ellipsoid (radians domain) to
centric")
.createGroup(1, 1, ECCENTRICITY, target, DIMENSION);
}
@@ -783,12 +803,12 @@ public class EllipsoidToCentricTransform extends
AbstractMathTransform implement
while (--numPts >= 0) {
final double p, λ, Z;
if (toSphericalCS) {
- final double Ω, r;
+ final double Ω, R;
λ = srcPts[srcOff++]; // Spherical longitude
Ω = srcPts[srcOff++]; // Spherical latitude
- r = srcPts[srcOff++]; // Spherical radius
- p = r * cos(Ω);
- Z = r * sin(Ω);
+ R = srcPts[srcOff++]; // Spherical radius
+ p = R * cos(Ω);
+ Z = R * sin(Ω);
} else {
final double X, Y;
X = srcPts[srcOff++]; // Toward prime meridian
diff --git
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
index d6ce33d92e..be6446c47e 100644
---
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
+++
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
@@ -653,6 +653,56 @@ public final class CoordinateOperationFinderTest extends
MathTransformTestCase {
validate();
}
+ /**
+ * Tests a conversion from geocentric spherical coordinates to an
arbitrary map projections.
+ * This is used in astronomy.
+ *
+ * @throws ParseException if a CRS used in this test cannot be parsed.
+ * @throws FactoryException if the operation cannot be created.
+ * @throws TransformException if an error occurred while converting the
test points.
+ */
+ @Test
+ public void testSphericalToProjection() throws ParseException,
FactoryException, TransformException {
+ final CoordinateReferenceSystem sourceCRS = parse(
+ "GEODCRS[\"Mars (2015) / Ocentric\",\n" +
+ " DATUM[\"Mars (2015)\",\n" +
+ " ELLIPSOID[\"Mars (2015)\", 3396190, 169.8944472236118,\n"
+
+ " LENGTHUNIT[\"metre\", 1, ID[\"EPSG\", 9001]]],\n" +
+ " ANCHOR[\"Viking 1 lander : 47.95137 W\"]],\n" +
+ " PRIMEM[\"Reference Meridian\", 0,\n" +
+ " ANGLEUNIT[\"degree\", 0.0174532925199433, ID[\"EPSG\",
9122]]],\n" +
+ " CS[spherical, 2],\n" +
+ " AXIS[\"planetocentric latitude (U)\", north,\n" +
+ " ANGLEUNIT[\"degree\", 0.0174532925199433]],\n" +
+ " AXIS[\"planetocentric longitude (V)\", east,\n" +
+ " ANGLEUNIT[\"degree\", 0.0174532925199433]],\n" +
+ " ID[\"IAU\", 49902, 2015],\n" +
+ " REMARK[\"Source of IAU Coordinate systems:
doi:10.1007/s10569-017-9805-5\"]]");
+
+ final CoordinateReferenceSystem targetCRS = parse(
+ "PROJCRS[\"Mars (2015) / Ocentric / Equirectangular, clon =
0\",\n" +
+ " BASEGEODCRS[\"Mars (2015) / Ocentric\",\n" +
+ " DATUM[\"Mars (2015)\",\n" +
+ " ELLIPSOID[\"Mars (2015)\", 3396190,
169.8944472236118,\n" +
+ " LENGTHUNIT[\"metre\", 1, ID[\"EPSG\", 9001]]],\n" +
+ " ANCHOR[\"Viking 1 lander : 47.95137 W\"]],\n" +
+ " PRIMEM[\"Reference Meridian\", 0,\n" +
+ " ANGLEUNIT[\"degree\", 0.0174532925199433,
ID[\"EPSG\", 9122]]],\n" +
+ " ID[\"IAU\", 49902, 2015]],\n" +
+ " CONVERSION[\"Equirectangular, clon = 0\",\n" +
+ " METHOD[\"Equidistant Cylindrical\", ID[\"EPSG\",
1028]]],\n" +
+ " CS[Cartesian, 2],\n" +
+ " AXIS[\"Easting (E)\", east,\n" +
+ " LENGTHUNIT[\"metre\", 1]],\n" +
+ " AXIS[\"Northing (N)\", north,\n" +
+ " LENGTHUNIT[\"metre\", 1]],\n" +
+ " ID[\"IAU\", 49912, 2015]]");
+
+ final CoordinateOperation operation =
finder().createOperation(sourceCRS, targetCRS);
+ assertSame(sourceCRS, operation.getSourceCRS());
+ assertSame(targetCRS, operation.getTargetCRS());
+ }
+
diff --git
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/GeocentricTranslationTest.java
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/GeocentricTranslationTest.java
index 986da2a0d2..5ac44cedde 100644
---
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/GeocentricTranslationTest.java
+++
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/GeocentricTranslationTest.java
@@ -378,7 +378,7 @@ public final class GeocentricTranslationTest extends
MathTransformTestCase {
" Parameter[“elt_2_2”, 1.567855942887398E-7]],\n" +
" Param_MT[“Ellipsoid (radians domain) to centric”,\n" +
" Parameter[“eccentricity”, 0.08181919084262157],\n" +
- " Parameter[“target”, “CARTESIAN”],\n" +
+ " Parameter[“csType”, “CARTESIAN”],\n" +
" Parameter[“dim”, 3]],\n" +
" Param_MT[“Affine”,\n" +
" Parameter[“num_row”, 4],\n" +
@@ -391,7 +391,7 @@ public final class GeocentricTranslationTest extends
MathTransformTestCase {
" Parameter[“elt_2_3”, 1.8335353697517302E-5]],\n" +
" Param_MT[“Centric to ellipsoid (radians domain)”,\n" +
" Parameter[“eccentricity”, 0.08199188997902956],\n" +
- " Parameter[“target”, “CARTESIAN”],\n" +
+ " Parameter[“csType”, “CARTESIAN”],\n" +
" Parameter[“dim”, 3]],\n" +
" Param_MT[“Affine”,\n" +
" Parameter[“num_row”, 4],\n" +
diff --git
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java
index 9d710a5993..87f8dc8b13 100644
---
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java
+++
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java
@@ -405,7 +405,7 @@ public class EllipsoidToCentricTransformTest extends
MathTransformTestCase {
" Parameter[“elt_2_2”, 1.567855942887398E-7]],\n" +
" Param_MT[“Ellipsoid (radians domain) to centric”,\n" +
" Parameter[“eccentricity”, 0.08181919084262157],\n" +
- " Parameter[“target”, “CARTESIAN”],\n" +
+ " Parameter[“csType”, “CARTESIAN”],\n" +
" Parameter[“dim”, 3]],\n" +
" Param_MT[“Affine”,\n" +
" Parameter[“num_row”, 4],\n" +
@@ -425,7 +425,7 @@ public class EllipsoidToCentricTransformTest extends
MathTransformTestCase {
" Parameter[“elt_2_2”, 1.567855942887398E-7]],\n" +
" Param_MT[“Centric to ellipsoid (radians domain)”,\n" +
" Parameter[“eccentricity”, 0.08181919084262157],\n" +
- " Parameter[“target”, “CARTESIAN”],\n" +
+ " Parameter[“csType”, “CARTESIAN”],\n" +
" Parameter[“dim”, 3]],\n" +
" Param_MT[“Affine”,\n" +
" Parameter[“num_row”, 4],\n" +
diff --git
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToSphericalTransformTest.java
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToSphericalTransformTest.java
index 8c7a71f120..aad896d86d 100644
---
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToSphericalTransformTest.java
+++
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToSphericalTransformTest.java
@@ -126,7 +126,7 @@ public final class EllipsoidToSphericalTransformTest
extends EllipsoidToCentricT
" Parameter[“elt_2_2”, 1.567855942887398E-7]],\n" +
" Param_MT[“Ellipsoid (radians domain) to centric”,\n" +
" Parameter[“eccentricity”, 0.08181919084262157],\n" +
- " Parameter[“target”, “SPHERICAL”],\n" +
+ " Parameter[“csType”, “SPHERICAL”],\n" +
" Parameter[“dim”, 3]],\n" +
" Param_MT[“Affine”,\n" +
" Parameter[“num_row”, 4],\n" +