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 6ec7df4c02 Concatenated operation handle automatically the change of 
coordinate system in the last step. For example, if the target CRS of the last 
`SingleOperation` uses a CartesianCS but the target CRS of the 
`ConcatenatedOperation` uses a SphericalCS, a conversion will be added 
automatically.
6ec7df4c02 is described below

commit 6ec7df4c0263d91bdf92d60c589b607ed490c5f3
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Mon Jan 15 19:42:19 2024 +0100

    Concatenated operation handle automatically the change of coordinate system 
in the last step.
    For example, if the target CRS of the last `SingleOperation` uses a 
CartesianCS but the target CRS
    of the `ConcatenatedOperation` uses a SphericalCS, a conversion will be 
added automatically.
---
 .../main/org/apache/sis/referencing/CommonCRS.java | 13 ++--
 .../operation/DefaultConcatenatedOperation.java    | 14 +++-
 .../transform/CoordinateSystemTransform.java       | 88 ++++++++++++++++++++--
 .../transform/DefaultMathTransformFactory.java     |  6 +-
 4 files changed, 105 insertions(+), 16 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
index 6a436a84fb..136ff858a3 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
@@ -22,7 +22,6 @@ import java.util.HashMap;
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import java.time.Instant;
-import static java.util.Collections.singletonMap;
 import javax.measure.Unit;
 import javax.measure.quantity.Time;
 import org.opengis.metadata.Identifier;
@@ -1919,7 +1918,7 @@ public enum CommonCRS {
          *   <tr><th>Unit:</th> <td>{@link Units#UNITY}</td></tr>
          * </table></blockquote>
          */
-        GRID(new 
DefaultEngineeringDatum(singletonMap(EngineeringDatum.NAME_KEY, "Cell 
indices"))),
+        GRID(new DefaultEngineeringDatum(Map.of(EngineeringDatum.NAME_KEY, 
"Cell indices"))),
 
         /**
          * A single-dimensional coordinate system for time in seconds since an 
unknown epoch.
@@ -1936,7 +1935,7 @@ public enum CommonCRS {
          *
          * @see Temporal
          */
-        TIME(new 
DefaultEngineeringDatum(singletonMap(EngineeringDatum.NAME_KEY, "Time")));
+        TIME(new DefaultEngineeringDatum(Map.of(EngineeringDatum.NAME_KEY, 
"Time")));
 
         /**
          * The datum.
@@ -1964,7 +1963,7 @@ public enum CommonCRS {
             if (crs == null) {
                 final String x, y;
                 final AxisDirection dx, dy;
-                final Map<String,Object> pcs = 
singletonMap(CartesianCS.NAME_KEY, datum.getName());
+                final Map<String,Object> pcs = Map.of(CartesianCS.NAME_KEY, 
datum.getName());
                 final Map<String,Object> properties = new HashMap<>(pcs);
                 CoordinateSystem cs = null;
                 switch (this) {
@@ -1988,15 +1987,15 @@ public enum CommonCRS {
                         x  = y  = "t";
                         dx = dy = AxisDirection.FUTURE;
                         cs = new DefaultTimeCS(pcs, new 
DefaultCoordinateSystemAxis(
-                                singletonMap(TimeCS.NAME_KEY, x), x, dx, 
Units.SECOND));
+                                Map.of(TimeCS.NAME_KEY, x), x, dx, 
Units.SECOND));
                         break;
                     }
                     default: throw new AssertionError(this);
                 }
                 if (cs == null) {
                     cs = new DefaultCartesianCS(pcs,
-                            new 
DefaultCoordinateSystemAxis(singletonMap(CartesianCS.NAME_KEY, x), x, dx, 
Units.PIXEL),
-                            new 
DefaultCoordinateSystemAxis(singletonMap(CartesianCS.NAME_KEY, y), y, dy, 
Units.PIXEL));
+                            new 
DefaultCoordinateSystemAxis(Map.of(CartesianCS.NAME_KEY, x), x, dx, 
Units.PIXEL),
+                            new 
DefaultCoordinateSystemAxis(Map.of(CartesianCS.NAME_KEY, y), y, dy, 
Units.PIXEL));
                 }
                 crs = new DefaultEngineeringCRS(properties, datum, cs);
             }
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
index 9fb03672f2..519fb54e7f 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
@@ -38,6 +38,7 @@ import 
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactor
 import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
 import org.apache.sis.referencing.util.PositionalAccuracyConstant;
 import org.apache.sis.referencing.util.CoordinateOperations;
+import org.apache.sis.referencing.util.ReferencingUtilities;
 import org.apache.sis.referencing.internal.Resources;
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.ComparisonMode;
@@ -167,8 +168,16 @@ final class DefaultConcatenatedOperation extends 
AbstractCoordinateOperation imp
         final List<CoordinateOperation> flattened = new 
ArrayList<>(operations.length);
         final CoordinateReferenceSystem crs = initialize(properties, 
operations, flattened, mtFactory,
                 sourceCRS, (sourceCRS == null), (coordinateOperationAccuracy 
== null));
+
         if (targetCRS == null) {
             targetCRS = crs;
+        } else if (mtFactory instanceof DefaultMathTransformFactory) {
+            final var dmf = (DefaultMathTransformFactory) mtFactory;
+            final MathTransform t = dmf.createCoordinateSystemChange(
+                    crs.getCoordinateSystem(),
+                    targetCRS.getCoordinateSystem(),
+                    ReferencingUtilities.getEllipsoid(crs));
+            transform = dmf.createConcatenatedTransform(transform, t);
         }
         /*
          * At this point we should have flattened.size() >= 2, except if some 
operations
@@ -305,7 +314,10 @@ final class DefaultConcatenatedOperation extends 
AbstractCoordinateOperation imp
                 }
             }
         }
-        verifyStepChaining(properties, operations.length, target, targetCRS, 
null);
+        if (!(mtFactory instanceof DefaultMathTransformFactory)) {
+            verifyStepChaining(properties, operations.length, target, 
targetCRS, null);
+            // Else verification will be done by the caller.
+        }
         return previous;
     }
 
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java
index d133e7756e..95d51daa4d 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java
@@ -17,6 +17,8 @@
 package org.apache.sis.referencing.operation.transform;
 
 import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
 import javax.measure.IncommensurableException;
 import org.opengis.util.FactoryException;
 import org.opengis.parameter.ParameterValueGroup;
@@ -38,6 +40,7 @@ import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
 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.operation.DefaultOperationMethod;
 
 
@@ -182,12 +185,87 @@ abstract class CoordinateSystemTransform extends 
AbstractMathTransform {
     }
 
     /**
-     * Implementation of {@link 
DefaultMathTransformFactory#createCoordinateSystemChange(CoordinateSystem,
-     * CoordinateSystem, Ellipsoid)}, defined here for reducing the {@code 
DefaultMathTransformFactory}
-     * weight in the common case where the conversions handled by this class 
are not needed.
+     * 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.
      */
-    static MathTransform create(final MathTransformFactory factory, final 
CoordinateSystem source,
-            final CoordinateSystem target, final ThreadLocal<OperationMethod> 
lastMethod) throws FactoryException
+    private static void getComponents(final CoordinateSystem cs, final 
List<CoordinateSystem> addTo) {
+        if (cs instanceof DefaultCompoundCS) {
+            addTo.addAll(((DefaultCompoundCS) cs).getComponents());
+        } else {
+            addTo.add(cs);
+        }
+    }
+
+    /**
+     * Implementation of {@code createCoordinateSystemChange(…)}, defined here 
for reducing the
+     * {@link DefaultMathTransformFactory} weight in the common case where the 
conversions handled
+     * by this class are not needed.
+     *
+     * @todo Handle the case where coordinate system components are not in the 
same order.
+     *
+     * @param  factory     the factory to use for creating math transforms.
+     * @param  source      the source coordinate system.
+     * @param  target      the target coordinate system.
+     * @param  lastMethod  where to set the coordinate operation method used.
+     * @return the transform from the given source CS to the given target CS.
+     * @throws FactoryException if an error occurred while creating a 
transform.
+     */
+    static MathTransform create(final MathTransformFactory factory,
+                                final CoordinateSystem source,
+                                final CoordinateSystem target,
+                                final ThreadLocal<OperationMethod> lastMethod)
+            throws FactoryException
+    {
+        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
+         * need to improve on that.
+         */
+        MathTransform result = null;
+        if (count == targets.size()) {
+            final int dimension = source.getDimension();
+            int firstAffectedCoordinate = 0;
+            for (int i=0; i<count; i++) {
+                final CoordinateSystem s = sources.get(i);
+                final CoordinateSystem t = targets.get(i);
+                final int sd = s.getDimension();
+                if (t.getDimension() != sd) {
+                    result = null;
+                    break;
+                }
+                final MathTransform subTransform = 
factory.createPassThroughTransform(
+                        firstAffectedCoordinate,
+                        single(factory, s, t, lastMethod),
+                        dimension - (firstAffectedCoordinate + sd));
+                if (result == null) {
+                    result = subTransform;
+                } else {
+                    result = factory.createConcatenatedTransform(result, 
subTransform);
+                }
+                firstAffectedCoordinate += sd;
+            }
+        }
+        // If we couldn't process components separately, try with the compound 
CS as a whole.
+        if (result == null) {
+            result = single(factory, source, target, lastMethod);
+        }
+        return result;
+    }
+
+    /**
+     * Implementation of {@code create(…)} for a single component.
+     * This implementation performs can handle changes of coordinate system 
type between
+     * {@link CartesianCS}, {@link SphericalCS}, {@link CylindricalCS} and 
{@link PolarCS}.
+     */
+    private static MathTransform single(final MathTransformFactory factory,
+                                        final CoordinateSystem source,
+                                        final CoordinateSystem target,
+                                        final ThreadLocal<OperationMethod> 
lastMethod)
+            throws FactoryException
     {
         int passthrough = 0;
         CoordinateSystemTransform kernel = null;
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
index 3afd8d1f4b..4ac8bd5642 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
@@ -163,7 +163,7 @@ import org.apache.sis.util.resources.Errors;
  * There is typically only one {@code MathTransformFactory} instance for the 
whole application.
  *
  * @author  Martin Desruisseaux (Geomatys, IRD)
- * @version 1.4
+ * @version 1.5
  *
  * @see MathTransformProvider
  * @see AbstractMathTransform
@@ -729,7 +729,7 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
          * </ul>
          *
          * This method is invoked by {@link 
DefaultMathTransformFactory#swapAndScaleAxes(MathTransform, Context)}.
-         * Users an override this method if they need to customize the 
normalization process.
+         * Users can override this method if they need to customize the 
normalization process.
          *
          * @param  role  whether the normalization or denormalization matrix 
is desired.
          * @return the requested matrix, or {@code null} if this {@code 
Context} has no information about the coordinate system.
@@ -1296,7 +1296,7 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
      * {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH North}) axis 
orientations.
      *
      * <h4>Controlling the normalization process</h4>
-     * Users who need a different normalized space than the default one way 
find more convenient to
+     * Users who need a different normalized space than the default one may 
find more convenient to
      * override the {@link Context#getMatrix 
Context.getMatrix(ContextualParameters.MatrixRole)} method.
      *
      * @param  parameterized  a transform for normalized input and output 
coordinates.

Reply via email to