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 52f7098f12 Cache the inverse operation. The main intend is to avoid 
information lost when the inverse of the inverse is later requested.
52f7098f12 is described below

commit 52f7098f12d7cbd73edccb4d9b08ce86f7d7b4d3
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Wed Jan 10 14:22:11 2024 +0100

    Cache the inverse operation. The main intend is to avoid information lost 
when the inverse of the inverse is later requested.
---
 .../operation/AbstractCoordinateOperation.java     | 49 +++++++++++++++++++++-
 .../operation/CoordinateOperationFinder.java       |  7 +---
 .../operation/CoordinateOperationRegistry.java     | 17 ++++++--
 .../operation/DefaultConcatenatedOperation.java    | 10 ++++-
 .../sis/referencing/util/CoordinateOperations.java | 14 +++++++
 .../bind/referencing/CC_CoordinateOperation.java   |  4 +-
 6 files changed, 87 insertions(+), 14 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
index d957fa3dc7..3fe9667080 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
@@ -102,7 +102,7 @@ import static org.apache.sis.util.Utilities.deepEquals;
  * synchronization.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.4
+ * @version 1.5
  * @since   0.6
  */
 @XmlType(name = "AbstractCoordinateOperationType", propOrder = {
@@ -208,6 +208,19 @@ public class AbstractCoordinateOperation extends 
AbstractIdentifiedObject implem
      */
     private transient Set<Integer> wrapAroundChanges;
 
+    /**
+     * The inverse of this coordinate operation, computed when first needed. 
This is stored for making
+     * possible to find the original operation when the inverse of an inverse 
operation is requested.
+     * Serialized for avoiding information lost if the inverse is requested 
after deserialization.
+     *
+     * <p>This field is not formally part of coordinate operation definition,
+     * so it is not compared by {@link #equals(Object, ComparisonMode)}.</p>
+     *
+     * @see #getCachedInverse(CoordinateOperation)
+     */
+    @SuppressWarnings("serial")         // Most SIS implementations are 
serializable.
+    private volatile CoordinateOperation inverse;
+
     /**
      * Creates a new coordinate operation initialized from the given 
properties.
      * It is caller's responsibility to:
@@ -329,6 +342,7 @@ public class AbstractCoordinateOperation extends 
AbstractIdentifiedObject implem
      * are consistent with {@link #transform} input and output dimensions.
      */
     final void checkDimensions(final Map<String,?> properties) {
+        @SuppressWarnings("LocalVariableHidesMemberVariable")
         final MathTransform transform = this.transform;                     // 
Protect from changes.
         if (transform != null) {
             final int interpDim = 
ReferencingUtilities.getDimension(interpolationCRS);
@@ -739,6 +753,38 @@ check:      for (int isTarget=0; ; isTarget++) {        // 
0 == source check; 1
         return wrapAroundChanges;
     }
 
+    /**
+     * Returns the inverse of the given coordinate operation, or {@code null} 
if unspecified.
+     * This method only checks the cached value and does not compute a new 
value if none is present.
+     *
+     * @param  forward  the operation for which to get the inverse.
+     * @return the cached inverse operation, or {@code null} if none.
+     */
+    static CoordinateOperation getCachedInverse(final CoordinateOperation 
forward) {
+        if (forward instanceof AbstractCoordinateOperation) {
+            final CoordinateOperation inverse = ((AbstractCoordinateOperation) 
forward).inverse;
+            if (inverse != null) {
+                return inverse;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Caches the inverse of the given coordinate operation.
+     *
+     * @param  forward  the operation for which to cache the inverse.
+     * @param  inverse  the inverse operation to cache.
+     */
+    static void setCachedInverse(final CoordinateOperation forward, final 
CoordinateOperation inverse) {
+        if (inverse instanceof AbstractCoordinateOperation) {
+            ((AbstractCoordinateOperation) inverse).inverse = forward;
+        }
+        if (forward instanceof AbstractCoordinateOperation) {
+            ((AbstractCoordinateOperation) forward).inverse = inverse;
+        }
+    }
+
     /**
      * Compares this coordinate operation with the specified object for 
equality. If the {@code mode} argument
      * is {@link ComparisonMode#STRICT} or {@link ComparisonMode#BY_CONTRACT 
BY_CONTRACT}, then all available
@@ -881,6 +927,7 @@ check:      for (int isTarget=0; ; isTarget++) {        // 
0 == source check; 1
     protected String formatTo(final Formatter formatter) {
         super.formatTo(formatter);
         formatter.newLine();
+        @SuppressWarnings("LocalVariableHidesMemberVariable")
         final CoordinateReferenceSystem sourceCRS = getSourceCRS();
         final CoordinateReferenceSystem targetCRS = getTargetCRS();
         final Convention convention = formatter.getConvention();
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
index 53d1602d2b..05d166c263 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
@@ -1178,12 +1178,7 @@ public class CoordinateOperationFinder extends 
CoordinateOperationRegistry {
      * Returns {@code true} if the given operation is non-null and use the 
affine operation method.
      */
     private static boolean isAffine(final CoordinateOperation operation) {
-        if (operation instanceof SingleOperation) {
-            if (IdentifiedObjects.isHeuristicMatchForName(((SingleOperation) 
operation).getMethod(), Constants.AFFINE)) {
-                return true;
-            }
-        }
-        return false;
+        return 
IdentifiedObjects.isHeuristicMatchForName(CoordinateOperations.getMethod(operation),
 Constants.AFFINE);
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
index 568569454f..8e0ca1307b 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
@@ -721,6 +721,10 @@ class CoordinateOperationRegistry {
      * see ISO 19111 for more information).
      */
     final CoordinateOperation inverse(final SingleOperation op) throws 
NoninvertibleTransformException, FactoryException {
+        CoordinateOperation inverse = 
AbstractCoordinateOperation.getCachedInverse(op);
+        if (inverse != null) {
+            return inverse;
+        }
         final CoordinateReferenceSystem sourceCRS = op.getSourceCRS();
         final CoordinateReferenceSystem targetCRS = op.getTargetCRS();
         final MathTransform transform = op.getMathTransform().inverse();
@@ -735,7 +739,9 @@ class CoordinateOperationRegistry {
         Class<? extends CoordinateOperation> type = null;
         if (op instanceof Transformation)  type = Transformation.class;
         else if (op instanceof Conversion) type = Conversion.class;
-        return createFromMathTransform(properties, targetCRS, sourceCRS, 
transform, method, null, type);
+        inverse = createFromMathTransform(properties, targetCRS, sourceCRS, 
transform, method, null, type);
+        AbstractCoordinateOperation.setCachedInverse(op, inverse);
+        return inverse;
     }
 
     /**
@@ -758,6 +764,10 @@ class CoordinateOperationRegistry {
         if (operation instanceof SingleOperation) {
             return inverse((SingleOperation) operation);
         }
+        CoordinateOperation inverse = 
AbstractCoordinateOperation.getCachedInverse(operation);
+        if (inverse != null) {
+            return inverse;
+        }
         if (operation instanceof ConcatenatedOperation) {
             final CoordinateOperation[] inverted = 
getSteps((ConcatenatedOperation) operation, true);
             ArraysExt.reverse(inverted);
@@ -766,9 +776,10 @@ class CoordinateOperationRegistry {
             if (transform != null) {
                 properties.put(DefaultConcatenatedOperation.TRANSFORM_KEY, 
transform.inverse());
             }
-            return factory.createConcatenatedOperation(properties, inverted);
+            inverse = factory.createConcatenatedOperation(properties, 
inverted);
+            AbstractCoordinateOperation.setCachedInverse(operation, inverse);
         }
-        return null;
+        return inverse;
     }
 
     /**
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 4b434f18f5..8317a2059b 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
@@ -37,6 +37,7 @@ import org.apache.sis.referencing.IdentifiedObjects;
 import 
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
 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.internal.Resources;
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.ComparisonMode;
@@ -229,7 +230,7 @@ final class DefaultConcatenatedOperation extends 
AbstractCoordinateOperation imp
         CoordinateReferenceSystem source;                   // Source CRS of 
current iteration.
         CoordinateReferenceSystem target = null;            // Target CRS of 
current and last iteration.
         for (int i=0; i<operations.length; i++) {
-            final CoordinateOperation op = operations[i];
+            CoordinateOperation op = operations[i];
             ArgumentChecks.ensureNonNullElement("operations", i, op);
             /*
              * Verify consistency of user argument: for each coordinate 
operation, the source CRS
@@ -243,10 +244,15 @@ final class DefaultConcatenatedOperation extends 
AbstractCoordinateOperation imp
                 var t  = source;
                 source = target;
                 target = t;
+                // Inverse the operation only if it produces a more natural 
definition.
+                if (CoordinateOperations.getMethod(op) instanceof 
InverseOperationMethod) {
+                    CoordinateOperation natural = getCachedInverse(op);
+                    if (natural != null) op = natural;
+                }
             }
             if (setSource) {
                 setSource = false;
-                sourceCRS = source;                                            
 // Take even if null.
+                sourceCRS = source;         // Take even if null.
             }
             /*
              * Now that we have verified the CRS chaining, we should be able 
to concatenate the transforms.
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/util/CoordinateOperations.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/util/CoordinateOperations.java
index 127a4f3c26..7653014f84 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/util/CoordinateOperations.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/util/CoordinateOperations.java
@@ -31,6 +31,7 @@ import org.opengis.referencing.crs.CRSFactory;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.crs.GeneralDerivedCRS;
 import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.SingleOperation;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.CoordinateOperationFactory;
 import org.opengis.referencing.operation.MathTransformFactory;
@@ -138,6 +139,19 @@ public final class CoordinateOperations extends Static {
         return new DefaultCoordinateOperationFactory(properties, mtFactory);
     }
 
+    /**
+     * Returns the method of the given coordinate operation, or {@code null} 
if none.
+     *
+     * @param  operation  the operation from which to get the method, or 
{@code null}.
+     * @return the coordinate operation method, or {@code null} if none.
+     */
+    public static OperationMethod getMethod(final CoordinateOperation 
operation) {
+        if (operation instanceof SingleOperation) {
+            return ((SingleOperation) operation).getMethod();
+        }
+        return null;
+    }
+
     /**
      * Returns the operation method for the specified name or identifier. The 
given argument shall be either a
      * method name (e.g. <q>Transverse Mercator</q>) or one of its identifiers 
(e.g. {@code "EPSG:9807"}).
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/CC_CoordinateOperation.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/CC_CoordinateOperation.java
index dc56f10b73..0c368c20fc 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/CC_CoordinateOperation.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/CC_CoordinateOperation.java
@@ -19,8 +19,8 @@ package org.apache.sis.xml.bind.referencing;
 import jakarta.xml.bind.annotation.XmlElementRef;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.PassThroughOperation;
-import org.opengis.referencing.operation.SingleOperation;
 import org.apache.sis.xml.bind.gco.PropertyType;
+import org.apache.sis.referencing.util.CoordinateOperations;
 import org.apache.sis.referencing.operation.AbstractCoordinateOperation;
 
 
@@ -98,7 +98,7 @@ public final class CC_CoordinateOperation extends 
PropertyType<CC_CoordinateOper
             if (((PassThroughOperation) operation).getOperation() == null) {
                 incomplete("coordOperation");
             }
-        } else if ((operation instanceof SingleOperation) && 
((SingleOperation) operation).getMethod() == null) {
+        } else if (CoordinateOperations.getMethod(operation) == null) {
             incomplete("method");
         }
     }

Reply via email to