You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sedona.apache.org by ji...@apache.org on 2022/09/20 17:42:44 UTC
[incubator-sedona] branch master updated: [SEDONA-170] Add ST_AddPoint and ST_RemovePoint to the Flink API (#692)
This is an automated email from the ASF dual-hosted git repository.
jiayu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-sedona.git
The following commit(s) were added to refs/heads/master by this push:
new 82c923d6 [SEDONA-170] Add ST_AddPoint and ST_RemovePoint to the Flink API (#692)
82c923d6 is described below
commit 82c923d6d579818fa4257100e59b370458567889
Author: Kengo Seki <se...@apache.org>
AuthorDate: Wed Sep 21 02:42:38 2022 +0900
[SEDONA-170] Add ST_AddPoint and ST_RemovePoint to the Flink API (#692)
---
.../java/org/apache/sedona/common/Functions.java | 46 +++++++++++++++++++
docs/api/flink/Function.md | 40 +++++++++++++++++
.../main/java/org/apache/sedona/flink/Catalog.java | 4 +-
.../apache/sedona/flink/expressions/Functions.java | 33 ++++++++++++++
.../java/org/apache/sedona/flink/FunctionTest.java | 28 ++++++++++++
.../sql/sedona_sql/expressions/Functions.scala | 52 +++++-----------------
6 files changed, 160 insertions(+), 43 deletions(-)
diff --git a/common/src/main/java/org/apache/sedona/common/Functions.java b/common/src/main/java/org/apache/sedona/common/Functions.java
index 3a1b49cc..0466e0d3 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -39,8 +39,14 @@ import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.wololo.jts2geojson.GeoJSONWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
public class Functions {
+ private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory();
+
public static double area(Geometry geometry) {
return geometry.getArea();
}
@@ -288,4 +294,44 @@ public class Functions {
public static boolean isValid(Geometry geometry) {
return new IsValidOp(geometry).isValid();
}
+
+ public static Geometry addPoint(Geometry linestring, Geometry point) {
+ return addPoint(linestring, point, -1);
+ }
+
+ public static Geometry addPoint(Geometry linestring, Geometry point, int position) {
+ if (linestring instanceof LineString && point instanceof Point) {
+ List<Coordinate> coordinates = new ArrayList<>(Arrays.asList(linestring.getCoordinates()));
+ if (-1 <= position && position <= coordinates.size()) {
+ if (position < 0) {
+ coordinates.add(point.getCoordinate());
+ } else {
+ coordinates.add(position, point.getCoordinate());
+ }
+ return GEOMETRY_FACTORY.createLineString(coordinates.toArray(new Coordinate[0]));
+ }
+ }
+ return null;
+ }
+
+ public static Geometry removePoint(Geometry linestring) {
+ if (linestring != null) {
+ int length = linestring.getCoordinates().length;
+ if (1 < length) {
+ return removePoint(linestring, length - 1);
+ }
+ }
+ return null;
+ }
+
+ public static Geometry removePoint(Geometry linestring, int position) {
+ if (linestring instanceof LineString) {
+ List<Coordinate> coordinates = new ArrayList<>(Arrays.asList(linestring.getCoordinates()));
+ if (2 < coordinates.size() && position < coordinates.size()) {
+ coordinates.remove(position);
+ return GEOMETRY_FACTORY.createLineString(coordinates.toArray(new Coordinate[0]));
+ }
+ }
+ return null;
+ }
}
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index defff6ea..21f8bb9d 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -13,6 +13,29 @@ SELECT ST_3DDistance(polygondf.countyshape, polygondf.countyshape)
FROM polygondf
```
+## ST_AddPoint
+
+Introduction: Return Linestring with additional point at the given index, if position is not available the point will be added at the end of line.
+
+Format: `ST_AddPoint(geom: geometry, point: geometry, position: integer)`
+
+Format: `ST_AddPoint(geom: geometry, point: geometry)`
+
+Since: `v1.3.0`
+
+Example:
+```SQL
+SELECT ST_AddPoint(ST_GeomFromText("LINESTRING(0 0, 1 1, 1 0)"), ST_GeomFromText("Point(21 52)"), 1)
+
+SELECT ST_AddPoint(ST_GeomFromText("Linestring(0 0, 1 1, 1 0)"), ST_GeomFromText("Point(21 52)"))
+```
+
+Output:
+```
+LINESTRING(0 0, 21 52, 1 1, 1 0)
+LINESTRING(0 0, 1 1, 1 0, 21 52)
+```
+
## ST_Area
Introduction: Return the area of A
@@ -577,6 +600,23 @@ Input: `POLYGON ((-0.5 -0.5, -0.5 0.5, 0.5 0.5, 0.5 -0.5, -0.5 -0.5))`
Output: `POLYGON ((-0.5 -0.5, 0.5 -0.5, 0.5 0.5, -0.5 0.5, -0.5 -0.5))`
+## ST_RemovePoint
+
+Introduction: Return Linestring with removed point at given index, position can be omitted and then last one will be removed.
+
+Format: `ST_RemovePoint(geom: geometry, position: integer)`
+
+Format: `ST_RemovePoint(geom: geometry)`
+
+Since: `v1.3.0`
+
+Example:
+```SQL
+SELECT ST_RemovePoint(ST_GeomFromText("LINESTRING(0 0, 1 1, 1 0)"), 1)
+```
+
+Output: `LINESTRING(0 0, 1 0)`
+
## ST_SetSRID
Introduction: Sets the spatial refence system identifier (SRID) of the geometry.
diff --git a/flink/src/main/java/org/apache/sedona/flink/Catalog.java b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
index 163dc0e1..ca9cd94c 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -77,7 +77,9 @@ public class Catalog {
new Functions.ST_IsRing(),
new Functions.ST_IsSimple(),
new Functions.ST_IsValid(),
- new Functions.ST_Normalize()
+ new Functions.ST_Normalize(),
+ new Functions.ST_AddPoint(),
+ new Functions.ST_RemovePoint()
};
}
diff --git a/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java b/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java
index 7a9c228d..3640aad1 100644
--- a/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java
+++ b/flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java
@@ -380,4 +380,37 @@ public class Functions {
return org.apache.sedona.common.Functions.normalize(geom);
}
}
+
+ public static class ST_AddPoint extends ScalarFunction {
+ @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
+ public Geometry eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o1,
+ @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o2) {
+ Geometry linestring = (Geometry) o1;
+ Geometry point = (Geometry) o2;
+ return org.apache.sedona.common.Functions.addPoint(linestring, point);
+ }
+
+ @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
+ public Geometry eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o1,
+ @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o2,
+ int position) {
+ Geometry linestring = (Geometry) o1;
+ Geometry point = (Geometry) o2;
+ return org.apache.sedona.common.Functions.addPoint(linestring, point, position);
+ }
+ }
+
+ public static class ST_RemovePoint extends ScalarFunction {
+ @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
+ public Geometry eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o) {
+ Geometry geom = (Geometry) o;
+ return org.apache.sedona.common.Functions.removePoint(geom);
+ }
+
+ @DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
+ public Geometry eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o, int offset) {
+ Geometry geom = (Geometry) o;
+ return org.apache.sedona.common.Functions.removePoint(geom, offset);
+ }
+ }
}
diff --git a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
index 24d11dcc..fcb8e164 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -430,4 +430,32 @@ public class FunctionTest extends TestBase{
Geometry result = (Geometry) first(polygonTable).getField(0);
assertEquals("POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))", result.toString());
}
+
+ @Test
+ public void testAddPoint() {
+ Table pointTable = tableEnv.sqlQuery("SELECT ST_AddPoint(ST_GeomFromWKT('LINESTRING (0 0, 1 1)'), ST_GeomFromWKT('POINT (2 2)'))");
+ assertEquals("LINESTRING (0 0, 1 1, 2 2)", first(pointTable).getField(0).toString());
+
+ }
+
+ @Test
+ public void testAddPointWithIndex() {
+ Table pointTable = tableEnv.sqlQuery("SELECT ST_AddPoint(ST_GeomFromWKT('LINESTRING (0 0, 1 1)'), ST_GeomFromWKT('POINT (2 2)'), 1)");
+ assertEquals("LINESTRING (0 0, 2 2, 1 1)", first(pointTable).getField(0).toString());
+
+ }
+
+ @Test
+ public void testRemovePoint() {
+ Table pointTable = tableEnv.sqlQuery("SELECT ST_RemovePoint(ST_GeomFromWKT('LINESTRING (0 0, 1 1, 2 2)'))");
+ assertEquals("LINESTRING (0 0, 1 1)", first(pointTable).getField(0).toString());
+
+ }
+
+ @Test
+ public void testRemovePointWithIndex() {
+ Table pointTable = tableEnv.sqlQuery("SELECT ST_RemovePoint(ST_GeomFromWKT('LINESTRING (0 0, 1 1, 2 2)'), 1)");
+ assertEquals("LINESTRING (0 0, 2 2)", first(pointTable).getField(0).toString());
+
+ }
}
diff --git a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
index 1da93a84..a563166e 100644
--- a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
+++ b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
@@ -39,8 +39,6 @@ import org.locationtech.jts.operation.linemerge.LineMerger
import org.locationtech.jts.precision.GeometryPrecisionReducer
import org.locationtech.jts.simplify.TopologyPreservingSimplifier
-import scala.util.{Failure, Success, Try}
-
/**
* Return the distance between two geometries.
*
@@ -843,44 +841,21 @@ case class ST_AddPoint(inputExpressions: Seq[Expression])
extends Expression with CodegenFallback {
inputExpressions.betweenLength(2, 3)
- private val geometryFactory = new GeometryFactory()
-
override def nullable: Boolean = true
override def eval(input: InternalRow): Any = {
val geometry = inputExpressions.head.toGeometry(input)
val point = inputExpressions(1).toGeometry(input)
- if (inputExpressions.length == 2) addPointToGeometry(geometry, point, -1) else {
+ val geom = if (inputExpressions.length == 2) Functions.addPoint(geometry, point) else {
val index = inputExpressions(2).toInt(input)
- addPointToGeometry(geometry, point, index)
+ Functions.addPoint(geometry, point, index)
}
- }
-
- private def addPointToGeometry(geometry: Geometry, pointGeom: Geometry, index: Int): GenericArrayData = {
- geometry match {
- case string: LineString => pointGeom match {
- case point: Point => addPointToLineString(string, point, index) match {
- case None => null
- case Some(geom) => geom.toGenericArrayData
- }
- case _ => null
- }
+ geom match {
+ case linestring: LineString => linestring.toGenericArrayData
case _ => null
}
}
- private def addPointToLineString(lineString: LineString, point: Point, index: Int): Option[LineString] = {
- val coordinates = lineString.getCoordinates
- val length = coordinates.length
- if (index == -1) Some(lineStringFromCoordinates(coordinates ++ Array(point.getCoordinate)))
- else if (index >= 0 && index <= length) Some(lineStringFromCoordinates(
- coordinates.slice(0, index) ++ Array(point.getCoordinate) ++ coordinates.slice(index, length)))
- else None
- }
-
- private def lineStringFromCoordinates(coordinates: Array[Coordinate]): LineString =
- geometryFactory.createLineString(coordinates)
-
override def dataType: DataType = GeometryUDT
override def children: Seq[Expression] = inputExpressions
@@ -894,23 +869,16 @@ case class ST_RemovePoint(inputExpressions: Seq[Expression])
extends Expression with CodegenFallback {
inputExpressions.betweenLength(1, 2)
- private val geometryFactory = new GeometryFactory()
-
override def nullable: Boolean = true
override def eval(input: InternalRow): Any = {
val linesString = inputExpressions(0).toGeometry(input)
- linesString match {
- case string: LineString =>
- val coordinates = string.getCoordinates
- val length = coordinates.length
- val pointToRemove = if (inputExpressions.length < 2) coordinates.length - 1
- else inputExpressions(1).eval(input).asInstanceOf[Int]
- if (coordinates.length <= pointToRemove | coordinates.length <= 2) null
- else {
- val coordinatesWithPointRemoved = coordinates.slice(0, pointToRemove) ++ coordinates.slice(pointToRemove + 1, length)
- geometryFactory.createLineString(coordinatesWithPointRemoved).toGenericArrayData
- }
+ val geom = if (inputExpressions.length < 2) Functions.removePoint(linesString) else {
+ val index = inputExpressions(1).toInt(input)
+ Functions.removePoint(linesString, index)
+ }
+ geom match {
+ case linestring: LineString => linestring.toGenericArrayData
case _ => null
}
}