[SCM] PostGIS branch master updated. 3.6.0rc2-481-gae7249900
git at osgeo.org
git at osgeo.org
Mon May 11 08:56:57 PDT 2026
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "PostGIS".
The branch, master has been updated
via ae7249900558365d48a7c5fe5ed34463becd8382 (commit)
from eeffb4311706d8b93c84b4817bbbbf3142cd3626 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit ae7249900558365d48a7c5fe5ed34463becd8382
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date: Mon May 11 08:56:23 2026 -0700
Fix ST_Length and ST_Perimeter for geography collections, closes #6076
ST_Length(geography) on collections now only sums linear components,
and ST_Perimeter(geography) now only sums areal components. Added
lwgeom_perimeter_spheroid to support the separation of logic.
Preserve legacy behaviour in ST_LengthSpheroid.
diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in
index 401ac78cf..3ac202217 100644
--- a/liblwgeom/liblwgeom.h.in
+++ b/liblwgeom/liblwgeom.h.in
@@ -1814,6 +1814,10 @@ extern double lwgeom_area_spheroid(const LWGEOM *lwgeom, const SPHEROID *spheroi
*/
extern double lwgeom_length_spheroid(const LWGEOM *geom, const SPHEROID *s);
+/**
+* Calculate the geodetic perimeter of a lwgeom on the unit sphere.
+*/
+extern double lwgeom_perimeter_spheroid(const LWGEOM *geom, const SPHEROID *s);
/**
* Calculate covers predicate for two lwgeoms on the sphere. Currently
* only handles point-in-polygon.
diff --git a/liblwgeom/lwgeodetic.c b/liblwgeom/lwgeodetic.c
index 128ce4591..252f54c29 100644
--- a/liblwgeom/lwgeodetic.c
+++ b/liblwgeom/lwgeodetic.c
@@ -3150,31 +3150,22 @@ double lwgeom_length_spheroid(const LWGEOM *geom, const SPHEROID *s)
assert(geom);
- /* No area in nothing */
+ /* No length in nothing */
if ( lwgeom_is_empty(geom) )
return 0.0;
type = geom->type;
- if ( type == POINTTYPE || type == MULTIPOINTTYPE )
+ if ( type == POINTTYPE || type == MULTIPOINTTYPE ||
+ type == POLYGONTYPE || type == MULTIPOLYGONTYPE ||
+ type == TRIANGLETYPE || type == TINTYPE ||
+ type == POLYHEDRALSURFACETYPE || type == CURVEPOLYTYPE ||
+ type == MULTISURFACETYPE )
return 0.0;
if ( type == LINETYPE )
return ptarray_length_spheroid(((LWLINE*)geom)->points, s);
- if ( type == POLYGONTYPE )
- {
- LWPOLY *poly = (LWPOLY*)geom;
- for ( i = 0; i < poly->nrings; i++ )
- {
- length += ptarray_length_spheroid(poly->rings[i], s);
- }
- return length;
- }
-
- if ( type == TRIANGLETYPE )
- return ptarray_length_spheroid(((LWTRIANGLE*)geom)->points, s);
-
if ( lwtype_is_collection( type ) )
{
LWCOLLECTION *col = (LWCOLLECTION*)geom;
@@ -3186,7 +3177,48 @@ double lwgeom_length_spheroid(const LWGEOM *geom, const SPHEROID *s)
return length;
}
- lwerror("unsupported type passed to lwgeom_length_sphere");
+ lwerror("unsupported type passed to lwgeom_length_spheroid");
+ return 0.0;
+}
+
+double lwgeom_perimeter_spheroid(const LWGEOM *geom, const SPHEROID *s)
+{
+ int type;
+ uint32_t i = 0;
+ double perimeter = 0.0;
+
+ assert(geom);
+
+ /* No perimeter in nothing */
+ if ( lwgeom_is_empty(geom) )
+ return 0.0;
+
+ type = geom->type;
+
+ if ( type == POLYGONTYPE )
+ {
+ LWPOLY *poly = (LWPOLY*)geom;
+ for ( i = 0; i < poly->nrings; i++ )
+ {
+ perimeter += ptarray_length_spheroid(poly->rings[i], s);
+ }
+ return perimeter;
+ }
+
+ if ( type == TRIANGLETYPE )
+ return ptarray_length_spheroid(((LWTRIANGLE*)geom)->points, s);
+
+ if ( lwtype_is_collection( type ) )
+ {
+ LWCOLLECTION *col = (LWCOLLECTION*)geom;
+
+ for ( i = 0; i < col->ngeoms; i++ )
+ {
+ perimeter += lwgeom_perimeter_spheroid(col->geoms[i], s);
+ }
+ return perimeter;
+ }
+
return 0.0;
}
diff --git a/postgis/geography_measurement.c b/postgis/geography_measurement.c
index ece265fc0..15090d670 100644
--- a/postgis/geography_measurement.c
+++ b/postgis/geography_measurement.c
@@ -599,12 +599,12 @@ Datum geography_perimeter(PG_FUNCTION_ARGS)
s.a = s.b = s.radius;
/* Calculate the length */
- length = lwgeom_length_spheroid(lwgeom, &s);
+ length = lwgeom_perimeter_spheroid(lwgeom, &s);
/* Something went wrong... */
if ( length < 0.0 )
{
- elog(ERROR, "lwgeom_length_spheroid returned length < 0.0");
+ elog(ERROR, "lwgeom_perimeter_spheroid returned length < 0.0");
PG_RETURN_NULL();
}
diff --git a/postgis/lwgeom_spheroid.c b/postgis/lwgeom_spheroid.c
index 572470fe2..bbfac2173 100644
--- a/postgis/lwgeom_spheroid.c
+++ b/postgis/lwgeom_spheroid.c
@@ -165,7 +165,7 @@ Datum LWGEOM_length_ellipsoid_linestring(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(0.0);
}
- length = lwgeom_length_spheroid(lwgeom, sphere);
+ length = lwgeom_length_spheroid(lwgeom, sphere) + lwgeom_perimeter_spheroid(lwgeom, sphere);
lwgeom_free(lwgeom);
PG_FREE_IF_COPY(geom, 0);
diff --git a/regress/core/geography.sql b/regress/core/geography.sql
index 9b80cd757..5f98c7066 100644
--- a/regress/core/geography.sql
+++ b/regress/core/geography.sql
@@ -149,6 +149,10 @@ SELECT 'lrs_llp_4', round(ST_LineLocatePoint(geography 'linestring(0 1, 50 1)',
SELECT 'lrs_substr_1', ST_AsText(ST_LineSubstring(geography 'linestring(0 20, 100 20)', 0.1, 0.2),2);
+-- Ticket #6076
+SELECT 'ticket_6076_length', round(ST_Length(ST_GeogFromText('GEOMETRYCOLLECTION (POINT (5 5), LINESTRING (0 0, 0 1), POLYGON ((0 0, 0 1, 1 0, 0 0)))'))::numeric, 3);
+SELECT 'ticket_6076_perimeter', round(ST_Perimeter(ST_GeogFromText('GEOMETRYCOLLECTION (POINT (5 5), LINESTRING (0 0, 0 1), POLYGON ((0 0, 0 1, 1 0, 0 0)))'))::numeric, 3);
+
--SELECT 'lrs_cp_1', ST_AsText(ST_ClosestPoint(geography 'Linestring(0 20, 50 20)', 'Point(25 20)'), 3);
--SELECT 'lrs_cp_2', ST_AsText(ST_ClosestPoint(geography 'Point(25 20)', geography 'Linestring(0 20, 50 20)'), 3);
diff --git a/regress/core/geography_expected b/regress/core/geography_expected
index 0ca174883..8584b7df0 100644
--- a/regress/core/geography_expected
+++ b/regress/core/geography_expected
@@ -66,4 +66,6 @@ lrs_llp_2|0.00
lrs_llp_3|1.00
ERROR: geography_line_locate_point: 2nd arg is not a point
lrs_substr_1|LINESTRING(9.28 23.25,18.97 25.93)
+ticket_6076_length|110574.389
+ticket_6076_perimeter|378793.448
lrs_sl_1|LINESTRING(25 42.79,25 40)
-----------------------------------------------------------------------
Summary of changes:
liblwgeom/liblwgeom.h.in | 4 ++++
liblwgeom/lwgeodetic.c | 46 ++++++++++++++++++++++++++++++++++-------
postgis/geography_measurement.c | 4 ++--
postgis/lwgeom_spheroid.c | 2 +-
regress/core/geography.sql | 4 ++++
regress/core/geography_expected | 2 ++
6 files changed, 52 insertions(+), 10 deletions(-)
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list