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 2024/05/28 18:56:31 UTC
(sedona) branch master updated: [SEDONA-566] Add ST_TriangulatePolygon (#1436)
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/sedona.git
The following commit(s) were added to refs/heads/master by this push:
new cb93d54d6 [SEDONA-566] Add ST_TriangulatePolygon (#1436)
cb93d54d6 is described below
commit cb93d54d65038f792ac49dc067181f2034be5ff5
Author: Jia Yu <ji...@apache.org>
AuthorDate: Tue May 28 11:56:25 2024 -0700
[SEDONA-566] Add ST_TriangulatePolygon (#1436)
* [TASK-143] Add ST_TriangulatePolygon (#141)
* fix: tests of forcePolygonCCW and isPolygonCCW
* feat: add ST_TriangulatePolygon
* fix: snowflake test
* chore: remove print statement
* chore: add point test
* Update versions
* Fix the lint issue
---------
Co-authored-by: Furqaan Khan <46...@users.noreply.github.com>
---
.../java/org/apache/sedona/common/Functions.java | 5 +++++
.../org/apache/sedona/common/FunctionsTest.java | 22 +++++++++++++++++++++-
docs/api/flink/Function.md | 22 ++++++++++++++++++++++
docs/api/snowflake/vector-data/Function.md | 20 ++++++++++++++++++++
docs/api/sql/Function.md | 22 ++++++++++++++++++++++
.../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 | 2 ++
python/tests/sql/test_function.py | 6 ++++++
.../sedona/snowflake/snowsql/TestFunctions.java | 9 +++++++++
.../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 | 7 +++++++
.../sql/sedona_sql/expressions/st_functions.scala | 3 +++
.../apache/sedona/sql/dataFrameAPITestScala.scala | 7 +++++++
.../org/apache/sedona/sql/functionTestScala.scala | 7 +++++++
20 files changed, 187 insertions(+), 1 deletion(-)
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 6093ad94a..f1a1988a4 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -47,6 +47,7 @@ import org.locationtech.jts.operation.valid.IsValidOp;
import org.locationtech.jts.operation.valid.TopologyValidationError;
import org.locationtech.jts.precision.GeometryPrecisionReducer;
import org.locationtech.jts.simplify.TopologyPreservingSimplifier;
+import org.locationtech.jts.triangulate.polygon.ConstrainedDelaunayTriangulator;
import org.wololo.jts2geojson.GeoJSONWriter;
import java.util.*;
@@ -900,6 +901,10 @@ public class Functions {
return isExteriorRingCW && isInteriorRingCW;
}
+ public static Geometry triangulatePolygon(Geometry geom) {
+ return ConstrainedDelaunayTriangulator.triangulate(geom);
+ }
+
public static double lineLocatePoint(Geometry geom, Geometry point)
{
double length = geom.getLength();
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 ad9741849..9107670aa 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -777,6 +777,7 @@ public class FunctionsTest extends TestBase {
assertEquals(expected, actual);
}
+ @Test
public void testForcePolygonCCW() throws ParseException {
Geometry polyCW = Constructors.geomFromWKT("POLYGON ((20 35, 45 20, 30 5, 10 10, 10 30, 20 35), (30 20, 20 25, 20 15, 30 20))", 0);
String actual = Functions.asWKT(Functions.forcePolygonCCW(polyCW));
@@ -821,8 +822,9 @@ public class FunctionsTest extends TestBase {
Geometry lineClosed = Constructors.geomFromWKT("LINESTRING (30 20, 20 25, 20 15, 30 20)", 0);
assertFalse(Functions.isPolygonCW(lineClosed));
- }
+ }
+ @Test
public void testIsPolygonCCW() throws ParseException {
Geometry polyCCW = Constructors.geomFromWKT("POLYGON ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35),(30 20, 20 15, 20 25, 30 20))", 0);
assertTrue(Functions.isPolygonCCW(polyCCW));
@@ -840,6 +842,24 @@ public class FunctionsTest extends TestBase {
assertFalse(Functions.isPolygonCCW(lineClosed));
}
+ @Test
+ public void testTriangulatePolygon() throws ParseException {
+ Geometry geom = Constructors.geomFromWKT("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 5, 5 8, 8 8, 8 5, 5 5))", 0);
+ String actual = Functions.asWKT(Functions.triangulatePolygon(geom));
+ String expected = "GEOMETRYCOLLECTION (POLYGON ((0 0, 0 10, 5 5, 0 0)), POLYGON ((5 8, 5 5, 0 10, 5 8)), POLYGON ((10 0, 0 0, 5 5, 10 0)), POLYGON ((10 10, 5 8, 0 10, 10 10)), POLYGON ((10 0, 5 5, 8 5, 10 0)), POLYGON ((5 8, 10 10, 8 8, 5 8)), POLYGON ((10 10, 10 0, 8 5, 10 10)), POLYGON ((8 5, 8 8, 10 10, 8 5)))";
+ assertEquals(expected, actual);
+
+ geom = Constructors.geomFromWKT("MULTIPOLYGON (((0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2)), ((4 4, 4 6, 6 6, 6 4, 4 4)), ((6 6, 6 8, 8 8, 8 6, 6 6)), ((3 3, 3 4, 4 4, 4 3, 3 3)), ((5 5, 5 6, 6 6, 6 5, 5 5)), ((7 7, 7 8, 8 8, 8 7, 7 7)))", 0);
+ actual = Functions.asWKT(Functions.triangulatePolygon(geom));
+ expected = "GEOMETRYCOLLECTION (POLYGON ((0 0, 0 10, 2 2, 0 0)), POLYGON ((2 8, 2 2, 0 10, 2 8)), POLYGON ((10 0, 0 0, 2 2, 10 0)), POLYGON ((8 8, 2 8, 0 10, 8 8)), POLYGON ((10 0, 2 2, 8 2, 10 0)), POLYGON ((8 8, 0 10, 10 10, 8 8)), POLYGON ((10 10, 10 0, 8 2, 10 10)), POLYGON ((8 2, 8 8, 10 10, 8 2)), POLYGON ((4 4, 4 6, 6 6, 4 4)), POLYGON ((6 6, 6 4, 4 4, 6 6)), POLYGON ((6 6, 6 8, 8 8, 6 6)), POLYGON ((8 8, 8 6, 6 6, 8 8)), POLYGON ((3 3, 3 4, 4 4, 3 3)), POLYGON ((4 4, 4 3, [...]
+ assertEquals(expected, actual);
+
+ geom = Constructors.geomFromWKT("POINT(0 1)", 0);
+ actual = Functions.asWKT(Functions.triangulatePolygon(geom));
+ expected = "GEOMETRYCOLLECTION EMPTY";
+ assertEquals(expected, actual);
+ }
+
@Test
public void geometricMedianTolerance() throws Exception {
MultiPoint multiPoint = GEOMETRY_FACTORY.createMultiPointFromCoords(
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index eb6a82e25..464052827 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -2955,6 +2955,28 @@ Output:
POINT (-70.01 44.37)
```
+## ST_TriangulatePolygon
+
+Introduction: Generates the constrained Delaunay triangulation for the input Polygon. The constrained Delaunay triangulation is a set of triangles created from the Polygon's vertices that covers the Polygon area precisely, while maximizing the combined interior angles across all triangles compared to other possible triangulations. This produces the highest quality triangulation representation of the Polygon geometry. The function returns a GeometryCollection of Polygon geometries compris [...]
+
+Format: `ST_TriangulatePolygon(geom: Geometry)`
+
+Since: `v1.6.1`
+
+SQL Example
+
+```sql
+SELECT ST_TriangulatePolygon(
+ ST_GeomFromWKT('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 5, 5 8, 8 8, 8 5, 5 5))')
+ )
+```
+
+Output:
+
+```
+GEOMETRYCOLLECTION (POLYGON ((0 0, 0 10, 5 5, 0 0)), POLYGON ((5 8, 5 5, 0 10, 5 8)), POLYGON ((10 0, 0 0, 5 5, 10 0)), POLYGON ((10 10, 5 8, 0 10, 10 10)), POLYGON ((10 0, 5 5, 8 5, 10 0)), POLYGON ((5 8, 10 10, 8 8, 5 8)), POLYGON ((10 10, 10 0, 8 5, 10 10)), POLYGON ((8 5, 8 8, 10 10, 8 5)))
+```
+
## ST_Union
Introduction:
diff --git a/docs/api/snowflake/vector-data/Function.md b/docs/api/snowflake/vector-data/Function.md
index b93f5f58a..8e04f1f59 100644
--- a/docs/api/snowflake/vector-data/Function.md
+++ b/docs/api/snowflake/vector-data/Function.md
@@ -2287,6 +2287,26 @@ Input: `ST_Translate(POINT(1, 3, 2), 1, 2)`
Output: `POINT(2, 5, 2)`
+## ST_TriangulatePolygon
+
+Introduction: Generates the constrained Delaunay triangulation for the input Polygon. The constrained Delaunay triangulation is a set of triangles created from the Polygon's vertices that covers the Polygon area precisely, while maximizing the combined interior angles across all triangles compared to other possible triangulations. This produces the highest quality triangulation representation of the Polygon geometry. The function returns a GeometryCollection of Polygon geometries compris [...]
+
+Format: `ST_TriangulatePolygon(geom: Geometry)`
+
+SQL Example
+
+```sql
+SELECT ST_TriangulatePolygon(
+ ST_GeomFromWKT('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 5, 5 8, 8 8, 8 5, 5 5))')
+ )
+```
+
+Output:
+
+```
+GEOMETRYCOLLECTION (POLYGON ((0 0, 0 10, 5 5, 0 0)), POLYGON ((5 8, 5 5, 0 10, 5 8)), POLYGON ((10 0, 0 0, 5 5, 10 0)), POLYGON ((10 10, 5 8, 0 10, 10 10)), POLYGON ((10 0, 5 5, 8 5, 10 0)), POLYGON ((5 8, 10 10, 8 8, 5 8)), POLYGON ((10 10, 10 0, 8 5, 10 10)), POLYGON ((8 5, 8 8, 10 10, 8 5)))
+```
+
## ST_Union
Introduction: Return the union of geometry A and B
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index 46a90ab95..2a6d19c5d 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -3065,6 +3065,28 @@ Output:
POINT (-70.01 44.37)
```
+## ST_TriangulatePolygon
+
+Introduction: Generates the constrained Delaunay triangulation for the input Polygon. The constrained Delaunay triangulation is a set of triangles created from the Polygon's vertices that covers the Polygon area precisely, while maximizing the combined interior angles across all triangles compared to other possible triangulations. This produces the highest quality triangulation representation of the Polygon geometry. The function returns a GeometryCollection of Polygon geometries compris [...]
+
+Format: `ST_TriangulatePolygon(geom: Geometry)`
+
+Since: `v1.6.1`
+
+SQL Example
+
+```sql
+SELECT ST_TriangulatePolygon(
+ ST_GeomFromWKT('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 5, 5 8, 8 8, 8 5, 5 5))')
+ )
+```
+
+Output:
+
+```
+GEOMETRYCOLLECTION (POLYGON ((0 0, 0 10, 5 5, 0 0)), POLYGON ((5 8, 5 5, 0 10, 5 8)), POLYGON ((10 0, 0 0, 5 5, 10 0)), POLYGON ((10 10, 5 8, 0 10, 10 10)), POLYGON ((10 0, 5 5, 8 5, 10 0)), POLYGON ((5 8, 10 10, 8 8, 5 8)), POLYGON ((10 10, 10 0, 8 5, 10 10)), POLYGON ((8 5, 8 8, 10 10, 8 5)))
+```
+
## ST_Union
Introduction:
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 01cdd2743..bedf26a5c 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -150,6 +150,7 @@ public class Catalog {
new Functions.ST_IsPolygonCCW(),
new Functions.ST_ForcePolygonCCW(),
new Functions.ST_Translate(),
+ new Functions.ST_TriangulatePolygon(),
new Functions.ST_Union(),
new Functions.ST_VoronoiPolygons(),
new Functions.ST_FrechetDistance(),
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 398940030..bd79b328a 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
@@ -1086,6 +1086,14 @@ public class Functions {
}
}
+ public static class ST_TriangulatePolygon 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 geometry = (Geometry) o;
+ return org.apache.sedona.common.Functions.triangulatePolygon(geometry);
+ }
+ }
+
public static class ST_Union 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 1e0953be5..ec2b8e777 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -1230,6 +1230,14 @@ public class FunctionTest extends TestBase{
assertEquals(expectedDims, actual);
}
+ @Test
+ public void testTriangulatePolygon() {
+ Table polyTable = tableEnv.sqlQuery("SELECT ST_TriangulatePolygon(ST_GeomFromWKT('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 5, 5 8, 8 8, 8 5, 5 5))')) as poly");
+ String actual = (String) first(polyTable.select(call(Functions.ST_AsText.class.getSimpleName(), $("poly")))).getField(0);
+ String expected = "GEOMETRYCOLLECTION (POLYGON ((0 0, 0 10, 5 5, 0 0)), POLYGON ((5 8, 5 5, 0 10, 5 8)), POLYGON ((10 0, 0 0, 5 5, 10 0)), POLYGON ((10 10, 5 8, 0 10, 10 10)), POLYGON ((10 0, 5 5, 8 5, 10 0)), POLYGON ((5 8, 10 10, 8 8, 5 8)), POLYGON ((10 10, 10 0, 8 5, 10 10)), POLYGON ((8 5, 8 8, 10 10, 8 5)))";
+ assertEquals(expected, actual);
+ }
+
@Test
public void testForceRHR() {
Table polyTable = tableEnv.sqlQuery("SELECT ST_ForceRHR(ST_GeomFromWKT('POLYGON ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35),(30 20, 20 15, 20 25, 30 20))')) AS polyCW");
diff --git a/python/sedona/sql/st_functions.py b/python/sedona/sql/st_functions.py
index c26ccfa0b..2be621456 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -1326,6 +1326,17 @@ def ST_Transform(geometry: ColumnOrName, source_crs: ColumnOrName, target_crs: O
args = (geometry, source_crs, target_crs, disable_error)
return _call_st_function("ST_Transform", args)
+@validate_argument_types
+def ST_TriangulatePolygon(geom: ColumnOrName) -> Column:
+ """Computes the constrained Delaunay triangulation of polygons. Holes and Multipolygons are supported.
+
+ :param geom: (Multi)Polygon to be triangulated.
+ :type geom: ColumnOrName
+ :return: Triangulated Polygon as GeometryCollection of Polygons
+ :rtype: Column
+ """
+ return _call_st_function("ST_TriangulatePolygon", geom)
+
@validate_argument_types
def ST_Union(a: ColumnOrName, b: Optional[ColumnOrName] = None) -> Column:
diff --git a/python/tests/sql/test_dataframe_api.py b/python/tests/sql/test_dataframe_api.py
index bb8d22c6f..977c460ca 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -180,6 +180,7 @@ test_configurations = [
(stf.ST_SymDifference, ("a", "b"), "overlapping_polys", "", "MULTIPOLYGON (((1 0, 0 0, 0 1, 1 1, 1 0)), ((2 0, 2 1, 3 1, 3 0, 2 0)))"),
(stf.ST_Transform, ("point", lambda: f.lit("EPSG:4326"), lambda: f.lit("EPSG:32649")), "point_geom", "ST_ReducePrecision(geom, 2)", "POINT (-34870890.91 1919456.06)"),
(stf.ST_Translate, ("geom", 1.0, 1.0,), "square_geom", "", "POLYGON ((2 1, 2 2, 3 2, 3 1, 2 1))"),
+ (stf.ST_TriangulatePolygon, ("geom",), "square_geom", "", "GEOMETRYCOLLECTION (POLYGON ((1 0, 1 1, 2 1, 1 0)), POLYGON ((2 1, 2 0, 1 0, 2 1)))"),
(stf.ST_Union, ("a", "b"), "overlapping_polys", "", "POLYGON ((1 0, 0 0, 0 1, 1 1, 2 1, 3 1, 3 0, 2 0, 1 0))"),
(stf.ST_Union, ("polys",), "array_polygons", "", "POLYGON ((2 3, 3 3, 3 -3, -3 -3, -3 3, -2 3, -2 4, 2 4, 2 3))"),
(stf.ST_VoronoiPolygons, ("geom",), "multipoint", "", "GEOMETRYCOLLECTION (POLYGON ((-1 -1, -1 2, 2 -1, -1 -1)), POLYGON ((-1 2, 2 2, 2 -1, -1 2)))"),
@@ -357,6 +358,7 @@ wrong_type_configurations = [
(stf.ST_SymDifference, ("", None)),
(stf.ST_Transform, (None, "", "")),
(stf.ST_Transform, ("", None, "")),
+ (stf.ST_TriangulatePolygon, (None,)),
(stf.ST_Union, (None, "")),
(stf.ST_Union, (None,)),
(stf.ST_X, (None,)),
diff --git a/python/tests/sql/test_function.py b/python/tests/sql/test_function.py
index c54a1eccf..fc9e5f5da 100644
--- a/python/tests/sql/test_function.py
+++ b/python/tests/sql/test_function.py
@@ -1412,6 +1412,12 @@ class TestPredicateJoin(TestBase):
actual = actualDf.selectExpr("ST_NRings(geom)").take(1)[0][0]
assert expected == actual
+ def test_trangulatePolygon(self):
+ baseDf = self.spark.sql("SELECT ST_GeomFromWKT('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 5, 5 8, 8 8, 8 5, 5 5))') as poly")
+ actual = baseDf.selectExpr("ST_AsText(ST_TriangulatePolygon(poly))").take(1)[0][0]
+ expected = "GEOMETRYCOLLECTION (POLYGON ((0 0, 0 10, 5 5, 0 0)), POLYGON ((5 8, 5 5, 0 10, 5 8)), POLYGON ((10 0, 0 0, 5 5, 10 0)), POLYGON ((10 10, 5 8, 0 10, 10 10)), POLYGON ((10 0, 5 5, 8 5, 10 0)), POLYGON ((5 8, 10 10, 8 8, 5 8)), POLYGON ((10 10, 10 0, 8 5, 10 10)), POLYGON ((8 5, 8 8, 10 10, 8 5)))"
+ assert actual == expected
+
def test_translate(self):
expected = "POLYGON ((3 5, 3 6, 4 6, 4 5, 3 5))"
actual_df = self.spark.sql(
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 805527286..a83645497 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
@@ -1114,6 +1114,15 @@ public class TestFunctions extends TestBase {
);
}
+ @Test
+ public void test_ST_TriangulatePolygon() {
+ registerUDF("ST_TriangulatePolygon", byte[].class);
+ verifySqlSingleRes(
+ "SELECT sedona.ST_AsText(sedona.ST_TriangulatePolygon(sedona.ST_GeomFromWKT('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 5, 5 8, 8 8, 8 5, 5 5))')))",
+ "GEOMETRYCOLLECTION (POLYGON ((0 0, 0 10, 5 5, 0 0)), POLYGON ((5 8, 5 5, 0 10, 5 8)), POLYGON ((10 0, 0 0, 5 5, 10 0)), POLYGON ((10 10, 5 8, 0 10, 10 10)), POLYGON ((10 0, 5 5, 8 5, 10 0)), POLYGON ((5 8, 10 10, 8 8, 5 8)), POLYGON ((10 10, 10 0, 8 5, 10 10)), POLYGON ((8 5, 8 8, 10 10, 8 5)))"
+ );
+ }
+
@Test
public void test_ST_Translate() {
registerUDF("ST_Translate", byte[].class, double.class, double.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 ef3b385c7..299cbcdc9 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
@@ -1073,6 +1073,15 @@ public class TestFunctionsV2
);
}
+ @Test
+ public void test_ST_TriangulatePolygon() {
+ registerUDFV2("ST_TriangulatePolygon", String.class);
+ verifySqlSingleRes(
+ "SELECT ST_AsText(sedona.ST_TriangulatePolygon(ST_GeomFromWKT('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 5, 5 8, 8 8, 8 5, 5 5))')))",
+ "GEOMETRYCOLLECTION(POLYGON((0 0,0 10,5 5,0 0)),POLYGON((5 8,5 5,0 10,5 8)),POLYGON((10 0,0 0,5 5,10 0)),POLYGON((10 10,5 8,0 10,10 10)),POLYGON((10 0,5 5,8 5,10 0)),POLYGON((5 8,10 10,8 8,5 8)),POLYGON((10 10,10 0,8 5,10 10)),POLYGON((8 5,8 8,10 10,8 5)))"
+ );
+ }
+
@Test
public void test_ST_Translate() {
registerUDFV2("ST_Translate", String.class, double.class, double.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 efd8fa786..c5f8b362c 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
@@ -1432,6 +1432,15 @@ public class UDFs {
);
}
+ @UDFAnnotations.ParamMeta(argNames = {"geom"})
+ public static byte[] ST_TriangulatePolygon(byte[] geom) {
+ return GeometrySerde.serialize(
+ Functions.triangulatePolygon(
+ GeometrySerde.deserialize(geom)
+ )
+ );
+ }
+
@UDFAnnotations.ParamMeta(argNames = {"geom", "deltaX", "deltaY"})
public static byte[] ST_Translate(byte[] geom, double deltaX, double deltaY) {
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 2374b2652..08bad21ec 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
@@ -1258,6 +1258,15 @@ public class UDFsV2
);
}
+ @UDFAnnotations.ParamMeta(argNames = {"geom"}, argTypes = {"Geometry"}, returnTypes = "Geometry")
+ public static String ST_TriangulatePolygon(String geom) {
+ return GeometrySerde.serGeoJson(
+ Functions.triangulatePolygon(
+ GeometrySerde.deserGeoJson(geom)
+ )
+ );
+ }
+
@UDFAnnotations.ParamMeta(argNames = {"geom", "deltaX", "deltaY"}, argTypes = {"Geometry", "double", "double"}, returnTypes = "Geometry")
public static String ST_Translate(String geom, double deltaX, double deltaY) {
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 a70dd0646..988a536cb 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
@@ -179,6 +179,7 @@ object Catalog {
function[ST_Force3D](0.0),
function[ST_NRings](),
function[ST_Translate](0.0),
+ function[ST_TriangulatePolygon](),
function[ST_VoronoiPolygons](0.0, null),
function[ST_FrechetDistance](),
function[ST_Affine](),
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 b1e01ee87..d4f8cd405 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
@@ -1173,6 +1173,13 @@ case class ST_Translate(inputExpressions: Seq[Expression])
}
}
+case class ST_TriangulatePolygon(inputExpressions: Seq[Expression])
+ extends InferredExpression(Functions.triangulatePolygon _) with FoldableExpression {
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
+ copy(inputExpressions = newChildren)
+ }
+}
+
case class ST_VoronoiPolygons(inputExpressions: Seq[Expression])
extends InferredExpression(nullTolerantInferrableFunction3(FunctionsGeoTools.voronoiPolygons)) with FoldableExpression {
protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
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 117fb8cb3..cbeec10dc 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
@@ -418,6 +418,9 @@ object st_functions extends DataFrameAPI {
def ST_Translate(geometry: String, deltaX: Double, deltaY: Double): Column = wrapExpression[ST_Translate](geometry, deltaX, deltaY, 0.0)
+ def ST_TriangulatePolygon(geom: Column): Column = wrapExpression[ST_TriangulatePolygon](geom)
+ def ST_TriangulatePolygon(geom: String): Column = wrapExpression[ST_TriangulatePolygon](geom)
+
def ST_VoronoiPolygons(geometry: Column, tolerance : Column, extendTo: Column): Column = wrapExpression[ST_VoronoiPolygons](geometry, tolerance, extendTo)
def ST_VoronoiPolygons(geometry: String, tolerance : Double, extendTo: String): Column = wrapExpression[ST_VoronoiPolygons](geometry, tolerance, extendTo)
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 e1f7975ee..01129a4fa 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
@@ -1218,6 +1218,13 @@ class dataFrameAPITestScala extends TestBaseScala {
assertEquals(expectedGeomDefaultValue, wktWriter.write(actualGeomDefaultValue))
}
+ it("Passed ST_TriangulatePolygon") {
+ val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 5, 5 8, 8 8, 8 5, 5 5))') as poly")
+ val actual = baseDf.select(ST_AsText(ST_TriangulatePolygon("poly"))).first().getString(0)
+ val expected = "GEOMETRYCOLLECTION (POLYGON ((0 0, 0 10, 5 5, 0 0)), POLYGON ((5 8, 5 5, 0 10, 5 8)), POLYGON ((10 0, 0 0, 5 5, 10 0)), POLYGON ((10 10, 5 8, 0 10, 10 10)), POLYGON ((10 0, 5 5, 8 5, 10 0)), POLYGON ((5 8, 10 10, 8 8, 5 8)), POLYGON ((10 10, 10 0, 8 5, 10 10)), POLYGON ((8 5, 8 8, 10 10, 8 5)))"
+ assertEquals(expected, actual)
+ }
+
it("Passed ST_ForceRHR") {
val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35),(30 20, 20 15, 20 25, 30 20))') AS poly")
val actual = baseDf.select(ST_AsText(ST_ForceRHR("poly"))).take(1)(0).get(0).asInstanceOf[String]
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 0bbeed2ca..2b19744f5 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
@@ -232,6 +232,13 @@ class functionTestScala extends TestBaseScala with Matchers with GeometrySample
assert(functionDf.take(1)(0).get(0).asInstanceOf[Double].equals(expected))
}
+ it("Passed ST_TriangulatePolygon") {
+ val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (5 5, 5 8, 8 8, 8 5, 5 5))') as poly")
+ val actual = baseDf.selectExpr("ST_AsText(ST_TriangulatePolygon(poly))").first().getString(0)
+ val expected = "GEOMETRYCOLLECTION (POLYGON ((0 0, 0 10, 5 5, 0 0)), POLYGON ((5 8, 5 5, 0 10, 5 8)), POLYGON ((10 0, 0 0, 5 5, 10 0)), POLYGON ((10 10, 5 8, 0 10, 10 10)), POLYGON ((10 0, 5 5, 8 5, 10 0)), POLYGON ((5 8, 10 10, 8 8, 5 8)), POLYGON ((10 10, 10 0, 8 5, 10 10)), POLYGON ((8 5, 8 8, 10 10, 8 5)))"
+ assert(expected.equals(actual))
+ }
+
it("Passed ST_Transform") {
var point = "POINT (120 60)"
val transformedResult = sparkSession.sql(s"""select ST_Transform(ST_geomFromWKT('$point'),'EPSG:4326', 'EPSG:3857', false)""").rdd.map(row => row.getAs[Geometry](0)).collect()(0)