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 2022/11/23 01:00:23 UTC
[incubator-sedona] branch master updated: [SEDONA-197] Added ST_ZMax and ST_ZMin to Apache Sedona (#717)
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/incubator-sedona.git
The following commit(s) were added to refs/heads/master by this push:
new ab4d8266 [SEDONA-197] Added ST_ZMax and ST_ZMin to Apache Sedona (#717)
ab4d8266 is described below
commit ab4d8266fe9b48b451b13c40d0a44747936db311
Author: Varsha Ravindra <va...@gmail.com>
AuthorDate: Tue Nov 22 18:00:18 2022 -0700
[SEDONA-197] Added ST_ZMax and ST_ZMin to Apache Sedona (#717)
---
.../java/org/apache/sedona/common/Functions.java | 22 +++++++++++++++
docs/api/flink/Function.md | 31 +++++++++++++++++++++
docs/api/sql/Function.md | 30 ++++++++++++++++++++
.../main/java/org/apache/sedona/flink/Catalog.java | 2 ++
.../apache/sedona/flink/expressions/Functions.java | 16 +++++++++++
.../java/org/apache/sedona/flink/FunctionTest.java | 32 +++++++++++++++++++++-
python/sedona/sql/st_functions.py | 24 ++++++++++++++++
python/tests/sql/test_function.py | 10 +++++++
.../scala/org/apache/sedona/sql/UDF/Catalog.scala | 2 ++
.../sql/sedona_sql/expressions/Functions.scala | 26 ++++++++++++++++++
.../sql/sedona_sql/expressions/st_functions.scala | 6 ++++
.../org/apache/sedona/sql/functionTestScala.scala | 19 +++++++++++++
12 files changed, 219 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 46755855..6ab744ca 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -155,6 +155,28 @@ public class Functions {
return max;
}
+ public static Double zMax(Geometry geometry) {
+ Coordinate[] points = geometry.getCoordinates();
+ double max = Double.MIN_VALUE;
+ for (int i=0; i < points.length; i++) {
+ if(java.lang.Double.isNaN(points[i].getZ()))
+ continue;
+ max = Math.max(points[i].getZ(), max);
+ }
+ return max == Double.MIN_VALUE ? null : max;
+ }
+
+ public static Double zMin(Geometry geometry) {
+ 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()))
+ continue;
+ min = Math.min(points[i].getZ(), min);
+ }
+ return min == Double.MAX_VALUE ? null : min;
+ }
+
public static Geometry transform(Geometry geometry, String sourceCRS, String targetCRS)
throws FactoryException, TransformException {
return transform(geometry, sourceCRS, targetCRS, false);
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index e7a63000..1a630cf9 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -832,3 +832,34 @@ SELECT ST_Z(ST_POINT(0.0 25.0 11.0))
```
Output: `11.0`
+
+## ST_ZMax
+
+Introduction: Returns Z maxima of the given geometry or null if there is no Z coordinate.
+
+Format: `ST_ZMax(geom: geometry)`
+
+Since: `v1.3.1`
+
+Spark SQL example:
+```SQL
+SELECT ST_ZMax(ST_GeomFromText('POLYGON((0 0 1, 1 1 1, 1 2 1, 1 1 1, 0 0 1))'))
+```
+
+Output: `1.0`
+
+## ST_ZMin
+
+Introduction: Returns Z minima of the given geometry or null if there is no Z coordinate.
+
+Format: `ST_ZMin(geom: geometry)`
+
+Since: `v1.3.1`
+
+Spark SQL example:
+```SQL
+SELECT ST_ZMin(ST_GeomFromText('LINESTRING(1 3 4, 5 6 7)'))
+```
+
+Output: `4.0`
+
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index 8453058c..df3982cd 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -1445,3 +1445,33 @@ SELECT ST_Z(ST_POINT(0.0 25.0 11.0))
```
Output: `11.0`
+
+## ST_ZMax
+
+Introduction: Returns Z maxima of the given geometry or null if there is no Z coordinate.
+
+Format: `ST_ZMax(geom: geometry)`
+
+Since: `v1.3.1`
+
+Spark SQL example:
+```SQL
+SELECT ST_ZMax(ST_GeomFromText('POLYGON((0 0 1, 1 1 1, 1 2 1, 1 1 1, 0 0 1))'))
+```
+
+Output: `1.0`
+
+## ST_ZMin
+
+Introduction: Returns Z minima of the given geometry or null if there is no Z coordinate.
+
+Format: `ST_ZMin(geom: geometry)`
+
+Since: `v1.3.1`
+
+Spark SQL example:
+```SQL
+SELECT ST_ZMin(ST_GeomFromText('LINESTRING(1 3 4, 5 6 7)'))
+```
+
+Output: `4.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 9b6d634f..24c892ba 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -70,6 +70,8 @@ public class Catalog {
new Functions.ST_YMin(),
new Functions.ST_XMax(),
new Functions.ST_XMin(),
+ new Functions.ST_ZMax(),
+ new Functions.ST_ZMin(),
new Functions.ST_BuildArea(),
new Functions.ST_SetSRID(),
new Functions.ST_SRID(),
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 e92a1d6d..d3ec3f9d 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
@@ -107,6 +107,22 @@ public class Functions {
}
}
+ public static class ST_ZMax extends ScalarFunction {
+ @DataTypeHint("Double")
+ public Double eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o){
+ Geometry geom = (Geometry) o;
+ return org.apache.sedona.common.Functions.zMax(geom);
+ }
+ }
+
+ public static class ST_ZMin extends ScalarFunction {
+ @DataTypeHint("Double")
+ public Double eval(@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o){
+ Geometry geom = (Geometry) o;
+ return org.apache.sedona.common.Functions.zMin(geom);
+ }
+ }
+
public static class ST_Transform extends ScalarFunction {
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
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 4a21efa3..95718f22 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -27,6 +27,7 @@ import org.locationtech.jts.geom.Polygon;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import static junit.framework.TestCase.assertNull;
import static org.apache.flink.table.api.Expressions.$;
import static org.apache.flink.table.api.Expressions.call;
import static org.junit.Assert.assertEquals;
@@ -169,7 +170,6 @@ public class FunctionTest extends TestBase{
assertEquals(-0.5, result, 0);
}
-
@Test
public void testGeomToGeoHash() {
Table pointTable = createPointTable(testDataSize);
@@ -374,6 +374,36 @@ public class FunctionTest extends TestBase{
assertEquals(7.89, first(pointTable).getField(0));
}
+ @Test
+ public void testZMax() {
+ Table polygonTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING(1 3 4, 5 6 7)') AS " + polygonColNames[0]);
+ polygonTable = polygonTable.select(call(Functions.ST_ZMax.class.getSimpleName(), $(polygonColNames[0])));
+ double result = (double) first(polygonTable).getField(0);
+ assertEquals(7.0, result, 0);
+ }
+
+ @Test
+ public void testZMaxWithNoZCoordinate() {
+ Table polygonTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING(1 3, 5 6)') AS " + polygonColNames[0]);
+ polygonTable = polygonTable.select(call(Functions.ST_ZMax.class.getSimpleName(), $(polygonColNames[0])));
+ assertNull(first(polygonTable).getField(0));
+ }
+
+ @Test
+ public void testZMin() {
+ Table polygonTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING(1 3 4, 5 6 7)') AS " + polygonColNames[0]);
+ polygonTable = polygonTable.select(call(Functions.ST_ZMin.class.getSimpleName(), $(polygonColNames[0])));
+ double result = (double) first(polygonTable).getField(0);
+ assertEquals(4.0, result, 0);
+ }
+
+ @Test
+ public void testZMinWithNoZCoordinate() {
+ Table polygonTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING(1 3, 5 6)') AS " + polygonColNames[0]);
+ polygonTable = polygonTable.select(call(Functions.ST_ZMin.class.getSimpleName(), $(polygonColNames[0])));
+ assertNull(first(polygonTable).getField(0));
+ }
+
@Test
public void testXMax() {
Table polygonTable = createPolygonTable(1);
diff --git a/python/sedona/sql/st_functions.py b/python/sedona/sql/st_functions.py
index 323a9e0a..ae4c8daf 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -97,6 +97,8 @@ __all__ = [
"ST_YMax",
"ST_YMin",
"ST_Z",
+ "ST_ZMax",
+ "ST_ZMin",
]
@@ -1070,3 +1072,25 @@ def ST_Z(point: ColumnOrName) -> Column:
:rtype: Column
"""
return _call_st_function("ST_Z", point)
+
+@validate_argument_types
+def ST_ZMax(geometry: ColumnOrName) -> Column:
+ """Return the maximum Z coordinate of a geometry.
+
+ :param geometry: Geometry column to get the maximum Z coordinate from.
+ :type geometry: ColumnOrName
+ :return: Maximum Z coordinate for the geometry as a double column.
+ :rtype: Column
+ """
+ return _call_st_function("ST_ZMax", geometry)
+
+@validate_argument_types
+def ST_ZMin(geometry: ColumnOrName) -> Column:
+ """Return the minimum Z coordinate of a geometry.
+
+ :param geometry: Geometry column to get the minimum Z coordinate from.
+ :type geometry: ColumnOrName
+ :return: Minimum Z coordinate for the geometry as a double column.
+ :rtype: Column
+ """
+ return _call_st_function("ST_ZMin", geometry)
\ No newline at end of file
diff --git a/python/tests/sql/test_function.py b/python/tests/sql/test_function.py
index fdac9c68..275bfcf6 100644
--- a/python/tests/sql/test_function.py
+++ b/python/tests/sql/test_function.py
@@ -417,6 +417,16 @@ class TestPredicateJoin(TestBase):
assert(not polygons.count())
+ def test_st_z_max(self):
+ linestring_df = self.spark.sql("SELECT ST_GeomFromWKT('LINESTRING Z (0 0 1, 0 1 2)') as geom")
+ linestring_row = [lnstr_row[0] for lnstr_row in linestring_df.selectExpr("ST_ZMax(geom)").collect()]
+ assert(linestring_row == [2.0])
+
+ def test_st_z_min(self):
+ linestring_df = self.spark.sql("SELECT ST_GeomFromWKT('POLYGON Z ((0 0 2, 0 1 1, 1 1 2, 1 0 2, 0 0 2))') as geom")
+ linestring_row = [lnstr_row[0] for lnstr_row in linestring_df.selectExpr("ST_ZMin(geom)").collect()]
+ assert(linestring_row == [1.0])
+
def test_st_start_point(self):
point_df = create_sample_points_df(self.spark, 5)
diff --git a/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala b/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
index 66c0ae70..11a1fe04 100644
--- a/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
+++ b/sql/src/main/scala/org/apache/sedona/sql/UDF/Catalog.scala
@@ -124,6 +124,8 @@ object Catalog {
function[ST_PointN](),
function[ST_AsEWKT](),
function[ST_Force_2D](),
+ function[ST_ZMax](),
+ function[ST_ZMin](),
function[ST_YMax](),
function[ST_YMin](),
function[ST_XMax](),
diff --git a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
index 298174c2..fb0875ea 100644
--- a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
+++ b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/Functions.scala
@@ -64,6 +64,32 @@ case class ST_YMin(inputExpressions: Seq[Expression])
}
}
+/**
+ * Return the Z maxima of the geometry.
+ *
+ * @param inputExpressions This function takes a geometry and returns the maximum of all Z-coordinate values.
+*/
+case class ST_ZMax(inputExpressions: Seq[Expression])
+ extends InferredUnaryExpression(Functions.zMax) with FoldableExpression {
+
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
+ copy(inputExpressions = newChildren)
+ }
+}
+
+/**
+ * Return the Z minima of the geometry.
+ *
+ * @param inputExpressions This function takes a geometry and returns the minimum of all Z-coordinate values.
+*/
+case class ST_ZMin(inputExpressions: Seq[Expression])
+ extends InferredUnaryExpression(Functions.zMin) with FoldableExpression {
+
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = {
+ copy(inputExpressions = newChildren)
+ }
+}
+
case class ST_3DDistance(inputExpressions: Seq[Expression])
extends InferredBinaryExpression(Functions.distance3d) with FoldableExpression {
diff --git a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
index 22928187..694f067c 100644
--- a/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
+++ b/sql/src/main/scala/org/apache/spark/sql/sedona_sql/expressions/st_functions.scala
@@ -254,4 +254,10 @@ object st_functions extends DataFrameAPI {
def ST_Z(point: Column): Column = wrapExpression[ST_Z](point)
def ST_Z(point: String): Column = wrapExpression[ST_Z](point)
+
+ def ST_ZMax(geometry: Column): Column = wrapExpression[ST_ZMax](geometry)
+ def ST_ZMax(geometry: String): Column = wrapExpression[ST_ZMax](geometry)
+
+ def ST_ZMin(geometry: Column): Column = wrapExpression[ST_ZMin](geometry)
+ def ST_ZMin(geometry: String): Column = wrapExpression[ST_ZMin](geometry)
}
diff --git a/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala b/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
index a0cd4a33..02c092cd 100644
--- a/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
+++ b/sql/src/test/scala/org/apache/sedona/sql/functionTestScala.scala
@@ -82,6 +82,25 @@ class functionTestScala extends TestBaseScala with Matchers with GeometrySample
assert(test.take(1)(0).get(0).asInstanceOf[Double] == -3.0)
}
+ it("Passed ST_ZMax") {
+ val test = sparkSession.sql("SELECT ST_ZMax(ST_GeomFromWKT('POLYGON((0 0 0,0 5 0,5 0 0,0 0 5),(1 1 0,3 1 0,1 3 0,1 1 0))'))")
+ assert(test.take(1)(0).get(0).asInstanceOf[Double] == 5.0)
+ }
+ it("Passed ST_ZMax with no Z coordinate") {
+ val test = sparkSession.sql("SELECT ST_ZMax(ST_GeomFromWKT('POLYGON((0 0,0 5,5 0,0 0),(1 1,3 1,1 3,1 1))'))")
+ assert(test.take(1)(0).get(0) == null)
+ }
+
+ it("Passed ST_ZMin") {
+ val test = sparkSession.sql("SELECT ST_ZMin(ST_GeomFromWKT('LINESTRING(1 3 4, 5 6 7)'))")
+ assert(test.take(1)(0).get(0).asInstanceOf[Double] == 4.0)
+ }
+
+ it("Passed ST_ZMin with no Z coordinate") {
+ val test = sparkSession.sql("SELECT ST_ZMin(ST_GeomFromWKT('LINESTRING(1 3, 5 6)'))")
+ assert(test.take(1)(0).get(0) == null)
+ }
+
it("Passed ST_Centroid") {
var polygonWktDf = sparkSession.read.format("csv").option("delimiter", "\t").option("header", "false").load(mixedWktGeometryInputLocation)
polygonWktDf.createOrReplaceTempView("polygontable")