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 c59ab622 [SEDONA-105] Add ST_PointOnSurface function (#606)
c59ab622 is described below
commit c59ab622ada2e133e3b075c830106c9cf5dcfb3b
Author: Hemendu Roy <[email protected]>
AuthorDate: Wed Apr 13 16:28:36 2022 -0700
[SEDONA-105] Add ST_PointOnSurface function (#606)
Co-authored-by: hemenduroy <[email protected]>
---
.../org/apache/sedona/core/utils/GeomUtils.java | 9 ++++++
docs/api/flink/Function.md | 32 +++++++++++++++++++
docs/api/sql/Function.md | 33 ++++++++++++++++++++
.../main/java/org/apache/sedona/flink/Catalog.java | 1 +
.../apache/sedona/flink/expressions/Functions.java | 9 ++++++
.../java/org/apache/sedona/flink/FunctionTest.java | 7 +++++
python/tests/sql/test_function.py | 23 +++++++++++++-
.../scala/org/apache/sedona/sql/UDF/Catalog.scala | 1 +
.../sql/sedona_sql/expressions/Functions.scala | 22 +++++++++++++
.../org/apache/sedona/sql/functionTestScala.scala | 36 ++++++++++++++++++++++
10 files changed, 172 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/org/apache/sedona/core/utils/GeomUtils.java
b/core/src/main/java/org/apache/sedona/core/utils/GeomUtils.java
index dfdc8cb3..27687050 100644
--- a/core/src/main/java/org/apache/sedona/core/utils/GeomUtils.java
+++ b/core/src/main/java/org/apache/sedona/core/utils/GeomUtils.java
@@ -71,4 +71,13 @@ public class GeomUtils
}
});
}
+ /*
+ * Returns a POINT that is guaranteed to lie on the surface.
+ */
+ public static Geometry getInteriorPoint(Geometry geometry) {
+ if(geometry==null) {
+ return null;
+ }
+ return geometry.getInteriorPoint();
+ }
}
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index 6444eca8..4a5b179d 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -101,6 +101,38 @@ Result:
+-----------------------------+
```
+## ST_PointOnSurface
+
+Introduction: Returns a POINT guaranteed to lie on the surface.
+
+Format: `ST_PointOnSurface(A:geometry)`
+
+Since: `v1.2.1`
+
+Examples:
+
+
+```SQL
+SELECT ST_PointOnSurface(df.geometry)
+FROM df
+```
+
+1. Input: `POINT (0 5)`
+
+ Output: `POINT (0 5)`
+
+2. Input: `LINESTRING(0 5, 0 10)`
+
+ Output: `POINT (0 5)`
+
+3. Input: `POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))`
+
+ Output: `POINT (2.5 2.5)`
+
+4. Input: `LINESTRING(0 5 1, 0 0 1, 0 10 2)`
+
+ Output: `POINT Z(0 0 1)`
+
## ST_Reverse
Introduction: Return the geometry with vertex order reversed
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index a7a02338..7c06e732 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -1030,6 +1030,39 @@ Result:
POLYGON ((3 -1, 3 -3, -3 -3, -3 3, 3 3, 3 1, 5 0, 3 -1))
```
+## ST_PointOnSurface
+
+Introduction: Returns a POINT guaranteed to lie on the surface.
+
+Format: `ST_PointOnSurface(A:geometry)`
+
+Since: `v1.2.1`
+
+Examples:
+
+```
+SELECT ST_AsText(ST_PointOnSurface(ST_GeomFromText('POINT(0 5)')));
+ st_astext
+------------
+ POINT(0 5)
+
+SELECT ST_AsText(ST_PointOnSurface(ST_GeomFromText('LINESTRING(0 5, 0 10)')));
+ st_astext
+------------
+ POINT(0 5)
+
+SELECT ST_AsText(ST_PointOnSurface(ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5
0, 0 0))')));
+ st_astext
+----------------
+ POINT(2.5 2.5)
+
+SELECT ST_AsText(ST_PointOnSurface(ST_GeomFromText('LINESTRING(0 5 1, 0 0 1, 0
10 2)')));
+ st_astext
+----------------
+ POINT Z(0 0 1)
+
+```
+
## ST_Reverse
Introduction: Return the geometry with vertex order reversed
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 4898575e..b855c74d 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -31,6 +31,7 @@ public class Catalog {
new Functions.ST_Transform(),
new Functions.ST_FlipCoordinates(),
new Functions.ST_GeoHash(),
+ new Functions.ST_PointOnSurface(),
new Functions.ST_Reverse()
};
}
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 46a919a1..bc615a55 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
@@ -85,6 +85,15 @@ public class Functions {
}
}
+ public static class ST_PointOnSurface 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;
+ GeomUtils.getInteriorPoint(geom);
+ return geom;
+ }
+ }
+
public static class ST_Reverse 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) {
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 e4a14511..87df7c17 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -66,6 +66,13 @@ public class FunctionTest extends TestBase{
}
@Test
+ public void testPointOnSurface() {
+ Table pointTable = createPointTable_real(testDataSize);
+ Table surfaceTable =
pointTable.select(call(Functions.ST_PointOnSurface.class.getSimpleName(),
$(pointColNames[0])));
+ Geometry result = (Geometry) first(surfaceTable).getField(0);
+ assertEquals("POINT (32 -118)", result.toString());
+ }
+
public void testReverse() {
Table polygonTable = createPolygonTable(1);
Table ReversedTable =
polygonTable.select(call(Functions.ST_Reverse.class.getSimpleName(),
$(polygonColNames[0])));
diff --git a/python/tests/sql/test_function.py
b/python/tests/sql/test_function.py
index dd68ca8f..e6250a2c 100644
--- a/python/tests/sql/test_function.py
+++ b/python/tests/sql/test_function.py
@@ -935,4 +935,25 @@ class TestPredicateJoin(TestBase):
return self.spark.createDataFrame([[wkt.loads(given_wkt)] for
given_wkt in wkt_list], self.geo_schema)
def __wkt_pair_list_with_index_to_data_frame(self, wkt_list: List) ->
DataFrame:
- return self.spark.createDataFrame([[index, wkt.loads(given_wkt)] for
index, given_wkt in wkt_list], self.geo_schema_with_index)
\ No newline at end of file
+ return self.spark.createDataFrame([[index, wkt.loads(given_wkt)] for
index, given_wkt in wkt_list], self.geo_schema_with_index)
+
+ def test_st_pointonsurface(self):
+ tests1 = {
+ "'POINT(0 5)'":"POINT (0 5)",
+ "'LINESTRING(0 5, 0 10)'":"POINT (0 5)",
+ "'POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'":"POINT (2.5 2.5)",
+ "'LINESTRING(0 5 1, 0 0 1, 0 10 2)'":"POINT Z(0 0 1)"
+ }
+
+ for input_geom, expected_geom in tests1.items():
+ pointOnSurface = self.spark.sql("select
ST_AsText(ST_PointOnSurface(ST_GeomFromText({})))".format(input_geom))
+ assert pointOnSurface.take(1)[0][0] == expected_geom
+
+ '''
+ ST_AsEWKT Has not been implemented yet
+ tests2 = { "'LINESTRING(0 5 1, 0 0 1, 0 10 2)'":"POINT(0 0 1)" }
+
+ for input_geom, expected_geom in tests2.items():
+ pointOnSurface = self.spark.sql("select
ST_AsEWKT(ST_PointOnSurface(ST_GeomFromEWKT({})))".format(input_geom))
+ assert pointOnSurface.take(1)[0][0] == expected_geom
+ '''
\ No newline at end of file
diff --git a/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
b/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
index 76750fcf..e078afb3 100644
--- a/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
+++ b/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
@@ -101,6 +101,7 @@ object Catalog {
ST_GeomFromGeoHash,
ST_Collect,
ST_Multi,
+ ST_PointOnSurface,
ST_Reverse,
// Expression for rasters
RS_NormalizedDifference,
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 2c8e632d..2261604b 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
@@ -1529,6 +1529,28 @@ case class ST_Multi(inputExpressions: Seq[Expression])
extends UnaryGeometryExpr
}
}
+/**
+ * Returns a POINT guaranteed to lie on the surface.
+ *
+ * @param inputExpressions Geometry
+ */
+case class ST_PointOnSurface(inputExpressions: Seq[Expression])
+ extends UnaryGeometryExpression with CodegenFallback {
+ assert(inputExpressions.length == 1)
+
+ override protected def nullSafeEval(geometry: Geometry): Any = {
+ new
GenericArrayData(GeometrySerializer.serialize(GeomUtils.getInteriorPoint(geometry)))
+ }
+
+ override def dataType: DataType = GeometryUDT
+
+ override def children: Seq[Expression] = inputExpressions
+
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) =
{
+ copy(inputExpressions = newChildren)
+ }
+}
+
/**
* Returns the geometry with vertex order reversed
*
diff --git a/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
b/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
index 5544fb9a..55b06401 100644
--- a/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
+++ b/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
@@ -1266,6 +1266,40 @@ class functionTestScala extends TestBaseScala with
Matchers with GeometrySample
}
+ it ("Should pass ST_PointOnSurface") {
+
+ val geomTestCases1 = Map(
+ "'POINT(0 5)'"
+ -> "POINT (0 5)",
+ "'LINESTRING(0 5, 0 10)'"
+ -> "POINT (0 5)",
+ "'POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'"
+ -> "POINT (2.5 2.5)",
+ "'LINESTRING(0 5 1, 0 0 1, 0 10 2)'"
+ -> "POINT Z(0 0 1)"
+ )
+
+ for((inputGeom, expectedGeom) <- geomTestCases1) {
+ var df = sparkSession.sql(s"select
ST_AsText(ST_PointOnSurface(ST_GeomFromText($inputGeom)))")
+ var result = df.collect()
+ assert(result.head.get(0).asInstanceOf[String]==expectedGeom)
+ }
+
+ /* ST_AsEWKT Has not been implemented yet
+
+ val geomTestCases2 = Map(
+ "'LINESTRING(0 5 1, 0 0 1, 0 10 2)'"
+ -> "POINT (0 0 1)"
+ )
+
+ for((inputGeom, expectedGeom) <- geomTestCases2) {
+ var df = sparkSession.sql(s"select
ST_AsEWKT(ST_PointOnSurface(ST_GeomFromEWKT($inputGeom)))")
+ var result = df.collect()
+ assert(result.head.get(0).asInstanceOf[String]==expectedGeom)
+ }
+ */
+ }
+
it ("Should pass ST_Reverse") {
val geomTestCases = Map(
"'POLYGON((-1 0 0, 1 0 0, 0 0 1, 0 1 0, -1 0 0))'"
@@ -1408,6 +1442,8 @@ class functionTestScala extends TestBaseScala with
Matchers with GeometrySample
assert(functionDf.first().get(0) == null)
functionDf = sparkSession.sql("select ST_Union(null, null)")
assert(functionDf.first().get(0) == null)
+ functionDf = sparkSession.sql("select ST_PointOnSurface(null)")
+ assert(functionDf.first().get(0) == null)
functionDf = sparkSession.sql("select ST_Reverse(null)")
assert(functionDf.first().get(0) == null)
}