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 dba56d7a20 [SEDONA-675] Add ST_InterpolatePoint (#1684)
dba56d7a20 is described below
commit dba56d7a20e70f0d982bafde670592933f339b84
Author: Pranav Toggi <[email protected]>
AuthorDate: Tue Nov 19 11:35:46 2024 -0800
[SEDONA-675] Add ST_InterpolatePoint (#1684)
---
.../java/org/apache/sedona/common/Functions.java | 53 +++++++++++++++++
.../org/apache/sedona/common/FunctionsTest.java | 25 ++++++++
docs/api/flink/Function.md | 26 +++++++++
docs/api/sql/Function.md | 26 +++++++++
.../main/java/org/apache/sedona/flink/Catalog.java | 1 +
.../apache/sedona/flink/expressions/Functions.java | 11 ++++
.../java/org/apache/sedona/flink/FunctionTest.java | 67 ++++++++++++++++++++++
python/sedona/sql/st_functions.py | 15 +++++
python/tests/sql/test_dataframe_api.py | 5 ++
.../scala/org/apache/sedona/sql/UDF/Catalog.scala | 3 +-
.../sql/sedona_sql/expressions/Functions.scala | 6 ++
.../sql/sedona_sql/expressions/st_functions.scala | 6 ++
.../apache/sedona/sql/dataFrameAPITestScala.scala | 25 ++++++++
.../org/apache/sedona/sql/functionTestScala.scala | 61 ++++++++++++++++++++
14 files changed, 329 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 9c01cbb5f1..c93bae3e2f 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -2377,4 +2377,57 @@ public class Functions {
AffineTransformation rotation =
AffineTransformation.rotationInstance(angle, originX, originY);
return rotation.transform(geometry);
}
+
+ /**
+ * This function returns the m coordinate of the closest point in a
LineString to the specified
+ * Point.
+ *
+ * @param geom1 The LineString (with or without M values) to be evaluated.
+ * @param geom2 The Point object to find the closest point to.
+ * @return The interpolated M value of the closest point on the LineString.
+ */
+ public static double interpolatePoint(Geometry geom1, Geometry geom2) {
+ if
(!(Geometry.TYPENAME_LINESTRING.equalsIgnoreCase(geom1.getGeometryType()))) {
+ throw new IllegalArgumentException(
+ String.format(
+ "First argument is of type %s, should be a LineString.",
geom1.getGeometryType()));
+ }
+ if (!(Geometry.TYPENAME_POINT.equalsIgnoreCase(geom2.getGeometryType()))) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Second argument is of type %s, should be a Point.",
geom2.getGeometryType()));
+ }
+ if (Float.isNaN((float) geom1.getCoordinate().getM())) {
+ throw new IllegalArgumentException("The given linestring does not have a
measure value.");
+ }
+
+ if (geom1.getSRID() != geom2.getSRID()) {
+ throw new IllegalArgumentException(
+ String.format(
+ "The Line has SRID %d and Point has SRID %d. The Line and Point
should be in the same SRID.",
+ geom1.getSRID(), geom2.getSRID()));
+ }
+
+ LineString line = (LineString) geom1;
+ Point point = (Point) geom2;
+
+ // Find the closest point on the line to the input point
+ Coordinate closestPoint = DistanceOp.nearestPoints(line, point)[0];
+
+ // Use LengthIndexedLine to extract the index at the closest point
+ LengthIndexedLine indexedLine = new LengthIndexedLine(line);
+ double index = indexedLine.indexOf(closestPoint);
+
+ // Extract the point at that index and compute its length fraction
+ double totalLength = indexedLine.getEndIndex();
+ double fractionAlongLine = index / totalLength;
+
+ // Get the start and end coordinates of the line
+ Geometry start = line.getStartPoint();
+ Geometry end = line.getEndPoint();
+
+ // Interpolate the M value
+ return fractionAlongLine * (end.getCoordinate().getM() -
start.getCoordinate().getM())
+ + start.getCoordinate().getM();
+ }
}
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 e9e9af6322..74ab3483b0 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -4086,4 +4086,29 @@ public class FunctionsTest extends TestBase {
"LINESTRING (0 0, -0.8390715290764524 -0.5440211108893698,
-0.2950504181870827 -1.383092639965822, 0 0)",
result);
}
+
+ @Test
+ public void interpolatePoint() throws ParseException {
+ Geometry line = Constructors.geomFromEWKT("LINESTRING M (0 0 0, 2 0 2, 4 0
4)");
+ Geometry point = Constructors.geomFromEWKT("POINT(1 1)");
+
+ double actual = Functions.interpolatePoint(line, point);
+ double expected = 1.0;
+ assertEquals(expected, actual, 1e-6);
+
+ line = Constructors.geomFromEWKT("LINESTRING M (0 0 0, -2 2 2, -4 4 4)");
+ point = Constructors.geomFromEWKT("POINT(-1 1)");
+ actual = Functions.interpolatePoint(line, point);
+ assertEquals(expected, actual, 1e-6);
+
+ line = Constructors.geomFromEWKT("LINESTRING M (0 0 0, 2 2 2, 4 0 4)");
+ point = Constructors.geomFromEWKT("POINT(2 0)");
+ actual = Functions.interpolatePoint(line, point);
+ assertEquals(expected, actual, 1e-6);
+
+ point = Constructors.geomFromEWKT("POINT(2.5 1)");
+ actual = Functions.interpolatePoint(line, point);
+ expected = 2.75;
+ assertEquals(expected, actual, 1e-6);
+ }
}
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index 4782f46555..56c358a3bf 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -2017,6 +2017,32 @@ Output:
LINEARRING (1 1, 2 1, 2 2, 1 2, 1 1)
```
+## ST_InterpolatePoint
+
+Introduction: Returns the interpolated measure value of a linear measured
LineString at the point closest to the specified point.
+
+!!!Note
+ Make sure that both geometries have the same SRID, otherwise the function
will throw an IllegalArgumentException.
+
+Format: `ST_InterpolatePoint(linestringM: Geometry, point: Geometry)`
+
+Since: `v1.7.0`
+
+SQL Example
+
+```sql
+SELECT ST_InterpolatePoint(
+ ST_GeomFromWKT("LINESTRING M (0 0 0, 2 0 2, 4 0 4)"),
+ ST_GeomFromWKT("POINT (1 1)")
+ )
+```
+
+Output:
+
+```
+1.0
+```
+
## ST_Intersection
Introduction: Return the intersection geometry of A and B
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index 1e946517d4..d909bd3cab 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -2023,6 +2023,32 @@ Output:
LINESTRING (1 1, 2 1, 2 2, 1 2, 1 1)
```
+## ST_InterpolatePoint
+
+Introduction: Returns the interpolated measure value of a linear measured
LineString at the point closest to the specified point.
+
+!!!Note
+ Make sure that both geometries have the same SRID, otherwise the function
will throw an IllegalArgumentException.
+
+Format: `ST_InterpolatePoint(linestringM: Geometry, point: Geometry)`
+
+Since: `v1.7.0`
+
+SQL Example
+
+```sql
+SELECT ST_InterpolatePoint(
+ ST_GeomFromWKT("LINESTRING M (0 0 0, 2 0 2, 4 0 4)"),
+ ST_GeomFromWKT("POINT (1 1)")
+ )
+```
+
+Output:
+
+```
+1.0
+```
+
## ST_Intersection
Introduction: Return the intersection geometry of A and B
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 21728c5727..5844fc30f0 100644
--- a/flink/src/main/java/org/apache/sedona/flink/Catalog.java
+++ b/flink/src/main/java/org/apache/sedona/flink/Catalog.java
@@ -88,6 +88,7 @@ public class Catalog {
new Functions.ST_DelaunayTriangles(),
new Functions.ST_EndPoint(),
new Functions.ST_GeometryType(),
+ new Functions.ST_InterpolatePoint(),
new Functions.ST_Intersection(),
new Functions.ST_Length(),
new Functions.ST_Length2D(),
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 bccdbe2364..83d53e999b 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
@@ -2068,4 +2068,15 @@ public class Functions {
return org.apache.sedona.common.Functions.rotate(geom1, angle, originX,
originY);
}
}
+
+ public static class ST_InterpolatePoint extends ScalarFunction {
+ @DataTypeHint("Double")
+ public double eval(
+ @DataTypeHint(value = "RAW", bridgedTo = Geometry.class) Object o1,
+ @DataTypeHint(value = "RAW", bridgedTo = Geometry.class) Object o2) {
+ Geometry geom1 = (Geometry) o1;
+ Geometry geom2 = (Geometry) o2;
+ return org.apache.sedona.common.Functions.interpolatePoint(geom1, geom2);
+ }
+ }
}
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 ca9b8c1908..d3d569d940 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -2776,4 +2776,71 @@ public class FunctionTest extends TestBase {
"POLYGON ((0.0700679430157733 0.5247497074078575, 2 0,
1.2974088252118154 1.227340882196042, 2.5247497074078575 1.9299320569842267,
0.5948176504236309 2.454681764392084, 1.2974088252118154 1.227340882196042,
0.0700679430157733 0.5247497074078575))";
assertEquals(expected, actual);
}
+
+ @Test
+ public void testInterpolatePoint() {
+ // Create a table with the test geometries
+ Table tbl =
+ tableEnv.sqlQuery(
+ "SELECT "
+ + "ST_GeomFromEWKT('LINESTRING M (0 0 0, 2 0 2, 4 0 4)') AS
line1, "
+ + "ST_GeomFromEWKT('POINT(1 1)') AS point1, "
+ + "ST_GeomFromEWKT('LINESTRING M (0 0 0, -2 2 2, -4 4 4)') AS
line2, "
+ + "ST_GeomFromEWKT('POINT(-1 1)') AS point2, "
+ + "ST_GeomFromEWKT('LINESTRING M (0 0 0, 2 2 2, 4 0 4)') AS
line3, "
+ + "ST_GeomFromEWKT('POINT(2 0)') AS point3, "
+ + "ST_GeomFromEWKT('POINT(2.5 1)') AS point4");
+
+ double actual =
+ (double)
+ first(
+ tbl.select(
+ call(
+
Functions.ST_InterpolatePoint.class.getSimpleName(),
+ $("line1"),
+ $("point1")))
+ .as("result"))
+ .getField(0);
+ double expected = 1.0; // Closest point on line is (1, 0) and interpolated
M is 1
+ assertEquals(expected, actual, 1e-6);
+
+ actual =
+ (double)
+ first(
+ tbl.select(
+ call(
+
Functions.ST_InterpolatePoint.class.getSimpleName(),
+ $("line2"),
+ $("point2")))
+ .as("result"))
+ .getField(0);
+ expected = 1.0; // Interpolated M value
+ assertEquals(expected, actual, 1e-6);
+
+ actual =
+ (double)
+ first(
+ tbl.select(
+ call(
+
Functions.ST_InterpolatePoint.class.getSimpleName(),
+ $("line3"),
+ $("point3")))
+ .as("result"))
+ .getField(0);
+ expected = 1.0; // Interpolated M value
+ assertEquals(expected, actual, 1e-6);
+
+ actual =
+ (double)
+ first(
+ tbl.select(
+ call(
+
Functions.ST_InterpolatePoint.class.getSimpleName(),
+ $("line3"),
+ $("point4")))
+ .as("result"))
+ .getField(0);
+ expected = 2.75;
+ assertEquals(expected, actual, 1e-6);
+ }
}
diff --git a/python/sedona/sql/st_functions.py
b/python/sedona/sql/st_functions.py
index 22fd373583..3bec08d7bf 100644
--- a/python/sedona/sql/st_functions.py
+++ b/python/sedona/sql/st_functions.py
@@ -2393,6 +2393,21 @@ def ST_Rotate(
return _call_st_function("ST_Rotate", args)
+@validate_argument_types
+def ST_InterpolatePoint(geom1: ColumnOrName, geom2: ColumnOrName) -> Column:
+ """Returns the interpolated Measure value at the point on the given
linestring M that is closest to the given point.
+
+ :param geom1: LineString M Geometry column or name.
+ :type geom1: ColumnOrName
+ :param geom2: Point Geometry column or name.
+ :type geom2: ColumnOrName
+ :rtype: Column
+ """
+
+ args = (geom1, geom2)
+ return _call_st_function("ST_InterpolatePoint", args)
+
+
# Automatically populate __all__
__all__ = [
name
diff --git a/python/tests/sql/test_dataframe_api.py
b/python/tests/sql/test_dataframe_api.py
index ca37349cb8..9c5c65e093 100644
--- a/python/tests/sql/test_dataframe_api.py
+++ b/python/tests/sql/test_dataframe_api.py
@@ -611,6 +611,7 @@ test_configurations = [
"",
"POLYGON ((2 0, 1 0, 1 1, 2 1, 2 0))",
),
+ (stf.ST_InterpolatePoint, ("linem", "point"), "linestringm_and_point", "",
1.0),
(stf.ST_IsCollection, ("geom",), "geom_collection", "", True),
(stf.ST_IsClosed, ("geom",), "closed_linestring_geom", "", True),
(stf.ST_IsEmpty, ("geom",), "empty_geom", "", True),
@@ -1620,6 +1621,10 @@ class TestDataFrameAPI(TestBase):
return TestDataFrameAPI.spark.sql(
"SELECT ST_GeomFromWKT('GEOMETRYCOLLECTION (LINESTRING (2 0, 2
1, 2 2), LINESTRING (2 2, 2 3, 2 4), LINESTRING (0 2, 1 2, 2 2), LINESTRING (2
2, 3 2, 4 2), LINESTRING (0 2, 1 3, 2 4), LINESTRING (2 4, 3 3, 4 2))') as geom"
)
+ elif request.param == "linestringm_and_point":
+ return TestDataFrameAPI.spark.sql(
+ "SELECT ST_GeomFromWKT('LINESTRING M (0 0 0, 2 0 2, 4 0 4)')
as linem, ST_GeomFromWKT('POINT (1 1)') as point"
+ )
raise ValueError(f"Invalid base_df name passed: {request.param}")
def _id_test_configuration(val):
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 f2ff868b45..442d0203c7 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
@@ -22,7 +22,7 @@ import org.apache.spark.sql.catalyst.FunctionIdentifier
import org.apache.spark.sql.catalyst.analysis.FunctionRegistry.FunctionBuilder
import org.apache.spark.sql.catalyst.expressions.{ExpectsInputTypes,
Expression, ExpressionInfo, Literal}
import org.apache.spark.sql.expressions.Aggregator
-import org.apache.spark.sql.sedona_sql.expressions._
+import org.apache.spark.sql.sedona_sql.expressions.{ST_InterpolatePoint, _}
import org.apache.spark.sql.sedona_sql.expressions.collect.ST_Collect
import org.apache.spark.sql.sedona_sql.expressions.raster._
import org.locationtech.jts.geom.Geometry
@@ -150,6 +150,7 @@ object Catalog {
function[ST_H3ToGeom](),
function[ST_H3KRing](),
function[ST_InteriorRingN](),
+ function[ST_InterpolatePoint](),
function[ST_Dump](),
function[ST_DumpPoints](),
function[ST_IsClosed](),
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 9a6ea689fa..91f833e936 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
@@ -1765,3 +1765,9 @@ case class ST_Rotate(inputExpressions: Seq[Expression])
protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) =
copy(inputExpressions = newChildren)
}
+
+case class ST_InterpolatePoint(inputExpressions: Seq[Expression])
+ extends
InferredExpression(inferrableFunction2(Functions.interpolatePoint)) {
+ protected def withNewChildrenInternal(newChildren: IndexedSeq[Expression]) =
+ copy(inputExpressions = newChildren)
+}
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 56a2227174..e7b11c3c17 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
@@ -926,4 +926,10 @@ object st_functions extends DataFrameAPI {
def ST_IsCollection(geometry: String): Column =
wrapExpression[ST_IsCollection](geometry)
+ def ST_InterpolatePoint(geom1: Column, geom2: Column): Column =
+ wrapExpression[ST_InterpolatePoint](geom1, geom2)
+
+ def ST_InterpolatePoint(geom1: String, geom2: String): Column =
+ wrapExpression[ST_InterpolatePoint](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 a2a4ded595..e0dbe5a60a 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
@@ -2383,5 +2383,30 @@ class dataFrameAPITestScala extends TestBaseScala {
assert(exception2.getMessage.contains("POLYGON ((0 0, 0 1, 1 1, 1 0, 0
0))"))
assert(exception2.getMessage.contains("ST_MakeLine"))
}
+
+ it("Passed ST_InterpolatePoint") {
+ val testData = Seq(
+ ("LINESTRING M (0 0 0, 2 0 2, 4 0 4)", "POINT(1 1)", 1.0),
+ ("LINESTRING M (0 0 0, -2 2 2, -4 4 4)", "POINT(-1 1)", 1.0),
+ ("LINESTRING M (0 0 0, 2 2 2, 4 0 4)", "POINT(2 0)", 1.0),
+ ("LINESTRING M (0 0 0, 2 2 2, 4 0 4)", "POINT(2.5 1)", 2.75)).toDF(
+ "lineEWKT",
+ "pointEWKT",
+ "expectedResult")
+
+ val geomDf = testData
+ .withColumn("line", ST_GeomFromEWKT(col("lineEWKT")))
+ .withColumn("point", ST_GeomFromEWKT(col("pointEWKT")))
+
+ geomDf
+ .withColumn("result", ST_InterpolatePoint(col("line"), col("point")))
+ .select("result", "expectedResult")
+ .collect()
+ .foreach { row =>
+ val actual = row.getAs[Double]("result")
+ val expected = row.getAs[Double]("expectedResult")
+ assert(actual == expected, s"Expected $expected but got $actual")
+ }
+ }
}
}
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 c05f745f57..e727cfdd10 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
@@ -3611,4 +3611,65 @@ class functionTestScala
exception.getMessage should include("The origin must be a non-empty Point
geometry.")
}
+ it("Should pass ST_InterpolatePoint") {
+ val geomTestCases = Map(
+ ("'LINESTRING M (0 0 0, 2 0 2, 4 0 4)'", "'POINT(1 1)'") -> 1.0,
+ ("'LINESTRING M (0 0 0, -2 2 2, -4 4 4)'", "'POINT(-1 1)'") -> 1.0,
+ ("'LINESTRING M (0 0 0, 2 2 2, 4 0 4)'", "'POINT(2 0)'") -> 1.0,
+ ("'LINESTRING M (0 0 0, 2 2 2, 4 0 4)'", "'POINT(2.5 1)'") -> 2.75)
+
+ for (((geom1, geom2), expectedResult) <- geomTestCases) {
+ val df = sparkSession.sql(s"""
+ |SELECT
+ | ST_InterpolatePoint(
+ | ST_GeomFromEWKT($geom1),
+ | ST_GeomFromEWKT($geom2)
+ | ) AS mValue
+ """.stripMargin)
+
+ val actual = df.take(1)(0).get(0).asInstanceOf[Double]
+ assert(actual == expectedResult)
+ }
+
+ // Test invalid arguments
+ var invalidOriginDf = sparkSession.sql("""
+ |SELECT
ST_InterpolatePoint(ST_GeomFromText('LINESTRING (50 160, 50 50, 100 50)'),
ST_GeomFromText('POINT (1 1)')) as result
+ """.stripMargin)
+
+ var exception = intercept[Exception] {
+ invalidOriginDf.collect()
+ }
+ exception.getMessage should include("The given linestring does not have a
measure value.")
+
+ invalidOriginDf = sparkSession.sql("""
+ |SELECT
ST_InterpolatePoint(ST_GeomFromText('POINT (0 1)'), ST_GeomFromText('POINT (1
1)')) as result
+ """.stripMargin)
+
+ exception = intercept[Exception] {
+ invalidOriginDf.collect()
+ }
+ exception.getMessage should include(
+ "First argument is of type Point, should be a LineString.")
+
+ invalidOriginDf = sparkSession.sql("""
+ |SELECT
ST_InterpolatePoint(ST_GeomFromText('LINESTRING M (0 0 0, 2 0 2, 4 0 4)'),
ST_GeomFromText('LINESTRING (50 160, 50 50, 100 50)')) as result
+ """.stripMargin)
+
+ exception = intercept[Exception] {
+ invalidOriginDf.collect()
+ }
+ exception.getMessage should include(
+ "Second argument is of type LineString, should be a Point.")
+
+ invalidOriginDf = sparkSession.sql("""
+ |SELECT
ST_InterpolatePoint(ST_SetSRID(ST_GeomFromText('LINESTRING M (0 0 0, 2 0 2, 4 0
4)'), 4326), ST_SetSRID(ST_GeomFromText('POINT (1 1)'), 3857)) as result
+ """.stripMargin)
+
+ exception = intercept[Exception] {
+ invalidOriginDf.collect()
+ }
+ exception.getMessage should include(
+ "The Line has SRID 4326 and Point has SRID 3857. The Line and Point
should be in the same SRID.")
+ }
+
}