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 2dbccbf4 [SEDONA-293] Implement ST_IsCollection (#910)
2dbccbf4 is described below
commit 2dbccbf46c88a8a0b767053c798ee5509d44e6fe
Author: Furqaanahmed Khan <[email protected]>
AuthorDate: Thu Jul 20 14:10:19 2023 -0400
[SEDONA-293] Implement ST_IsCollection (#910)
---
.../java/org/apache/sedona/common/Functions.java | 8 +++++++
.../org/apache/sedona/common/FunctionsTest.java | 21 ++++++++++++++++
docs/api/flink/Function.md | 28 ++++++++++++++++++++++
docs/api/sql/Function.md | 27 +++++++++++++++++++++
.../main/java/org/apache/sedona/flink/Catalog.java | 1 +
.../apache/sedona/flink/expressions/Functions.java | 8 +++++++
.../java/org/apache/sedona/flink/FunctionTest.java | 16 +++++++++++++
python/sedona/sql/st_functions.py | 11 +++++++++
python/tests/sql/test_dataframe_api.py | 1 +
.../scala/org/apache/sedona/sql/UDF/Catalog.scala | 1 +
.../sql/sedona_sql/expressions/Functions.scala | 12 ++++++++++
.../sql/sedona_sql/expressions/st_functions.scala | 4 ++++
.../apache/sedona/sql/dataFrameAPITestScala.scala | 16 +++++++++++++
.../org/apache/sedona/sql/functionTestScala.scala | 6 +++++
14 files changed, 160 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 666a9f5e..e2c9427a 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -988,6 +988,14 @@ public class Functions {
return GeomUtils.getFrechetDistance(g1, g2);
}
+ public static boolean isCollection(Geometry geometry) {
+ String geoType = geometry.getGeometryType();
+ return Geometry.TYPENAME_GEOMETRYCOLLECTION.equalsIgnoreCase(geoType)
||
+ Geometry.TYPENAME_MULTIPOINT.equalsIgnoreCase(geoType) ||
+ Geometry.TYPENAME_MULTIPOLYGON.equalsIgnoreCase(geoType) ||
+ Geometry.TYPENAME_MULTILINESTRING.equalsIgnoreCase(geoType);
+ }
+
public static Geometry boundingDiagonal(Geometry geometry) {
if (geometry.isEmpty()) {
return GEOMETRY_FACTORY.createLineString();
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 4e2b329d..ffa121a0 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -1153,6 +1153,27 @@ public class FunctionsTest {
assertEquals("ST_Angle supports either only POINT or only LINESTRING
geometries.", e.getMessage());
}
+ @Test
+ public void isCollectionWithCollection() {
+ Point[] points = new Point[]{
+ GEOMETRY_FACTORY.createPoint(new Coordinate(5.0, 6.0)),
+ GEOMETRY_FACTORY.createPoint(new Coordinate(7.0, 8.0))
+ };
+ GeometryCollection geometryCollection =
GEOMETRY_FACTORY.createGeometryCollection(points);
+
+ boolean actualResult = Functions.isCollection(geometryCollection);
+ boolean expectedResult = true;
+ assertEquals(actualResult, expectedResult);
+ }
+
+ @Test
+ public void isCollectionWithOutCollection() {
+ Point point = GEOMETRY_FACTORY.createPoint(new Coordinate(6.0, 6.0));
+
+ boolean actualResult = Functions.isCollection(point);
+ boolean expectedResult = false;
+ assertEquals(actualResult, expectedResult);
+ }
public void affineEmpty3D() {
LineString emptyLineString = GEOMETRY_FACTORY.createLineString();
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index c34bc585..b5204809 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -1087,6 +1087,34 @@ Example:
SELECT ST_IsClosed(ST_GeomFromText('LINESTRING(0 0, 1 1, 1 0)'))
```
+## ST_IsCollection
+
+Introduction: Returns `TRUE` if the geometry type of the input is a geometry
collection type.
+Collection types are the following:
+
+- GEOMETRYCOLLECTION
+- MULTI{POINT, POLYGON, LINESTRING}
+
+Format: `ST_IsCollection(geom: geometry)`
+
+Since: `v1.5.0`
+
+Example:
+
+```sql
+SELECT ST_IsCollection(ST_GeomFromText('MULTIPOINT(0 0), (6 6)'))
+```
+
+Output: `true`
+
+Example:
+
+```sql
+SELECT ST_IsCollection(ST_GeomFromText('POINT(5 5)'))
+```
+
+Output: `false`
+
## ST_IsEmpty
Introduction: Test if a geometry is empty geometry
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index 8edda106..eb6a5020 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -1082,6 +1082,33 @@ SELECT ST_IsClosed(ST_GeomFromText('LINESTRING(0 0, 1 1,
1 0)'))
Output: `false`
+## ST_IsCollection
+
+Introduction: Returns `TRUE` if the geometry type of the input is a geometry
collection type.
+Collection types are the following:
+
+- GEOMETRYCOLLECTION
+- MULTI{POINT, POLYGON, LINESTRING}
+
+Format: `ST_IsCollection(geom: geometry)`
+
+Since: `v1.5.0`
+
+Example:
+
+```sql
+SELECT ST_IsCollection(ST_GeomFromText('MULTIPOINT(0 0), (6 6)'))
+```
+
+Output: `true`
+
+Example:
+```sql
+SELECT ST_IsCollection(ST_GeomFromText('POINT(5 5)'))
+```
+
+Output: `false`
+
## ST_IsEmpty
Introduction: Test if a geometry is empty geometry
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 d779b1ef..89c350e4 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -135,6 +135,7 @@ public class Catalog {
new Functions.ST_Angle(),
new Functions.ST_Degrees(),
new Functions.ST_HausdorffDistance(),
+ new Functions.ST_IsCollection(),
new Functions.ST_CoordDim(),
};
}
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 bff5913e..c84cb532 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
@@ -948,6 +948,14 @@ public class Functions {
}
}
+ public static class ST_IsCollection extends ScalarFunction {
+ @DataTypeHint("Boolean")
+ public boolean eval(@DataTypeHint(value = "RAW", bridgedTo =
org.locationtech.jts.geom.Geometry.class) Object o) {
+ Geometry geom = (Geometry) o;
+ return org.apache.sedona.common.Functions.isCollection(geom);
+ }
+ }
+
public static class ST_Angle extends ScalarFunction {
@DataTypeHint("Double")
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 219a9989..d4f2a8d3 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -1047,6 +1047,22 @@ public class FunctionTest extends TestBase{
assertEquals(expectedDefault, actualDefault);
}
+ @Test
+ public void testIsCollectionForCollection() {
+ Table collectionTable = tableEnv.sqlQuery("SELECT
ST_GeomFromWKT('GEOMETRYCOLLECTION(POINT(2 3), POINT(4 6), LINESTRING(15 15, 20
20))') AS collection");
+ Table resultTable =
collectionTable.select(call(Functions.ST_IsCollection.class.getSimpleName(),
$("collection")));
+ boolean result = (boolean) first(resultTable).getField(0);
+ assertTrue(result);
+ }
+
+ @Test
+ public void testIsCollectionForNotCollection() {
+ Table collectionTable = tableEnv.sqlQuery("SELECT
ST_GeomFromWKT('POINT(10 10)') AS collection");
+ Table resultTable =
collectionTable.select(call(Functions.ST_IsCollection.class.getSimpleName(),
$("collection")));
+ boolean result = (boolean) first(resultTable).getField(0);
+ assertFalse(result);
+ }
+
@Test
public void testCoordDimFor2D() {
Table polygonTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('POINT(3
7)') AS " + polygonColNames[0]);
diff --git a/python/sedona/sql/st_functions.py
b/python/sedona/sql/st_functions.py
index 97cdaac3..296f38fe 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -119,6 +119,7 @@ __all__ = [
"ST_Degrees",
"ST_FrechetDistance",
"ST_CoordDim",
+ "ST_IsCollection",
"ST_Affine",
"ST_BoundingDiagonal"
]
@@ -1434,3 +1435,13 @@ def ST_CoordDim(geometry: ColumnOrName) -> Column:
"""
return _call_st_function("ST_CoordDim", geometry)
+@validate_argument_types
+def ST_IsCollection(geometry: ColumnOrName) -> Column:
+ """Check if the geometry is of GeometryCollection type.
+
+ :param geometry: Column for geometry collection
+ :type geometry: ColumnOrName
+ :return: True if geometry is a collection of geometries.
+ :rtype: Column
+ """
+ return _call_st_function("ST_IsCollection", geometry)
\ No newline at end of file
diff --git a/python/tests/sql/test_dataframe_api.py
b/python/tests/sql/test_dataframe_api.py
index 7adf1bca..2c84e147 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -104,6 +104,7 @@ test_configurations = [
(stf.ST_HausdorffDistance, ("point", "line",), "point_and_line", "",
5.0990195135927845),
(stf.ST_InteriorRingN, ("geom", 0), "geom_with_hole", "", "LINESTRING (1
1, 2 2, 2 1, 1 1)"),
(stf.ST_Intersection, ("a", "b"), "overlapping_polys", "", "POLYGON ((2 0,
1 0, 1 1, 2 1, 2 0))"),
+ (stf.ST_IsCollection, ("geom",), "geom_collection", "", True),
(stf.ST_IsClosed, ("geom",), "closed_linestring_geom", "", True),
(stf.ST_IsEmpty, ("geom",), "empty_geom", "", True),
(stf.ST_IsRing, ("line",), "linestring_geom", "", False),
diff --git a/sql/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
b/sql/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
index 06b7750e..5c4d08af 100644
--- a/sql/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
+++ b/sql/common/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
@@ -111,6 +111,7 @@ object Catalog {
function[ST_Dump](),
function[ST_DumpPoints](),
function[ST_IsClosed](),
+ function[ST_IsCollection](),
function[ST_NumInteriorRings](),
function[ST_AddPoint](-1),
function[ST_RemovePoint](-1),
diff --git
a/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
b/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
index a9bba934..9cd4fd47 100644
---
a/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
+++
b/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
@@ -1083,3 +1083,15 @@ case class ST_CoordDim(inputExpressions: Seq[Expression])
}
}
+/**
+ * Returns True if geometry is a collection of geometries
+ *
+ * @param inputExpressions
+ */
+case class ST_IsCollection(inputExpressions: Seq[Expression])
+ extends InferredExpression(Functions.isCollection _) {
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]):
Expression = {
+ copy(inputExpressions = newChildren)
+ }
+}
+
diff --git
a/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
b/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
index be28d32e..fa2ed11f 100644
---
a/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
+++
b/sql/common/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
@@ -384,5 +384,9 @@ object st_functions extends DataFrameAPI {
def ST_CoordDim(geometry: String): Column =
wrapExpression[ST_CoordDim](geometry)
+ def ST_IsCollection(geometry: Column): Column =
wrapExpression[ST_IsCollection](geometry)
+
+ def ST_IsCollection(geometry: String): Column =
wrapExpression[ST_IsCollection](geometry)
+
}
\ No newline at end of file
diff --git
a/sql/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala
b/sql/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala
index 51de7d2b..44664529 100644
---
a/sql/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala
+++
b/sql/common/src/test/scala/org/apache/sedona/sql/dataFrameAPITestScala.scala
@@ -1076,6 +1076,22 @@ class dataFrameAPITestScala extends TestBaseScala {
assert(expected == actual)
}
+ it("Passed ST_IsCollection with a collection") {
+ val baseDf = sparkSession.sql("SELECT
ST_GeomFromWKT('GEOMETRYCOLLECTION(POINT(3 2), POINT(6 4))') AS collection")
+ val df = baseDf.select(ST_IsCollection("collection"))
+ val actualResult = df.take(1)(0).getBoolean(0)
+ val expectedResult = true
+ assert(actualResult == expectedResult)
+ }
+
+ it("Passed ST_IsCollection without a collection") {
+ val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POINT(9 9)') AS
collection")
+ val df = baseDf.select(ST_IsCollection("collection"))
+ val actualResult = df.take(1)(0).getBoolean(0)
+ val expectedResult = false
+ assert(actualResult == expectedResult)
+ }
+
it("Passed ST_Angle - 4 Points") {
val polyDf = sparkSession.sql("SELECT ST_GeomFromWKT('POINT (10 10)') AS
p1, ST_GeomFromWKT('POINT (0 0)') AS p2," +
" ST_GeomFromWKT('POINT (90 90)') AS p3, ST_GeomFromWKT('POINT (100
80)') AS p4")
diff --git
a/sql/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
b/sql/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
index 56bf832f..b2580228 100644
--- a/sql/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
+++ b/sql/common/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
@@ -2176,6 +2176,12 @@ class functionTestScala extends TestBaseScala with
Matchers with GeometrySample
assert(test.take(1)(0).get(0).asInstanceOf[Int] == 4)
}
+ it("Should pass ST_IsCollection") {
+ val test = sparkSession.sql("SELECT
ST_IsCollection(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(2 3), POINT(4 6),
LINESTRING(15 15, 20 20))'))")
+ val expected = true
+ assert(test.take(1)(0).get(0).asInstanceOf[Boolean] == expected)
+ }
+
it ("should pass GeometryType") {
val geomTestCases = Map (
("'POINT (51.3168 -0.56)'") -> "'POINT'",