sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jso...@apache.org
Subject [sis] branch geoapi-4.0 updated: Filter : add SQL/MM ST_Point function
Date Mon, 25 Nov 2019 14:16:42 GMT
This is an automated email from the ASF dual-hosted git repository.

jsorel 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 3f2318c  Filter : add SQL/MM ST_Point function
3f2318c is described below

commit 3f2318c5d0d25f00c1510678c913d9bc886cb340
Author: jsorel <johann.sorel@geomatys.com>
AuthorDate: Mon Nov 25 15:16:18 2019 +0100

    Filter : add SQL/MM ST_Point function
---
 .../src/main/java/org/apache/sis/filter/SQLMM.java |  25 ++-
 .../java/org/apache/sis/filter/ST_Envelope.java    |   3 +
 .../java/org/apache/sis/filter/ST_Intersects.java  |   5 +
 .../main/java/org/apache/sis/filter/ST_Point.java  | 123 ++++++++++++
 .../test/java/org/apache/sis/filter/SQLMMTest.java | 210 +++++++++++----------
 5 files changed, 266 insertions(+), 100 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/SQLMM.java b/core/sis-feature/src/main/java/org/apache/sis/filter/SQLMM.java
index 28b6816..935b90a 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/SQLMM.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/SQLMM.java
@@ -24,6 +24,7 @@ import org.opengis.util.FactoryException;
 import org.apache.sis.internal.feature.FunctionRegister;
 import org.apache.sis.internal.feature.Resources;
 import org.apache.sis.util.ArgumentChecks;
+import org.locationtech.jts.geom.GeometryFactory;
 
 
 /**
@@ -39,6 +40,12 @@ import org.apache.sis.util.ArgumentChecks;
  * @module
  */
 final class SQLMM implements FunctionRegister {
+
+    /**
+     * JTS factory used by multiple functions.
+     */
+    static final GeometryFactory GF = new GeometryFactory();
+
     /**
      * Creates the default register.
      */
@@ -58,8 +65,15 @@ final class SQLMM implements FunctionRegister {
      */
     @Override
     public Collection<String> getNames() {
-        return Arrays.asList(ST_Transform.NAME, ST_Centroid.NAME, ST_Buffer.NAME,
-                ST_Simplify.NAME, ST_SimplifyPreserveTopology.NAME);
+        return Arrays.asList(
+                ST_Buffer.NAME,
+                ST_Centroid.NAME,
+                ST_Envelope.NAME,
+                //ST_Intersects.NAME, TODO fixme, this class is not a proper function
+                ST_Point.NAME,
+                ST_Simplify.NAME,
+                ST_SimplifyPreserveTopology.NAME,
+                ST_Transform.NAME);
     }
 
     /**
@@ -80,11 +94,14 @@ final class SQLMM implements FunctionRegister {
         }
         try {
             switch (name) {
-                case ST_Transform.NAME:                 return new ST_Transform(parameters);
-                case ST_Centroid.NAME:                  return new ST_Centroid(parameters);
                 case ST_Buffer.NAME:                    return new ST_Buffer(parameters);
+                case ST_Centroid.NAME:                  return new ST_Centroid(parameters);
+                case ST_Envelope.NAME:                  return new ST_Envelope(parameters);
+                //case ST_Intersects.NAME:                return new ST_Intersects(parameters);
+                case ST_Point.NAME:                     return new ST_Point(parameters);
                 case ST_Simplify.NAME:                  return new ST_Simplify(parameters);
                 case ST_SimplifyPreserveTopology.NAME:  return new ST_SimplifyPreserveTopology(parameters);
+                case ST_Transform.NAME:                 return new ST_Transform(parameters);
                 default: throw new IllegalArgumentException(Resources.format(Resources.Keys.UnknownFunction_1,
name));
             }
         } catch (FactoryException e) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Envelope.java b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Envelope.java
index c383721..5e57ac7 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Envelope.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Envelope.java
@@ -46,6 +46,9 @@ import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
  * system unchanged.
  *
  * @author Alexis Manin (Geomatys)
+ * @version 2.0
+ * @since   2.0
+ * @module
  */
 public class ST_Envelope extends NamedFunction implements FeatureExpression {
 
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 a77f21c..9d0bd2c 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
@@ -43,6 +43,11 @@ import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 
 /**
  * TODO: refine once Geometry API is stable.
+ *
+ * @author  Alexis Manin (Geomatys)
+ * @version 2.0
+ * @since   2.0
+ * @module
  */
 public final class ST_Intersects extends SpatialFunction implements Intersects, Serializable
{
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Point.java b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Point.java
new file mode 100644
index 0000000..5e00125
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/ST_Point.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.filter;
+
+import org.apache.sis.feature.builder.AttributeTypeBuilder;
+import org.apache.sis.feature.builder.FeatureTypeBuilder;
+import org.apache.sis.feature.builder.PropertyTypeBuilder;
+import org.apache.sis.internal.feature.FeatureExpression;
+import org.apache.sis.referencing.CRS;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.Point;
+import org.opengis.feature.FeatureType;
+import org.opengis.filter.expression.Expression;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.util.FactoryException;
+
+/**
+ * An expression which creates a point geometry from separate coordinates.
+ * This expression expects multiple combined arguments:
+ * <ul>
+ *   <li>X, Y</li>
+ *   <li>X, Y, CoordinateReferenceSystem</li>
+ * </ul>
+ *
+ * <p>
+ *  Todo : many other arguments are defined is the SQL/MM specification.
+ * </p>
+ *
+ * @author  Johann Sorel (Geomatys)
+ * @version 2.0
+ * @since   2.0
+ * @module
+ */
+public class ST_Point extends NamedFunction implements FeatureExpression {
+
+    /**
+     * Name of this function as defined by SQL/MM standard.
+     */
+    static final String NAME = "ST_Point";
+
+    private CoordinateReferenceSystem constantCrs;
+
+    /**
+     * Creates a new function with the given parameters. It is caller's responsibility to
ensure
+     * that the given array is non-null, has been cloned and does not contain null elements.
+     *
+     * @throws IllegalArgumentException if the number of arguments is less then two.
+     */
+    ST_Point(final Expression[] parameters) {
+        super(parameters);
+        if (parameters.length < 2) {
+            throw new IllegalArgumentException("ST_Point function expect 2 or more parameters");
+        }
+
+        if (this.parameters.size() > 2) {
+            Object cdt = this.parameters.get(2).evaluate(null);
+            if (cdt instanceof Number) {
+                try {
+                    constantCrs = CRS.forCode("EPSG:" + ((Number) cdt).intValue());
+                } catch (FactoryException ex) {
+                    warning(ex);
+                }
+            } else if (cdt instanceof CoordinateReferenceSystem) {
+                constantCrs = (CoordinateReferenceSystem) cdt;
+            }
+        }
+    }
+
+    /**
+     * Returns the name of this function, which is {@value #NAME}.
+     */
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public Object evaluate(Object object) {
+        Number x = parameters.get(0).evaluate(object, Number.class);
+        Number y = parameters.get(1).evaluate(object, Number.class);
+        CoordinateReferenceSystem crs = constantCrs;
+        if (crs == null && parameters.size() > 2) {
+            Object cdt = parameters.get(2).evaluate(object);
+            if (cdt instanceof Number) {
+                try {
+                    crs = CRS.forCode("EPSG:" + ((Number) cdt).intValue());
+                } catch (FactoryException ex) {
+                    warning(ex);
+                }
+            } else if (cdt instanceof CoordinateReferenceSystem) {
+                crs = (CoordinateReferenceSystem) cdt;
+            }
+        }
+
+        final Point point = SQLMM.GF.createPoint(new Coordinate(x.doubleValue(), y.doubleValue()));
+        point.setUserData(crs);
+        return point;
+    }
+
+    @Override
+    public PropertyTypeBuilder expectedType(FeatureType valueType, FeatureTypeBuilder addTo)
{
+        final AttributeTypeBuilder<Point> atb = addTo.addAttribute(Point.class).setName(NAME);
+        if (constantCrs != null) {
+            atb.setCRS(constantCrs);
+        }
+        return atb;
+    }
+
+}
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 bbc13e6..605d62e 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
@@ -65,7 +65,7 @@ import static org.opengis.test.Assert.assertInstanceOf;
 public final strictfp class SQLMMTest extends TestCase {
 
     private static final String P_NAME = "geom";
-    
+
     /**
      * The factory to use for creating the objects to test.
      */
@@ -166,32 +166,6 @@ public final strictfp class SQLMMTest extends TestCase {
     }
 
     /**
-     * Test SQL/MM {@link ST_Centroid} function.
-     */
-    @Test
-    public void testCentroid() {
-        assertRequireArguments("ST_Centroid");
-        /*
-         * Creates a single linestring for testing the centroid function. The CRS is not
used by this computation,
-         * but we declare it in order to verify that the information is propagated to the
result.
-         */
-        final LineString geometry = geometryFactory.createLineString(new Coordinate[] {
-            new Coordinate(10, 20),
-            new Coordinate(30, 20)
-        });
-        geometry.setSRID(4326);
-        geometry.setUserData(HardCodedCRS.WGS84_φλ);
-        /*
-         * Execute the function and check the result.
-         */
-        final Point result = evaluate(Point.class, null, factory.function("ST_Centroid",
factory.literal(geometry)));
-        assertEquals("userData", HardCodedCRS.WGS84_φλ, result.getUserData());
-        assertEquals("SRID", 4326, result.getSRID());
-        assertEquals(20, result.getX(), STRICT);
-        assertEquals(20, result.getY(), STRICT);
-    }
-
-    /**
      * Test SQL/MM {@link ST_Buffer} function.
      */
     @Test
@@ -218,57 +192,66 @@ public final strictfp class SQLMMTest extends TestCase {
     }
 
     /**
-     * Test SQL/MM {@link ST_Simplify} function.
+     * Test SQL/MM {@link ST_Centroid} function.
      */
     @Test
-    public void ST_SimplifyTest() {
-        assertRequireArguments("ST_Simplify");
+    public void testCentroid() {
+        assertRequireArguments("ST_Centroid");
         /*
-         * Creates a single line for testing the simplify function. The CRS is not used by
this computation,
+         * Creates a single linestring for testing the centroid function. The CRS is not
used by this computation,
          * but we declare it in order to verify that the information is propagated to the
result.
          */
-        final LineString geometry = geometryFactory.createLineString(new Coordinate[]{new
Coordinate(10, 20), new Coordinate(15, 20), new Coordinate(20, 20)});
-        geometry.setUserData(HardCodedCRS.WGS84_φλ);
+        final LineString geometry = geometryFactory.createLineString(new Coordinate[] {
+            new Coordinate(10, 20),
+            new Coordinate(30, 20)
+        });
         geometry.setSRID(4326);
+        geometry.setUserData(HardCodedCRS.WGS84_φλ);
         /*
          * Execute the function and check the result.
          */
-        final LineString result = evaluate(LineString.class, null, factory.function("ST_Simplify",
factory.literal(geometry), factory.literal(10)));
+        final Point result = evaluate(Point.class, null, factory.function("ST_Centroid",
factory.literal(geometry)));
         assertEquals("userData", HardCodedCRS.WGS84_φλ, result.getUserData());
         assertEquals("SRID", 4326, result.getSRID());
-        Coordinate[] coordinates = result.getCoordinates();
-        assertEquals(2, coordinates.length);
-        assertEquals(10, coordinates[0].x, STRICT);
-        assertEquals(20, coordinates[0].y, STRICT);
-        assertEquals(20, coordinates[1].x, STRICT);
-        assertEquals(20, coordinates[1].y, STRICT);
+        assertEquals(20, result.getX(), STRICT);
+        assertEquals(20, result.getY(), STRICT);
     }
 
-    /**
-     * Test SQL/MM {@link ST_SimplifyPreserveTopology} function.
-     */
     @Test
-    public void ST_SimplifyPreserveTopologyTest() {
-        assertRequireArguments("ST_SimplifyPreserveTopology");
-        /*
-         * Creates a single line for testing the simplify function. The CRS is not used by
this computation,
-         * but we declare it in order to verify that the information is propagated to the
result.
-         */
-        final LineString geometry = geometryFactory.createLineString(new Coordinate[]{new
Coordinate(10, 20), new Coordinate(15, 20), new Coordinate(20, 20)});
-        geometry.setUserData(HardCodedCRS.WGS84_φλ);
-        geometry.setSRID(4326);
-        /*
-         * Execute the function and check the result.
-         */
-        final LineString result = evaluate(LineString.class, null, factory.function("ST_SimplifyPreserveTopology",
factory.literal(geometry), factory.literal(10)));
-        assertEquals("userData", HardCodedCRS.WGS84_φλ, result.getUserData());
-        assertEquals("SRID", 4326, result.getSRID());
-        Coordinate[] coordinates = result.getCoordinates();
-        assertEquals(2, coordinates.length);
-        assertEquals(10, coordinates[0].x, STRICT);
-        assertEquals(20, coordinates[0].y, STRICT);
-        assertEquals(20, coordinates[1].x, STRICT);
-        assertEquals(20, coordinates[1].y, STRICT);
+    public void ST_Envelope() {
+        try {
+            new ST_Envelope(new Expression[2]);
+            fail("ST_Envelope operator should accept a single parameter");
+        } catch (IllegalArgumentException e) {
+            // expected behavior
+        }
+
+        try {
+            new ST_Envelope(null);
+            fail("ST_Envelope operator should accept a single parameter");
+        } catch (IllegalArgumentException e) {
+            // expected behavior
+        }
+
+        final LineString pt = geometryFactory.createLineString(new Coordinate[]{
+                new Coordinate(12, 3.3),
+                new Coordinate(13.1, 4.4),
+                new Coordinate(12.02, 5.7)
+        });
+        ST_Envelope operator = new ST_Envelope(new Expression[]{factory.literal(pt)});
+        final GeneralEnvelope expectedEnv = new GeneralEnvelope(2);
+        expectedEnv.setEnvelope(12, 3.3, 13.1, 5.7);
+        Envelope evaluated = (Envelope) operator.evaluate(null);
+        assertTrue(String.format("Bad result:%nExpected: %s%nBut got: %s", expectedEnv.toString(),
evaluated.toString()), expectedEnv.equals(evaluated, 1e-10, false));
+        evaluated = (Envelope) operator.evaluate(null);
+        assertTrue(String.format("Bad result:%nExpected: %s%nBut got: %s", expectedEnv.toString(),
evaluated.toString()), expectedEnv.equals(evaluated, 1e-10, false));
+
+        // After testing literal data, we'll now try to extract data from a feature.
+        final Feature f = mock();
+        f.setPropertyValue(P_NAME, pt);
+        operator = new ST_Envelope(new Expression[]{factory.property(P_NAME)});
+        evaluated = (Envelope) operator.evaluate(f);
+        assertTrue(String.format("Bad result:%nExpected: %s%nBut got: %s", expectedEnv.toString(),
evaluated.toString()), expectedEnv.equals(evaluated, 1e-10, false));
     }
 
     @Test
@@ -338,41 +321,76 @@ public final strictfp class SQLMMTest extends TestCase {
         assertTrue("Intersection should be found when CRS are compatible", new ST_Intersects(factory.literal(pointUtm78),
factory.literal(ringUtm00)).evaluate(null));
     }
 
+    /**
+     * Test SQL/MM {@link ST_Point} function.
+     */
     @Test
-    public void ST_Envelope() {
-        try {
-            new ST_Envelope(new Expression[2]);
-            fail("ST_Envelope operator should accept a single parameter");
-        } catch (IllegalArgumentException e) {
-            // expected behavior
-        }
-
-        try {
-            new ST_Envelope(null);
-            fail("ST_Envelope operator should accept a single parameter");
-        } catch (IllegalArgumentException e) {
-            // expected behavior
-        }
+    public void ST_PointTest() {
+        assertRequireArguments("ST_Point");
+        /*
+         * Execute the function and check the result.
+         */
+        final Point result = evaluate(Point.class, null, factory.function("ST_Point",
+                factory.literal(10.0),
+                factory.literal(20.0),
+                factory.literal(HardCodedCRS.WGS84)));
+        assertEquals("userData", HardCodedCRS.WGS84, result.getUserData());
+        assertEquals(10.0, result.getX(), STRICT);
+        assertEquals(20.0, result.getY(), STRICT);
+    }
 
-        final LineString pt = geometryFactory.createLineString(new Coordinate[]{
-                new Coordinate(12, 3.3),
-                new Coordinate(13.1, 4.4),
-                new Coordinate(12.02, 5.7)
-        });
-        ST_Envelope operator = new ST_Envelope(new Expression[]{factory.literal(pt)});
-        final GeneralEnvelope expectedEnv = new GeneralEnvelope(2);
-        expectedEnv.setEnvelope(12, 3.3, 13.1, 5.7);
-        Envelope evaluated = (Envelope) operator.evaluate(null);
-        assertTrue(String.format("Bad result:%nExpected: %s%nBut got: %s", expectedEnv.toString(),
evaluated.toString()), expectedEnv.equals(evaluated, 1e-10, false));
-        evaluated = (Envelope) operator.evaluate(null);
-        assertTrue(String.format("Bad result:%nExpected: %s%nBut got: %s", expectedEnv.toString(),
evaluated.toString()), expectedEnv.equals(evaluated, 1e-10, false));
+    /**
+     * Test SQL/MM {@link ST_Simplify} function.
+     */
+    @Test
+    public void ST_SimplifyTest() {
+        assertRequireArguments("ST_Simplify");
+        /*
+         * Creates a single line for testing the simplify function. The CRS is not used by
this computation,
+         * but we declare it in order to verify that the information is propagated to the
result.
+         */
+        final LineString geometry = geometryFactory.createLineString(new Coordinate[]{new
Coordinate(10, 20), new Coordinate(15, 20), new Coordinate(20, 20)});
+        geometry.setUserData(HardCodedCRS.WGS84_φλ);
+        geometry.setSRID(4326);
+        /*
+         * Execute the function and check the result.
+         */
+        final LineString result = evaluate(LineString.class, null, factory.function("ST_Simplify",
factory.literal(geometry), factory.literal(10)));
+        assertEquals("userData", HardCodedCRS.WGS84_φλ, result.getUserData());
+        assertEquals("SRID", 4326, result.getSRID());
+        Coordinate[] coordinates = result.getCoordinates();
+        assertEquals(2, coordinates.length);
+        assertEquals(10, coordinates[0].x, STRICT);
+        assertEquals(20, coordinates[0].y, STRICT);
+        assertEquals(20, coordinates[1].x, STRICT);
+        assertEquals(20, coordinates[1].y, STRICT);
+    }
 
-        // After testing literal data, we'll now try to extract data from a feature.
-        final Feature f = mock();
-        f.setPropertyValue(P_NAME, pt);
-        operator = new ST_Envelope(new Expression[]{factory.property(P_NAME)});
-        evaluated = (Envelope) operator.evaluate(f);
-        assertTrue(String.format("Bad result:%nExpected: %s%nBut got: %s", expectedEnv.toString(),
evaluated.toString()), expectedEnv.equals(evaluated, 1e-10, false));
+    /**
+     * Test SQL/MM {@link ST_SimplifyPreserveTopology} function.
+     */
+    @Test
+    public void ST_SimplifyPreserveTopologyTest() {
+        assertRequireArguments("ST_SimplifyPreserveTopology");
+        /*
+         * Creates a single line for testing the simplify function. The CRS is not used by
this computation,
+         * but we declare it in order to verify that the information is propagated to the
result.
+         */
+        final LineString geometry = geometryFactory.createLineString(new Coordinate[]{new
Coordinate(10, 20), new Coordinate(15, 20), new Coordinate(20, 20)});
+        geometry.setUserData(HardCodedCRS.WGS84_φλ);
+        geometry.setSRID(4326);
+        /*
+         * Execute the function and check the result.
+         */
+        final LineString result = evaluate(LineString.class, null, factory.function("ST_SimplifyPreserveTopology",
factory.literal(geometry), factory.literal(10)));
+        assertEquals("userData", HardCodedCRS.WGS84_φλ, result.getUserData());
+        assertEquals("SRID", 4326, result.getSRID());
+        Coordinate[] coordinates = result.getCoordinates();
+        assertEquals(2, coordinates.length);
+        assertEquals(10, coordinates[0].x, STRICT);
+        assertEquals(20, coordinates[0].y, STRICT);
+        assertEquals(20, coordinates[1].x, STRICT);
+        assertEquals(20, coordinates[1].y, STRICT);
     }
 
     /**


Mime
View raw message