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 586f44a6d9 Add "Geographic/topocentric conversions" (EPSG:9837).
586f44a6d9 is described below
commit 586f44a6d9960efb722eb4cd253c3299be4a7dea
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Aug 8 22:00:09 2022 +0200
Add "Geographic/topocentric conversions" (EPSG:9837).
https://issues.apache.org/jira/browse/SIS-259
---
.../provider/GeocentricToTopocentric.java | 97 ++++++++++----
.../provider/GeographicToTopocentric.java | 142 +++++++++++++++++++++
...g.opengis.referencing.operation.OperationMethod | 1 +
.../referencing/provider/ProvidersTest.java | 1 +
.../provider/TopocentricConversionMock.java | 63 ---------
.../sis/test/integration/ConsistencyTest.java | 1 +
...g.opengis.referencing.operation.OperationMethod | 1 -
7 files changed, 214 insertions(+), 92 deletions(-)
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToTopocentric.java
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToTopocentric.java
index 87e6da2f1f..e6ede8a086 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToTopocentric.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToTopocentric.java
@@ -36,14 +36,15 @@ import org.apache.sis.internal.util.Constants;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
+import static java.lang.Math.toRadians;
/**
- * The provider for the <cite>"Geocentric/topocentric conversions"</cite>
(EPSG:9836)).
+ * The provider for the <cite>"Geocentric/topocentric conversions"</cite>
(EPSG:9836).
* This operation is implemented using existing {@link MathTransform}
implementations;
* there is no need for a class specifically for this transform.
*
- * @author Martin Desruisseaux (IRD, Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
* @version 1.3
* @since 1.3
* @module
@@ -121,7 +122,7 @@ public final class GeocentricToTopocentric extends
AbstractProvider {
}
/**
- * Notifies {@code DefaultMathTransformFactory} that
Geographic/topocentric conversions
+ * Notifies {@code DefaultMathTransformFactory} that
Geocentric/topocentric conversions
* require values for the {@code "semi_major"} and {@code "semi_minor"}
parameters.
*
* @return 1, meaning that the operation requires a source ellipsoid.
@@ -144,44 +145,84 @@ public final class GeocentricToTopocentric extends
AbstractProvider {
public MathTransform createMathTransform(final MathTransformFactory
factory, final ParameterValueGroup values)
throws FactoryException
{
- return create(factory, Parameters.castOrWrap(values));
+ try {
+ return create(factory, Parameters.castOrWrap(values), false);
+ } catch (TransformException e) {
+ throw new FactoryException(e);
+ }
}
/**
* Implementation of {@link #createMathTransform(MathTransformFactory,
ParameterValueGroup)}
* shared with {@link GeographicToTopocentric}.
+ *
+ * @param factory the factory to use for creating the transform.
+ * @param values the parameter values that define the transform to
create.
+ * @param geographic {@code true} if the source coordinates are
geographic, or
+ * {@code false} if the source coordinates are
geocentric.
*/
- static MathTransform create(final MathTransformFactory factory, final
Parameters values)
- throws FactoryException
+ static MathTransform create(final MathTransformFactory factory, final
Parameters values, final boolean geographic)
+ throws FactoryException, TransformException
{
final ParameterValue<?> ap = values.parameter(Constants.SEMI_MAJOR);
final Unit<Length> unit = ap.getUnit().asType(Length.class);
final double a = ap.doubleValue();
final double b =
values.parameter(Constants.SEMI_MINOR).doubleValue(unit);
- final double x = values.doubleValue(ORIGIN_X, unit);
- final double y = values.doubleValue(ORIGIN_Y, unit);
- final double z = values.doubleValue(ORIGIN_Z, unit);
- final double[] coordinates = new double[] {x/a, y/a, z/a};
- final MathTransform t = new EllipsoidToCentricTransform(a, b, unit,
false, EllipsoidToCentricTransform.TargetType.CARTESIAN);
- try {
- t.inverse().transform(coordinates, 0, coordinates, 0, 1);
- final double λ = coordinates[0]; // In radians.
- final double φ = coordinates[1];
- final double sinλ = sin(λ);
- final double cosλ = cos(λ);
- final double sinφ = sin(φ);
- final double cosφ = cos(φ);
+ final double x, y, z, λ, φ;
+ final MathTransform toGeocentric;
+ if (geographic) {
/*
- * Following transform uses the inverse of the matrix R given in
EPSG guidance note
- * because it allows us to put the (x,y,z) translation terms
directly in the matrix.
+ * Full conversion from (longitude, latitude, height) in degrees
+ * to geocentric coordinates in linear units (usually metres).
*/
- return factory.createAffineTransform(new Matrix4(
- -sinλ, -sinφ*cosλ, cosφ*cosλ, x,
- cosλ, -sinφ*sinλ, cosφ*sinλ, y,
- 0, cosφ, sinφ, z,
- 0, 0, 0, 1)).inverse();
- } catch (TransformException e) {
- throw new FactoryException(e);
+ toGeocentric =
EllipsoidToCentricTransform.createGeodeticConversion(factory,
+ a, b, unit, true,
EllipsoidToCentricTransform.TargetType.CARTESIAN);
+
+ final double[] origin = new double[] {
+ values.doubleValue(GeographicToTopocentric.ORIGIN_X),
+ values.doubleValue(GeographicToTopocentric.ORIGIN_Y),
+ values.doubleValue(GeographicToTopocentric.ORIGIN_Z)};
+
+ λ = toRadians(origin[0]);
+ φ = toRadians(origin[1]);
+ toGeocentric.transform(origin, 0, origin, 0, 1);
+ x = origin[0];
+ y = origin[1];
+ z = origin[2];
+ } else {
+ /*
+ * Shorter conversion from (longitude, latitude) in radians to
+ * geocentric coordinates as fractions of semi-major axis length.
+ * This conversion is used only in this block and is not kept.
+ */
+ toGeocentric = new EllipsoidToCentricTransform(
+ a, b, unit, false,
EllipsoidToCentricTransform.TargetType.CARTESIAN);
+
+ final double[] origin = new double[] {
+ (x = values.doubleValue(ORIGIN_X, unit)) / a,
+ (y = values.doubleValue(ORIGIN_Y, unit)) / a,
+ (z = values.doubleValue(ORIGIN_Z, unit)) / a};
+
+ toGeocentric.inverse().transform(origin, 0, origin, 0, 1);
+ λ = origin[0]; // Already in radians.
+ φ = origin[1];
+ }
+ final double sinλ = sin(λ);
+ final double cosλ = cos(λ);
+ final double sinφ = sin(φ);
+ final double cosφ = cos(φ);
+ /*
+ * Following transform uses the inverse of the matrix R given in EPSG
guidance note
+ * because it allows us to put the (x,y,z) translation terms directly
in the matrix.
+ */
+ MathTransform mt = factory.createAffineTransform(new Matrix4(
+ -sinλ, -sinφ*cosλ, cosφ*cosλ, x,
+ cosλ, -sinφ*sinλ, cosφ*sinλ, y,
+ 0, cosφ, sinφ, z,
+ 0, 0, 0, 1)).inverse();
+ if (geographic) {
+ mt = factory.createConcatenatedTransform(toGeocentric, mt);
}
+ return mt;
}
}
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToTopocentric.java
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToTopocentric.java
new file mode 100644
index 0000000000..f247f195c8
--- /dev/null
+++
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToTopocentric.java
@@ -0,0 +1,142 @@
+/*
+ * 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.provider;
+
+import org.opengis.util.FactoryException;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.operation.Conversion;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.measure.Units;
+import org.apache.sis.parameter.Parameters;
+
+
+/**
+ * The provider for the <cite>"Geographic/topocentric conversions"</cite>
(EPSG:9837).
+ * This operation is implemented using existing {@link MathTransform}
implementations;
+ * there is no need for a class specifically for this transform.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.3
+ * @since 1.3
+ * @module
+ */
+public class GeographicToTopocentric extends AbstractProvider {
+ /**
+ * For cross-version compatibility.
+ */
+ private static final long serialVersionUID = -3829993731324133815L;
+
+ /**
+ * The operation parameter descriptor for the <cite>Longitude of
topocentric origin</cite> parameter value.
+ *
+ * <!-- Generated by ParameterNameTableGenerator -->
+ */
+ static final ParameterDescriptor<Double> ORIGIN_X;
+
+ /**
+ * The operation parameter descriptor for the <cite>Latitude of
topocentric origin</cite> parameter value.
+ *
+ * <!-- Generated by ParameterNameTableGenerator -->
+ */
+ static final ParameterDescriptor<Double> ORIGIN_Y;
+
+ /**
+ * The operation parameter descriptor for the <cite>Ellipsoidal height of
topocentric origin</cite> parameter value.
+ *
+ * <!-- Generated by ParameterNameTableGenerator -->
+ */
+ static final ParameterDescriptor<Double> ORIGIN_Z;
+
+ /**
+ * The group of all parameters expected by this coordinate operation.
+ */
+ private static final ParameterDescriptorGroup PARAMETERS;
+ static {
+ final ParameterBuilder builder = builder();
+ ORIGIN_X = createLongitude(builder
+ .addIdentifier("8835")
+ .addName("Longitude of topocentric origin"));
+
+ ORIGIN_Y = createLatitude(builder
+ .addIdentifier("8834")
+ .addName("Latitude of topocentric origin"), true);
+
+ ORIGIN_Z = builder
+ .addIdentifier("8836")
+ .addName("Ellipsoidal height of topocentric origin")
+ .create(0, Units.METRE);
+
+ PARAMETERS = builder
+ .addIdentifier("9837")
+ .addName("Geographic/topocentric conversions")
+ .createGroupForMapProjection(ORIGIN_Y, ORIGIN_X, ORIGIN_Z);
+ // Not really a map projection, but we leverage the same axis
parameters.
+ }
+
+ /**
+ * Constructs a provider for the 3-dimensional case.
+ */
+ public GeographicToTopocentric() {
+ super(3, 3, PARAMETERS);
+ }
+
+ /**
+ * Returns the operation type.
+ *
+ * @return {@code Conversion.class}.
+ */
+ @Override
+ public Class<Conversion> getOperationType() {
+ return Conversion.class;
+ }
+
+ /**
+ * Notifies {@code DefaultMathTransformFactory} that
Geographic/topocentric conversions
+ * require values for the {@code "semi_major"} and {@code "semi_minor"}
parameters.
+ *
+ * @return 1, meaning that the operation requires a source ellipsoid.
+ */
+ @Override
+ public int getEllipsoidsMask() {
+ return 1;
+ }
+
+ /**
+ * Creates a transform from the specified group of parameter values.
+ * The unit of measurement of input coordinates will be the units of the
ellipsoid axes.
+ *
+ * @param factory the factory to use for creating the transform.
+ * @param values the parameter values that define the transform to
create.
+ * @return the conversion from geographic to topocentric coordinates.
+ * @throws FactoryException if an error occurred while creating a
transform.
+ */
+ @Override
+ public MathTransform createMathTransform(final MathTransformFactory
factory, final ParameterValueGroup values)
+ throws FactoryException
+ {
+ try {
+ return GeocentricToTopocentric.create(factory,
Parameters.castOrWrap(values), true);
+ } catch (TransformException e) {
+ throw new FactoryException(e);
+ }
+ }
+}
diff --git
a/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
b/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
index 7c942a8f7c..4c04e55057 100644
---
a/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
+++
b/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
@@ -77,3 +77,4 @@ org.apache.sis.internal.referencing.provider.Interpolation1D
org.apache.sis.internal.referencing.provider.SatelliteTracking
org.apache.sis.internal.referencing.provider.Wraparound
org.apache.sis.internal.referencing.provider.GeocentricToTopocentric
+org.apache.sis.internal.referencing.provider.GeographicToTopocentric
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
index b9d6055e36..12e85a3d1f 100644
---
a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
+++
b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
@@ -72,6 +72,7 @@ public final strictfp class ProvidersTest extends TestCase {
GeographicToGeocentric.class,
GeocentricToGeographic.class,
GeocentricToTopocentric.class,
+ GeographicToTopocentric.class,
Geographic3Dto2D.class,
Geographic2Dto3D.class,
Molodensky.class,
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TopocentricConversionMock.java
b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TopocentricConversionMock.java
deleted file mode 100644
index c46a4481dd..0000000000
---
a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TopocentricConversionMock.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.provider;
-
-import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.parameter.ParameterDescriptorGroup;
-import org.apache.sis.parameter.ParameterBuilder;
-import org.apache.sis.measure.Units;
-
-
-/**
- * The provider for <cite>"Geographic/topocentric conversions"</cite>
conversion (EPSG:9837).
- *
- * This conversion is not yet implemented in Apache SIS, but we need to at
least accept the parameters
- * for a Well Known Text (WKT) parsing test in the {@link
org.apache.sis.io.wkt.WKTParserTest} class.
- *
- * <p>This class may be promoted to a real operation if we implement the
formulas in a future Apache SIS version.</p>
- *
- * @author Martin Desruisseaux (Geomatys)
- * @version 0.8
- * @since 0.6
- * @module
- */
-@SuppressWarnings("serial")
-public final strictfp class TopocentricConversionMock extends ProviderMock {
- /**
- * The group of all parameters expected by this coordinate operation.
- */
- private static final ParameterDescriptorGroup PARAMETERS;
- static {
- final ParameterBuilder builder = builder();
- final ParameterDescriptor<?>[] parameters = {
- createLatitude (builder.addIdentifier("8834").addName("Latitude of
topocentric origin"), true),
- createLongitude(builder.addIdentifier("8835").addName("Longitude
of topocentric origin")),
- builder.addIdentifier("8836").addName("Ellipsoidal height of
topocentric origin").create(0, Units.METRE)
- };
- PARAMETERS = builder
- .addIdentifier("9837")
- .addName("Geographic/topocentric conversions")
- .createGroup(parameters);
- }
-
- /**
- * Creates a new <cite>"Geographic/topocentric conversions"</cite>
operation method.
- */
- public TopocentricConversionMock() {
- super(3, 3, PARAMETERS);
- }
-}
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
index fab5bee949..10470181af 100644
---
a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
+++
b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
@@ -75,6 +75,7 @@ public final strictfp class ConsistencyTest extends TestCase {
private static final Set<String> EXCLUDES = new HashSet<>(Arrays.asList(
"CRS:1", // Computer display: WKT parser alters the (i,j)
axis names.
"EPSG:5819", // EPSG topocentric example A: error while parsing
WKT.
+ "EPSG:5820", // EPSG topocentric example B: error while parsing
WKT.
"AUTO2:42001", // This projection requires parameters, but we
provide none.
"AUTO2:42002", // This projection requires parameters, but we
provide none.
"AUTO2:42003", // This projection requires parameters, but we
provide none.
diff --git
a/core/sis-referencing/src/test/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
b/core/sis-referencing/src/test/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
index b6d93bb6ff..2fcd0f566f 100644
---
a/core/sis-referencing/src/test/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
+++
b/core/sis-referencing/src/test/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
@@ -1,4 +1,3 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements;
# and to You under the Apache License, Version 2.0.
-org.apache.sis.internal.referencing.provider.TopocentricConversionMock
org.apache.sis.internal.referencing.provider.SeismicBinGridMock