You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by js...@apache.org on 2019/11/25 14:16:42 UTC
[sis] branch geoapi-4.0 updated: Filter : add SQL/MM ST_Point
function
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 <jo...@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);
}
/**