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)
   }

Reply via email to