[SCM] PostGIS branch stable-3.6 updated. 3.6.3-4-g79f2b6bc4
git at osgeo.org
git at osgeo.org
Mon May 11 08:58:25 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, stable-3.6 has been updated
via 79f2b6bc45c66b01d3455c14591fbff4e2b90cf0 (commit)
via 2d60db735cd96d889d7e43474deb436563ec3b77 (commit)
from 8591f818942c094254d0f9bbaface72de2795180 (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 79f2b6bc45c66b01d3455c14591fbff4e2b90cf0
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date: Mon May 11 08:58:16 2026 -0700
News item for #6076
diff --git a/NEWS b/NEWS
index 769000fe3..249ca7adb 100644
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,8 @@ PostGIS 3.6.4
* Fixes *
--
+- #6076, ST_Length(geography) for GeometryCollection not consistent
+ with geometry implementation
PostGIS 3.6.3
commit 2d60db735cd96d889d7e43474deb436563ec3b77
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 391c383aa..16bace594 100644
--- a/liblwgeom/liblwgeom.h.in
+++ b/liblwgeom/liblwgeom.h.in
@@ -1811,6 +1811,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 8c11edff5..a8af0f2d9 100644
--- a/postgis/lwgeom_spheroid.c
+++ b/postgis/lwgeom_spheroid.c
@@ -370,7 +370,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:
NEWS | 3 ++-
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 ++
7 files changed, 54 insertions(+), 11 deletions(-)
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list