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 5279c36d1 [SEDONA-599] [SEDONA-600] Add ST_MinimumClearance,
ST_MinimumClearanceLine (#1469)
5279c36d1 is described below
commit 5279c36d1f76a981d95ca0790a7affa58ab86f05
Author: Jia Yu <[email protected]>
AuthorDate: Fri Jun 7 15:06:17 2024 -0700
[SEDONA-599] [SEDONA-600] Add ST_MinimumClearance, ST_MinimumClearanceLine
(#1469)
* [TASK-253] Add ST_MinimumClearance (#194)
* [TASK-209] Add ST_MinimumClearanceLine (#196)
* Update versions
---------
Co-authored-by: Furqaan Khan <[email protected]>
---
.../java/org/apache/sedona/common/Functions.java | 9 +++
.../org/apache/sedona/common/FunctionsTest.java | 66 ++++++++++++++++++++++
docs/api/flink/Function.md | 51 +++++++++++++++++
docs/api/snowflake/vector-data/Function.md | 47 +++++++++++++++
docs/api/sql/Function.md | 51 +++++++++++++++++
.../main/java/org/apache/sedona/flink/Catalog.java | 2 +
.../apache/sedona/flink/expressions/Functions.java | 16 ++++++
.../java/org/apache/sedona/flink/FunctionTest.java | 16 ++++++
python/sedona/sql/st_functions.py | 21 +++++++
python/tests/sql/test_dataframe_api.py | 4 ++
python/tests/sql/test_function.py | 10 ++++
.../sedona/snowflake/snowsql/TestFunctions.java | 18 ++++++
.../sedona/snowflake/snowsql/TestFunctionsV2.java | 18 ++++++
.../org/apache/sedona/snowflake/snowsql/UDFs.java | 16 ++++++
.../apache/sedona/snowflake/snowsql/UDFsV2.java | 16 ++++++
.../scala/org/apache/sedona/sql/UDF/Catalog.scala | 2 +
.../sql/sedona_sql/expressions/Functions.scala | 15 +++++
.../sql/sedona_sql/expressions/st_functions.scala | 6 ++
.../apache/sedona/sql/dataFrameAPITestScala.scala | 14 +++++
.../org/apache/sedona/sql/functionTestScala.scala | 14 +++++
20 files changed, 412 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 e2bf5c6ea..09f083804 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -44,6 +44,7 @@ import org.locationtech.jts.operation.valid.IsSimpleOp;
import org.locationtech.jts.operation.valid.IsValidOp;
import org.locationtech.jts.operation.valid.TopologyValidationError;
import org.locationtech.jts.precision.GeometryPrecisionReducer;
+import org.locationtech.jts.precision.MinimumClearance;
import org.locationtech.jts.simplify.PolygonHullSimplifier;
import org.locationtech.jts.simplify.TopologyPreservingSimplifier;
import org.locationtech.jts.simplify.VWSimplifier;
@@ -864,6 +865,14 @@ public class Functions {
return Pair.of(centre, radius);
}
+ public static double minimumClearance(Geometry geometry) {
+ return MinimumClearance.getDistance(geometry);
+ }
+
+ public static Geometry minimumClearanceLine(Geometry geometry) {
+ return MinimumClearance.getLine(geometry);
+ }
+
public static Geometry lineSubString(Geometry geom, double fromFraction,
double toFraction) {
double length = geom.getLength();
LengthIndexedLine indexedLine = new LengthIndexedLine(geom);
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 b7a79d1af..b157c3ab9 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -1679,6 +1679,72 @@ public class FunctionsTest extends TestBase {
assertEquals(7.071067,
Functions.minimumBoundingRadius(polygon).getRight(), 1e-6);
}
+ @Test
+ public void minimumClearance() throws ParseException {
+ Geometry geometry = Constructors.geomFromEWKT("POLYGON ((0 0, 1 0, 1
1, 0.5 3.2e-4, 0 0))");
+ double actual = Functions.minimumClearance(geometry);
+ double expected = 0.00032;
+ assertEquals(expected, actual, FP_TOLERANCE);
+
+ geometry = Constructors.geomFromEWKT("POLYGON ((10 10, 20 20, 20.1
20.1, 30 25, 40 30, 50 40, 40 50, 30 45, 20 40, 10 30, 10 10))");
+ actual = Functions.minimumClearance(geometry);
+ expected = 0.14142135623731153;
+ assertEquals(expected, actual, FP_TOLERANCE);
+
+ geometry = Constructors.geomFromEWKT("POLYGON ((65 18, 62 16, 64.5 16,
62 14, 65 14, 65 18))");
+ actual = Functions.minimumClearance(geometry);
+ expected = 0.5;
+ assertEquals(expected, actual, FP_TOLERANCE2);
+
+ geometry = Constructors.geomFromEWKT("POLYGON ((65.10498 18.625425,
62.182617 16.36231, 64.863281 16.40447, 62.006836 14.157882, 65.522461
14.008696, 65.10498 18.625425))");
+ actual = Functions.minimumClearance(geometry);
+ expected = 0.4407369162202361;
+ assertEquals(expected, actual, FP_TOLERANCE);
+
+ geometry = Constructors.geomFromEWKT("MULTIPOINT(10 10, 20 20)");
+ actual = Functions.minimumClearance(geometry);
+ expected = 14.142135623730951;
+ assertEquals(expected, actual, FP_TOLERANCE);
+
+ geometry = Constructors.geomFromEWKT("POINT(10 10)");
+ actual = Functions.minimumClearance(geometry);
+ expected = Double.MAX_VALUE;
+ assertEquals(expected, actual, FP_TOLERANCE2);
+ }
+
+ @Test
+ public void minimumClearanceLine() throws ParseException {
+ Geometry geometry = Constructors.geomFromEWKT("POLYGON ((0 0, 1 0, 1
1, 0.5 3.2e-4, 0 0))");
+ String actual = Functions.minimumClearanceLine(geometry).toText();
+ String expected = "LINESTRING (0.5 0.00032, 0.5 0)";
+ assertEquals(expected, actual);
+
+ geometry = Constructors.geomFromEWKT("POLYGON ((10 10, 20 20, 20.1
20.1, 30 25, 40 30, 50 40, 40 50, 30 45, 20 40, 10 30, 10 10))");
+ actual = Functions.minimumClearanceLine(geometry).toText();
+ expected = "LINESTRING (20 20, 20.1 20.1)";
+ assertEquals(expected, actual);
+
+ geometry = Constructors.geomFromEWKT("POLYGON ((65 18, 62 16, 64.5 16,
62 14, 65 14, 65 18))");
+ actual = Functions.minimumClearanceLine(geometry).toText();
+ expected = "LINESTRING (64.5 16, 65 16)";
+ assertEquals(expected, actual);
+
+ geometry = Constructors.geomFromEWKT("POLYGON ((65.10498 18.625425,
62.182617 16.36231, 64.863281 16.40447, 62.006836 14.157882, 65.522461
14.008696, 65.10498 18.625425))");
+ actual = Functions.minimumClearanceLine(geometry).toText();
+ expected = "LINESTRING (64.863281 16.40447, 65.30222689577225
16.44416294526772)";
+ assertEquals(expected, actual);
+
+ geometry = Constructors.geomFromEWKT("MULTIPOINT(10 10, 20 20)");
+ actual = Functions.minimumClearanceLine(geometry).toText();
+ expected = "LINESTRING (20 20, 10 10)";
+ assertEquals(expected, actual);
+
+ geometry = Constructors.geomFromEWKT("POINT(10 10)");
+ actual = Functions.minimumClearanceLine(geometry).toText();
+ expected = "LINESTRING EMPTY";
+ assertEquals(expected, actual);
+ }
+
@Test
public void nRingsPolygonOnlyExternal() throws Exception {
Polygon polygon = GEOMETRY_FACTORY.createPolygon(coordArray(1, 0, 1,
1, 2, 1, 2, 0, 1, 0));
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index 9ccc3a91c..4c9195fbd 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -2472,6 +2472,57 @@ Output:
36.05551275463989
```
+## ST_MinimumClearance
+
+Introduction: The minimum clearance is a metric that quantifies a geometry's
tolerance to changes in coordinate precision or vertex positions. It represents
the maximum distance by which vertices can be adjusted without introducing
invalidity to the geometry's structure. A larger minimum clearance value
indicates greater robustness against such perturbations.
+
+For a geometry with a minimum clearance of `x`, the following conditions hold:
+
+- No two distinct vertices are separated by a distance less than `x`.
+- No vertex lies within a distance `x` from any line segment it is not an
endpoint of.
+
+For geometries with no definable minimum clearance, such as single Point
geometries or MultiPoint geometries where all points occupy the same location,
the function returns `Double.MAX_VALUE`.
+
+Format: `ST_MinimumClearance(geometry: Geometry)`
+
+Since: `v1.6.1`
+
+SQL Example
+
+```sql
+SELECT ST_MinimumClearance(
+ ST_GeomFromWKT('POLYGON ((65 18, 62 16, 64.5 16, 62 14, 65 14, 65
18))')
+)
+```
+
+Output:
+
+```
+0.5
+```
+
+## ST_MinimumClearanceLine
+
+Introduction: This function returns a two-point LineString geometry
representing the minimum clearance distance of the input geometry. If the input
geometry does not have a defined minimum clearance, such as for single Points
or coincident MultiPoints, an empty LineString geometry is returned instead.
+
+Format: `ST_MinimumClearanceLine(geometry: Geometry)`
+
+Since: `v1.6.1`
+
+SQL Example:
+
+```sql
+SELECT ST_MinimumClearanceLine(
+ ST_GeomFromWKT('POLYGON ((65 18, 62 16, 64.5 16, 62 14, 65 14, 65
18))')
+)
+```
+
+Output:
+
+```
+LINESTRING (64.5 16, 65 16)
+```
+
## ST_MinimumBoundingCircle
Introduction: Returns the smallest circle polygon that contains a geometry.
The optional quadrantSegments parameter determines how many segments to use per
quadrant and the default number of segments is 48.
diff --git a/docs/api/snowflake/vector-data/Function.md
b/docs/api/snowflake/vector-data/Function.md
index 43e208727..21997d894 100644
--- a/docs/api/snowflake/vector-data/Function.md
+++ b/docs/api/snowflake/vector-data/Function.md
@@ -1786,6 +1786,53 @@ Output:
36.05551275463989
```
+## ST_MinimumClearance
+
+Introduction: The minimum clearance is a metric that quantifies a geometry's
tolerance to changes in coordinate precision or vertex positions. It represents
the maximum distance by which vertices can be adjusted without introducing
invalidity to the geometry's structure. A larger minimum clearance value
indicates greater robustness against such perturbations.
+
+For a geometry with a minimum clearance of `x`, the following conditions hold:
+
+- No two distinct vertices are separated by a distance less than `x`.
+- No vertex lies within a distance `x` from any line segment it is not an
endpoint of.
+
+For geometries with no definable minimum clearance, such as single Point
geometries or MultiPoint geometries where all points occupy the same location,
the function returns `Double.MAX_VALUE`.
+
+Format: `ST_MinimumClearance(geometry: Geometry)`
+
+SQL Example
+
+```sql
+SELECT ST_MinimumClearance(
+ ST_GeomFromWKT('POLYGON ((65 18, 62 16, 64.5 16, 62 14, 65 14, 65
18))')
+)
+```
+
+Output:
+
+```
+0.5
+```
+
+## ST_MinimumClearanceLine
+
+Introduction: This function returns a two-point LineString geometry
representing the minimum clearance distance of the input geometry. If the input
geometry does not have a defined minimum clearance, such as for single Points
or coincident MultiPoints, an empty LineString geometry is returned instead.
+
+Format: `ST_MinimumClearanceLine(geometry: Geometry)`
+
+SQL Example:
+
+```sql
+SELECT ST_MinimumClearanceLine(
+ ST_GeomFromWKT('POLYGON ((65 18, 62 16, 64.5 16, 62 14, 65 14, 65
18))')
+)
+```
+
+Output:
+
+```
+LINESTRING (64.5 16, 65 16)
+```
+
## ST_MinimumBoundingCircle
Introduction: Returns the smallest circle polygon that contains a geometry.
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index c842b5385..e4d36ef90 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -2484,6 +2484,57 @@ Output:
36.05551275463989
```
+## ST_MinimumClearance
+
+Introduction: The minimum clearance is a metric that quantifies a geometry's
tolerance to changes in coordinate precision or vertex positions. It represents
the maximum distance by which vertices can be adjusted without introducing
invalidity to the geometry's structure. A larger minimum clearance value
indicates greater robustness against such perturbations.
+
+For a geometry with a minimum clearance of `x`, the following conditions hold:
+
+- No two distinct vertices are separated by a distance less than `x`.
+- No vertex lies within a distance `x` from any line segment it is not an
endpoint of.
+
+For geometries with no definable minimum clearance, such as single Point
geometries or MultiPoint geometries where all points occupy the same location,
the function returns `Double.MAX_VALUE`.
+
+Format: `ST_MinimumClearance(geometry: Geometry)`
+
+Since: `v1.6.1`
+
+SQL Example
+
+```sql
+SELECT ST_MinimumClearance(
+ ST_GeomFromWKT('POLYGON ((65 18, 62 16, 64.5 16, 62 14, 65 14, 65
18))')
+)
+```
+
+Output:
+
+```
+0.5
+```
+
+## ST_MinimumClearanceLine
+
+Introduction: This function returns a two-point LineString geometry
representing the minimum clearance distance of the input geometry. If the input
geometry does not have a defined minimum clearance, such as for single Points
or coincident MultiPoints, an empty LineString geometry is returned instead.
+
+Format: `ST_MinimumClearanceLine(geometry: Geometry)`
+
+Since: `v1.6.1`
+
+SQL Example:
+
+```sql
+SELECT ST_MinimumClearanceLine(
+ ST_GeomFromWKT('POLYGON ((65 18, 62 16, 64.5 16, 62 14, 65 14, 65
18))')
+)
+```
+
+Output:
+
+```
+LINESTRING (64.5 16, 65 16)
+```
+
## ST_MinimumBoundingCircle
Introduction: Returns the smallest circle polygon that contains a geometry.
The optional quadrantSegments parameter determines how many segments to use per
quadrant and the default number of segments has been changed to 48 since v1.5.0.
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 197280738..785205c7e 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -149,6 +149,8 @@ public class Catalog {
new Functions.ST_MakePolygon(),
new Functions.ST_MakeValid(),
new Functions.ST_MaxDistance(),
+ new Functions.ST_MinimumClearance(),
+ new Functions.ST_MinimumClearanceLine(),
new Functions.ST_MinimumBoundingCircle(),
new Functions.ST_MinimumBoundingRadius(),
new Functions.ST_Multi(),
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 72d7d2c95..b1a09c6f6 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
@@ -912,6 +912,22 @@ public class Functions {
}
}
+ public static class ST_MinimumClearance extends ScalarFunction {
+ @DataTypeHint(value = "Double")
+ public Double eval(@DataTypeHint(value = "RAW", bridgedTo =
org.locationtech.jts.geom.Geometry.class) Object o) {
+ Geometry geometry = (Geometry) o;
+ return
org.apache.sedona.common.Functions.minimumClearance(geometry);
+ }
+ }
+
+ public static class ST_MinimumClearanceLine 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.minimumClearanceLine(geometry);
+ }
+ }
+
public static class ST_MinimumBoundingCircle 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 9e53a7495..8d305a839 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -1093,6 +1093,22 @@ public class FunctionTest extends TestBase{
assertEquals(expected, actual);
}
+ @Test
+ public void testMinimumClearance() {
+ Table table = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('POLYGON ((65
18, 62 16, 64.5 16, 62 14, 65 14, 65 18))') as geom");
+ Double actual = (Double)
first(table.select(call(Functions.ST_MinimumClearance.class.getSimpleName(),
$("geom")))).getField(0);
+ Double expected = 0.5;
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testMinimumClearanceLine() {
+ Table table = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('POLYGON ((65
18, 62 16, 64.5 16, 62 14, 65 14, 65 18))') as geom");
+ String actual = ((Geometry)
first(table.select(call(Functions.ST_MinimumClearanceLine.class.getSimpleName(),
$("geom")))).getField(0)).toText();
+ String expected = "LINESTRING (64.5 16, 65 16)";
+ assertEquals(expected, actual);
+ }
+
@Test
public void testMinimumBoundingCircle() {
Table table = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING (0
0, 1 0)') AS geom");
diff --git a/python/sedona/sql/st_functions.py
b/python/sedona/sql/st_functions.py
index 75b95c332..27577653c 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -1042,6 +1042,27 @@ def ST_MaxDistance(geom1: ColumnOrName, geom2:
ColumnOrName) -> Column:
"""
return _call_st_function("ST_MaxDistance", (geom1, geom2))
+@validate_argument_types
+def ST_MinimumClearance(geometry: ColumnOrName) -> Column:
+ """Calculate the minimum clearance between two vertices
+
+ :param geometry: Geometry column
+ :type geometry: ColumnOrName
+ :return: Minimum Clearance between the geometries
+ :rtype: Column
+ """
+ return _call_st_function("ST_MinimumClearance", geometry)
+
+@validate_argument_types
+def ST_MinimumClearanceLine(geometry: ColumnOrName) -> Column:
+ """Calculate the minimum clearance Linestring between two vertices
+
+ :param geometry: Geometry column
+ :type geometry: ColumnOrName
+ :return: Minimum Clearance Linestring between the geometries
+ :rtype: Column
+ """
+ return _call_st_function("ST_MinimumClearanceLine", geometry)
@validate_argument_types
def ST_MinimumBoundingCircle(geometry: ColumnOrName, quadrant_segments:
Optional[Union[ColumnOrName, int]] = None) -> Column:
diff --git a/python/tests/sql/test_dataframe_api.py
b/python/tests/sql/test_dataframe_api.py
index 9a8d170f9..7c7b9276b 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -171,6 +171,8 @@ test_configurations = [
(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))"),
+ (stf.ST_MinimumClearance, ("geom",), "invalid_geom", "", 2.0),
+ (stf.ST_MinimumClearanceLine, ("geom",), "invalid_geom", "", "LINESTRING
(5 3, 3 3)"),
(stf.ST_MinimumBoundingCircle, ("line", 8), "linestring_geom",
"ST_ReducePrecision(geom, 2)", "POLYGON ((4.95 -0.49, 4.81 -0.96, 4.58 -1.39,
4.27 -1.77, 3.89 -2.08, 3.46 -2.31, 2.99 -2.45, 2.5 -2.5, 2.01 -2.45, 1.54
-2.31, 1.11 -2.08, 0.73 -1.77, 0.42 -1.39, 0.19 -0.96, 0.05 -0.49, 0 0, 0.05
0.49, 0.19 0.96, 0.42 1.39, 0.73 1.77, 1.11 2.08, 1.54 2.31, 2.01 2.45, 2.5
2.5, 2.99 2.45, 3.46 2.31, 3.89 2.08, 4.27 1.77, 4.58 1.39, 4.81 0.96, 4.95
0.49, 5 0, 4.95 -0.49))"),
(stf.ST_MinimumBoundingCircle, ("line", 2), "linestring_geom",
"ST_ReducePrecision(geom, 2)", "POLYGON ((4.27 -1.77, 2.5 -2.5, 0.73 -1.77, 0
0, 0.73 1.77, 2.5 2.5, 4.27 1.77, 5 0, 4.27 -1.77))"),
(stf.ST_MinimumBoundingRadius, ("line",), "linestring_geom", "",
{"center": "POINT (2.5 0)", "radius": 2.5}),
@@ -371,6 +373,8 @@ wrong_type_configurations = [
(stf.ST_MaxDistance, (None, None)),
(stf.ST_MaxDistance, (None, "")),
(stf.ST_MaxDistance, ("", None)),
+ (stf.ST_MinimumClearance, (None,)),
+ (stf.ST_MinimumClearanceLine, (None,)),
(stf.ST_MinimumBoundingCircle, (None,)),
(stf.ST_MinimumBoundingRadius, (None,)),
(stf.ST_Multi, (None,)),
diff --git a/python/tests/sql/test_function.py
b/python/tests/sql/test_function.py
index 37da2fbfa..e492d9477 100644
--- a/python/tests/sql/test_function.py
+++ b/python/tests/sql/test_function.py
@@ -648,6 +648,16 @@ class TestPredicateJoin(TestBase):
assert (empty_dataframe.count() == 0)
+ def test_st_minimum_clearance(self):
+ baseDf = self.spark.sql("SELECT ST_GeomFromWKT('POLYGON ((65 18, 62
16, 64.5 16, 62 14, 65 14, 65 18))') as geom")
+ actual = baseDf.selectExpr("ST_MinimumClearance(geom)").take(1)[0][0]
+ assert actual == 0.5
+
+ def test_st_minimum_clearance_line(self):
+ baseDf = self.spark.sql("SELECT ST_GeomFromWKT('POLYGON ((65 18, 62
16, 64.5 16, 62 14, 65 14, 65 18))') as geom")
+ actual =
baseDf.selectExpr("ST_MinimumClearanceLine(geom)").take(1)[0][0].wkt
+ assert actual == "LINESTRING (64.5 16, 65 16)"
+
def test_st_boundary(self):
wkt_list = [
"LINESTRING(1 1,0 0, -1 1)",
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 edfe2b9b4..adf91db89 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
@@ -673,6 +673,24 @@ public class TestFunctions extends TestBase {
"MULTIPOLYGON (((1 5, 3 3, 1 1, 1 5)), ((5 3, 7 5, 7 1, 5 3)))"
);
}
+
+ @Test
+ public void test_ST_MinimumClearance() {
+ registerUDF("ST_MinimumClearance", byte[].class);
+ verifySqlSingleRes(
+ "select
sedona.ST_MinimumClearance(sedona.ST_GeomFromText('POLYGON ((65 18, 62 16, 64.5
16, 62 14, 65 14, 65 18))'))",
+ 0.5
+ );
+ }
+
+ @Test
+ public void test_ST_MinimumClearanceLine() {
+ registerUDF("ST_MinimumClearanceLine", byte[].class);
+ verifySqlSingleRes(
+ "select
sedona.ST_AsText(sedona.ST_MinimumClearanceLine(sedona.ST_GeomFromText('POLYGON
((65 18, 62 16, 64.5 16, 62 14, 65 14, 65 18))')))",
+ "LINESTRING (64.5 16, 65 16)"
+ );
+ }
@Test
public void test_ST_MinimumBoundingCircle() {
registerUDF("ST_MinimumBoundingCircle", 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 1927789a6..4a19a14e4 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
@@ -628,6 +628,24 @@ public class TestFunctionsV2
);
}
+ @Test
+ public void test_ST_MinimumClearance() {
+ registerUDFV2("ST_MinimumClearance", String.class);
+ verifySqlSingleRes(
+ "select sedona.ST_MinimumClearance(ST_GeomFromText('POLYGON
((65 18, 62 16, 64.5 16, 62 14, 65 14, 65 18))'))",
+ 0.5
+ );
+ }
+
+ @Test
+ public void test_ST_MinimumClearanceLine() {
+ registerUDFV2("ST_MinimumClearanceLine", String.class);
+ verifySqlSingleRes(
+ "select
ST_AsText(sedona.ST_MinimumClearanceLine(ST_GeomFromText('POLYGON ((65 18, 62
16, 64.5 16, 62 14, 65 14, 65 18))')))",
+ "LINESTRING(64.5 16,65 16)"
+ );
+ }
+
@Test
public void test_ST_MinimumBoundingCircle() {
registerUDFV2("ST_MinimumBoundingCircle", 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 6e362dba2..8ed03b719 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
@@ -914,6 +914,22 @@ public class UDFs {
);
}
+ @UDFAnnotations.ParamMeta(argNames = {"geometry"})
+ public static double ST_MinimumClearance(byte[] geometry) throws
IOException {
+ return Functions.minimumClearance(
+ GeometrySerde.deserialize(geometry)
+ );
+ }
+
+ @UDFAnnotations.ParamMeta(argNames = {"geometry"})
+ public static byte[] ST_MinimumClearanceLine(byte[] geometry) throws
IOException {
+ return GeometrySerde.serialize(
+ Functions.minimumClearanceLine(
+ GeometrySerde.deserialize(geometry)
+ )
+ );
+ }
+
@UDFAnnotations.ParamMeta(argNames = {"geometry", "quadrantSegments"})
public static byte[] ST_MinimumBoundingCircle(byte[] geometry, int
quadrantSegments) {
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 a30f775f5..337cdb104 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
@@ -756,6 +756,22 @@ public class UDFsV2
);
}
+ @UDFAnnotations.ParamMeta(argNames = {"geometry"}, argTypes = {"Geometry"})
+ public static Double ST_MinimumClearance(String geometry) throws
IOException {
+ return Functions.minimumClearance(
+ GeometrySerde.deserGeoJson(geometry)
+ );
+ }
+
+ @UDFAnnotations.ParamMeta(argNames = {"geometry"}, argTypes =
{"Geometry"}, returnTypes = "Geometry")
+ public static String ST_MinimumClearanceLine(String geometry) {
+ return GeometrySerde.serGeoJson(
+ Functions.minimumClearanceLine(
+ GeometrySerde.deserGeoJson(geometry)
+ )
+ );
+ }
+
@UDFAnnotations.ParamMeta(argNames = {"geometry", "quadrantSegments"},
argTypes = {"Geometry", "int"}, returnTypes = "Geometry")
public static String ST_MinimumBoundingCircle(String geometry, int
quadrantSegments) {
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 018b535e6..425fd221d 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
@@ -130,6 +130,8 @@ object Catalog {
function[ST_M](),
function[ST_MMin](),
function[ST_MMax](),
+ function[ST_MinimumClearance](),
+ function[ST_MinimumClearanceLine](),
function[ST_MinimumBoundingRadius](),
function[ST_MinimumBoundingCircle](BufferParameters.DEFAULT_QUADRANT_SEGMENTS *
6),
function[ST_EndPoint](),
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 2e1711e70..f59d592ab 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
@@ -506,6 +506,21 @@ case class ST_Boundary(inputExpressions: Seq[Expression])
}
}
+case class ST_MinimumClearance(inputExpressions: Seq[Expression])
+ extends InferredExpression(Functions.minimumClearance _) {
+
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) =
{
+ copy(inputExpressions = newChildren)
+ }
+}
+
+case class ST_MinimumClearanceLine(inputExpressions: Seq[Expression])
+ extends InferredExpression(Functions.minimumClearanceLine _) {
+
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) =
{
+ copy(inputExpressions = newChildren)
+ }
+}
case class ST_MinimumBoundingRadius(inputExpressions: Seq[Expression])
extends Expression with FoldableExpression with CodegenFallback {
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 e7b441486..2c8facd22 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
@@ -266,6 +266,12 @@ object st_functions extends DataFrameAPI {
def ST_MaxDistance(geom1: Column, geom2: Column): Column =
wrapExpression[ST_MaxDistance](geom1, geom2)
def ST_MaxDistance(geom1: String, geom2: String): Column =
wrapExpression[ST_MaxDistance](geom1, geom2)
+ def ST_MinimumClearance(geometry: Column): Column =
wrapExpression[ST_MinimumClearance](geometry)
+ def ST_MinimumClearance(geometry: String): Column =
wrapExpression[ST_MinimumClearance](geometry)
+
+ def ST_MinimumClearanceLine(geometry: Column): Column =
wrapExpression[ST_MinimumClearanceLine](geometry)
+ def ST_MinimumClearanceLine(geometry: String): Column =
wrapExpression[ST_MinimumClearanceLine](geometry)
+
def ST_MinimumBoundingCircle(geometry: Column): Column =
wrapExpression[ST_MinimumBoundingCircle](geometry,
BufferParameters.DEFAULT_QUADRANT_SEGMENTS * 6)
def ST_MinimumBoundingCircle(geometry: String): Column =
wrapExpression[ST_MinimumBoundingCircle](geometry,
BufferParameters.DEFAULT_QUADRANT_SEGMENTS * 6)
def ST_MinimumBoundingCircle(geometry: Column, quadrantSegments: Column):
Column = wrapExpression[ST_MinimumBoundingCircle](geometry, quadrantSegments)
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 807935b72..4bbb18b47 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
@@ -1021,6 +1021,20 @@ class dataFrameAPITestScala extends TestBaseScala {
assert(actualResult == expectedResult)
}
+ it("Passed ST_MinimumClearance") {
+ val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((65 18,
62 16, 64.5 16, 62 14, 65 14, 65 18))') as geom")
+ val actual = baseDf.select(ST_MinimumClearance("geom")).first().get(0)
+ val expected = 0.5
+ assertEquals(expected, actual)
+ }
+
+ it("Passed ST_MinimumClearanceLine") {
+ val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((65 18,
62 16, 64.5 16, 62 14, 65 14, 65 18))') as geom")
+ val actual =
baseDf.select(ST_MinimumClearanceLine("geom")).first().get(0).asInstanceOf[Geometry].toText
+ val expected = "LINESTRING (64.5 16, 65 16)"
+ assertEquals(expected, actual)
+ }
+
it("Passed ST_MinimumBoundingCircle with default quadrantSegments") {
val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING (0 0, 1
0)') AS geom")
val df =
baseDf.select(ST_MinimumBoundingCircle("geom").as("geom")).selectExpr("ST_ReducePrecision(geom,
2)")
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 38af32109..9da42a057 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
@@ -1676,6 +1676,20 @@ class functionTestScala extends TestBaseScala with
Matchers with GeometrySample
assert(newY == oldX)
}
+ it("Should pass ST_MinimumClearance") {
+ val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((65 18, 62
16, 64.5 16, 62 14, 65 14, 65 18))') as geom")
+ val actual = baseDf.selectExpr("ST_MinimumClearance(geom)").first().get(0)
+ val expected = 0.5
+ assertEquals(expected, actual)
+ }
+
+ it("Should pass ST_MinimumClearanceLine") {
+ val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((65 18, 62
16, 64.5 16, 62 14, 65 14, 65 18))') as geom")
+ val actual =
baseDf.selectExpr("ST_MinimumClearanceLine(geom)").first().get(0).asInstanceOf[Geometry].toText
+ val expected = "LINESTRING (64.5 16, 65 16)"
+ assertEquals(expected, actual)
+ }
+
it("Should pass ST_MinimumBoundingCircle") {
Given("Sample geometry data frame")
val geometryTable = Seq(