This is an automated email from the ASF dual-hosted git repository.

jiayu pushed a commit to branch SEDONA-578
in repository https://gitbox.apache.org/repos/asf/sedona.git

commit 19e2e55e319e42fb91b22c96c9cc7d7e9eff4594
Author: Pranav Toggi <[email protected]>
AuthorDate: Mon Apr 8 19:16:01 2024 -0400

    [TASK-4] Add ST_Points (#157)
    
    * init
    
    * init 2
    
    * add flink test
    
    * add scala, python, snowflake tests
    
    * add docs
    
    * Fix scala implementation
    
    * Fix test
    
    * Add ST_LineFromWKB
    
    * fix typo
    
    * Fix scala implementation
    
    * add scala dataframeapi test
    
    * Add flink tests
    
    * Add python dataframeapi test
    
    * Fix test
    
    * Fix doc
    
    * Fix test
    
    * Add tests
    
    * Fix test
    
    * Fix typo
    
    * Init
    
    * Implement for common and flink
    
    * Implement for scala; add tests
    
    * Fix typo
    
    * Implement for python, snowflake
    
    * Update docs
    
    * Fix tests
    
    * Fix tests
    
    * Fix test
    
    * Remove show()
---
 .../java/org/apache/sedona/common/Functions.java   | 19 ++++++++++++++++
 .../org/apache/sedona/common/FunctionsTest.java    | 26 ++++++++++++++++++++++
 docs/api/flink/Function.md                         | 20 +++++++++++++++++
 docs/api/snowflake/vector-data/Function.md         | 18 +++++++++++++++
 docs/api/sql/Function.md                           | 20 +++++++++++++++++
 .../main/java/org/apache/sedona/flink/Catalog.java |  1 +
 .../apache/sedona/flink/expressions/Functions.java |  8 +++++++
 .../java/org/apache/sedona/flink/FunctionTest.java |  8 +++++++
 python/sedona/sql/st_functions.py                  | 11 +++++++++
 python/tests/sql/test_dataframe_api.py             |  1 +
 python/tests/sql/test_function.py                  | 20 +++++++++++++++++
 .../sedona/snowflake/snowsql/TestFunctions.java    | 11 +++++++++
 .../sedona/snowflake/snowsql/TestFunctionsV2.java  |  9 ++++++++
 .../org/apache/sedona/snowflake/snowsql/UDFs.java  |  9 ++++++++
 .../apache/sedona/snowflake/snowsql/UDFsV2.java    |  9 ++++++++
 .../scala/org/apache/sedona/sql/UDF/Catalog.scala  |  1 +
 .../sql/sedona_sql/expressions/Functions.scala     |  8 +++++++
 .../sql/sedona_sql/expressions/st_functions.scala  |  3 +++
 .../apache/sedona/sql/dataFrameAPITestScala.scala  |  9 ++++++++
 .../org/apache/sedona/sql/functionTestScala.scala  | 12 ++++++++++
 20 files changed, 223 insertions(+)

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 774a2bfe3..d6dceb1f5 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -1728,4 +1728,23 @@ public class Functions {
             return GEOMETRY_FACTORY.createGeometryCollection(null);
         }
     }
+
+    /**
+     * Creates a MultiPoint containing all coordinates of the given geometry.
+     * Duplicates, M and Z coordinates are preserved.
+     *
+     * @param geometry The input geometry
+     * @return A MultiPoint geometry
+     */
+    public static Geometry points(Geometry geometry) {
+        if (geometry == null) {
+            return null;
+        }
+
+        // Extracting all coordinates from the geometry
+        Coordinate[] coordinates = geometry.getCoordinates();
+
+        // Creating a MultiPoint from the extracted coordinates
+        return GEOMETRY_FACTORY.createMultiPointFromCoords(coordinates);
+    }
 }
diff --git a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java 
b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
index 4fe7d1578..9f233f71b 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -2438,4 +2438,30 @@ public class FunctionsTest extends TestBase {
         String invalidReasonESRI = Functions.isValidReason(invalidGeom, 
ESRI_VALIDITY);
         assertEquals("Self-intersection at or near point (10.0, 20.0, NaN)", 
invalidReasonESRI);
     }
+
+    @Test
+    public void points() throws ParseException {
+        Geometry polygon = Constructors.geomFromEWKT("POLYGON ((0 0, 1 1, 5 1, 
5 0, 1 0, 0 0))");
+        Geometry lineString = Constructors.geomFromEWKT("LINESTRING (0 0, 1 1, 
2 2)");
+        Geometry point = Constructors.geomFromEWKT("POINT (0 0)");
+        Geometry multiPoint = Constructors.geomFromEWKT("MULTIPOINT ((0 0), (1 
1), (2 2))");
+        Geometry multiLineString = Constructors.geomFromEWKT("MULTILINESTRING 
((0 0, 1 1), (2 2, 3 3))");
+        Geometry multiPolygon = Constructors.geomFromEWKT("MULTIPOLYGON (((0 
0, 1 1, 1 0, 0 0)), ((2 2, 3 3, 3 2, 2 2)))");
+        Geometry geometry3D = Constructors.geomFromEWKT("POLYGON Z ((0 0 1, 1 
1 2, 2 2 3, 0 0 1))");
+
+        String result = Functions.asEWKT(Functions.points(polygon));
+        assertEquals("MULTIPOINT ((0 0), (1 1), (5 1), (5 0), (1 0), (0 0))", 
result);
+        result = Functions.asEWKT(Functions.points(lineString));
+        assertEquals("MULTIPOINT ((0 0), (1 1), (2 2))", result);
+        result = Functions.asEWKT(Functions.points(point));
+        assertEquals("MULTIPOINT ((0 0))", result);
+        result = Functions.asEWKT(Functions.points(multiPoint));
+        assertEquals("MULTIPOINT ((0 0), (1 1), (2 2))", result);
+        result = Functions.asEWKT(Functions.points(multiLineString));
+        assertEquals("MULTIPOINT ((0 0), (1 1), (2 2), (3 3))", result);
+        result = Functions.asEWKT(Functions.points(multiPolygon));
+        assertEquals("MULTIPOINT ((0 0), (1 1), (1 0), (0 0), (2 2), (3 3), (3 
2), (2 2))", result);
+        String result1 = Functions.asEWKT(Functions.points(geometry3D));
+        assertEquals("MULTIPOINT Z((0 0 1), (1 1 2), (2 2 3), (0 0 1))", 
result1);
+    }
 }
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index 28726f8b6..6b48f3278 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -2514,6 +2514,26 @@ FROM df
 
    Output: `POINT Z(0 0 1)`
 
+## ST_Points
+
+Introduction: Returns a MultiPoint geometry consisting of all the coordinates 
of the input geometry. It preserves duplicate points as well as M and Z 
coordinates.
+
+Format: `ST_Points(geom: Geometry)`
+
+Since: `vTBD`
+
+SQL Example
+
+```sql
+SELECT ST_AsText(ST_Points(ST_GeomFromEWKT('LINESTRING (2 4, 3 3, 4 2, 7 
3)')));
+```
+
+Output:
+
+```
+MULTIPOINT ((2 4), (3 3), (4 2), (7,3))
+```
+
 ## ST_Polygon
 
 Introduction: Function to create a polygon built from the given LineString and 
sets the spatial reference system from the srid
diff --git a/docs/api/snowflake/vector-data/Function.md 
b/docs/api/snowflake/vector-data/Function.md
index 54afc40d6..61325853c 100644
--- a/docs/api/snowflake/vector-data/Function.md
+++ b/docs/api/snowflake/vector-data/Function.md
@@ -1891,6 +1891,24 @@ SELECT 
ST_AsText(ST_PointOnSurface(ST_GeomFromText('LINESTRING(0 5 1, 0 0 1, 0 1
 
 ```
 
+## ST_Points
+
+Introduction: Returns a MultiPoint geometry consisting of all the coordinates 
of the input geometry. It preserves duplicate points as well as M and Z 
coordinates.
+
+Format: `ST_Points(geom: Geometry)`
+
+SQL Example
+
+```sql
+SELECT ST_AsText(ST_Points(ST_GeomFromEWKT('LINESTRING (2 4, 3 3, 4 2, 7 
3)')));
+```
+
+Output:
+
+```
+MULTIPOINT ((2 4), (3 3), (4 2), (7,3))
+```
+
 ## ST_Polygon
 
 Introduction: Function to create a polygon built from the given LineString and 
sets the spatial reference system from the srid
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index a09573fa3..5dc6f3e67 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -2523,6 +2523,26 @@ SELECT 
ST_AsText(ST_PointOnSurface(ST_GeomFromText('LINESTRING(0 5 1, 0 0 1, 0 1
 
 ```
 
+## ST_Points
+
+Introduction: Returns a MultiPoint geometry consisting of all the coordinates 
of the input geometry. It preserves duplicate points as well as M and Z 
coordinates.
+
+Format: `ST_Points(geom: Geometry)`
+
+Since: `vTBD`
+
+SQL Example
+
+```sql
+SELECT ST_AsText(ST_Points(ST_GeomFromEWKT('LINESTRING (2 4, 3 3, 4 2, 7 
3)')));
+```
+
+Output:
+
+```
+MULTIPOINT ((2 4), (3 3), (4 2), (7,3))
+```
+
 ## ST_Polygon
 
 Introduction: Function to create a polygon built from the given LineString and 
sets the spatial reference system from the srid
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 234e58b59..b1dd1692f 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -133,6 +133,7 @@ public class Catalog {
                 new Functions.ST_MMin(),
                 new Functions.ST_MMax(),
                 new Functions.ST_MakeLine(),
+                new Functions.ST_Points(),
                 new Functions.ST_Polygon(),
                 new Functions.ST_Polygonize(),
                 new Functions.ST_MakePolygon(),
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 7397087c5..56b8b1a44 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
@@ -813,6 +813,14 @@ public class Functions {
         }
     }
 
+    public static class ST_Points 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) {
+            Geometry geom = (Geometry) o1;
+            return org.apache.sedona.common.Functions.points(geom);
+        }
+    }
+
     public static class ST_Polygon 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,
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 9d4d6bb79..b12c37cba 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -969,6 +969,14 @@ public class FunctionTest extends TestBase{
         assertEquals("LINESTRING (2 2, 3 3)", result.toString());
     }
 
+    @Test
+    public void testPoints() {
+        Table table = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('POLYGON ((0 0, 
1 1, 5 1, 5 0, 1 0, 0 0))') AS polygon");
+        table = table.select(call(Functions.ST_Points.class.getSimpleName(), 
$("polygon")));
+        Geometry result = (Geometry) first(table).getField(0);
+        assertEquals("MULTIPOINT ((0 0), (1 1), (5 1), (5 0), (1 0), (0 0))", 
result.toString());
+    }
+
     @Test
     public void testPolygon() {
         Table table = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING (0 
0, 1 0, 1 1, 0 0)') AS line");
diff --git a/python/sedona/sql/st_functions.py 
b/python/sedona/sql/st_functions.py
index 07814947a..bd222d86a 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -917,6 +917,17 @@ def ST_MakeLine(geom1: ColumnOrName, geom2: 
Optional[ColumnOrName] = None) -> Co
     args = (geom1,) if geom2 is None else (geom1, geom2)
     return _call_st_function("ST_MakeLine", args)
 
+@validate_argument_types
+def ST_Points(geometry: ColumnOrName) -> Column:
+    """Creates a MultiPoint geometry consisting of all the coordinates of the 
input geometry
+
+    :param geometry: input geometry.
+    :type geometry: ColumnOrName
+    :return: Multipoint geometry
+    :rtype: Column
+    """
+    return _call_st_function("ST_Points", (geometry))
+
 @validate_argument_types
 def ST_Polygon(line_string: ColumnOrName, srid: ColumnOrNameOrNumber) -> 
Column:
     """Create a polygon built from the given LineString and sets the spatial 
reference system from the srid.
diff --git a/python/tests/sql/test_dataframe_api.py 
b/python/tests/sql/test_dataframe_api.py
index 420a26ed1..045fae719 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -154,6 +154,7 @@ test_configurations = [
     (stf.ST_MMax, ("line",), "4D_line", "", 3.0),
     (stf.ST_MakeValid, ("geom",), "invalid_geom", "", "MULTIPOLYGON (((1 5, 3 
3, 1 1, 1 5)), ((5 3, 7 5, 7 1, 5 3)))"),
     (stf.ST_MakeLine, ("line1", "line2"), "two_lines", "", "LINESTRING (0 0, 1 
1, 0 0, 3 2)"),
+    (stf.ST_Points, ("line",), "linestring_geom", "ST_Normalize(geom)", 
"MULTIPOINT (0 0, 1 0, 2 0, 3 0, 4 0, 5 0)"),
     (stf.ST_Polygon, ("geom", 4236), "closed_linestring_geom", "", "POLYGON 
((0 0, 1 0, 1 1, 0 0))"),
     (stf.ST_Polygonize, ("geom",), "noded_linework", "ST_Normalize(geom)", 
"GEOMETRYCOLLECTION (POLYGON ((0 2, 1 3, 2 4, 2 3, 2 2, 1 2, 0 2)), POLYGON ((2 
2, 2 3, 2 4, 3 3, 4 2, 3 2, 2 2)))"),
     (stf.ST_MakePolygon, ("geom",), "closed_linestring_geom", "", "POLYGON ((0 
0, 1 0, 1 1, 0 0))"),
diff --git a/python/tests/sql/test_function.py 
b/python/tests/sql/test_function.py
index 1df5e8508..eba49e795 100644
--- a/python/tests/sql/test_function.py
+++ b/python/tests/sql/test_function.py
@@ -998,6 +998,26 @@ class TestPredicateJoin(TestBase):
         for actual, expected in result:
             assert actual == expected
 
+    def test_st_points(self):
+        # Given
+        geometry_df = self.spark.createDataFrame(
+            [
+                # Adding only the input that will result in a non-null polygon
+                ["MULTILINESTRING ((0 0, 1 1), (2 2, 3 3))", "MULTIPOINT ((0 
0), (1 1), (2 2), (3 3))"]
+            ]
+        ).selectExpr("ST_GeomFromText(_1) AS geom", "_2 AS expected")
+
+        # When calling st_points
+        geom_poly = geometry_df.withColumn("actual", 
expr("st_normalize(st_points(geom))"))
+
+        result = geom_poly.filter("actual IS NOT 
NULL").selectExpr("ST_AsText(actual)", "expected"). \
+            collect()
+
+        assert result.__len__() == 1
+
+        for actual, expected in result:
+            assert actual == expected
+
     def test_st_polygon(self):
         # Given
         geometry_df = self.spark.createDataFrame(
diff --git 
a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java
 
b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java
index a83645497..7ccd6184b 100644
--- 
a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java
+++ 
b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java
@@ -720,6 +720,17 @@ public class TestFunctions extends TestBase {
                 "POINT (2.5 2.5)"
         );
     }
+
+    @Test
+    public void test_ST_Points() {
+        registerUDF("ST_Points", byte[].class);
+        registerUDF("ST_AsEWKT", byte[].class);
+        verifySqlSingleRes(
+                "select 
sedona.ST_AsEWKT(sedona.ST_Points(sedona.ST_GeomFromText('LINESTRING(0 0, 0 1, 
0 2, 0 3, 0 4)')))",
+                "MULTIPOINT ((0 0), (0 1), (0 2), (0 3), (0 4))"
+        );
+    }
+
     @Test
     public void test_ST_Polygon() {
         registerUDF("ST_Polygon", byte[].class, int.class);
diff --git 
a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctionsV2.java
 
b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctionsV2.java
index 299cbcdc9..58f36de43 100644
--- 
a/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctionsV2.java
+++ 
b/snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctionsV2.java
@@ -668,6 +668,15 @@ public class TestFunctionsV2
         );
     }
 
+    @Test
+    public void test_ST_Points() {
+        registerUDFV2("ST_Points", String.class);
+        verifySqlSingleRes(
+                "select 
ST_AsEWKT(sedona.ST_Points(ST_GeometryFromWKT('LINESTRING(0 0, 0 1, 0 2, 0 3, 0 
4)')))",
+                "SRID=0;MULTIPOINT((0 0),(0 1),(0 2),(0 3),(0 4))"
+        );
+    }
+
     @Test
     public void test_ST_Polygon() {
         registerUDFV2("ST_Polygon", String.class, int.class);
diff --git 
a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java 
b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java
index a4ed232b6..4c4b8a534 100644
--- a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java
+++ b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFs.java
@@ -992,6 +992,15 @@ public class UDFs {
         );
     }
 
+    @UDFAnnotations.ParamMeta(argNames = {"geometry"})
+    public static byte[] ST_Points(byte[] geometry) {
+        return GeometrySerde.serialize(
+                Functions.points(
+                        GeometrySerde.deserialize(geometry)
+                )
+        );
+    }
+
     @UDFAnnotations.ParamMeta(argNames = {"geometry", "srid"})
     public static byte[] ST_Polygon(byte[] geometry, int srid) {
         return GeometrySerde.serialize(
diff --git 
a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java 
b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java
index 08bad21ec..583693c23 100644
--- a/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java
+++ b/snowflake/src/main/java/org/apache/sedona/snowflake/snowsql/UDFsV2.java
@@ -808,6 +808,15 @@ public class UDFsV2
         );
     }
 
+    @UDFAnnotations.ParamMeta(argNames = {"geometry"}, argTypes = 
{"Geometry"}, returnTypes = "Geometry")
+    public static String ST_Points(String geometry) {
+        return GeometrySerde.serGeoJson(
+                Functions.points(
+                        GeometrySerde.deserGeoJson(geometry)
+                )
+        );
+    }
+
     @UDFAnnotations.ParamMeta(argNames = {"geometry", "srid"}, argTypes = 
{"Geometry", "int"}, returnTypes = "Geometry")
     public static String ST_Polygon(String geometry, int srid) {
         return GeometrySerde.serGeoJson(
diff --git 
a/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala 
b/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
index a411f67b7..eacd30c0e 100644
--- a/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
+++ b/spark/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
@@ -54,6 +54,7 @@ object Catalog {
     function[ST_GeomFromKML](),
     function[ST_CoordDim](),
     function[ST_Point](),
+    function[ST_Points](),
     function[ST_MakePoint](null, null),
     function[ST_PointZ](0),
     function[ST_PointM](0),
diff --git 
a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
 
b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
index 21613b37c..e52b89809 100644
--- 
a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
+++ 
b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
@@ -786,6 +786,14 @@ case class ST_MakeLine(inputExpressions: Seq[Expression])
   }
 }
 
+case class ST_Points(inputExpressions: Seq[Expression])
+  extends InferredExpression(Functions.points _) {
+
+  protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = 
{
+    copy(inputExpressions = newChildren)
+  }
+}
+
 case class ST_Polygon(inputExpressions: Seq[Expression])
   extends InferredExpression(Functions.makepolygonWithSRID _) {
 
diff --git 
a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
 
b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
index 65cec5a29..601f33f73 100644
--- 
a/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
+++ 
b/spark/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
@@ -229,6 +229,9 @@ object st_functions extends DataFrameAPI {
   def ST_MakeLine(geom1: Column, geom2: Column): Column = 
wrapExpression[ST_MakeLine](geom1, geom2)
   def ST_MakeLine(geom1: String, geom2: String): Column = 
wrapExpression[ST_MakeLine](geom1, geom2)
 
+  def ST_Points(geom: Column): Column = wrapExpression[ST_Points](geom)
+  def ST_Points(geom: String): Column = wrapExpression[ST_Points](geom)
+
   def ST_Polygon(lineString: Column, srid: Column): Column = 
wrapExpression[ST_Polygon](lineString, srid)
   def ST_Polygon(lineString: String, srid: Integer): Column = 
wrapExpression[ST_Polygon](lineString, srid)
 
diff --git 
a/spark/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala 
b/spark/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala
index 70e7201dd..1d37d89c0 100644
--- 
a/spark/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala
+++ 
b/spark/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala
@@ -514,6 +514,15 @@ class dataFrameAPITestScala extends TestBaseScala {
       assert(actualResult == expectedResult)
     }
 
+    it("Passed ST_Points") {
+      val invalidDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((0 0, 
1 1, 5 1, 5 0, 1 0, 0 0))') AS geom")
+      val df = invalidDf.select(ST_Normalize(ST_Points("geom")))
+      val actualResult = df.take(1)(0).get(0).asInstanceOf[Geometry]
+      actualResult.normalize()
+      val expectedResult = "MULTIPOINT ((0 0), (0 0), (1 0), (1 1), (5 0), (5 
1))"
+      assert(actualResult.toText()  == expectedResult)
+    }
+
     it("Passed ST_Polygon") {
       val invalidDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING (0 
0, 1 0, 1 1, 0 0)') AS geom")
       val df = invalidDf.select(ST_Polygon("geom", 4236))
diff --git 
a/spark/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala 
b/spark/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
index 98f4975ea..9eb8d5704 100644
--- a/spark/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
+++ b/spark/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
@@ -431,6 +431,18 @@ class functionTestScala extends TestBaseScala with 
Matchers with GeometrySample
       assert(row.get(1).asInstanceOf[Geometry].toText.equals("LINESTRING (5 6, 
7 8, 9 10)"))
     }
 
+    it("Passed ST_Points") {
+
+      val testtable = sparkSession.sql(
+        "SELECT ST_Points(ST_GeomFromText('MULTIPOLYGON (((0 0, 1 1, 1 0, 0 
0)), ((2 2, 3 3, 3 2, 2 2)))'))"
+      )
+
+      val result = testtable.take(1)(0).get(0).asInstanceOf[Geometry]
+
+      result.normalize()
+      assert(result.toText()  == "MULTIPOINT ((0 0), (0 0), (1 0), (1 1), (2 
2), (2 2), (3 2), (3 3))")
+    }
+
     it("Passed ST_Polygon") {
 
       var testtable = sparkSession.sql(

Reply via email to