This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits 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 42a8abce5b Mave `Envelopes.transform(CoordinateOperation, …)` more
tolerant to the case where the envelope CRS does not match the coordinate
operation source CRS.
42a8abce5b is described below
commit 42a8abce5bc00ba7a6899eea142fe755d71503aa
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Tue Jul 21 17:46:55 2026 +0200
Mave `Envelopes.transform(CoordinateOperation, …)` more tolerant to the case
where the envelope CRS does not match the coordinate operation source CRS.
---
.../main/org/apache/sis/geometry/Envelopes.java | 39 ++++++++++++----------
.../sis/referencing/datum/DatumOrEnsemble.java | 2 +-
.../operation/CoordinateOperationContext.java | 6 ++--
.../operation/CoordinateOperationFinder.java | 23 +++++++------
.../operation/provider/DatumShiftMethod.java | 6 +++-
5 files changed, 43 insertions(+), 33 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/Envelopes.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/Envelopes.java
index 96f352fd07..dff81ab9eb 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/Envelopes.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/geometry/Envelopes.java
@@ -49,6 +49,7 @@ import
org.apache.sis.referencing.operation.CoordinateOperationContext;
import org.apache.sis.referencing.operation.AbstractCoordinateOperation;
import org.apache.sis.referencing.operation.transform.AbstractMathTransform;
import org.apache.sis.referencing.operation.transform.WraparoundTransform;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
import org.apache.sis.referencing.internal.shared.CoordinateOperations;
import org.apache.sis.referencing.internal.shared.DirectPositionView;
import org.apache.sis.referencing.internal.shared.TemporalAccessor;
@@ -102,7 +103,7 @@ import static
org.apache.sis.util.StringBuilders.trimFractionalPart;
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Johann Sorel (Geomatys)
- * @version 1.6
+ * @version 1.7
*
* @see org.apache.sis.metadata.iso.extent.Extents
* @see CRS
@@ -577,11 +578,12 @@ nextPoint: for (int pointIndex = 0;;) {
// Break condition at th
* or when it cross the ±180° longitude.</p>
*
* <h4>Usage note</h4>
- * If the envelope CRS is non-null, then the caller should ensure that the
operation source CRS
- * is the same as the envelope CRS. In case of mismatch, this method
transforms the envelope
- * to the operation source CRS before to apply the operation. This extra
step may cause a lost
- * of accuracy. In order to prevent this method from performing such
pre-transformation (if not desired),
- * callers can ensure that the envelope CRS is {@code null} before to call
this method.
+ * If the given envelope has a non-null <abbr>CRS</abbr>, then the caller
should ensure that the
+ * {@linkplain Envelope#getCoordinateReferenceSystem() envelope
<abbr>CRS</abbr>} is equivalent
+ * to the {@linkplain CoordinateOperation#getSourceCRS() operation source
<abbr>CRS</abbr>}.
+ * In case of mismatch, this method may add an operation step from the
former to the latter.
+ * IF such extra step is not desired or for more predictable results,
+ * callers can force the envelope <abbr>CRS</abbr> to {@code null} before
to call this method.
*
* @param operation the operation to use.
* @param envelope envelope to transform, or {@code null}. This
envelope will not be modified.
@@ -592,7 +594,7 @@ nextPoint: for (int pointIndex = 0;;) { //
Break condition at th
*
* @since 0.5
*/
- public static GeneralEnvelope transform(final CoordinateOperation
operation, Envelope envelope)
+ public static GeneralEnvelope transform(final CoordinateOperation
operation, final Envelope envelope)
throws TransformException
{
ArgumentChecks.ensureNonNull("operation", operation);
@@ -600,31 +602,34 @@ nextPoint: for (int pointIndex = 0;;) {
// Break condition at th
return null;
}
boolean isOperationComplete = true;
- final CoordinateReferenceSystem sourceCRS = operation.getSourceCRS();
+ MathTransform mt = operation.getMathTransform();
+ CoordinateReferenceSystem sourceCRS = operation.getSourceCRS();
if (sourceCRS != null) {
final CoordinateReferenceSystem crs =
envelope.getCoordinateReferenceSystem();
if (crs != null && !CRS.equivalent(crs, sourceCRS)) {
/*
* Argument-check: the envelope CRS seems inconsistent with
the given operation.
- * However, we need to push the check a little bit further,
since 3D-GeographicCRS
- * are considered not equal to CompoundCRS[2D-GeographicCRS +
ellipsoidal height].
+ * But this is not sure since `CRS.equivalent(…)` sometime
returns false negative.
* Checking for identity MathTransform is a more powerfull
(but more costly) check.
- * Since we have the MathTransform, perform an opportunist
envelope transform if it
- * happen to be required.
+ * The very tolerant accuracy is an indication that datum
shift can be ignored.
*/
- final MathTransform mt;
+ final MathTransform prefix;
try {
- mt = CRS.findOperation(crs, sourceCRS,
null).getMathTransform();
+ final var context = new CoordinateOperationContext();
+ context.setDesiredAccuracy(Double.POSITIVE_INFINITY);
+ prefix = CRS.findOperation(new
DefaultCoordinateMetadata(crs, null),
+ new
DefaultCoordinateMetadata(sourceCRS, null),
+ context).getMathTransform();
} catch (FactoryException e) {
throw new
TransformException(Errors.format(Errors.Keys.CanNotTransformEnvelope), e);
}
- if (!mt.isIdentity()) {
+ if (!prefix.isIdentity()) {
+ mt = MathTransforms.concatenate(prefix, mt);
+ sourceCRS = crs;
isOperationComplete = false;
- envelope = transform(mt, envelope);
}
}
}
- final MathTransform mt = operation.getMathTransform();
final double[] centerPt = new double[mt.getTargetDimensions()];
final GeneralEnvelope transformed = transform(mt, envelope, centerPt,
null);
/*
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DatumOrEnsemble.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DatumOrEnsemble.java
index 2821c8960d..863a15f1ed 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DatumOrEnsemble.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DatumOrEnsemble.java
@@ -111,7 +111,7 @@ public final class DatumOrEnsemble {
}
/**
- * Returns the datum or ensemble of a coordinate operation from
<var>source</var> to <var>target</var>.
+ * Returns the datum or datum ensemble of a coordinate operation from
<var>source</var> to <var>target</var>.
* If the two given coordinate reference systems are associated to equal
datum (ignoring metadata),
* then this method returns the <var>target</var> datum. Otherwise, this
method returns
* the largest ensemble which fully contains the datum or datum ensemble
of the other <abbr>CRS</abbr>.
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationContext.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationContext.java
index aab9161cbd..2fc0570dff 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationContext.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationContext.java
@@ -251,10 +251,10 @@ public class CoordinateOperationContext implements
Localized {
* Returns the desired accuracy in metres.
* A value of 0 means to search for the most accurate operation.
*
- * <p>When searching for the most accurate operation, SIS considers only
the operations specified by the authority.
+ * <p>When searching for the most accurate operation, <abbr>SIS</abbr>
considers only the operations specified by the authority.
* For example, the <cite>Molodensky</cite> method is a better datum shift
approximation than <cite>Abridged Molodensky</cite>.
- * But if all coordinate operations defined by the authority use the
Abridged Molodensky method, then SIS will ignore
- * the Molodensky one.</p>
+ * But if all coordinate operations defined by the authority use the
Abridged Molodensky method,
+ * then the Molodensky operation will not be used despite being
theoretically more accurate.</p>
*
* @return the desired accuracy in metres.
*/
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 baa510d453..8b95682a0f 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
@@ -67,6 +67,7 @@ import
org.apache.sis.referencing.operation.provider.DatumShiftMethod;
import org.apache.sis.referencing.operation.provider.GeocentricAffine;
import org.apache.sis.util.Utilities;
import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.Classes;
import org.apache.sis.util.collection.BackingStoreException;
import org.apache.sis.util.internal.shared.Constants;
import org.apache.sis.util.internal.shared.DoubleDouble;
@@ -330,7 +331,9 @@ public class CoordinateOperationFinder extends
CoordinateOperationRegistry {
// │ Any single CRS ↔ CRS of the same type
│
//
└────────────────────────────────────────────────────────────────────────┘
if (sourceCRS instanceof SingleCRS && targetCRS instanceof SingleCRS) {
- return createOperationStepFallback((SingleCRS) sourceCRS,
(SingleCRS) targetCRS);
+ if (Classes.implementSameInterfaces(sourceCRS.getClass(),
targetCRS.getClass(), SingleCRS.class)) {
+ return createOperationStepFallback((SingleCRS) sourceCRS,
(SingleCRS) targetCRS);
+ }
}
//
┌────────────────────────────────────────────────────────────────────────┐
// │ Compound ↔ various CRS
│
@@ -837,18 +840,13 @@ public class CoordinateOperationFinder extends
CoordinateOperationRegistry {
/**
* Creates an operation between two coordinate reference systems having no
specialized method.
- * The two given <abbr>CRS</abbr> should be of the same type. This is not
verified directly by
- * this method. However, because the <abbr>CRS</abbr> type is determined
by the datum type
+ * The two given <abbr>CRS</abbr> should be of the same type, but this is
verified indirectly:
+ * because the <abbr>CRS</abbr> type is determined by the datum type
* (sometimes completed by the <abbr>CS</abbr> type), having equivalent
datum and compatible
* <abbr>CS</abbr> should be a sufficient criterion for saying that the
<abbr>CRS</abbr> are
* of the same type.
*
- * <p>This method should be invoked as in last resort only.</p>
- *
- * <h4>Implementation type</h4>
- * The method body is a pattern repeated in most {@code
createOperationStep(…)} methods of this class.
- * Except that in other methods, the logic is interleaved with more
complex checks for datum changes.
- * Understanding the code of this method can help to understand the code
of other methods.
+ * <p>This method should be invoked in last resort only.</p>
*
* @param sourceCRS input coordinate reference system.
* @param targetCRS output coordinate reference system.
@@ -868,10 +866,13 @@ public class CoordinateOperationFinder extends
CoordinateOperationRegistry {
typeOfChange = AXIS_CHANGES;
} else {
finalDatum = DatumOrEnsemble.ofTarget(sourceCRS, targetCRS);
- if (finalDatum.isEmpty()) {
+ if (finalDatum.isPresent()) {
+ typeOfChange = SAME_DATUM_ENSEMBLE;
+ } else if (desiredAccuracy == Double.POSITIVE_INFINITY) {
+ typeOfChange = UNSPECIFIED_DATUM_CHANGE;
+ } else {
throw new
OperationNotFoundException(datumChangeNotFound(sourceDatum, targetDatum));
}
- typeOfChange = SAME_DATUM_ENSEMBLE;
}
final CoordinateSystem sourceCS = sourceCRS.getCoordinateSystem();
final CoordinateSystem targetCS = targetCRS.getCoordinateSystem();
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/DatumShiftMethod.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/DatumShiftMethod.java
index 37c500e2ff..f48509ae6b 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/DatumShiftMethod.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/DatumShiftMethod.java
@@ -16,6 +16,8 @@
*/
package org.apache.sis.referencing.operation.provider;
+import org.apache.sis.referencing.internal.PositionalAccuracyConstant;
+
/**
* The method to use for applying a datum shift.
@@ -61,7 +63,9 @@ public enum DatumShiftMethod {
* @see <a href="https://issues.apache.org/jira/browse/SIS-369">SIS-369</a>
*/
public static DatumShiftMethod forAccuracy(final double desired) {
- if (desired >= 5) {
+ if (desired >= PositionalAccuracyConstant.UNKNOWN_ACCURACY) {
+ return NONE;
+ } else if (desired >= 5) {
return MOLODENSKY;
} else {
return GEOCENTRIC_DOMAIN;