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 ee3a28d71 [SEDONA-571][SEDONA-574] Add ST_MMin, ST_MMax (#1442)
ee3a28d71 is described below
commit ee3a28d7134f4804e881f97bbfded11c2dda9917
Author: Jia Yu <[email protected]>
AuthorDate: Tue May 28 21:29:18 2024 -0700
[SEDONA-571][SEDONA-574] Add ST_MMin, ST_MMax (#1442)
* Add ST_MMin (#149)
* Add ST_MMax (#152)
---------
Co-authored-by: Furqaan Khan <[email protected]>
---
.../java/org/apache/sedona/common/Functions.java | 22 +++++++++++
.../org/apache/sedona/common/FunctionsTest.java | 24 ++++++++++++
docs/api/flink/Function.md | 44 ++++++++++++++++++++++
docs/api/sql/Function.md | 44 ++++++++++++++++++++++
.../main/java/org/apache/sedona/flink/Catalog.java | 2 +
.../apache/sedona/flink/expressions/Functions.java | 16 ++++++++
.../java/org/apache/sedona/flink/FunctionTest.java | 22 +++++++++++
python/sedona/sql/st_functions.py | 22 +++++++++++
python/tests/sql/test_dataframe_api.py | 6 +++
python/tests/sql/test_function.py | 18 +++++++++
.../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 | 20 ++++++++++
.../org/apache/sedona/sql/functionTestScala.scala | 22 +++++++++++
15 files changed, 285 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 ba9971c52..774a2bfe3 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -398,6 +398,28 @@ public class Functions {
return null;
}
+ public static Double mMin(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].getM()))
+ continue;
+ min = Math.min(points[i].getM(), min);
+ }
+ return min == Double.MAX_VALUE ? null : min;
+ }
+
+ public static Double mMax(Geometry geometry) {
+ 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()))
+ continue;
+ max = Math.max(points[i].getM(), max);
+ }
+ return max == -Double.MAX_VALUE ? null : max;
+ }
+
public static double xMin(Geometry geometry) {
Coordinate[] points = geometry.getCoordinates();
double min = Double.MAX_VALUE;
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 62e47a462..6d15e20ca 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -424,6 +424,30 @@ public class FunctionsTest extends TestBase {
assertNull(actualRes);
}
+ @Test
+ public void testMMin() throws ParseException {
+ Geometry geom = Constructors.geomFromWKT("LINESTRING ZM(1 1 1 1, 2 2 2
2, 3 3 3 3, -1 -1 -1 -1)", 0);
+ Double actual = Functions.mMin(geom);
+ Double expected = -1.0;
+ assertEquals(expected, actual);
+
+ geom = Constructors.geomFromWKT("LINESTRING(1 1 1, 2 2 2, 3 3 3, -1 -1
-1)", 0);
+ actual = Functions.mMin(geom);
+ assertNull(actual);
+ }
+
+ @Test
+ public void testMMax() throws ParseException {
+ Geometry geom = Constructors.geomFromWKT("LINESTRING ZM(1 1 1 1, 2 2 2
2, 3 3 3 3, -1 -1 -1 -1)", 0);
+ Double actual = Functions.mMax(geom);
+ Double expected = 3.0;
+ assertEquals(expected, actual);
+
+ geom = Constructors.geomFromWKT("LINESTRING(1 1 1, 2 2 2, 3 3 3, -1 -1
-1)", 0);
+ actual = Functions.mMax(geom);
+ assertNull(actual);
+ }
+
@Test
public void dimensionGeometry3D() {
Point point3D = GEOMETRY_FACTORY.createPoint(new Coordinate(1, 1, 1));
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index 55ac471b8..318c97354 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -2068,6 +2068,50 @@ Output:
4.0
```
+## ST_MMax
+
+Introduction: Returns M maxima of the given geometry or null if there is no M
coordinate.
+
+Format: `ST_MMax(geom: Geometry)`
+
+Since: `vTBD`
+
+SQL Example
+
+```sql
+SELECT ST_MMax(
+ ST_GeomFromWKT('POLYGON ZM ((30 10 5 1, 40 40 10 2, 20 40 15 3, 10 20
20 4, 30 10 5 1))')
+)
+```
+
+Output:
+
+```
+4.0
+```
+
+## ST_MMin
+
+Introduction: Returns M minima of the given geometry or null if there is no M
coordinate.
+
+Format: `ST_MMin(geom: Geometry)`
+
+Since: `vTBD`
+
+SQL Example:
+
+```sql
+SELECT ST_MMin(
+ ST_GeomFromWKT('LINESTRING ZM(1 1 1 1, 2 2 2 2, 3 3 3 3, -1 -1 -1 -1)')
+)
+```
+
+Output:
+
+```
+-1.0
+```
+
## ST_MakeLine
Introduction: Creates a LineString containing the points of Point, MultiPoint,
or LineString geometries. Other geometry types cause an error.
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index dccb5fad0..928770887 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -2075,6 +2075,50 @@ Output:
4.0
```
+## ST_MMax
+
+Introduction: Returns M maxima of the given geometry or null if there is no M
coordinate.
+
+Format: `ST_MMax(geom: Geometry)`
+
+Since: `vTBD`
+
+SQL Example
+
+```sql
+SELECT ST_MMax(
+ ST_GeomFromWKT('POLYGON ZM ((30 10 5 1, 40 40 10 2, 20 40 15 3, 10 20
20 4, 30 10 5 1))')
+)
+```
+
+Output:
+
+```
+4.0
+```
+
+## ST_MMin
+
+Introduction: Returns M minima of the given geometry or null if there is no M
coordinate.
+
+Format: `ST_MMin(geom: Geometry)`
+
+Since: `vTBD`
+
+SQL Example:
+
+```sql
+SELECT ST_MMin(
+ ST_GeomFromWKT('LINESTRING ZM(1 1 1 1, 2 2 2 2, 3 3 3 3, -1 -1 -1 -1)')
+)
+```
+
+Output:
+
+```
+-1.0
+```
+
## ST_MakeLine
Introduction: Creates a LineString containing the points of Point, MultiPoint,
or LineString geometries. Other geometry types cause an error.
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 fe47f5f86..6b5639f97 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -128,6 +128,8 @@ public class Catalog {
new Functions.ST_LineSubstring(),
new Functions.ST_HasM(),
new Functions.ST_M(),
+ new Functions.ST_MMin(),
+ new Functions.ST_MMax(),
new Functions.ST_MakeLine(),
new Functions.ST_Polygon(),
new Functions.ST_Polygonize(),
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 150da9e99..7397087c5 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
@@ -765,6 +765,22 @@ public class Functions {
}
}
+ public static class ST_MMin 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.mMin(geom);
+ }
+ }
+
+ public static class ST_MMax 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.mMax(geom);
+ }
+ }
+
public static class ST_MakeLine extends ScalarFunction {
@DataTypeHint(value = "RAW", bridgedTo =
org.locationtech.jts.geom.Geometry.class)
public Geometry eval(@DataTypeHint(value = "RAW", bridgedTo =
org.locationtech.jts.geom.Geometry.class) Object o1,
diff --git a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
index e9b4053a9..9d4d6bb79 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -713,6 +713,28 @@ public class FunctionTest extends TestBase{
assertEquals(4, actual, FP_TOLERANCE);
}
+ @Test
+ public void testMMin() {
+ Table lineTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING
ZM(1 1 1 1, 2 2 2 2, 3 3 3 3, -1 -1 -1 -1)') AS line");
+ double actual = (double)
first(lineTable.select(call(Functions.ST_MMin.class.getSimpleName(),
$("line")))).getField(0);
+ assertEquals(-1.0, actual, FP_TOLERANCE);
+
+ lineTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING(1 1,
2 2, 3 3, -1 -1)') AS line");
+ Double actualNull = (Double)
first(lineTable.select(call(Functions.ST_MMin.class.getSimpleName(),
$("line")))).getField(0);
+ assertNull(actualNull);
+ }
+
+ @Test
+ public void testMMax() {
+ Table lineTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING
ZM(1 1 1 1, 2 2 2 2, 3 3 3 3, -1 -1 -1 -1)') AS line");
+ double actual = (double)
first(lineTable.select(call(Functions.ST_MMax.class.getSimpleName(),
$("line")))).getField(0);
+ assertEquals(3, actual, FP_TOLERANCE);
+
+ lineTable = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING(1 1,
2 2, 3 3, -1 -1)') AS line");
+ Double actualNull = (Double)
first(lineTable.select(call(Functions.ST_MMax.class.getSimpleName(),
$("line")))).getField(0);
+ assertNull(actualNull);
+ }
+
@Test
public void testZMax() {
Table polygonTable = tableEnv.sqlQuery("SELECT
ST_GeomFromWKT('LINESTRING(1 3 4, 5 6 7)') AS " + polygonColNames[0]);
diff --git a/python/sedona/sql/st_functions.py
b/python/sedona/sql/st_functions.py
index 2b45d9e03..07814947a 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -880,6 +880,28 @@ def ST_M(geom: ColumnOrName) -> Column:
"""
return _call_st_function("ST_M", geom)
+@validate_argument_types
+def ST_MMin(geom: ColumnOrName) -> Column:
+ """Return the minimum M coordinate of a geometry.
+
+ :param geometry: Geometry column to get the minimum M coordinate from.
+ :type geometry: ColumnOrName
+ :return: Minimum M coordinate for the geometry as a double column.
+ :rtype: Column
+ """
+ return _call_st_function("ST_MMin", geom)
+
+@validate_argument_types
+def ST_MMax(geom: ColumnOrName) -> Column:
+ """Return the maximum M coordinate of a geometry.
+
+ :param geometry: Geometry column to get the maximum M coordinate from.
+ :type geometry: ColumnOrName
+ :return: Minimum M coordinate for the geometry as a double column.
+ :rtype: Column
+ """
+ return _call_st_function("ST_MMax", geom)
+
@validate_argument_types
def ST_MakeLine(geom1: ColumnOrName, geom2: Optional[ColumnOrName] = None) ->
Column:
diff --git a/python/tests/sql/test_dataframe_api.py
b/python/tests/sql/test_dataframe_api.py
index 8df2440fa..628aceefa 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -148,6 +148,8 @@ test_configurations = [
(stf.ST_LineSubstring, ("line", 0.5, 1.0), "linestring_geom", "",
"LINESTRING (2.5 0, 3 0, 4 0, 5 0)"),
(stf.ST_HasM, ("point",), "4D_point", "", True),
(stf.ST_M, ("point",), "4D_point", "", 4.0),
+ (stf.ST_MMin, ("line",), "4D_line", "", -1.0),
+ (stf.ST_MMax, ("line",), "4D_line", "", 3.0),
(stf.ST_MakeValid, ("geom",), "invalid_geom", "", "MULTIPOLYGON (((1 5, 3
3, 1 1, 1 5)), ((5 3, 7 5, 7 1, 5 3)))"),
(stf.ST_MakeLine, ("line1", "line2"), "two_lines", "", "LINESTRING (0 0, 1
1, 0 0, 3 2)"),
(stf.ST_Polygon, ("geom", 4236), "closed_linestring_geom", "", "POLYGON
((0 0, 1 0, 1 1, 0 0))"),
@@ -319,6 +321,8 @@ wrong_type_configurations = [
(stf.ST_LineSubstring, ("", 0.5, None)),
(stf.ST_HasM, (None,)),
(stf.ST_M, (None,)),
+ (stf.ST_MMin, (None,)),
+ (stf.ST_MMax, (None,)),
(stf.ST_MakeValid, (None,)),
(stf.ST_MakePolygon, (None,)),
(stf.ST_MinimumBoundingCircle, (None,)),
@@ -451,6 +455,8 @@ class TestDataFrameAPI(TestBase):
return TestDataFrameAPI.spark.sql("SELECT ST_PointZ(0.0, 0.0, 0.0)
AS a, ST_PointZ(3.0, 0.0, 4.0) AS b")
elif request.param == "4D_point":
return TestDataFrameAPI.spark.sql("SELECT ST_GeomFromWKT('POINT
ZM(1 2 3 4)') AS point")
+ elif request.param == "4D_line":
+ return TestDataFrameAPI.spark.sql("SELECT
ST_GeomFromWKT('LINESTRING ZM(1 1 1 1, 2 2 2 2, 3 3 3 3, -1 -1 -1 -1)') AS
line")
elif request.param == "invalid_geom":
return TestDataFrameAPI.spark.sql("SELECT ST_GeomFromWKT('POLYGON
((1 5, 1 1, 3 3, 5 3, 7 1, 7 5, 5 3, 3 3, 1 5))') AS geom")
elif request.param == "overlapping_polys":
diff --git a/python/tests/sql/test_function.py
b/python/tests/sql/test_function.py
index bc0aeb990..1df5e8508 100644
--- a/python/tests/sql/test_function.py
+++ b/python/tests/sql/test_function.py
@@ -941,6 +941,24 @@ class TestPredicateJoin(TestBase):
actual = baseDf.selectExpr("ST_M(point)").take(1)[0][0]
assert actual == 4.0
+ def test_st_m_min(self):
+ baseDf = self.spark.sql("SELECT ST_GeomFromWKT('LINESTRING ZM(1 1 1 1,
2 2 2 2, 3 3 3 3, -1 -1 -1 -1)') AS line")
+ actual = baseDf.selectExpr("ST_MMin(line)").take(1)[0][0]
+ assert actual == -1.0
+
+ baseDf = self.spark.sql("SELECT ST_GeomFromWKT('LINESTRING(1 1, 2 2, 3
3, -1 -1)') AS line")
+ actual = baseDf.selectExpr("ST_MMin(line)").take(1)[0][0]
+ assert actual is None
+
+ def test_st_m_max(self):
+ baseDf = self.spark.sql("SELECT ST_GeomFromWKT('LINESTRING ZM(1 1 1 1,
2 2 2 2, 3 3 3 3, -1 -1 -1 -1)') AS line")
+ actual = baseDf.selectExpr("ST_MMax(line)").take(1)[0][0]
+ assert actual == 3.0
+
+ baseDf = self.spark.sql("SELECT ST_GeomFromWKT('LINESTRING(1 1, 2 2, 3
3, -1 -1)') AS line")
+ actual = baseDf.selectExpr("ST_MMax(line)").take(1)[0][0]
+ assert actual is None
+
def test_st_subdivide_explode_lateral(self):
# Given
geometry_df = self.__wkt_list_to_data_frame(
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 334ac8e71..3e7eacf0a 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
@@ -114,6 +114,8 @@ object Catalog {
function[ST_Boundary](),
function[ST_HasM](),
function[ST_M](),
+ function[ST_MMin](),
+ function[ST_MMax](),
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 b395dd0f8..21613b37c 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
@@ -527,6 +527,21 @@ case class ST_M(inputExpressions: Seq[Expression])
}
}
+case class ST_MMin(inputExpressions: Seq[Expression])
+ extends InferredExpression(Functions.mMin _) {
+
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) =
{
+ copy(inputExpressions = newChildren)
+ }
+}
+
+case class ST_MMax(inputExpressions: Seq[Expression])
+ extends InferredExpression(Functions.mMax _) {
+
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) =
{
+ copy(inputExpressions = newChildren)
+ }
+}
/**
* Return a linestring being a substring of the input one starting and ending
at the given fractions of total 2d length.
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 dd7395bd1..65cec5a29 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
@@ -218,6 +218,12 @@ object st_functions extends DataFrameAPI {
def ST_M(geoms: Column): Column = wrapExpression[ST_M](geoms)
def ST_M(geoms: String): Column = wrapExpression[ST_M](geoms)
+ def ST_MMin(geoms: Column): Column = wrapExpression[ST_MMin](geoms)
+ def ST_MMin(geoms: String): Column = wrapExpression[ST_MMin](geoms)
+
+ def ST_MMax(geoms: Column): Column = wrapExpression[ST_MMax](geoms)
+ def ST_MMax(geoms: String): Column = wrapExpression[ST_MMax](geoms)
+
def ST_MakeLine(geoms: Column): Column = wrapExpression[ST_MakeLine](geoms)
def ST_MakeLine(geoms: String): Column = wrapExpression[ST_MakeLine](geoms)
def ST_MakeLine(geom1: Column, geom2: Column): Column =
wrapExpression[ST_MakeLine](geom1, geom2)
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 6d0946b44..3bf263be4 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
@@ -64,6 +64,26 @@ class dataFrameAPITestScala extends TestBaseScala {
assert(actual == 40.0)
}
+ it("Passed ST_MMin") {
+ var baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING ZM(1 1
1 1, 2 2 2 2, 3 3 3 3, -1 -1 -1 -1)') as line")
+ val actual = baseDf.select(ST_MMin("line")).first().getDouble(0)
+ assert(actual == -1.0)
+
+ baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING(1 1, 2 2, 3
3, -1 -1)') AS line")
+ val actualNull = baseDf.select(ST_MMin("line")).first().get(0)
+ assert(actualNull == null)
+ }
+
+ it("Passed ST_MMax()") {
+ var baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING ZM(1 1
1 1, 2 2 2 2, 3 3 3 3, -1 -1 -1 -1)') as line")
+ val actual = baseDf.select(ST_MMax("line")).first().getDouble(0)
+ assert(actual == 3.0)
+
+ baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING(1 1, 2 2, 3
3, -1 -1)') AS line")
+ val actualNull = baseDf.select(ST_MMax("line")).first().get(0)
+ assert(actualNull == null)
+ }
+
it("Passed st_pointm") {
val pointDf = sparkSession.sql("SELECT ST_PointM(1,2,100) as point1,
ST_PointM(1,2,100,4326) as point2")
val point1 = pointDf.select(ST_AsEWKT("point1")).take(1)(0).getString(0)
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 5dee828db..98f4975ea 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
@@ -397,6 +397,28 @@ class functionTestScala extends TestBaseScala with
Matchers with GeometrySample
assert(actual == 4.0)
}
+ it("Passed ST_MMin") {
+ var baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING ZM(1 1
1 1, 2 2 2 2, 3 3 3 3, -1 -1 -1 -1)') as line")
+ val actual = baseDf.selectExpr("ST_MMin(line)").first().getDouble(0)
+ assert(actual == -1.0)
+
+ baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING(1 1, 2 2, 3
3, -1 -1)') AS line")
+ val actualNull = baseDf.selectExpr("ST_MMin(line)").first().get(0)
+ assert(actualNull == null)
+ }
+
+ it("Passed ST_MMax") {
+ var baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING ZM(1 1
1 1, 2 2 2 2, 3 3 3 3, -1 -1 -1 -1)') as line")
+ val actual = baseDf.selectExpr("ST_MMax(line)").first().getDouble(0)
+ assert(actual == 3.0)
+
+ baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('LINESTRING(1 1, 2 2, 3
3, -1 -1)') AS line")
+ val actualNull = baseDf.selectExpr("ST_MMax(line)").first().get(0)
+ assert(actualNull == null)
+
+ print(sparkSession.sql("SELECT ST_MMax(ST_GeomFromWKT('POLYGON ZM ((30
10 5 1, 40 40 10 2, 20 40 15 3, 10 20 20 4, 30 10 5 1))'))").first().get(0))
+ }
+
it("Passed ST_MakeLine") {
val testtable = sparkSession.sql(
"""SELECT