Skip to content

Commit 2fa3bd8

Browse files
furqaankhanjiayuasu
authored andcommitted
[SEDONA-693] Add ST_Perimeter2D (apache#1745)
* feat: add ST_Perimeter2D, alias of ST_Perimeter * fix: port function to flink * chore: change note to info in annotation
1 parent b6099d1 commit 2fa3bd8

File tree

18 files changed

+387
-4
lines changed

18 files changed

+387
-4
lines changed

docs/api/flink/Function.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3191,6 +3191,54 @@ Output:
31913191
2216860.5497177234
31923192
```
31933193

3194+
## ST_Perimeter2D
3195+
3196+
Introduction: This function calculates the 2D perimeter of a given geometry. It supports Polygon, MultiPolygon, and GeometryCollection geometries (as long as the GeometryCollection contains polygonal geometries). For other types, it returns 0. To measure lines, use [ST_Length](#st_length).
3197+
3198+
To get the perimeter in meters, set `use_spheroid` to `true`. This calculates the geodesic perimeter using the WGS84 spheroid. When using `use_spheroid`, the `lenient` parameter defaults to true, assuming the geometry uses EPSG:4326. To throw an exception instead, set `lenient` to `false`.
3199+
3200+
!!!Info
3201+
This function is an alias for [ST_Perimeter](#st_perimeter).
3202+
3203+
Format:
3204+
3205+
`ST_Perimeter2D(geom: Geometry)`
3206+
3207+
`ST_Perimeter2D(geom: Geometry, use_spheroid: Boolean)`
3208+
3209+
`ST_Perimeter2D(geom: Geometry, use_spheroid: Boolean, lenient: Boolean = True)`
3210+
3211+
Since: `v1.7.1`
3212+
3213+
SQL Example:
3214+
3215+
```sql
3216+
SELECT ST_Perimeter2D(
3217+
ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))')
3218+
)
3219+
```
3220+
3221+
Output:
3222+
3223+
```
3224+
20.0
3225+
```
3226+
3227+
SQL Example:
3228+
3229+
```sql
3230+
SELECT ST_Perimeter2D(
3231+
ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))', 4326),
3232+
true, false
3233+
)
3234+
```
3235+
3236+
Output:
3237+
3238+
```
3239+
2216860.5497177234
3240+
```
3241+
31943242
## ST_PointN
31953243

31963244
Introduction: Return the Nth point in a single linestring or circular linestring in the geometry. Negative values are counted backwards from the end of the LineString, so that -1 is the last point. Returns NULL if there is no linestring in the geometry.

docs/api/snowflake/vector-data/Function.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2425,6 +2425,52 @@ Output:
24252425
2216860.5497177234
24262426
```
24272427

2428+
## ST_Perimeter2D
2429+
2430+
Introduction: This function calculates the 2D perimeter of a given geometry. It supports Polygon, MultiPolygon, and GeometryCollection geometries (as long as the GeometryCollection contains polygonal geometries). For other types, it returns 0. To measure lines, use [ST_Length](#st_length).
2431+
2432+
To get the perimeter in meters, set `use_spheroid` to `true`. This calculates the geodesic perimeter using the WGS84 spheroid. When using `use_spheroid`, the `lenient` parameter defaults to true, assuming the geometry uses EPSG:4326. To throw an exception instead, set `lenient` to `false`.
2433+
2434+
!!!Info
2435+
This function is an alias for [ST_Perimeter](#st_perimeter).
2436+
2437+
Format:
2438+
2439+
`ST_Perimeter2D(geom: Geometry)`
2440+
2441+
`ST_Perimeter2D(geom: Geometry, use_spheroid: Boolean)`
2442+
2443+
`ST_Perimeter2D(geom: Geometry, use_spheroid: Boolean, lenient: Boolean = True)`
2444+
2445+
SQL Example:
2446+
2447+
```sql
2448+
SELECT ST_Perimeter2D(
2449+
ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))')
2450+
)
2451+
```
2452+
2453+
Output:
2454+
2455+
```
2456+
20.0
2457+
```
2458+
2459+
SQL Example:
2460+
2461+
```sql
2462+
SELECT ST_Perimeter2D(
2463+
ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))', 4326),
2464+
true, false
2465+
)
2466+
```
2467+
2468+
Output:
2469+
2470+
```
2471+
2216860.5497177234
2472+
```
2473+
24282474
## ST_PointN
24292475

24302476
Introduction: Return the Nth point in a single linestring or circular linestring in the geometry. Negative values are counted backwards from the end of the LineString, so that -1 is the last point. Returns NULL if there is no linestring in the geometry.

docs/api/sql/Function.md

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -720,12 +720,14 @@ SQL Example
720720

721721
```sql
722722
ST_BinaryDistanceBandColumn(geometry, 1.0, true, true, false, struct(id, geometry))
723-
````
723+
```
724724

725725
Output:
726726

727-
```
727+
```sql
728+
{% raw %}
728729
[{{15, POINT (3 1.9)}, 1.0}, {{16, POINT (3 2)}, 1.0}, {{17, POINT (3 2.1)}, 1.0}, {{18, POINT (3 2.2)}, 1.0}]
730+
{% endraw %}
729731
```
730732

731733
## ST_Boundary
@@ -3500,6 +3502,54 @@ Output:
35003502
2216860.5497177234
35013503
```
35023504

3505+
## ST_Perimeter2D
3506+
3507+
Introduction: This function calculates the 2D perimeter of a given geometry. It supports Polygon, MultiPolygon, and GeometryCollection geometries (as long as the GeometryCollection contains polygonal geometries). For other types, it returns 0. To measure lines, use [ST_Length](#st_length).
3508+
3509+
To get the perimeter in meters, set `use_spheroid` to `true`. This calculates the geodesic perimeter using the WGS84 spheroid. When using `use_spheroid`, the `lenient` parameter defaults to true, assuming the geometry uses EPSG:4326. To throw an exception instead, set `lenient` to `false`.
3510+
3511+
!!!Info
3512+
This function is an alias for [ST_Perimeter](#st_perimeter).
3513+
3514+
Format:
3515+
3516+
`ST_Perimeter2D(geom: Geometry)`
3517+
3518+
`ST_Perimeter2D(geom: Geometry, use_spheroid: Boolean)`
3519+
3520+
`ST_Perimeter2D(geom: Geometry, use_spheroid: Boolean, lenient: Boolean = True)`
3521+
3522+
Since: `v1.7.1`
3523+
3524+
SQL Example:
3525+
3526+
```sql
3527+
SELECT ST_Perimeter2D(
3528+
ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))')
3529+
)
3530+
```
3531+
3532+
Output:
3533+
3534+
```
3535+
20.0
3536+
```
3537+
3538+
SQL Example:
3539+
3540+
```sql
3541+
SELECT ST_Perimeter2D(
3542+
ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))', 4326),
3543+
true, false
3544+
)
3545+
```
3546+
3547+
Output:
3548+
3549+
```
3550+
2216860.5497177234
3551+
```
3552+
35033553
## ST_PointN
35043554

35053555
Introduction: Return the Nth point in a single linestring or circular linestring in the geometry. Negative values are counted backwards from the end of the LineString, so that -1 is the last point. Returns NULL if there is no linestring in the geometry.
@@ -4654,12 +4704,14 @@ SQL Example
46544704

46554705
```sql
46564706
ST_WeightedDistanceBandColumn(geometry, 1.0, -1.0, true, true, 1.0, false, struct(id, geometry))
4657-
````
4707+
```
46584708

46594709
Output:
46604710

4661-
```
4711+
```sql
4712+
{% raw %}
46624713
[{{15, POINT (3 1.9)}, 1.0}, {{16, POINT (3 2)}, 9.999999999999991}, {{17, POINT (3 2.1)}, 4.999999999999996}, {{18, POINT (3 2.2)}, 3.3333333333333304}]
4714+
{% endraw %}
46634715
```
46644716

46654717
## ST_X

flink/src/main/java/org/apache/sedona/flink/Catalog.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ public static UserDefinedFunction[] getFuncs() {
102102
new Functions.ST_FlipCoordinates(),
103103
new Functions.ST_GeoHash(),
104104
new Functions.ST_Perimeter(),
105+
new Functions.ST_Perimeter2D(),
105106
new Functions.ST_PointOnSurface(),
106107
new Functions.ST_Scale(),
107108
new Functions.ST_ScaleGeom(),

flink/src/main/java/org/apache/sedona/flink/expressions/Functions.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,33 @@ public Double eval(
622622
}
623623
}
624624

625+
public static class ST_Perimeter2D extends ScalarFunction {
626+
@DataTypeHint(value = "Double")
627+
public Double eval(
628+
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
629+
Object o) {
630+
Geometry geom = (Geometry) o;
631+
return org.apache.sedona.common.Functions.perimeter(geom);
632+
}
633+
634+
@DataTypeHint(value = "Double")
635+
public Double eval(
636+
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o,
637+
Boolean use_spheroid) {
638+
Geometry geom = (Geometry) o;
639+
return org.apache.sedona.common.Functions.perimeter(geom, use_spheroid);
640+
}
641+
642+
@DataTypeHint(value = "Double")
643+
public Double eval(
644+
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class) Object o,
645+
Boolean use_spheroid,
646+
boolean lenient) {
647+
Geometry geom = (Geometry) o;
648+
return org.apache.sedona.common.Functions.perimeter(geom, use_spheroid, lenient);
649+
}
650+
}
651+
625652
public static class ST_PointOnSurface extends ScalarFunction {
626653
@DataTypeHint(value = "RAW", bridgedTo = org.locationtech.jts.geom.Geometry.class)
627654
public Geometry eval(

flink/src/test/java/org/apache/sedona/flink/FunctionTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,32 @@ public void testPerimeter() {
821821
assertEquals(443770.91724830196, perimeter, FP_TOLERANCE);
822822
}
823823

824+
@Test
825+
public void testPerimeter2D() {
826+
Table polygonTable = createPolygonTable(testDataSize);
827+
Table perimeterTable =
828+
polygonTable.select(
829+
call(Functions.ST_Perimeter2D.class.getSimpleName(), $(polygonColNames[0])));
830+
Double perimeter = (Double) first(perimeterTable).getField(0);
831+
assertEquals(4.0, perimeter, FP_TOLERANCE);
832+
833+
polygonTable =
834+
tableEnv.sqlQuery(
835+
"SELECT ST_GeomFromWKT('POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))', 4326) AS geom");
836+
perimeterTable =
837+
polygonTable.select(
838+
call(Functions.ST_Perimeter2D.class.getSimpleName(), $("geom"), true, false));
839+
perimeter = (Double) first(perimeterTable).getField(0);
840+
assertEquals(443770.91724830196, perimeter, FP_TOLERANCE);
841+
842+
polygonTable =
843+
tableEnv.sqlQuery("SELECT ST_GeomFromWKT('POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))') AS geom");
844+
perimeterTable =
845+
polygonTable.select(call(Functions.ST_Perimeter2D.class.getSimpleName(), $("geom"), true));
846+
perimeter = (Double) first(perimeterTable).getField(0);
847+
assertEquals(443770.91724830196, perimeter, FP_TOLERANCE);
848+
}
849+
824850
@Test
825851
public void testPointOnSurface() {
826852
Table pointTable = createPointTable_real(testDataSize);

python/sedona/sql/st_functions.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,30 @@ def ST_Perimeter(
12241224
return _call_st_function("ST_Perimeter", args)
12251225

12261226

1227+
@validate_argument_types
1228+
def ST_Perimeter2D(
1229+
geom: ColumnOrName,
1230+
use_spheroid: Optional[Union[ColumnOrName, bool]] = None,
1231+
lenient: Optional[Union[ColumnOrName, bool]] = None,
1232+
) -> Column:
1233+
"""Returns the perimeter of a Polygon/MultiPolygon geometries. Otherwise, returns 0
1234+
1235+
@param geom: Polygonal geometry
1236+
@param use_spheroid: Use Spheroid
1237+
@param lenient: suppresses the exception
1238+
@return: Perimeter of a Polygon/MultiPolygon geometries
1239+
"""
1240+
1241+
args = (geom, use_spheroid, lenient)
1242+
1243+
if lenient is None:
1244+
if use_spheroid is None:
1245+
args = (geom,)
1246+
else:
1247+
args = (geom, use_spheroid)
1248+
return _call_st_function("ST_Perimeter2D", args)
1249+
1250+
12271251
@validate_argument_types
12281252
def ST_Points(geometry: ColumnOrName) -> Column:
12291253
"""Creates a MultiPoint geometry consisting of all the coordinates of the input geometry

python/tests/sql/test_dataframe_api.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,15 @@
825825
"ceil(geom)",
826826
378794,
827827
),
828+
(stf.ST_Perimeter2D, ("geom",), "triangle_geom", "", 3.414213562373095),
829+
(stf.ST_Perimeter2D, ("geom", True), "triangle_geom", "ceil(geom)", 378794),
830+
(
831+
stf.ST_Perimeter2D,
832+
(lambda: stf.ST_SetSRID("geom", 4326), True),
833+
"triangle_geom",
834+
"ceil(geom)",
835+
378794,
836+
),
828837
(
829838
stf.ST_Points,
830839
("line",),

python/tests/sql/test_function.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,6 +1683,25 @@ def test_st_perimeter(self):
16831683
expected = 443770.91724830196
16841684
assert expected == actual
16851685

1686+
def test_st_perimeter2D(self):
1687+
baseDf = self.spark.sql(
1688+
"SELECT ST_GeomFromWKT('POLYGON((743238 2967416,743238 2967450,743265 2967450,743265.625 2967416,743238 2967416))') AS geom"
1689+
)
1690+
actual = baseDf.selectExpr("ST_Perimeter2D(geom)").take(1)[0][0]
1691+
expected = 122.63074400009504
1692+
assert actual == expected
1693+
1694+
baseDf = self.spark.sql(
1695+
"SELECT ST_GeomFromWKT('POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))', 4326) AS geom"
1696+
)
1697+
actual = baseDf.selectExpr("ST_Perimeter2D(geom, true)").first()[0]
1698+
expected = 443770.91724830196
1699+
assert expected == actual
1700+
1701+
actual = baseDf.selectExpr("ST_Perimeter2D(geom, true, false)").first()[0]
1702+
expected = 443770.91724830196
1703+
assert expected == actual
1704+
16861705
def test_st_points(self):
16871706
# Given
16881707
geometry_df = self.spark.createDataFrame(

snowflake-tester/src/test/java/org/apache/sedona/snowflake/snowsql/TestFunctions.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,25 @@ public void test_ST_Perimeter() {
808808
2216861.0);
809809
}
810810

811+
@Test
812+
public void test_ST_Perimeter2D() {
813+
registerUDF("ST_Perimeter2D", byte[].class);
814+
verifySqlSingleRes(
815+
"SELECT sedona.ST_Perimeter2D(sedona.ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'))",
816+
20.0);
817+
818+
registerUDF("ST_Perimeter2D", byte[].class, boolean.class);
819+
verifySqlSingleRes(
820+
"SELECT CEIL(sedona.ST_Perimeter2D(sedona.ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'), true))",
821+
2216861.0);
822+
823+
registerUDF("ST_Perimeter2D", byte[].class, boolean.class, boolean.class);
824+
registerUDF("ST_GeomFromText", String.class, int.class);
825+
verifySqlSingleRes(
826+
"SELECT CEIL(sedona.ST_Perimeter2D(sedona.ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))', 4326), true, false))",
827+
2216861.0);
828+
}
829+
811830
@Test
812831
public void test_ST_PointOnSurface() {
813832
registerUDF("ST_PointOnSurface", byte[].class);

0 commit comments

Comments
 (0)