This is an automated email from the ASF dual-hosted git repository.

jiayu pushed a commit to branch SEDONA-589
in repository https://gitbox.apache.org/repos/asf/sedona.git

commit efc296d1e1e4dc39820a9fded0a1238df2d65a58
Author: Furqaan Khan <[email protected]>
AuthorDate: Thu Apr 25 22:42:37 2024 -0400

    [TASK-32] Add ST_LongestLine (#169)
    
    * temp commit
    
    * Revert "temp commit"
    
    This reverts commit 8cd8ecc6b3ae533379b779ba08c23b12df47e2fc.
    
    * feat: Add ST_LongestLine
---
 .../java/org/apache/sedona/common/Functions.java   | 18 ++++++++++++
 .../org/apache/sedona/common/FunctionsTest.java    | 32 ++++++++++++++++++++++
 docs/api/flink/Function.md                         | 23 ++++++++++++++++
 docs/api/snowflake/vector-data/Function.md         | 21 ++++++++++++++
 docs/api/sql/Function.md                           | 23 ++++++++++++++++
 .../main/java/org/apache/sedona/flink/Catalog.java |  1 +
 .../apache/sedona/flink/expressions/Functions.java | 10 +++++++
 .../java/org/apache/sedona/flink/FunctionTest.java | 10 +++++++
 python/sedona/sql/st_functions.py                  | 13 +++++++++
 python/tests/sql/test_dataframe_api.py             |  4 +++
 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  | 11 ++++++++
 .../apache/sedona/snowflake/snowsql/UDFsV2.java    | 10 +++++++
 .../scala/org/apache/sedona/sql/UDF/Catalog.scala  |  1 +
 .../sql/sedona_sql/expressions/Functions.scala     |  8 ++++++
 .../sql/sedona_sql/expressions/st_functions.scala  |  3 ++
 .../apache/sedona/sql/dataFrameAPITestScala.scala  |  7 +++++
 .../org/apache/sedona/sql/functionTestScala.scala  |  7 +++++
 20 files changed, 227 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 ac88ce04f..5025fd19f 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -1062,6 +1062,24 @@ public class Functions {
         return isExteriorRingCCW && isInteriorRingCCW;
     }
 
+    public static Geometry longestLine(Geometry geom1, Geometry geom2) {
+        double maxLength = 0;
+        Coordinate longestStart = null;
+        Coordinate longestEnd = null;
+
+        for (Coordinate coord1: geom1.getCoordinates()) {
+            for (Coordinate coord2: geom2.getCoordinates()) {
+                double length = coord1.distance(coord2);
+                if (length > maxLength) {
+                    maxLength = length;
+                    longestStart = coord1;
+                    longestEnd = coord2;
+                }
+            }
+        }
+        return geom1.getFactory().createLineString(new Coordinate[] 
{longestStart, longestEnd});
+    }
+
     public static Geometry difference(Geometry leftGeometry, Geometry 
rightGeometry) {
         boolean isIntersects = leftGeometry.intersects(rightGeometry);
         if (!isIntersects) {
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 017f65e64..ab0ebe0db 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -1012,6 +1012,38 @@ public class FunctionsTest extends TestBase {
         assertEquals("Median failed to converge within 1.0E-06 after 5 
iterations.", e.getMessage());
     }
 
+    @Test
+    public void longestLine() throws ParseException {
+        Geometry geom1 = Constructors.geomFromWKT("POLYGON ((30 10, 40 40, 20 
40, 10 20, 30 10))", 0);
+        Geometry geom2 = Functions.buffer(Constructors.geomFromWKT("POINT 
(10.123456 -20.654321)", 0), 30);
+        String actual = Functions.asWKT(Functions.longestLine(geom1, geom2));
+        String expected = "LINESTRING (40 40, -1.3570469709526929 
-48.37070697533861)";
+        assertEquals(expected, actual);
+
+        geom1 = Constructors.geomFromWKT("POLYGON ((190 150, 20 10, 160 70, 
190 150))", 0);
+        geom2 = Constructors.geomFromWKT("POINT(80 160)", 0);
+        actual = 
Functions.asWKT(Functions.reducePrecision(Functions.longestLine(geom1, 
Functions.buffer(geom2, 30)), 8));
+        expected = "LINESTRING (20 10, 91.48050297 187.71638598)";
+        assertEquals(expected, actual);
+
+        geom1 = Constructors.geomFromWKT("POINT (160 40)", 0);
+        geom2 = Constructors.geomFromWKT("LINESTRING (10 30, 50 50, 30 110, 70 
90, 180 140, 130 190)", 0);
+        actual = Functions.asWKT(Functions.longestLine(geom1, geom2));
+        expected = "LINESTRING (160 40, 130 190)";
+        assertEquals(expected, actual);
+
+        geom1 = Constructors.geomFromWKT("POLYGON ((40 180, 110 160, 180 180, 
180 120, 140 90, 160 40, 80 10, 70 40, 20 50, 40 180),(60 140, 99 77.5, 90 140, 
60 140))", 0);
+        actual = 
Functions.asWKT(Functions.normalize(Functions.longestLine(geom1, geom1)));
+        expected = "LINESTRING (20 50, 180 180)";
+        assertEquals(expected, actual);
+
+        geom1 = Constructors.geomFromWKT("POINT Z (10 20 5)", 0);
+        geom2 = Constructors.geomFromWKT("POLYGON Z ((30 40 10, 40 50 15, 50 
60 20, 30 40 10))", 0);
+        actual = Functions.asWKT(Functions.longestLine(geom1, geom2));
+        expected = "LINESTRING Z(10 20 5, 50 60 20)";
+        assertEquals(expected, actual);
+    }
+
     @Test
     public void makepolygonWithSRID() {
         Geometry lineString1 = GEOMETRY_FACTORY.createLineString(coordArray(0, 
0, 1, 1, 1, 0, 0, 0));
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index 9a51cae82..7653b709c 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -2184,6 +2184,29 @@ Output:
 LINESTRING (69.28469348539744 94.28469348539744, 100 125, 111.70035626068274 
140.21046313888758)
 ```
 
+## ST_LongestLine
+
+Introduction: Returns the LineString geometry representing the maximum 
distance between any two points from the input geometries.
+
+Format: `ST_LongestLine(geom1: Geometry, geom2: Geometry)`
+
+Since: `vTBD`
+
+SQL Example:
+
+```sql
+SELECT ST_LongestLine(
+        ST_GeomFromText("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))"),
+        ST_GeomFromText("POLYGON ((10 20, 30 30, 40 20, 30 10, 10 20))")
+)
+```
+
+Output:
+
+```
+LINESTRING (40 40, 10 20)
+```
+
 ## ST_M
 
 Introduction: Returns M Coordinate of given Point, null otherwise.
diff --git a/docs/api/snowflake/vector-data/Function.md 
b/docs/api/snowflake/vector-data/Function.md
index 0da9461f0..95e41d2ca 100644
--- a/docs/api/snowflake/vector-data/Function.md
+++ b/docs/api/snowflake/vector-data/Function.md
@@ -1636,6 +1636,27 @@ SQL example:
 SELECT ST_LineSubstring(ST_GeomFromWKT('LINESTRING(25 50, 100 125, 150 190)'), 
0.333, 0.666) as Substring
 ```
 
+## ST_LongestLine
+
+Introduction: Returns the LineString geometry representing the maximum 
distance between any two points from the input geometries.
+
+Format: `ST_LongestLine(geom1: Geometry, geom2: Geometry)`
+
+SQL Example:
+
+```sql
+SELECT ST_LongestLine(
+        ST_GeomFromText("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))"),
+        ST_GeomFromText("POLYGON ((10 20, 30 30, 40 20, 30 10, 10 20))")
+)
+```
+
+Output:
+
+```
+LINESTRING (40 40, 10 20)
+```
+
 Output:
 
 ```
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index 9a7a3eafe..9587b8cbe 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -2191,6 +2191,29 @@ Output:
 LINESTRING (69.28469348539744 94.28469348539744, 100 125, 111.70035626068274 
140.21046313888758)
 ```
 
+## ST_LongestLine
+
+Introduction: Returns the LineString geometry representing the maximum 
distance between any two points from the input geometries.
+
+Format: `ST_LongestLine(geom1: Geometry, geom2: Geometry)`
+
+Since: `vTBD`
+
+SQL Example:
+
+```sql
+SELECT ST_LongestLine(
+        ST_GeomFromText("POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))"),
+        ST_GeomFromText("POLYGON ((10 20, 30 30, 40 20, 30 10, 10 20))")
+)
+```
+
+Output:
+
+```
+LINESTRING (40 40, 10 20)
+```
+
 ## ST_M
 
 Introduction: Returns M Coordinate of given Point, null otherwise.
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 df8c86186..91705e59c 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -82,6 +82,7 @@ public class Catalog {
                 new Functions.ST_LengthSpheroid(),
                 new Functions.ST_LineInterpolatePoint(),
                 new Functions.ST_LineLocatePoint(),
+                new Functions.ST_LongestLine(),
                 new FunctionsGeoTools.ST_Transform(),
                 new Functions.ST_FlipCoordinates(),
                 new Functions.ST_GeoHash(),
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 c1e031b83..dcc36b029 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
@@ -354,6 +354,16 @@ public class Functions {
         }
     }
 
+    public static class ST_LongestLine 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 g1,
+                             @DataTypeHint(value = "RAW", bridgedTo = 
org.locationtech.jts.geom.Geometry.class) Object g2) {
+            Geometry geom1 = (Geometry) g1;
+            Geometry geom2 = (Geometry) g2;
+            return org.apache.sedona.common.Functions.longestLine(geom1, 
geom2);
+        }
+    }
+
     public static class ST_YMin extends ScalarFunction {
         @DataTypeHint("Double")
         public Double 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 6db3f9493..c1e0bff00 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -444,6 +444,16 @@ public class FunctionTest extends TestBase{
         assertEquals(expected, actual, 0.1);
     }
 
+    @Test
+    public void testLongestLine() {
+        Table tbl = tableEnv.sqlQuery(
+                "SELECT ST_GeomFromWKT('POLYGON ((40 180, 110 160, 180 180, 
180 120, 140 90, 160 40, 80 10, 70 40, 20 50, 40 180),(60 140, 99 77.5, 90 140, 
60 140))') as geom1");
+        String actual = (String) 
first(tbl.select(call(Functions.ST_LongestLine.class.getSimpleName(), 
$("geom1"), $("geom1"))).as("geom")
+                .select(call(Functions.ST_AsText.class.getSimpleName(), 
$("geom")))).getField(0);
+        String expected = "LINESTRING (180 180, 20 50)";
+        assertEquals(expected, actual);
+    }
+
     @Test
     public void testLineInterpolatePoint() {
         Table table = tableEnv.sqlQuery("SELECT ST_GeomFromWKT('LINESTRING (0 
0, 2 0)') AS line");
diff --git a/python/sedona/sql/st_functions.py 
b/python/sedona/sql/st_functions.py
index 82ca9c2fe..f38c0cebf 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -881,6 +881,19 @@ def ST_LineSubstring(line_string: ColumnOrName, 
start_fraction: ColumnOrNameOrNu
     """
     return _call_st_function("ST_LineSubstring", (line_string, start_fraction, 
end_fraction))
 
+@validate_argument_types
+def ST_LongestLine(geom1: ColumnOrName, geom2: ColumnOrName) -> Column:
+    """Compute the longest line between the two geometries
+
+    :param geom1:
+    :type geom1: ColumnOrName
+    :param geom2:
+    :type geom2: ColumnOrName
+    :return: Longest line between the two input geometries
+    :rtype: Column
+    """
+    return _call_st_function("ST_LongestLine", (geom1, geom2))
+
 @validate_argument_types
 def ST_HasZ(geom: ColumnOrName) -> Column:
     """Check whether geometry has Z coordinate
diff --git a/python/tests/sql/test_dataframe_api.py 
b/python/tests/sql/test_dataframe_api.py
index 42818f07f..3bb66493e 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -154,6 +154,7 @@ test_configurations = [
     (stf.ST_LineLocatePoint, ("line", "point"), "line_and_point", "", 0.5),
     (stf.ST_LineMerge, ("geom",), "multiline_geom", "", "LINESTRING (0 0, 1 0, 
1 1, 0 0)"),
     (stf.ST_LineSubstring, ("line", 0.5, 1.0), "linestring_geom", "", 
"LINESTRING (2.5 0, 3 0, 4 0, 5 0)"),
+    (stf.ST_LongestLine, ("geom", "geom"), "geom_collection", "", "LINESTRING 
(0 0, 1 0)"),
     (stf.ST_HasZ, ("a",), "two_points", "", True),
     (stf.ST_HasM, ("point",), "4D_point", "", True),
     (stf.ST_M, ("point",), "4D_point", "", 4.0),
@@ -337,6 +338,9 @@ wrong_type_configurations = [
     (stf.ST_LineSubstring, (None, 0.5, 1.0)),
     (stf.ST_LineSubstring, ("", None, 1.0)),
     (stf.ST_LineSubstring, ("", 0.5, None)),
+    (stf.ST_LongestLine, (None, "")),
+    (stf.ST_LongestLine, (None, None)),
+    (stf.ST_LongestLine, ("", None)),
     (stf.ST_HasZ, (None,)),
     (stf.ST_HasM, (None,)),
     (stf.ST_M, (None,)),
diff --git a/python/tests/sql/test_function.py 
b/python/tests/sql/test_function.py
index 7686eb81a..73897126b 100644
--- a/python/tests/sql/test_function.py
+++ b/python/tests/sql/test_function.py
@@ -1386,6 +1386,12 @@ class TestPredicateJoin(TestBase):
                 "select 
ST_AsText(ST_LineFromMultiPoint(ST_GeomFromText({})))".format(input_geom))
             assert line_geometry.take(1)[0][0] == expected_geom
 
+    def test_st_longest_line(self):
+        basedf = self.spark.sql("SELECT ST_GeomFromWKT('POLYGON ((40 180, 110 
160, 180 180, 180 120, 140 90, 160 40, 80 10, 70 40, 20 50, 40 180),(60 140, 99 
77.5, 90 140, 60 140))') as geom")
+        actual = basedf.selectExpr("ST_AsText(ST_LongestLine(geom, 
geom))").take(1)[0][0]
+        expected = "LINESTRING (180 180, 20 50)"
+        assert expected == actual
+
     def test_st_s2_cell_ids(self):
         test_cases = [
             "'POLYGON((-1 0, 1 0, 0 0, 0 1, -1 0))'",
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 c0842d36b..7d0e0e19a 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
@@ -590,6 +590,15 @@ public class TestFunctions extends TestBase {
         );
     }
 
+    @Test
+    public void test_ST_LongestLine() {
+        registerUDF("ST_LongestLine", byte[].class, byte[].class);
+        verifySqlSingleRes(
+                "SELECT 
sedona.ST_AsText(sedona.ST_LongestLine(sedona.ST_GeomFromWKT('POLYGON ((40 180, 
110 160, 180 180, 180 120, 140 90, 160 40, 80 10, 70 40, 20 50, 40 180),(60 
140, 99 77.5, 90 140, 60 140))'), sedona.ST_GeomFromWKT('POLYGON ((40 180, 110 
160, 180 180, 180 120, 140 90, 160 40, 80 10, 70 40, 20 50, 40 180),(60 140, 99 
77.5, 90 140, 60 140))')))",
+                "LINESTRING (180 180, 20 50)"
+        );
+    }
+
     @Test
     public void test_ST_MakeLine() {
         registerUDF("ST_MakeLine", byte[].class, byte[].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 350ccbace..2154027f2 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
@@ -590,6 +590,16 @@ public class TestFunctionsV2
                 "LINESTRING(45.173118104 45.743370112,50 20,90 
80,112.975930502 49.365425998)"
         );
     }
+
+    @Test
+    public void test_ST_LongestLine() {
+        registerUDFV2("ST_LongestLine", String.class, String.class);
+        verifySqlSingleRes(
+                "SELECT 
ST_AsText(sedona.ST_LongestLine(ST_GeomFromWKT('POLYGON ((40 180, 110 160, 180 
180, 180 120, 140 90, 160 40, 80 10, 70 40, 20 50, 40 180),(60 140, 99 77.5, 90 
140, 60 140))'), ST_GeomFromWKT('POLYGON ((40 180, 110 160, 180 180, 180 120, 
140 90, 160 40, 80 10, 70 40, 20 50, 40 180),(60 140, 99 77.5, 90 140, 60 
140))')))",
+                "LINESTRING(180 180,20 50)"
+        );
+    }
+
     @Test
     public void test_ST_MakePolygon() {
         registerUDFV2("ST_MakePolygon", 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 b478f1ee0..a184cc6ec 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
@@ -766,6 +766,17 @@ public class UDFs {
                 )
         );
     }
+
+    @UDFAnnotations.ParamMeta(argNames = {"geom1", "geom2"})
+    public static byte[] ST_LongestLine(byte[] geom1, byte[] geom2) {
+        return GeometrySerde.serialize(
+                Functions.longestLine(
+                        GeometrySerde.deserialize(geom1),
+                        GeometrySerde.deserialize(geom2)
+                )
+        );
+    }
+
     @UDFAnnotations.ParamMeta(argNames = {"point1", "point2"})
     public static byte[] ST_MakeLine(byte[] geom1, byte[] geom2) {
         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 4c419b71d..720f106b3 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
@@ -684,6 +684,16 @@ public class UDFsV2
         );
     }
 
+    @UDFAnnotations.ParamMeta(argNames = {"geom1", "geom2"}, argTypes = 
{"Geometry", "Geometry"}, returnTypes = "Geometry")
+    public static String ST_LongestLine(String geom1, String geom2) {
+        return GeometrySerde.serGeoJson(
+                Functions.longestLine(
+                        GeometrySerde.deserGeoJson(geom1),
+                        GeometrySerde.deserGeoJson(geom2)
+                )
+        );
+    }
+
     @UDFAnnotations.ParamMeta(argNames = {"point1", "point2"}, argTypes = 
{"Geometry", "Geometry"}, returnTypes = "Geometry")
     public static String ST_MakeLine(String geom1, String geom2) {
         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 509687a6d..fe53d86fa 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
@@ -150,6 +150,7 @@ object Catalog {
     function[ST_LineSubstring](),
     function[ST_LineInterpolatePoint](),
     function[ST_LineLocatePoint](),
+    function[ST_LongestLine](),
     function[ST_SubDivideExplode](),
     function[ST_SubDivide](),
     function[ST_MakeLine](),
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 d414d30d0..d7a836580 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
@@ -1185,6 +1185,14 @@ case class ST_LengthSpheroid(inputExpressions: 
Seq[Expression])
   }
 }
 
+case class ST_LongestLine(inputExpressions: Seq[Expression])
+  extends InferredExpression(Functions.longestLine _) {
+
+  protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = 
{
+    copy(inputExpressions = newChildren)
+  }
+}
+
 case class ST_NumPoints(inputExpressions: Seq[Expression])
   extends InferredExpression(Functions.numPoints _) {
   protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) = 
{
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 a54e59044..77d2223e2 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
@@ -221,6 +221,9 @@ object st_functions extends DataFrameAPI {
   def ST_LineSubstring(lineString: Column, startFraction: Column, endFraction: 
Column): Column = wrapExpression[ST_LineSubstring](lineString, startFraction, 
endFraction)
   def ST_LineSubstring(lineString: String, startFraction: Double, endFraction: 
Double): Column = wrapExpression[ST_LineSubstring](lineString, startFraction, 
endFraction)
 
+  def ST_LongestLine(geom1: Column, geom2: Column): Column = 
wrapExpression[ST_LongestLine](geom1, geom2)
+  def ST_LongestLine(geom1: String, geom2: String): Column = 
wrapExpression[ST_LongestLine](geom1, geom2)
+
   def ST_HasZ(geoms: Column): Column = wrapExpression[ST_HasZ](geoms)
   def ST_HasZ(geoms: String): Column = wrapExpression[ST_HasZ](geoms)
 
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 72a55323d..f97fb6525 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
@@ -928,6 +928,13 @@ class dataFrameAPITestScala extends TestBaseScala {
       assert(actualResult == expectedResult)
     }
 
+    it("Passed ST_LongestLine") {
+      val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((40 180, 
110 160, 180 180, 180 120, 140 90, 160 40, 80 10, 70 40, 20 50, 40 180),(60 
140, 99 77.5, 90 140, 60 140))') as geom")
+      val actual = baseDf.select(ST_LongestLine("geom", 
"geom")).first().get(0).asInstanceOf[Geometry].toText
+      val expected = "LINESTRING (180 180, 20 50)"
+      assert(expected.equals(actual))
+    }
+
     it("Passed ST_FlipCoordinates") {
       val baseDf = sparkSession.sql("SELECT ST_Point(0.0, 1.0) AS geom")
       val df = baseDf.select(ST_FlipCoordinates("geom"))
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 cf7e40460..1dc0359e5 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
@@ -1626,6 +1626,13 @@ class functionTestScala extends TestBaseScala with 
Matchers with GeometrySample
         "GEOMETRYCOLLECTION EMPTY")
   }
 
+  it("Should pass ST_LongestLine") {
+    val baseDf = sparkSession.sql("SELECT ST_GeomFromWKT('POLYGON ((40 180, 
110 160, 180 180, 180 120, 140 90, 160 40, 80 10, 70 40, 20 50, 40 180),(60 
140, 99 77.5, 90 140, 60 140))') as geom")
+    val actual = baseDf.selectExpr("ST_LongestLine(geom, 
geom)").first().get(0).asInstanceOf[Geometry].toText
+    val expected = "LINESTRING (180 180, 20 50)"
+    assert(expected.equals(actual))
+  }
+
   it("Should pass ST_FlipCoordinates") {
     val pointDF = createSamplePointDf(5, "geom")
     val oldX = pointDF.take(1)(0).get(0).asInstanceOf[Geometry].getCoordinate.x

Reply via email to