This is an automated email from the ASF dual-hosted git repository.
jiayu pushed a commit to branch geopandas-tier2-batch-e
in repository https://gitbox.apache.org/repos/asf/sedona.git
The following commit(s) were added to refs/heads/geopandas-tier2-batch-e by
this push:
new c081ba7d89 Handle zero-length lines and empty points in
ST_LineLocatePoint
c081ba7d89 is described below
commit c081ba7d8908b358e45db213778d117eb1ecb4c9
Author: Jia Yu <[email protected]>
AuthorDate: Fri Mar 13 01:50:00 2026 -0700
Handle zero-length lines and empty points in ST_LineLocatePoint
- Return null for empty point input (was NPE from point.getCoordinate())
- Guard project non-normalized mode: return 0.0 for zero-length lines,
propagate null for empty lines (matches geopandas behavior)
- Add Java tests for empty point and zero-length line edge cases
- Add Scala Spark test for ST_LineLocatePoint with POINT EMPTY
---
.../main/java/org/apache/sedona/common/Functions.java | 2 +-
.../java/org/apache/sedona/common/FunctionsTest.java | 19 +++++++++++++++++++
python/sedona/spark/geopandas/geoseries.py | 6 ++++--
.../org/apache/sedona/sql/functionTestScala.scala | 6 ++++++
4 files changed, 30 insertions(+), 3 deletions(-)
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 0359b8efe0..0c7f487b65 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -1487,7 +1487,7 @@ public class Functions {
}
public static Double lineLocatePoint(Geometry geom, Geometry point) {
- if (geom.isEmpty()) return null;
+ if (geom.isEmpty() || point.isEmpty()) return null;
double length = geom.getLength();
LengthIndexedLine indexedLine = new LengthIndexedLine(geom);
return indexedLine.indexOf(point.getCoordinate()) / length;
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 f2c0561d5f..882a18de82 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -4414,6 +4414,25 @@ public class FunctionsTest extends TestBase {
assertNull(Functions.lineLocatePoint(emptyLine, point));
}
+ @Test
+ public void lineLocatePointEmptyPoint() {
+ LineString line =
+ GEOMETRY_FACTORY.createLineString(
+ new Coordinate[] {new Coordinate(0, 0), new Coordinate(1, 1)});
+ Geometry emptyPoint = GEOMETRY_FACTORY.createPoint();
+ assertNull(Functions.lineLocatePoint(line, emptyPoint));
+ }
+
+ @Test
+ public void lineLocatePointZeroLength() {
+ LineString zeroLen =
+ GEOMETRY_FACTORY.createLineString(
+ new Coordinate[] {new Coordinate(1, 1), new Coordinate(1, 1)});
+ Geometry point = GEOMETRY_FACTORY.createPoint(new Coordinate(2, 2));
+ Double result = Functions.lineLocatePoint(zeroLen, point);
+ assertTrue(Double.isNaN(result));
+ }
+
@Test
public void lineInterpolatePointEmpty() {
LineString emptyLine = GEOMETRY_FACTORY.createLineString();
diff --git a/python/sedona/spark/geopandas/geoseries.py
b/python/sedona/spark/geopandas/geoseries.py
index 2f162f362a..f3d96dba30 100644
--- a/python/sedona/spark/geopandas/geoseries.py
+++ b/python/sedona/spark/geopandas/geoseries.py
@@ -1402,8 +1402,10 @@ class GeoSeries(GeoFrame, pspd.Series):
if normalized:
spark_expr = stf.ST_LineLocatePoint(F.col("L"), F.col("R"))
else:
- spark_expr = stf.ST_LineLocatePoint(F.col("L"), F.col("R")) *
stf.ST_Length(
- F.col("L")
+ locate = stf.ST_LineLocatePoint(F.col("L"), F.col("R"))
+ length = stf.ST_Length(F.col("L"))
+ spark_expr = F.when(locate.isNull(), F.lit(None)).otherwise(
+ F.when(length == 0, F.lit(0.0)).otherwise(locate * length)
)
result = self._row_wise_operation(
spark_expr,
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 b1317da171..377e598b48 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
@@ -2503,6 +2503,12 @@ class functionTestScala
assert(df.take(1)(0).isNullAt(0))
}
+ it("Should return null for ST_LineLocatePoint with empty point") {
+ val df = sparkSession.sql(
+ "SELECT ST_LineLocatePoint(ST_GeomFromWKT('LINESTRING(0 0, 1 1)'),
ST_GeomFromWKT('POINT EMPTY')) AS loc")
+ assert(df.take(1)(0).isNullAt(0))
+ }
+
it("Should return POINT EMPTY for ST_LineInterpolatePoint with empty
geometry") {
val df = sparkSession.sql(
"SELECT ST_LineInterpolatePoint(ST_GeomFromWKT('LINESTRING EMPTY'), 0.5)
AS pt")