This is an automated email from the ASF dual-hosted git repository.

amanin pushed a commit to branch refactor/sql-store
in repository https://gitbox.apache.org/repos/asf/sis.git

commit bea8309f0e3ca8e8bf2c4d11c599d60a8686d01c
Author: Alexis Manin <[email protected]>
AuthorDate: Thu Oct 10 11:16:48 2019 +0200

    fix(Feature): Add CRS resolution strategy for filter operations.
---
 .../java/org/apache/sis/filter/CRSMatching.java    | 106 ++++++++++++++++++++
 .../java/org/apache/sis/filter/ST_Intersects.java  | 110 +++++++++++++++------
 .../java/org/apache/sis/filter/package-info.java   |  45 ++++++++-
 .../test/java/org/apache/sis/filter/SQLMMTest.java |  43 +++++++-
 .../sis/internal/feature/GeometriesTestCase.java   |   2 +-
 .../main/java/org/apache/sis/referencing/CRS.java  |  80 +++++++--------
 6 files changed, 307 insertions(+), 79 deletions(-)

diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/filter/CRSMatching.java 
b/core/sis-feature/src/main/java/org/apache/sis/filter/CRSMatching.java
new file mode 100644
index 0000000..23dfdf2
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/CRSMatching.java
@@ -0,0 +1,106 @@
+package org.apache.sis.filter;
+
+import java.util.Optional;
+
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.util.FactoryException;
+
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.util.Utilities;
+import org.apache.sis.util.collection.BackingStoreException;
+
+import static org.apache.sis.referencing.IdentifiedObjects.getIdentifierOrName;
+
+/**
+ * TODO: improve CRS conversion/suggestion by allowing user to input a 
geographic region of interest.
+ */
+@FunctionalInterface
+public interface CRSMatching {
+
+    static CRSMatching left(final CoordinateReferenceSystem source) {
+        if (source == null) {
+            return other -> {
+                if (other == null) return new NullMatch();
+                else throw new IllegalArgumentException("No match can be 
established with given CRS because source one is null.");
+            };
+        } else {
+            return other -> {
+                if (other == null) throw new IllegalArgumentException("No 
match can be established with previous CRS because input one is null");
+                final CoordinateReferenceSystem commonCrs = 
CRS.suggestCommonTarget(null, source, other);
+                if (commonCrs == null) throw new 
IllegalArgumentException(String.format(
+                        "No common space can be found between %s and %s",
+                        getIdentifierOrName(source), getIdentifierOrName(other)
+                ));
+                return new DefaultMatch(commonCrs, source, other);
+            };
+        }
+    }
+
+    Match right(final CoordinateReferenceSystem other);
+
+    interface Match {
+        Optional<CoordinateReferenceSystem> getCommonCRS();
+        Optional<CoordinateOperation> fromLeft();
+        Optional<CoordinateOperation> fromRight();
+    }
+
+    final class NullMatch implements Match {
+
+        @Override
+        public Optional<CoordinateReferenceSystem> getCommonCRS() {
+            return Optional.empty();
+        }
+
+        @Override
+        public Optional<CoordinateOperation> fromLeft() {
+            return Optional.empty();
+        }
+
+        @Override
+        public Optional<CoordinateOperation> fromRight() {
+            return Optional.empty();
+        }
+    }
+
+    final class DefaultMatch implements Match {
+
+        final CoordinateReferenceSystem commonCRS;
+        final Optional<CoordinateOperation> fromLeft;
+        final Optional<CoordinateOperation> fromRight;
+
+        public DefaultMatch(CoordinateReferenceSystem commonCRS, 
CoordinateReferenceSystem left, CoordinateReferenceSystem right) {
+            this.commonCRS = commonCRS;
+            try {
+                fromLeft = createOp(left, commonCRS);
+                fromRight = createOp(right, commonCRS);
+            } catch (FactoryException e) {
+                throw new BackingStoreException(e);
+            }
+        }
+
+        @Override
+        public Optional<CoordinateReferenceSystem> getCommonCRS() {
+            return Optional.of(commonCRS);
+        }
+
+        @Override
+        public Optional<CoordinateOperation> fromLeft() {
+            return fromLeft;
+        }
+
+        @Override
+        public Optional<CoordinateOperation> fromRight() {
+            return fromRight;
+        }
+    }
+
+    static Optional<CoordinateOperation> createOp(final 
CoordinateReferenceSystem source, final CoordinateReferenceSystem target) 
throws FactoryException {
+        if (Utilities.equalsIgnoreMetadata(source, target)) {
+            return Optional.empty();
+        } else {
+            final CoordinateOperation op = CRS.findOperation(source, target, 
null);
+            return Optional.of(op);
+        }
+    }
+}
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Intersects.java 
b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Intersects.java
index 407d291..f5ddf46 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Intersects.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Intersects.java
@@ -1,5 +1,7 @@
 package org.apache.sis.filter;
 
+import java.util.AbstractMap;
+import java.util.Map;
 import java.util.function.Predicate;
 
 import org.opengis.filter.FilterVisitor;
@@ -7,8 +9,14 @@ import org.opengis.filter.expression.Expression;
 import org.opengis.filter.expression.Literal;
 import org.opengis.filter.spatial.Intersects;
 import org.opengis.geometry.Geometry;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.util.FactoryException;
 
 import org.apache.sis.internal.feature.GeometryWrapper;
+import org.apache.sis.internal.feature.jts.JTS;
+import org.apache.sis.util.collection.BackingStoreException;
 
 import org.locationtech.jts.geom.prep.PreparedGeometry;
 import org.locationtech.jts.geom.prep.PreparedGeometryFactory;
@@ -38,11 +46,12 @@ public class ST_Intersects implements Intersects {
         ensureNonNull("Left operand", left);
         ensureNonNull("Right operand", right);
         if (left instanceof Literal && right instanceof Literal) {
-            intersects = constantOp((Literal) left, (Literal) right);
+            final boolean constantResult = nonOptimizedIntersects(null);
+            intersects = it -> constantResult;
         } else if (left instanceof Literal) {
-            intersects = intersect(right, (Literal) left);
+            intersects = intersect((Literal) left, right);
         } else if (right instanceof Literal) {
-            intersects = intersect(left, (Literal) right);
+            intersects = intersect((Literal) right, left);
         } else intersects = this::nonOptimizedIntersects;
     }
 
@@ -50,46 +59,83 @@ public class ST_Intersects implements Intersects {
         final Object leftEval = left.evaluate(candidate);
         final Object rightEval = right.evaluate(candidate);
         if (leftEval == null || rightEval == null) return false;
-        return toJTS(leftEval).intersects(toJTS(rightEval));
+
+        final Map.Entry<org.locationtech.jts.geom.Geometry, 
CoordinateReferenceSystem> leftEntry = toJTS(leftEval);
+        final Map.Entry<org.locationtech.jts.geom.Geometry, 
CoordinateReferenceSystem> rightEntry = toJTS(rightEval);
+        final CRSMatching.Match match = 
CRSMatching.left(leftEntry.getValue()).right(rightEntry.getValue());
+
+        final org.locationtech.jts.geom.Geometry leftGeom = match.fromLeft()
+                .map(op -> transformSilently(leftEntry.getKey(), op))
+                .orElse(leftEntry.getKey());
+        final org.locationtech.jts.geom.Geometry rightGeom = match.fromRight()
+                .map(op -> transformSilently(rightEntry.getKey(), op))
+                .orElse(rightEntry.getKey());
+
+        return leftGeom.intersects(rightGeom);
     }
 
-    private static org.locationtech.jts.geom.Geometry toJTS(Object value) {
-        if (value instanceof GeometryWrapper) value = ((GeometryWrapper) 
value).geometry;
-        if (value instanceof org.locationtech.jts.geom.Geometry) return 
(org.locationtech.jts.geom.Geometry) value;
-        throw new UnsupportedOperationException("Unsupported geometry type: 
"+value.getClass().getCanonicalName());
+    private static org.locationtech.jts.geom.Geometry 
transformSilently(org.locationtech.jts.geom.Geometry target, 
CoordinateOperation op) {
+        try {
+            return JTS.transform(target, op);
+        } catch (TransformException e) {
+            throw new BackingStoreException(e);
+        }
     }
 
-    private Predicate constantOp(Literal left, Literal right) {
-        final boolean result = left.getValue() != null
-                && right.getValue() != null
-                && toJTS(left.getValue()).intersects(toJTS(right.getValue()));
-        return it -> result;
+    private static Map.Entry<org.locationtech.jts.geom.Geometry, 
CoordinateReferenceSystem> toJTS(Object value) {
+        CoordinateReferenceSystem crs = null;
+        if (value instanceof Geometry) crs = ((Geometry) 
value).getCoordinateReferenceSystem();
+        if (value instanceof GeometryWrapper) value = ((GeometryWrapper) 
value).geometry;
+        if (value instanceof org.locationtech.jts.geom.Geometry) {
+            final org.locationtech.jts.geom.Geometry geom = 
(org.locationtech.jts.geom.Geometry) value;
+            if (crs == null) {
+                try {
+                    crs = JTS.getCoordinateReferenceSystem(geom);
+                } catch (FactoryException e) {
+                    throw new BackingStoreException("Cannot extract CRS from 
operand", e);
+                }
+            }
+            return new AbstractMap.SimpleImmutableEntry<>(geom, crs);
+        }
+        throw new UnsupportedOperationException("Unsupported geometry type: 
"+value.getClass().getCanonicalName());
     }
 
-    private static Predicate intersect(Expression left, Literal right) {
-        Object value = right.getValue();
+    private static Predicate intersect(Literal left, Expression right) {
+        Object value = left.getValue();
         ensureNonNull("Literal value", value);
         // TODO: make more consistent strategy once Geometry API is stable.
-        if (value instanceof GeometryWrapper) value = ((GeometryWrapper) 
value).geometry;
-        if (value instanceof org.locationtech.jts.geom.Geometry) {
-            final PreparedGeometry pg = new 
PreparedGeometryFactory().create((org.locationtech.jts.geom.Geometry) value);
+        try {
+            final Map.Entry<org.locationtech.jts.geom.Geometry, 
CoordinateReferenceSystem> leftEntry = toJTS(value);
+            final CRSMatching crsMatching = 
CRSMatching.left(leftEntry.getValue());
+            final PreparedGeometry optimizedGeom = new 
PreparedGeometryFactory().create((org.locationtech.jts.geom.Geometry) value);
             return it -> {
-                Object val = left.evaluate(it);
+                Object val = right.evaluate(it);
                 if (val == null) return false;
-                return pg.intersects(toJTS(val));
+                final Map.Entry<org.locationtech.jts.geom.Geometry, 
CoordinateReferenceSystem> rightEntry = toJTS(val);
+                final CRSMatching.Match match = 
crsMatching.right(rightEntry.getValue());
+                final org.locationtech.jts.geom.Geometry rightGeom = 
match.fromRight()
+                        .map(op -> transformSilently(rightEntry.getKey(), op))
+                        .orElse(rightEntry.getKey());
+                return match.fromLeft()
+                        .map(op -> transformSilently(leftEntry.getKey(), op))
+                        .map(geom -> geom.intersects(rightGeom))
+                        .orElseGet(() -> optimizedGeom.intersects(rightGeom));
             };
-        } else if (value instanceof Geometry) {
-            final Geometry geom = (Geometry) value;
-            return it -> {
-                final Geometry newVal = left.evaluate(it, Geometry.class);
-                if (newVal == null) {
-                    final Object testVal = left.evaluate(it);
-                    if (testVal == null) return false;
-                    throw new UnsupportedOperationException("Unsupported 
geometry type: "+testVal.getClass().getCanonicalName());
-                }
-                return geom.intersects(newVal);
-            };
-        } else throw new UnsupportedOperationException("Unsupported geometry 
type: "+value.getClass().getCanonicalName());
+        } catch (UnsupportedOperationException e) {
+            if (value instanceof Geometry) {
+                final Geometry geom = (Geometry) value;
+                return it -> {
+                    final Geometry newVal = left.evaluate(it, Geometry.class);
+                    if (newVal == null) {
+                        final Object testVal = left.evaluate(it);
+                        if (testVal == null) return false;
+                        throw new UnsupportedOperationException("Unsupported 
geometry type: "+testVal.getClass().getCanonicalName());
+                    }
+                    return geom.intersects(newVal);
+                };
+            }
+        }
+        throw new UnsupportedOperationException("Unsupported geometry type: 
"+value.getClass().getCanonicalName());
     }
 
     @Override
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/filter/package-info.java 
b/core/sis-feature/src/main/java/org/apache/sis/filter/package-info.java
index 7291456..cc40a87 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/package-info.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/package-info.java
@@ -19,12 +19,53 @@
  * Filters features according their properties.
  * A <cite>filter expression</cite> is a construct used to constraint a 
feature set to a subset.
  *
+ * All operations in this package try to follow rules of both following 
standards:
+ * <ul>
+ *     <li><a href="https://www.iso.org/fr/standard/53698.html";>ISO/IEC 
13249-3:2011 - SQLMM</a></li>
+ *     <li><a 
href="http://docs.opengeospatial.org/is/09-026r2/09-026r2.html";>OGC® Filter 
Encoding 2.0 Encoding Standard</a></li>
+ * </ul>
+ *
+ * <div class="section">General considerations:</div>
+ * <div class="section">Coordinate reference system handling:</div>
+ * As stated by Filter encoding 2.0.2, section 7.8.4, heterogeneous coordinate 
reference systems must be handled by
+ * libraries, one way or another. The standard does not define any strategy. 
As Apache-SIS contains a powerful
+ * transform system, we'll try to handle differences in the following way:
+ * <ul>
+ *     <li>
+ *         If all evaluated geometries define a srid, but their not the same, 
we'll try to project them in a common
+ *         space. The strategy will be guided by {@link 
org.apache.sis.referencing.CRS#suggestCommonTarget(org.opengis.metadata.extent.GeographicBoundingBox,
 org.opengis.referencing.crs.CoordinateReferenceSystem...) Referencing utility 
method}.
+ *         If it cannot provide a common space, we will fail any ongoing 
operation.
+ *     </li>
+ *     <li>
+ *         Missing information:
+ *         <ul>
+ *              <li>If no geometry contains any srid, consider they're defined 
in the same space, and proceed</li>
+ *              <li>If one geometry define a CRS but the other do not, 
consider that an ambiguity resides: fail.</li>
+ *         </ul>
+ *     </li>
+ * </ul>
+ *
+ * <div class="section">Optimisations</div>
+ * For now, few to no optimisation is done in the operators. Most of important 
ones would require one of the two
+ * following things:
+ * <ul>
+ *     <li>
+ *         Context information: Filters does not know in advance the feature 
type they're operating upon, which is
+ *         vital to define some calculus parameters, as property value 
conversion strategy, spatial system changes, etc.
+ *         Such information would allow operators to prepare data at 
initialisation time.
+ *     </li>
+ *     <li>
+ *         User hints: some operations could be set faster at the cost of 
precision. To activate such things, it would
+ *         require user consent. Most naïve example is spatial reference 
system conversion, which could be de-activated
+ *         for systems with nearly equal parameters (see {@link 
org.apache.sis.util.Utilities#equalsApproximately(java.lang.Object, 
java.lang.Object)}.
+ *     </li>
+ * </ul>
+ * extra-information for
+ * the operator, as well as hints from the user to allow sac
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
  *
- * @see <a 
href="http://docs.opengeospatial.org/is/09-026r2/09-026r2.html";>OGC® Filter 
Encoding 2.0 Encoding Standard</a>
- *
  * @since 1.0
  * @module
  */
diff --git 
a/core/sis-feature/src/test/java/org/apache/sis/filter/SQLMMTest.java 
b/core/sis-feature/src/test/java/org/apache/sis/filter/SQLMMTest.java
index 75a2fbc..8b2cda5 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/filter/SQLMMTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/filter/SQLMMTest.java
@@ -25,6 +25,7 @@ import org.opengis.filter.expression.Literal;
 import org.opengis.filter.expression.PropertyName;
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.ProjectedCRS;
 
 import org.apache.sis.feature.builder.FeatureTypeBuilder;
 import org.apache.sis.geometry.GeneralEnvelope;
@@ -40,6 +41,7 @@ import org.locationtech.jts.geom.LineString;
 import org.locationtech.jts.geom.LinearRing;
 import org.locationtech.jts.geom.Point;
 
+import static 
org.apache.sis.internal.feature.GeometriesTestCase.expectFailFast;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -170,22 +172,53 @@ public class SQLMMTest extends TestCase {
         });
 
         final Literal lring = factory.literal(ring);
-        ST_Intersects st = new ST_Intersects(new 
Expression[]{factory.literal(gf.createPoint(new Coordinate(2, 4))), lring});
+        ST_Intersects st = intersects(factory.literal(gf.createPoint(new 
Coordinate(2, 4))), lring);
         // Ensure argument nullity does not modify behavior
         assertFalse("Unexpected intersection", st.evaluate(null));
         assertFalse("Unexpected intersection", st.evaluate(new Object()));
 
         // Border should intersect
         final Feature f = mock();
-        f.setPropertyValue(P_NAME, gf.createPoint(second));
+        final Point point = gf.createPoint(second);
+        f.setPropertyValue(P_NAME, point);
         final PropertyName geomName = factory.property(P_NAME);
-        st = new ST_Intersects(new Expression[]{geomName, lring});
+        st = intersects(geomName, lring);
         assertTrue("Border point should intersect triangle", st.evaluate(f));
         // Ensure inverting expression does not modify behavior.
-        st = new ST_Intersects(new Expression[]{lring, geomName});
+        st = intersects(lring, geomName);
         assertTrue("Border point should intersect triangle", st.evaluate(f));
 
-        // TODO: add CRS checking tests.
+        // Ensure CRS conversion works as expected (see package-info).
+        // Missing
+        point.setUserData(CommonCRS.defaultGeographic());
+        expectFailFast(() -> intersects(geomName, lring).evaluate(f), 
IllegalArgumentException.class);
+        final Literal lPoint = factory.literal(point);
+        expectFailFast(() -> intersects(lPoint, lring).evaluate(null), 
IllegalArgumentException.class);
+
+        // Disjoint
+        final ProjectedCRS nadUtm = CommonCRS.NAD27.universal(32, 37);
+        final ProjectedCRS wgsUtm = CommonCRS.WGS84.universal(-2, 4);
+
+        point.setUserData(nadUtm);
+        ring.setUserData(wgsUtm);
+        expectFailFast(() -> intersects(geomName, lring).evaluate(f), 
IllegalArgumentException.class);
+        expectFailFast(() -> intersects(lPoint, lring).evaluate(null), 
IllegalArgumentException.class);
+
+        // TODO: activate back after fixing CRS.suggestCommonTarget
+        // utm domain contained in CRS:84
+//        ring.setUserData(CommonCRS.defaultGeographic());
+//        assertTrue("Intersection should be found when CRS are compatible", 
intersects(geomName, lring).evaluate(f));
+//        assertTrue("Intersection should be found when CRS are compatible", 
intersects(lPoint, lring).evaluate(null));
+
+        // Common base CRS
+//        ring.setUserData(CommonCRS.WGS84.universal(0, 0));
+//        point.setUserData(CommonCRS.WGS84.universal(7, 8));
+//        assertTrue("Intersection should be found when CRS are compatible", 
intersects(geomName, lring).evaluate(f));
+//        assertTrue("Intersection should be found when CRS are compatible", 
intersects(lPoint, lring).evaluate(null));
+    }
+
+    private static ST_Intersects intersects(final Expression left, Expression 
right) {
+        return new ST_Intersects(new Expression[]{left, right});
     }
 
     /**
diff --git 
a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java
 
b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java
index 7aa7a44..f49d481 100644
--- 
a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java
+++ 
b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java
@@ -194,7 +194,7 @@ public abstract strictfp class GeometriesTestCase extends 
TestCase {
         expectFailFast(() -> factory.tryConvertToGeometry(wrapped3d, NONE), 
IllegalArgumentException.class);
     }
 
-    private static void expectFailFast(Callable whichMustFail, Class<? extends 
Exception>... expectedErrorTypes) {
+    public static void expectFailFast(Callable whichMustFail, Class<? extends 
Exception>... expectedErrorTypes) {
         try {
             final Object result = whichMustFail.call();
             fail("Fail fast expected, but successfully returned "+result);
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
index 1b9b49d..a8912d4 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
@@ -16,82 +16,84 @@
  */
 package org.apache.sis.referencing;
 
-import java.util.Map;
-import java.util.List;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 import java.util.logging.LogRecord;
-import org.opengis.util.FactoryException;
+
 import org.opengis.geometry.Envelope;
-import org.opengis.referencing.NoSuchAuthorityCodeException;
+import org.opengis.geometry.Geometry;
+import org.opengis.metadata.citation.Citation;
+import org.opengis.metadata.extent.BoundingPolygon;
+import org.opengis.metadata.extent.Extent;
+import org.opengis.metadata.extent.GeographicBoundingBox;
+import org.opengis.metadata.extent.GeographicExtent;
 import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.cs.CartesianCS;
-import org.opengis.referencing.cs.EllipsoidalCS;
-import org.opengis.referencing.cs.AxisDirection;
-import org.opengis.referencing.cs.CoordinateSystem;
-import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.NoSuchAuthorityCodeException;
+import org.opengis.referencing.crs.CRSAuthorityFactory;
 import org.opengis.referencing.crs.CRSFactory;
-import org.opengis.referencing.crs.SingleCRS;
 import org.opengis.referencing.crs.CompoundCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.crs.CRSAuthorityFactory;
+import org.opengis.referencing.crs.EngineeringCRS;
+import org.opengis.referencing.crs.GeneralDerivedCRS;
 import org.opengis.referencing.crs.GeodeticCRS;
 import org.opengis.referencing.crs.GeographicCRS;
-import org.opengis.referencing.crs.GeneralDerivedCRS;
 import org.opengis.referencing.crs.ProjectedCRS;
+import org.opengis.referencing.crs.SingleCRS;
 import org.opengis.referencing.crs.TemporalCRS;
 import org.opengis.referencing.crs.VerticalCRS;
-import org.opengis.referencing.crs.EngineeringCRS;
+import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.datum.GeodeticDatum;
 import org.opengis.referencing.operation.Conversion;
-import org.opengis.referencing.operation.OperationNotFoundException;
-import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.extent.Extent;
-import org.opengis.metadata.extent.BoundingPolygon;
-import org.opengis.metadata.extent.GeographicBoundingBox;
-import org.opengis.metadata.extent.GeographicExtent;
 import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.OperationNotFoundException;
 import org.opengis.referencing.operation.TransformException;
-import org.apache.sis.measure.Units;
+import org.opengis.util.FactoryException;
+
 import org.apache.sis.geometry.Envelopes;
 import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.internal.referencing.AxisDirections;
+import org.apache.sis.internal.referencing.CoordinateOperations;
+import org.apache.sis.internal.referencing.DefinitionVerifier;
 import org.apache.sis.internal.referencing.EllipsoidalHeightCombiner;
 import org.apache.sis.internal.referencing.PositionalAccuracyConstant;
-import org.apache.sis.internal.referencing.CoordinateOperations;
 import org.apache.sis.internal.referencing.ReferencingUtilities;
-import org.apache.sis.internal.referencing.DefinitionVerifier;
 import org.apache.sis.internal.referencing.Resources;
 import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.internal.system.Modules;
 import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.internal.system.Modules;
 import org.apache.sis.internal.util.Numerics;
-import org.apache.sis.referencing.cs.AxisFilter;
-import org.apache.sis.referencing.cs.CoordinateSystems;
-import org.apache.sis.referencing.cs.DefaultVerticalCS;
+import org.apache.sis.measure.Units;
+import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
+import org.apache.sis.metadata.iso.extent.Extents;
+import org.apache.sis.referencing.crs.DefaultCompoundCRS;
+import org.apache.sis.referencing.crs.DefaultEngineeringCRS;
 import org.apache.sis.referencing.crs.DefaultGeographicCRS;
 import org.apache.sis.referencing.crs.DefaultProjectedCRS;
 import org.apache.sis.referencing.crs.DefaultVerticalCRS;
-import org.apache.sis.referencing.crs.DefaultCompoundCRS;
-import org.apache.sis.referencing.crs.DefaultEngineeringCRS;
+import org.apache.sis.referencing.cs.AxisFilter;
+import org.apache.sis.referencing.cs.CoordinateSystems;
+import org.apache.sis.referencing.cs.DefaultVerticalCS;
+import org.apache.sis.referencing.factory.GeodeticObjectFactory;
+import org.apache.sis.referencing.factory.UnavailableFactoryException;
 import org.apache.sis.referencing.operation.AbstractCoordinateOperation;
 import org.apache.sis.referencing.operation.CoordinateOperationContext;
-import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
 import org.apache.sis.referencing.operation.DefaultConversion;
-import org.apache.sis.referencing.factory.GeodeticObjectFactory;
-import org.apache.sis.referencing.factory.UnavailableFactoryException;
-import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
-import org.apache.sis.metadata.iso.extent.Extents;
-import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.logging.Logging;
-import org.apache.sis.util.logging.WarningListener;
+import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.Utilities;
 import org.apache.sis.util.Static;
+import org.apache.sis.util.Utilities;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.logging.WarningListener;
+import org.apache.sis.util.resources.Errors;
 
 // Branch-dependent imports
-import org.opengis.geometry.Geometry;
 
 
 /**
@@ -431,7 +433,7 @@ public final class CRS extends Static {
      * Suggests a coordinate reference system which could be a common target 
for coordinate operations having the
      * given sources. This method compares the {@linkplain 
#getGeographicBoundingBox(CoordinateReferenceSystem)
      * domain of validity} of all given CRSs. If a CRS has a domain of 
validity that contains the domain of all other
-     * CRS, than that CRS is returned. Otherwise this method verifies if a 
{@linkplain GeneralDerivedCRS#getBaseCRS()
+     * CRS, then that CRS is returned. Otherwise this method verifies if a 
{@linkplain GeneralDerivedCRS#getBaseCRS()
      * base CRS} (usually a {@linkplain 
org.apache.sis.referencing.crs.DefaultGeographicCRS geographic CRS} instance)
      * would be suitable. If no suitable CRS is found, then this method 
returns {@code null}.
      *

Reply via email to