sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ama...@apache.org
Subject [sis] 34/45: WIP(Feature): CRS matching for filters.
Date Tue, 12 Nov 2019 16:45:01 GMT
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 944474a6f6fd74a272739887b0172ffda8d41adc
Author: Alexis Manin <amanin@apache.org>
AuthorDate: Thu Oct 10 12:55:51 2019 +0200

    WIP(Feature): CRS matching for filters.
---
 .../java/org/apache/sis/filter/CRSMatching.java    |  16 ++-
 .../java/org/apache/sis/filter/ST_Intersects.java  | 110 +++++++++++++++------
 2 files changed, 89 insertions(+), 37 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
index 78c4d9f..8f8a265 100644
--- 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
@@ -9,6 +9,7 @@ import org.opengis.util.FactoryException;
 import org.apache.sis.referencing.CRS;
 import org.apache.sis.util.NullArgumentException;
 import org.apache.sis.util.Utilities;
+import org.apache.sis.util.collection.BackingStoreException;
 
 /**
  * TODO: improve CRS conversion/suggestion by infering a geographic region of interest.
@@ -27,7 +28,7 @@ public interface CRSMatching {
         } else {
             return new CRSMatching() {
                 @Override
-                public Match right(CoordinateReferenceSystem other) throws FactoryException
{
+                public Match right(CoordinateReferenceSystem other) {
                     if (other == null) throw new NullArgumentException("No match can be established
with previous CRS because input one is null");
                     final CoordinateReferenceSystem commonCrs = CRS.suggestCommonTarget(null,
source, other);
                     return new DefaultMatch(commonCrs, source, other);
@@ -35,7 +36,8 @@ public interface CRSMatching {
             };
         }
     }
-    Match right(final CoordinateReferenceSystem other) throws FactoryException;
+
+    Match right(final CoordinateReferenceSystem other);
 
     interface Match {
         Optional<CoordinateReferenceSystem> getCommonCRS();
@@ -67,10 +69,14 @@ public interface CRSMatching {
         final Optional<CoordinateOperation> fromLeft;
         final Optional<CoordinateOperation> fromRight;
 
-        public DefaultMatch(CoordinateReferenceSystem commonCRS, CoordinateReferenceSystem
left, CoordinateReferenceSystem right) throws FactoryException {
+        public DefaultMatch(CoordinateReferenceSystem commonCRS, CoordinateReferenceSystem
left, CoordinateReferenceSystem right) {
             this.commonCRS = commonCRS;
-            fromLeft = createOp(left, commonCRS);
-            fromRight = createOp(right, commonCRS);
+            try {
+                fromLeft = createOp(left, commonCRS);
+                fromRight = createOp(right, commonCRS);
+            } catch (FactoryException e) {
+                throw new BackingStoreException(e);
+            }
         }
 
         @Override
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


Mime
View raw message