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 7fe698362e [SEDONA-679] Fix ST_LengthSpheroid behavior (#1691)
7fe698362e is described below
commit 7fe698362ed552b82a2cf834d91b418399672fa4
Author: Furqaan Khan <[email protected]>
AuthorDate: Sat Nov 23 00:59:09 2024 -0500
[SEDONA-679] Fix ST_LengthSpheroid behavior (#1691)
* feat: remove support for polygonal geometry in ST_LengthSpheroid
* lint fix
---
.../java/org/apache/sedona/common/Functions.java | 2 +-
.../org/apache/sedona/common/sphere/Spheroid.java | 37 +++++++++++++++++++---
.../org/apache/sedona/common/FunctionsTest.java | 33 +++++++++++++++++--
docs/api/flink/Function.md | 7 ++--
docs/api/snowflake/vector-data/Function.md | 11 +++++--
docs/api/sql/Function.md | 7 ++--
.../java/org/apache/sedona/flink/FunctionTest.java | 4 +--
.../sedona/snowflake/snowsql/TestFunctions.java | 4 +--
.../sedona/snowflake/snowsql/TestFunctionsV2.java | 3 +-
.../org/apache/sedona/sql/functionTestScala.scala | 2 +-
10 files changed, 88 insertions(+), 22 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 8502c241bd..5a35d10d98 100644
--- a/common/src/main/java/org/apache/sedona/common/Functions.java
+++ b/common/src/main/java/org/apache/sedona/common/Functions.java
@@ -1120,7 +1120,7 @@ public class Functions {
private static double calculateLength(Geometry geometry, boolean
use_spheroid) {
if (use_spheroid) {
- return Spheroid.length(geometry);
+ return Spheroid.baseLength(geometry);
} else {
return length(geometry);
}
diff --git a/common/src/main/java/org/apache/sedona/common/sphere/Spheroid.java
b/common/src/main/java/org/apache/sedona/common/sphere/Spheroid.java
index 50a3beb77b..546fec4f84 100644
--- a/common/src/main/java/org/apache/sedona/common/sphere/Spheroid.java
+++ b/common/src/main/java/org/apache/sedona/common/sphere/Spheroid.java
@@ -72,13 +72,40 @@ public class Spheroid {
}
/**
- * Calculate the length of a geometry using the Spheroid formula. Equivalent
to PostGIS
+ * Calculates length just for linear geometries or geometry collection
containing linear
+ * geometries.
+ *
+ * @param geometry
+ * @return
+ */
+ public static double length(Geometry geometry) {
+ String geomType = geometry.getGeometryType();
+ if (geomType.equalsIgnoreCase(Geometry.TYPENAME_LINESTRING)
+ || geomType.equalsIgnoreCase(Geometry.TYPENAME_POINT)
+ || geomType.equalsIgnoreCase(Geometry.TYPENAME_MULTIPOINT)
+ || geomType.equalsIgnoreCase(Geometry.TYPENAME_MULTILINESTRING)) {
+ return baseLength(geometry);
+ } else if
(geomType.equalsIgnoreCase(Geometry.TYPENAME_GEOMETRYCOLLECTION)) {
+ double length = 0;
+ for (int i = 0; i < geometry.getNumGeometries(); i++) {
+ length += length(geometry.getGeometryN(i));
+ }
+ return length;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Base function to calculate the spheroid length/perimeter
+ *
+ * <p>Calculate the length of a geometry using the Spheroid formula.
Equivalent to PostGIS
* ST_LengthSpheroid and PostGIS ST_Length(useSpheroid=true) WGS84 ellipsoid
is used.
*
* @param geom
* @return
*/
- public static double length(Geometry geom) {
+ public static double baseLength(Geometry geom) {
String geomType = geom.getGeometryType();
if (geomType.equals(Geometry.TYPENAME_LINEARRING)
|| geomType.equals(Geometry.TYPENAME_LINESTRING)) {
@@ -93,11 +120,11 @@ public class Spheroid {
return compute.perimeter;
} else if (geomType.equals(Geometry.TYPENAME_POLYGON)) {
Polygon poly = (Polygon) geom;
- double length = length(poly.getExteriorRing());
+ double length = baseLength(poly.getExteriorRing());
if (poly.getNumInteriorRing() > 0) {
for (int i = 0; i < poly.getNumInteriorRing(); i++) {
- length += length(poly.getInteriorRingN(i));
+ length += baseLength(poly.getInteriorRingN(i));
}
}
@@ -107,7 +134,7 @@ public class Spheroid {
|| geomType.equals(Geometry.TYPENAME_GEOMETRYCOLLECTION)) {
double length = 0.0;
for (int i = 0; i < geom.getNumGeometries(); i++) {
- length += length(geom.getGeometryN(i));
+ length += baseLength(geom.getGeometryN(i));
}
return length;
} else {
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 72b850b900..208b9268d7 100644
--- a/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
+++ b/common/src/test/java/org/apache/sedona/common/FunctionsTest.java
@@ -1695,7 +1695,7 @@ public class FunctionsTest extends TestBase {
assertEquals(1.0018754171394622E7, Spheroid.length(line), FP_TOLERANCE2);
Polygon polygon = GEOMETRY_FACTORY.createPolygon(coordArray(0, 0, 90, 0,
0, 0));
- assertEquals(2.0037508342789244E7, Spheroid.length(polygon),
FP_TOLERANCE2);
+ assertEquals(0.0, Spheroid.length(polygon), FP_TOLERANCE2);
MultiPoint multiPoint = GEOMETRY_FACTORY.createMultiPoint(new Point[]
{point, point});
assertEquals(0, Spheroid.length(multiPoint), FP_TOLERANCE2);
@@ -1706,17 +1706,44 @@ public class FunctionsTest extends TestBase {
MultiPolygon multiPolygon =
GEOMETRY_FACTORY.createMultiPolygon(new Polygon[] {polygon, polygon});
- assertEquals(4.007501668557849E7, Spheroid.length(multiPolygon),
FP_TOLERANCE2);
+ assertEquals(0.0, Spheroid.length(multiPolygon), FP_TOLERANCE2);
GeometryCollection geometryCollection =
GEOMETRY_FACTORY.createGeometryCollection(new Geometry[] {point, line,
multiLineString});
assertEquals(3.0056262514183864E7, Spheroid.length(geometryCollection),
FP_TOLERANCE2);
+ }
+
+ @Test
+ public void spheroidBaseLength() throws ParseException {
+ Point point = GEOMETRY_FACTORY.createPoint(new Coordinate(90, 0));
+ assertEquals(0, Spheroid.baseLength(point), FP_TOLERANCE2);
+
+ LineString line = GEOMETRY_FACTORY.createLineString(coordArray(0, 0, 90,
0));
+ assertEquals(1.0018754171394622E7, Spheroid.baseLength(line),
FP_TOLERANCE2);
+
+ Polygon polygon = GEOMETRY_FACTORY.createPolygon(coordArray(0, 0, 90, 0,
0, 0));
+ assertEquals(2.0037508342789244E7, Spheroid.baseLength(polygon),
FP_TOLERANCE2);
+
+ MultiPoint multiPoint = GEOMETRY_FACTORY.createMultiPoint(new Point[]
{point, point});
+ assertEquals(0, Spheroid.baseLength(multiPoint), FP_TOLERANCE2);
+
+ MultiLineString multiLineString =
+ GEOMETRY_FACTORY.createMultiLineString(new LineString[] {line, line});
+ assertEquals(2.0037508342789244E7, Spheroid.baseLength(multiLineString),
FP_TOLERANCE2);
+
+ MultiPolygon multiPolygon =
+ GEOMETRY_FACTORY.createMultiPolygon(new Polygon[] {polygon, polygon});
+ assertEquals(4.007501668557849E7, Spheroid.baseLength(multiPolygon),
FP_TOLERANCE2);
+
+ GeometryCollection geometryCollection =
+ GEOMETRY_FACTORY.createGeometryCollection(new Geometry[] {point, line,
multiLineString});
+ assertEquals(3.0056262514183864E7,
Spheroid.baseLength(geometryCollection), FP_TOLERANCE2);
Geometry polygonWithHole =
Constructors.geomFromWKT(
"POLYGON((-122.33 47.61, -122.32 47.62, -122.31 47.61, -122.30
47.62, -122.29 47.61, -122.30 47.60, -122.31 47.59, -122.32 47.60, -122.33
47.61), (-122.315 47.605, -122.305 47.615, -122.295 47.605, -122.305 47.595,
-122.315 47.605))",
4326);
- assertEquals(16106.506409488933, Spheroid.length(polygonWithHole),
FP_TOLERANCE2);
+ assertEquals(16106.506409488933, Spheroid.baseLength(polygonWithHole),
FP_TOLERANCE2);
}
@Test
diff --git a/docs/api/flink/Function.md b/docs/api/flink/Function.md
index 8bcaa9e41d..62cb86685f 100644
--- a/docs/api/flink/Function.md
+++ b/docs/api/flink/Function.md
@@ -2389,6 +2389,9 @@ Geometry must be in EPSG:4326 (WGS84) projection and must
be in ==lon/lat== orde
!!!note
By default, this function uses lon/lat order since `v1.5.0`. Before, it
used lat/lon order.
+!!!Warning
+ Since `v1.7.0`, this function only supports LineString, MultiLineString,
and GeometryCollections containing linear geometries. Use
[ST_Perimeter](#st_perimeter) for polygons.
+
Format: `ST_LengthSpheroid (A: Geometry)`
Since: `v1.4.1`
@@ -2396,13 +2399,13 @@ Since: `v1.4.1`
Example:
```sql
-SELECT ST_LengthSpheroid(ST_GeomFromWKT('Polygon ((0 0, 90 0, 0 0))'))
+SELECT ST_LengthSpheroid(ST_GeomFromWKT('LINESTRING (0 0, 2 0)'))
```
Output:
```
-20037508.342789244
+222638.98158654713
```
## ST_LineFromMultiPoint
diff --git a/docs/api/snowflake/vector-data/Function.md
b/docs/api/snowflake/vector-data/Function.md
index 7d0e6e408d..ef7f4f778a 100644
--- a/docs/api/snowflake/vector-data/Function.md
+++ b/docs/api/snowflake/vector-data/Function.md
@@ -1734,15 +1734,22 @@ Introduction: Return the geodesic perimeter of A using
WGS84 spheroid. Unit is m
Geometry must be in EPSG:4326 (WGS84) projection and must be in ==lat/lon==
order. You can use ==ST_FlipCoordinates== to swap lat and lon.
+!!!Warning
+ This function only supports LineString, MultiLineString, and
GeometryCollections containing linear geometries. Use
[ST_Perimeter](#st_perimeter) for polygons.
+
Format: `ST_LengthSpheroid (A:geometry)`
SQL example:
```sql
-SELECT ST_LengthSpheroid(ST_GeomFromWKT('Polygon ((0 0, 0 90, 0 0))'))
+SELECT ST_LengthSpheroid(ST_GeomFromWKT('LINESTRING (0 0, 2 0)'))
```
-Output: `20037508.342789244`
+Output:
+
+```
+222638.98158654713
+```
## ST_LineFromMultiPoint
diff --git a/docs/api/sql/Function.md b/docs/api/sql/Function.md
index ac63ca7cf9..a42dc9e466 100644
--- a/docs/api/sql/Function.md
+++ b/docs/api/sql/Function.md
@@ -2434,6 +2434,9 @@ Geometry must be in EPSG:4326 (WGS84) projection and must
be in ==lon/lat== orde
!!!note
By default, this function uses lon/lat order since `v1.5.0`. Before, it
used lat/lon order.
+!!!Warning
+ Since `v1.7.0`, this function only supports LineString, MultiLineString,
and GeometryCollections containing linear geometries. Use
[ST_Perimeter](#st_perimeter) for polygons.
+
Format: `ST_LengthSpheroid (A: Geometry)`
Since: `v1.4.1`
@@ -2441,13 +2444,13 @@ Since: `v1.4.1`
SQL Example
```sql
-SELECT ST_LengthSpheroid(ST_GeomFromWKT('Polygon ((0 0, 90 0, 0 0))'))
+SELECT ST_LengthSpheroid(ST_GeomFromWKT('LINESTRING (0 0, 2 0)'))
```
Output:
```
-20037508.342789244
+222638.98158654713
```
## ST_LineFromMultiPoint
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 cbb9fec605..6ee9160c4a 100644
--- a/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
+++ b/flink/src/test/java/org/apache/sedona/flink/FunctionTest.java
@@ -654,8 +654,8 @@ public class FunctionTest extends TestBase {
@Test
public void testLengthSpheroid() {
Table tbl =
- tableEnv.sqlQuery("SELECT ST_LengthSpheroid(ST_GeomFromWKT('Polygon
((0 0, 90 0, 0 0))'))");
- Double expected = 20037508.342789244;
+ tableEnv.sqlQuery("SELECT ST_LengthSpheroid(ST_GeomFromWKT('LINESTRING
(0 0, 2 0)'))");
+ Double expected = 222638.98158654713;
Double actual = (Double) first(tbl).getField(0);
assertEquals(expected, actual, 0.1);
}
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 c3fdd3160a..ed319f92bc 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
@@ -1190,8 +1190,8 @@ public class TestFunctions extends TestBase {
public void test_ST_LengthSpheroid() {
registerUDF("ST_LengthSpheroid", byte[].class);
verifySqlSingleRes(
- "select sedona.ST_LengthSpheroid(sedona.ST_GeomFromWKT('Polygon ((0 0,
90 0, 0 0))'))",
- 20037508.342789244);
+ "select
CEIL(sedona.ST_LengthSpheroid(sedona.ST_GeomFromWKT('LINESTRING (0 0, 2 0)')))",
+ 222639.0);
}
@Test
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 e1b9ccc7de..cfcdddcd20 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
@@ -1142,8 +1142,7 @@ public class TestFunctionsV2 extends TestBase {
public void test_ST_LengthSpheroid() {
registerUDFV2("ST_LengthSpheroid", String.class);
verifySqlSingleRes(
- "select sedona.ST_LengthSpheroid(ST_GeomFromWKT('Polygon ((0 0, 90 0,
90 90, 0 90, 0 0))'))",
- 30022685.630020067);
+ "select CEIL(sedona.ST_LengthSpheroid(ST_GeomFromWKT('LINESTRING (0 0,
2 0)')))", 222639.0);
}
@Test
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 9bda2da441..82dbff82c1 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
@@ -2891,7 +2891,7 @@ class functionTestScala
val geomTestCases = Map(
("'POINT (-0.56 51.3168)'") -> "0.0",
("'LineString (0 0, 90 0)'") -> "10018754.17139462",
- ("'Polygon ((0 0, 90 0, 0 0))'") -> "20037508.34278924")
+ ("'Polygon ((0 0, 90 0, 0 0))'") -> "0.0")
for (((geom1), expectedResult) <- geomTestCases) {
val df = sparkSession.sql(
s"SELECT ST_LengthSpheroid(ST_GeomFromWKT($geom1)), " +