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 3fe212fd2 [SEDONA-601] Add ST_DelaunayTriangles (#1470)
3fe212fd2 is described below
commit 3fe212fd23834764ff51cac10b6e8ddc38111286
Author: Jia Yu <[email protected]>
AuthorDate: Fri Jun 7 15:08:12 2024 -0700
[SEDONA-601] Add ST_DelaunayTriangles (#1470)
* [TASK-44] Add ST_DelaunayTriangles (#200)
* temp commit
* docs: add docs for all 3 engines
* chore: port to snowflake
* fix: snowflake tests
* fix: snowflake tests
* Update versions
---------
Co-authored-by: Furqaan Khan <[email protected]>
---
.../java/org/apache/sedona/common/Functions.java | 38 +++++++++++++++++-----
.../org/apache/sedona/common/FunctionsTest.java | 19 +++++++++++
docs/api/flink/Function.md | 33 +++++++++++++++++++
docs/api/snowflake/vector-data/Function.md | 31 ++++++++++++++++++
docs/api/sql/Function.md | 33 +++++++++++++++++++
.../main/java/org/apache/sedona/flink/Catalog.java | 1 +
.../apache/sedona/flink/expressions/Functions.java | 23 +++++++++++++
.../java/org/apache/sedona/flink/FunctionTest.java | 16 +++++++++
python/sedona/sql/st_functions.py | 24 ++++++++++++++
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 | 10 ++++++
.../org/apache/sedona/snowflake/snowsql/UDFs.java | 29 +++++++++++++++++
.../apache/sedona/snowflake/snowsql/UDFsV2.java | 29 +++++++++++++++++
.../scala/org/apache/sedona/sql/UDF/Catalog.scala | 1 +
.../sql/sedona_sql/expressions/Functions.scala | 9 +++++
.../sql/sedona_sql/expressions/st_functions.scala | 8 +++++
.../apache/sedona/sql/dataFrameAPITestScala.scala | 15 +++++++++
.../org/apache/sedona/sql/functionTestScala.scala | 15 +++++++++
20 files changed, 343 insertions(+), 8 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 09f083804..33dd033c1 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -48,6 +48,7 @@ import org.locationtech.jts.precision.MinimumClearance;
import org.locationtech.jts.simplify.PolygonHullSimplifier;
import org.locationtech.jts.simplify.TopologyPreservingSimplifier;
import org.locationtech.jts.simplify.VWSimplifier;
+import org.locationtech.jts.triangulate.DelaunayTriangulationBuilder;
import
org.locationtech.jts.triangulate.polygon.ConstrainedDelaunayTriangulator;
import org.wololo.jts2geojson.GeoJSONWriter;
@@ -403,7 +404,7 @@ public class Functions {
Coordinate[] points = geometry.getCoordinates();
double min = Double.MAX_VALUE;
for(int i=0; i < points.length; i++){
- if(java.lang.Double.isNaN(points[i].getM()))
+ if(Double.isNaN(points[i].getM()))
continue;
min = Math.min(points[i].getM(), min);
}
@@ -414,7 +415,7 @@ public class Functions {
Coordinate[] points = geometry.getCoordinates();
double max = - Double.MAX_VALUE;
for (int i=0; i < points.length; i++) {
- if(java.lang.Double.isNaN(points[i].getM()))
+ if(Double.isNaN(points[i].getM()))
continue;
max = Math.max(points[i].getM(), max);
}
@@ -461,7 +462,7 @@ public class Functions {
Coordinate[] points = geometry.getCoordinates();
double max = - Double.MAX_VALUE;
for (int i=0; i < points.length; i++) {
- if(java.lang.Double.isNaN(points[i].getZ()))
+ if(Double.isNaN(points[i].getZ()))
continue;
max = Math.max(points[i].getZ(), max);
}
@@ -472,7 +473,7 @@ public class Functions {
Coordinate[] points = geometry.getCoordinates();
double min = Double.MAX_VALUE;
for(int i=0; i < points.length; i++){
- if(java.lang.Double.isNaN(points[i].getZ()))
+ if(Double.isNaN(points[i].getZ()))
continue;
min = Math.min(points[i].getZ(), min);
}
@@ -590,13 +591,13 @@ public class Functions {
Double y_cord = geom.getY();
Double z_cord = geom.getZ();
Double m_cord = geom.getM();
- if(!java.lang.Double.isNaN(x_cord))
+ if(!Double.isNaN(x_cord))
count_dimension++;
- if(!java.lang.Double.isNaN(y_cord))
+ if(!Double.isNaN(y_cord))
count_dimension++;
- if(!java.lang.Double.isNaN(z_cord))
+ if(!Double.isNaN(z_cord))
count_dimension++;
- if(!java.lang.Double.isNaN(m_cord))
+ if(!Double.isNaN(m_cord))
count_dimension++;
return count_dimension;
}
@@ -762,6 +763,27 @@ public class Functions {
}
}
+ public static Geometry delaunayTriangle(Geometry geometry) {
+ return delaunayTriangle(geometry, 0.0, 0);
+ }
+
+ public static Geometry delaunayTriangle(Geometry geometry, double
tolerance) {
+ return delaunayTriangle(geometry, tolerance, 0);
+ }
+
+ public static Geometry delaunayTriangle(Geometry geometry, double
tolerance, int flag) {
+ DelaunayTriangulationBuilder dTBuilder = new
DelaunayTriangulationBuilder();
+ dTBuilder.setSites(geometry);
+ dTBuilder.setTolerance(tolerance);
+ if (flag == 0) {
+ return dTBuilder.getTriangles(geometry.getFactory());
+ } else if (flag == 1) {
+ return dTBuilder.getEdges(geometry.getFactory());
+ } else {
+ throw new IllegalArgumentException("Select a valid flag option (0
or 1).");
+ }
+ }
+
public static int zmFlag(Geometry geom) {
Coordinate coords = geom.getCoordinate();
boolean hasZ = !Double.isNaN(coords.getZ());
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 b157c3ab9..7c90ae320 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -1286,6 +1286,25 @@ public class FunctionsTest extends TestBase {
assertEquals(expected4, result4);
}
+ @Test
+ public void delaunayTriangles() throws ParseException {
+ Geometry poly = Constructors.geomFromEWKT("POLYGON((175 150, 20 40, 50
60, 125 100, 175 150))");
+ Geometry point = Constructors.geomFromEWKT("POINT (110 170)");
+ Geometry combined = Functions.union(poly, point);
+ String actual = Functions.delaunayTriangle(combined).toText();
+ String expected = "GEOMETRYCOLLECTION (POLYGON ((20 40, 125 100, 50
60, 20 40)), POLYGON ((20 40, 50 60, 110 170, 20 40)), POLYGON ((110 170, 50
60, 125 100, 110 170)), POLYGON ((110 170, 125 100, 175 150, 110 170)))";
+ assertEquals(expected, actual);
+
+ poly = Constructors.geomFromEWKT("MULTIPOLYGON (((10 10, 10 20, 20 20,
20 10, 10 10)),((25 10, 25 20, 35 20, 35 10, 25 10)))");
+ actual = Functions.delaunayTriangle(poly, 20).toText();
+ expected = "GEOMETRYCOLLECTION (POLYGON ((10 20, 10 10, 35 10, 10
20)))";
+ assertEquals(expected, actual);
+
+ actual = Functions.delaunayTriangle(poly, 0, 1).toText();
+ expected = "MULTILINESTRING ((25 20, 35 20), (20 20, 25 20), (10 20,
20 20), (10 10, 10 20), (10 10, 20 10), (20 10, 25 10), (25 10, 35 10), (35 10,
35 20), (25 20, 35 10), (25 10, 25 20), (20 20, 25 10), (20 10, 20 20), (10 20,
20 10))";
+ assertEquals(expected, actual);
+ }
+
@Test
public void spheroidLength() {
Point point = GEOMETRY_FACTORY.createPoint(new Coordinate(90, 0));
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index 4c9195fbd..3cc6d415c 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -1055,6 +1055,39 @@ Output:
11.309932474020195
```
+## ST_DelaunayTriangles
+
+Introduction: This function computes the [Delaunay
triangulation](https://en.wikipedia.org/wiki/Delaunay_triangulation) for the
set of vertices in the input geometry. An optional `tolerance` parameter allows
snapping nearby input vertices together prior to triangulation and can improve
robustness in certain scenarios by handling near-coincident vertices. The
default for `tolerance` is 0. The Delaunay triangulation geometry is bounded
by the convex hull of the input vertex set.
+
+The output geometry representation depends on the provided `flag`:
+
+- `0` - a GeometryCollection of triangular Polygons (default option)
+- `1` - a MultiLinestring of the edges of the triangulation
+
+Format:
+
+`ST_DelaunayTriangles(geometry: Geometry)`
+
+`ST_DelaunayTriangles(geometry: Geometry, tolerance: Double)`
+
+`ST_DelaunayTriangles(geometry: Geometry, tolerance: Double, flag: Integer)`
+
+Since: `v1.6.1`
+
+SQL Example
+
+```sql
+SELECT ST_DelaunayTriangles(
+ ST_GeomFromWKT('POLYGON ((10 10, 15 30, 20 25, 25 35, 30 20, 40 30, 50
10, 45 5, 35 15, 30 5, 25 15, 20 10, 15 20, 10 10))')
+)
+```
+
+Output:
+
+```
+GEOMETRYCOLLECTION (POLYGON ((15 30, 10 10, 15 20, 15 30)), POLYGON ((15 30,
15 20, 20 25, 15 30)), POLYGON ((15 30, 20 25, 25 35, 15 30)), POLYGON ((25 35,
20 25, 30 20, 25 35)), POLYGON ((25 35, 30 20, 40 30, 25 35)), POLYGON ((40 30,
30 20, 35 15, 40 30)), POLYGON ((40 30, 35 15, 50 10, 40 30)), POLYGON ((50 10,
35 15, 45 5, 50 10)), POLYGON ((30 5, 45 5, 35 15, 30 5)), POLYGON ((30 5, 35
15, 25 15, 30 5)), POLYGON ((30 5, 25 15, 20 10, 30 5)), POLYGON ((30 5, 20 10,
10 10, 30 5)), PO [...]
+```
+
## ST_Difference
Introduction: Return the difference between geometry A and B (return part of
geometry A that does not intersect geometry B)
diff --git a/docs/api/snowflake/vector-data/Function.md
b/docs/api/snowflake/vector-data/Function.md
index 21997d894..ba4574d64 100644
--- a/docs/api/snowflake/vector-data/Function.md
+++ b/docs/api/snowflake/vector-data/Function.md
@@ -750,6 +750,37 @@ Output:
11.309932474020195
```
+## ST_DelaunayTriangles
+
+Introduction: This function computes the [Delaunay
triangulation](https://en.wikipedia.org/wiki/Delaunay_triangulation) for the
set of vertices in the input geometry. An optional `tolerance` parameter allows
snapping nearby input vertices together prior to triangulation and can improve
robustness in certain scenarios by handling near-coincident vertices. The
default for `tolerance` is 0. The Delaunay triangulation geometry is bounded
by the convex hull of the input vertex set.
+
+The output geometry representation depends on the provided `flag`:
+
+- `0` - a GeometryCollection of triangular Polygons (default option)
+- `1` - a MultiLinestring of the edges of the triangulation
+
+Format:
+
+`ST_DelaunayTriangles(geometry: Geometry)`
+
+`ST_DelaunayTriangles(geometry: Geometry, tolerance: Double)`
+
+`ST_DelaunayTriangles(geometry: Geometry, tolerance: Double, flag: Integer)`
+
+SQL Example
+
+```sql
+SELECT ST_DelaunayTriangles(
+ ST_GeomFromWKT('POLYGON ((10 10, 15 30, 20 25, 25 35, 30 20, 40 30, 50
10, 45 5, 35 15, 30 5, 25 15, 20 10, 15 20, 10 10))')
+)
+```
+
+Output:
+
+```
+GEOMETRYCOLLECTION (POLYGON ((15 30, 10 10, 15 20, 15 30)), POLYGON ((15 30,
15 20, 20 25, 15 30)), POLYGON ((15 30, 20 25, 25 35, 15 30)), POLYGON ((25 35,
20 25, 30 20, 25 35)), POLYGON ((25 35, 30 20, 40 30, 25 35)), POLYGON ((40 30,
30 20, 35 15, 40 30)), POLYGON ((40 30, 35 15, 50 10, 40 30)), POLYGON ((50 10,
35 15, 45 5, 50 10)), POLYGON ((30 5, 45 5, 35 15, 30 5)), POLYGON ((30 5, 35
15, 25 15, 30 5)), POLYGON ((30 5, 25 15, 20 10, 30 5)), POLYGON ((30 5, 20 10,
10 10, 30 5)), PO [...]
+```
+
## ST_Difference
Introduction: Return the difference between geometry A and B (return part of
geometry A that does not intersect geometry B)
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index e4d36ef90..c9beecc14 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -958,6 +958,39 @@ Output:
11.309932474020195
```
+## ST_DelaunayTriangles
+
+Introduction: This function computes the [Delaunay
triangulation](https://en.wikipedia.org/wiki/Delaunay_triangulation) for the
set of vertices in the input geometry. An optional `tolerance` parameter allows
snapping nearby input vertices together prior to triangulation and can improve
robustness in certain scenarios by handling near-coincident vertices. The
default for `tolerance` is 0. The Delaunay triangulation geometry is bounded
by the convex hull of the input vertex set.
+
+The output geometry representation depends on the provided `flag`:
+
+- `0` - a GeometryCollection of triangular Polygons (default option)
+- `1` - a MultiLinestring of the edges of the triangulation
+
+Format:
+
+`ST_DelaunayTriangles(geometry: Geometry)`
+
+`ST_DelaunayTriangles(geometry: Geometry, tolerance: Double)`
+
+`ST_DelaunayTriangles(geometry: Geometry, tolerance: Double, flag: Integer)`
+
+Since: `v1.6.1`
+
+SQL Example
+
+```sql
+SELECT ST_DelaunayTriangles(
+ ST_GeomFromWKT('POLYGON ((10 10, 15 30, 20 25, 25 35, 30 20, 40 30, 50
10, 45 5, 35 15, 30 5, 25 15, 20 10, 15 20, 10 10))')
+)
+```
+
+Output:
+
+```
+GEOMETRYCOLLECTION (POLYGON ((15 30, 10 10, 15 20, 15 30)), POLYGON ((15 30,
15 20, 20 25, 15 30)), POLYGON ((15 30, 20 25, 25 35, 15 30)), POLYGON ((25 35,
20 25, 30 20, 25 35)), POLYGON ((25 35, 30 20, 40 30, 25 35)), POLYGON ((40 30,
30 20, 35 15, 40 30)), POLYGON ((40 30, 35 15, 50 10, 40 30)), POLYGON ((50 10,
35 15, 45 5, 50 10)), POLYGON ((30 5, 45 5, 35 15, 30 5)), POLYGON ((30 5, 35
15, 25 15, 30 5)), POLYGON ((30 5, 25 15, 20 10, 30 5)), POLYGON ((30 5, 20 10,
10 10, 30 5)), PO [...]
+```
+
## ST_Difference
Introduction: Return the difference between geometry A and B (return part of
geometry A that does not intersect geometry B)
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 785205c7e..c744a1655 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -78,6 +78,7 @@ public class Catalog {
new Functions.ST_H3ToGeom(),
new Functions.ST_Dump(),
new Functions.ST_DumpPoints(),
+ new Functions.ST_DelaunayTriangles(),
new Functions.ST_EndPoint(),
new Functions.ST_GeometryType(),
new Functions.ST_Intersection(),
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 b1a09c6f6..5082c4c90 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
@@ -1437,6 +1437,29 @@ public class Functions {
}
}
+ public static class ST_DelaunayTriangles 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,
+ @DataTypeHint(value = "Double") Double tolerance,
+ @DataTypeHint(value = "Integer") Integer flag) {
+ Geometry geometry = (Geometry) o;
+ return
org.apache.sedona.common.Functions.delaunayTriangle(geometry, tolerance, flag);
+ }
+
+ @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,
+ @DataTypeHint(value = "Double") Double tolerance)
{
+ Geometry geometry = (Geometry) o;
+ return
org.apache.sedona.common.Functions.delaunayTriangle(geometry, tolerance);
+ }
+
+ @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.delaunayTriangle(geometry);
+ }
+ }
+
public static class ST_IsValidReason extends ScalarFunction {
@DataTypeHint("String")
public String 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 8d305a839..045a96c99 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -1579,6 +1579,22 @@ public class FunctionTest extends TestBase{
}
+ @Test
+ public void testDelaunayTriangle() {
+ Table polyTable = tableEnv.sqlQuery("SELECT
ST_GeomFromWKT('MULTIPOLYGON (((10 10, 10 20, 20 20, 20 10, 10 10)),((25 10, 25
20, 35 20, 35 10, 25 10)))') AS geom");
+ String actual = ((Geometry)
first(polyTable.select(call(Functions.ST_DelaunayTriangles.class.getSimpleName(),
$("geom")))).getField(0)).toText();
+ String expected = "GEOMETRYCOLLECTION (POLYGON ((10 20, 10 10, 20 10,
10 20)), POLYGON ((10 20, 20 10, 20 20, 10 20)), POLYGON ((20 20, 20 10, 25 10,
20 20)), POLYGON ((20 20, 25 10, 25 20, 20 20)), POLYGON ((25 20, 25 10, 35 10,
25 20)), POLYGON ((25 20, 35 10, 35 20, 25 20)))";
+ assertEquals(expected, actual);
+
+ actual = ((Geometry)
first(polyTable.select(call(Functions.ST_DelaunayTriangles.class.getSimpleName(),
$("geom"), 20))).getField(0)).toText();
+ expected = "GEOMETRYCOLLECTION (POLYGON ((10 20, 10 10, 35 10, 10
20)))";
+ assertEquals(expected, actual);
+
+ actual = ((Geometry)
first(polyTable.select(call(Functions.ST_DelaunayTriangles.class.getSimpleName(),
$("geom"), 20, 1))).getField(0)).toText();
+ expected = "MULTILINESTRING ((10 20, 35 10), (10 10, 10 20), (10 10,
35 10))";
+ assertEquals(expected, actual);
+ }
+
@Test
public void testHausdorffDistance() {
Table polyTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('POINT (0.0
1.0)') AS g1, ST_GeomFromWKT('LINESTRING (0 0, 1 0, 2 0, 3 0, 4 0, 5 0)') AS
g2");
diff --git a/python/sedona/sql/st_functions.py
b/python/sedona/sql/st_functions.py
index 27577653c..4b1829c72 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -1849,6 +1849,30 @@ def ST_Degrees(angleInRadian: Union[ColumnOrName,
float]) -> Column:
:return: Angle in Degrees
"""
return _call_st_function("ST_Degrees", angleInRadian)
+
+@validate_argument_types
+def ST_DelaunayTriangles(geometry: ColumnOrName, tolerance:
Optional[Union[ColumnOrName, float]] = None, flag: Optional[Union[ColumnOrName,
int]] = None) -> Column:
+ """
+ Computes the Delaunay Triangles of the vertices of the input geometry.
+
+ :param geometry: Input geometry
+ :type geometry: ColumnOrName
+ :param tolerance:
+ :type tolerance: ColumnOrName or float
+ :param flag: Selects the output type
+ :type flag: ColumnOrName or int
+ :return: Delaunay triangles of the input geometry
+ :rtype: ColumnOrName
+ """
+
+ if flag is None and tolerance is None:
+ args = (geometry)
+ elif flag is None:
+ args = (geometry, tolerance)
+ else:
+ args = (geometry, tolerance, flag)
+ return _call_st_function("ST_DelaunayTriangles", args)
+
@validate_argument_types
def ST_HausdorffDistance(g1: ColumnOrName, g2: ColumnOrName, densityFrac:
Optional[Union[ColumnOrName, float]] = -1) -> Column:
"""
diff --git a/python/tests/sql/test_dataframe_api.py
b/python/tests/sql/test_dataframe_api.py
index 7c7b9276b..d57c3b466 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -118,6 +118,7 @@ test_configurations = [
(stf.ST_DistanceSpheroid, ("point", "point"), "point_geom", "", 0.0),
(stf.ST_DistanceSphere, ("point", "point"), "point_geom", "", 0.0),
(stf.ST_DistanceSphere, ("point", "point", 6378137.0), "point_geom", "",
0.0),
+ (stf.ST_DelaunayTriangles, ("multipoint", ), "multipoint_geom", "",
"GEOMETRYCOLLECTION (POLYGON ((10 40, 20 20, 40 30, 10 40)), POLYGON ((40 30,
20 20, 30 10, 40 30)))"),
(stf.ST_Dump, ("geom",), "multipoint", "", ["POINT (0 0)", "POINT (1 1)"]),
(stf.ST_DumpPoints, ("line",), "linestring_geom", "", ["POINT (0 0)",
"POINT (1 0)", "POINT (2 0)", "POINT (3 0)", "POINT (4 0)", "POINT (5 0)"]),
(stf.ST_EndPoint, ("line",), "linestring_geom", "", "POINT (5 0)"),
@@ -320,6 +321,7 @@ wrong_type_configurations = [
(stf.ST_Distance, ("", None)),
(stf.ST_Dump, (None,)),
(stf.ST_DumpPoints, (None,)),
+ (stf.ST_DelaunayTriangles, (None,)),
(stf.ST_EndPoint, (None,)),
(stf.ST_Envelope, (None,)),
(stf.ST_ExteriorRing, (None,)),
diff --git a/python/tests/sql/test_function.py
b/python/tests/sql/test_function.py
index e492d9477..3a8b00f58 100644
--- a/python/tests/sql/test_function.py
+++ b/python/tests/sql/test_function.py
@@ -420,6 +420,12 @@ class TestPredicateJoin(TestBase):
diff = self.spark.sql("select ST_Difference(a,b) from test_diff")
assert diff.take(1)[0][0].wkt == "POLYGON EMPTY"
+ def test_st_delaunay_triangles(self):
+ baseDf = self.spark.sql("SELECT ST_GeomFromWKT('MULTIPOLYGON (((10 10,
10 20, 20 20, 20 10, 10 10)),((25 10, 25 20, 35 20, 35 10, 25 10)))') AS geom")
+ actual =
baseDf.selectExpr("ST_DelaunayTriangles(geom)").take(1)[0][0].wkt
+ expected = "GEOMETRYCOLLECTION (POLYGON ((10 20, 10 10, 20 10, 10
20)), POLYGON ((10 20, 20 10, 20 20, 10 20)), POLYGON ((20 20, 20 10, 25 10, 20
20)), POLYGON ((20 20, 25 10, 25 20, 20 20)), POLYGON ((25 20, 25 10, 35 10, 25
20)), POLYGON ((25 20, 35 10, 35 20, 25 20)))"
+ assert expected == actual
+
def test_st_sym_difference_part_of_right_overlaps_left(self):
test_table = self.spark.sql(
"select ST_GeomFromWKT('POLYGON ((-1 -1, 1 -1, 1 1, -1 1, -1
-1))') as a,ST_GeomFromWKT('POLYGON ((0 -2, 2 -2, 2 0, 0 0, 0 -2))') as b")
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 adf91db89..707ff1036 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
@@ -315,6 +315,15 @@ public class TestFunctions extends TestBase {
);
}
+ @Test
+ public void test_ST_DelaunayTriangles() {
+ registerUDF("ST_DelaunayTriangles", byte[].class);
+ verifySqlSingleRes(
+ "select
sedona.ST_AsText(sedona.ST_DelaunayTriangles(sedona.ST_GeomFromText('POLYGON
((10 10, 15 30, 20 25, 25 35, 30 20, 40 30, 50 10, 45 5, 35 15, 30 5, 25 15, 20
10, 15 20, 10 10))')))",
+ "GEOMETRYCOLLECTION (POLYGON ((15 30, 10 10, 15 20, 15 30)),
POLYGON ((15 30, 15 20, 20 25, 15 30)), POLYGON ((15 30, 20 25, 25 35, 15 30)),
POLYGON ((25 35, 20 25, 30 20, 25 35)), POLYGON ((25 35, 30 20, 40 30, 25 35)),
POLYGON ((40 30, 30 20, 35 15, 40 30)), POLYGON ((40 30, 35 15, 50 10, 40 30)),
POLYGON ((50 10, 35 15, 45 5, 50 10)), POLYGON ((30 5, 45 5, 35 15, 30 5)),
POLYGON ((30 5, 35 15, 25 15, 30 5)), POLYGON ((30 5, 25 15, 20 10, 30 5)),
POLYGON ((30 5, 20 10, [...]
+ );
+ }
+
@Test
public void test_ST_Degrees() {
registerUDF("ST_Degrees", 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 4a19a14e4..20d9f5389 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
@@ -320,6 +320,16 @@ public class TestFunctionsV2
"POLYGON((0 -3,-3 -3,-3 3,0 3,0 -3))"
);
}
+
+ @Test
+ public void test_ST_DelaunayTriangles() {
+ registerUDFV2("ST_DelaunayTriangles", String.class);
+ verifySqlSingleRes(
+ "select
ST_AsText(sedona.ST_DelaunayTriangles(ST_GeomFromText('POLYGON ((10 10, 15 30,
20 25, 25 35, 30 20, 40 30, 50 10, 45 5, 35 15, 30 5, 25 15, 20 10, 15 20, 10
10))')))",
+ "GEOMETRYCOLLECTION(POLYGON((15 30,10 10,15 20,15
30)),POLYGON((15 30,15 20,20 25,15 30)),POLYGON((15 30,20 25,25 35,15
30)),POLYGON((25 35,20 25,30 20,25 35)),POLYGON((25 35,30 20,40 30,25
35)),POLYGON((40 30,30 20,35 15,40 30)),POLYGON((40 30,35 15,50 10,40
30)),POLYGON((50 10,35 15,45 5,50 10)),POLYGON((30 5,45 5,35 15,30
5)),POLYGON((30 5,35 15,25 15,30 5)),POLYGON((30 5,25 15,20 10,30
5)),POLYGON((30 5,20 10,10 10,30 5)),POLYGON((10 10,20 10,15 20,10
10)),POLYGON((15 [...]
+ );
+ }
+
@Test
public void test_ST_Dimension() {
registerUDFV2("ST_Dimension", String.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 8ed03b719..7b5a7f174 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
@@ -355,6 +355,35 @@ public class UDFs {
);
}
+ @UDFAnnotations.ParamMeta(argNames = {"geometry"})
+ public static byte[] ST_DelaunayTriangles(byte[] geometry) {
+ return GeometrySerde.serialize(
+ Functions.delaunayTriangle(
+ GeometrySerde.deserialize(geometry)
+ )
+ );
+ }
+
+ @UDFAnnotations.ParamMeta(argNames = {"geometry", "tolerance"})
+ public static byte[] ST_DelaunayTriangles(byte[] geometry, double
tolerance) {
+ return GeometrySerde.serialize(
+ Functions.delaunayTriangle(
+ GeometrySerde.deserialize(geometry),
+ tolerance
+ )
+ );
+ }
+
+ @UDFAnnotations.ParamMeta(argNames = {"geometry", "tolerance", "flag"})
+ public static byte[] ST_DelaunayTriangles(byte[] geometry, double
tolerance, int flag) {
+ return GeometrySerde.serialize(
+ Functions.delaunayTriangle(
+ GeometrySerde.deserialize(geometry),
+ tolerance, flag
+ )
+ );
+ }
+
@UDFAnnotations.ParamMeta(argNames = {"geometry"})
public static Integer ST_Dimension(byte[] geometry) {
return Functions.dimension(
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 337cdb104..7d3107a57 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
@@ -354,6 +354,35 @@ public class UDFsV2
);
}
+ @UDFAnnotations.ParamMeta(argNames = {"geometry"}, argTypes =
{"Geometry"}, returnTypes = "Geometry")
+ public static String ST_DelaunayTriangles(String geometry) {
+ return GeometrySerde.serGeoJson(
+ Functions.delaunayTriangle(
+ GeometrySerde.deserGeoJson(geometry)
+ )
+ );
+ }
+
+ @UDFAnnotations.ParamMeta(argNames = {"geometry", "tolerance"}, argTypes =
{"Geometry", "double"}, returnTypes = "Geometry")
+ public static String ST_DelaunayTriangles(String geometry, double
tolerance) {
+ return GeometrySerde.serGeoJson(
+ Functions.delaunayTriangle(
+ GeometrySerde.deserGeoJson(geometry),
+ tolerance
+ )
+ );
+ }
+
+ @UDFAnnotations.ParamMeta(argNames = {"geometry", "tolerance", "flag"},
argTypes = {"Geometry", "double", "int"}, returnTypes = "Geometry")
+ public static String ST_DelaunayTriangles(String geometry, double
tolerance, int flag) {
+ return GeometrySerde.serGeoJson(
+ Functions.delaunayTriangle(
+ GeometrySerde.deserGeoJson(geometry),
+ tolerance, flag
+ )
+ );
+ }
+
@UDFAnnotations.ParamMeta(argNames = {"leftGeometry", "rightGeometry"},
argTypes = {"Geometry", "Geometry"}, returnTypes = "Geometry")
public static String ST_Difference(String leftGeometry, String
rightGeometry) {
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 425fd221d..364919521 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
@@ -217,6 +217,7 @@ object Catalog {
function[ST_BoundingDiagonal](),
function[ST_Angle](),
function[ST_Degrees](),
+ function[ST_DelaunayTriangles](),
function[ST_HausdorffDistance](-1),
function[ST_DWithin](),
function[ST_IsValidReason](),
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 f59d592ab..697bf6128 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
@@ -1399,6 +1399,15 @@ case class ST_Degrees(inputExpressions: Seq[Expression])
}
}
+case class ST_DelaunayTriangles(inputExpressions: Seq[Expression])
+ extends InferredExpression(inferrableFunction3(Functions.delaunayTriangle),
+ inferrableFunction2(Functions.delaunayTriangle),
+ inferrableFunction1(Functions.delaunayTriangle)) with FoldableExpression {
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) =
{
+ copy(inputExpressions = newChildren)
+ }
+}
+
/**
* Return the number of ddimensions in geometry.
*
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 2c8facd22..77fd8fa4e 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
@@ -539,6 +539,14 @@ object st_functions extends DataFrameAPI {
def ST_Degrees(angleInRadian: Column): Column =
wrapExpression[ST_Degrees](angleInRadian)
def ST_Degrees(angleInRadian: Double): Column =
wrapExpression[ST_Degrees](angleInRadian)
+
+ def ST_DelaunayTriangles(geometry: Column, tolerance: Column, flags:
Column): Column = wrapExpression[ST_DelaunayTriangles](geometry, tolerance,
flags)
+ def ST_DelaunayTriangles(geometry: String, tolerance: Double, flags:
Integer): Column = wrapExpression[ST_DelaunayTriangles](geometry, tolerance,
flags)
+ def ST_DelaunayTriangles(geometry: Column, tolerance: Column): Column =
wrapExpression[ST_DelaunayTriangles](geometry, tolerance)
+ def ST_DelaunayTriangles(geometry: String, tolerance: Double): Column =
wrapExpression[ST_DelaunayTriangles](geometry, tolerance)
+ def ST_DelaunayTriangles(geometry: Column): Column =
wrapExpression[ST_DelaunayTriangles](geometry)
+ def ST_DelaunayTriangles(geometry: String): Column =
wrapExpression[ST_DelaunayTriangles](geometry)
+
def ST_HausdorffDistance(g1: Column, g2: Column) =
wrapExpression[ST_HausdorffDistance](g1, g2, -1)
def ST_HausdorffDistance(g1: String, g2: String) =
wrapExpression[ST_HausdorffDistance](g1, g2, -1);
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 4bbb18b47..e22f3727b 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
@@ -1699,6 +1699,21 @@ class dataFrameAPITestScala extends TestBaseScala {
assertEquals(expectedDegrees, actualDegrees, 1e-9)
}
+ it("Should pass ST_DelaunayTriangles") {
+ val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('MULTIPOLYGON (((10
10, 10 20, 20 20, 20 10, 10 10)),((25 10, 25 20, 35 20, 35 10, 25 10)))') AS
geom")
+ var actual =
baseDf.select(ST_DelaunayTriangles("geom")).first().get(0).asInstanceOf[Geometry].toText
+ var expected = "GEOMETRYCOLLECTION (POLYGON ((10 20, 10 10, 20 10, 10
20)), POLYGON ((10 20, 20 10, 20 20, 10 20)), POLYGON ((20 20, 20 10, 25 10, 20
20)), POLYGON ((20 20, 25 10, 25 20, 20 20)), POLYGON ((25 20, 25 10, 35 10, 25
20)), POLYGON ((25 20, 35 10, 35 20, 25 20)))"
+ assertEquals(expected, actual)
+
+ actual = baseDf.select(ST_DelaunayTriangles("geom",
20)).first().get(0).asInstanceOf[Geometry].toText
+ expected = "GEOMETRYCOLLECTION (POLYGON ((10 20, 10 10, 35 10, 10 20)))"
+ assertEquals(expected, actual)
+
+ actual = baseDf.select(ST_DelaunayTriangles("geom", 20,
1)).first().get(0).asInstanceOf[Geometry].toText
+ expected = "MULTILINESTRING ((10 20, 35 10), (10 10, 10 20), (10 10, 35
10))"
+ assertEquals(expected, actual)
+ }
+
it("Passed ST_HausdorffDistance") {
val polyDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((1 2, 2
1, 2 0, 4 1, 1 2))') AS g1, " +
"ST_GeomFromWKT('MULTILINESTRING ((1 1, 2 1, 4 4, 5 5), (10 10, 11 11,
12 12, 14 14), (-11 -20, -11 -21, -15 -19))') AS g2")
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 9da42a057..ccec742fd 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
@@ -2545,6 +2545,21 @@ class functionTestScala extends TestBaseScala with
Matchers with GeometrySample
}
}
+ it("Should pass ST_DelaunayTriangles") {
+ val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('MULTIPOLYGON (((10
10, 10 20, 20 20, 20 10, 10 10)),((25 10, 25 20, 35 20, 35 10, 25 10)))') AS
geom")
+ var actual =
baseDf.selectExpr("ST_DelaunayTriangles(geom)").first().get(0).asInstanceOf[Geometry].toText
+ var expected = "GEOMETRYCOLLECTION (POLYGON ((10 20, 10 10, 20 10, 10
20)), POLYGON ((10 20, 20 10, 20 20, 10 20)), POLYGON ((20 20, 20 10, 25 10, 20
20)), POLYGON ((20 20, 25 10, 25 20, 20 20)), POLYGON ((25 20, 25 10, 35 10, 25
20)), POLYGON ((25 20, 35 10, 35 20, 25 20)))"
+ assertEquals(expected, actual)
+
+ actual = baseDf.selectExpr("ST_DelaunayTriangles(geom,
20)").first().get(0).asInstanceOf[Geometry].toText
+ expected = "GEOMETRYCOLLECTION (POLYGON ((10 20, 10 10, 35 10, 10 20)))"
+ assertEquals(expected, actual)
+
+ actual = baseDf.selectExpr("ST_DelaunayTriangles(geom, 20,
1)").first().get(0).asInstanceOf[Geometry].toText
+ expected = "MULTILINESTRING ((10 20, 35 10), (10 10, 10 20), (10 10, 35
10))"
+ assertEquals(expected, actual)
+ }
+
it ("should pass ST_Angle - 2 lines") {
val geomTestCases = Map(
("'LINESTRING (0 0, 1 1)'", "'LINESTRING (0 0, 3 2)'") ->
(0.19739555984988044, 11.309932474020195)