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"); } }