[SCM] PostGIS branch master updated. 3.5.0-448-ge3e7ae72c

git at osgeo.org git at osgeo.org
Thu Jul 10 21:33:23 PDT 2025


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  e3e7ae72c1863fd1369ff23555d0acf495d196c9 (commit)
       via  1fcce085b4f4be3f0f51c93d7b37514ae14ce91a (commit)
       via  39601c33a64116dcb2447705e4276d957e9dfa01 (commit)
       via  cf378d24aa3e89d1e628927ac42ecd534b6facc6 (commit)
       via  54012ef1659aaab0b30e43823ddc6a34a6a6ce5d (commit)
      from  b077696e7f0cad9361be3d43392a340d77365643 (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 e3e7ae72c1863fd1369ff23555d0acf495d196c9
Author: Loïc Bartoletti <loic.bartoletti at oslandia.com>
Date:   Thu Jun 5 10:38:14 2025 +0200

    doc(NEWS): Add entry for ST_NumGeometry/ST_GeometryN changes

diff --git a/NEWS b/NEWS
index 583a31c6b..3ebeae776 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,8 @@ Daniel Nylander (Swedish Team)
   - #5799, make ST_TileEnvelope clips envelopes to tile plane extent (Paul Ramsey)
   - #5829, remove constraint checking from geometry_columns view (Paul Ramsey)
   - #3373, GT-255 [topology] Support for upgrading domains (Ayo Adesugba, U.S. Census Bureau)
+  - GT-252, ST_NumGeometries/ST_GeometryN treat TIN and PolyhedralSurface as unitary geometries,
+    use ST_NumPatches/ST_PatchN for patch access (Loïc Bartoletti)
 
 * Deprecated signatures *
 
@@ -36,7 +38,7 @@ Daniel Nylander (Swedish Team)
   - [raster] New GUC postgis.gdal_cpl_debug, enables GDAL debugging messages
     and routes them into the PostgreSQL logging system. (Paul Ramsey)
   - #5841, Change interrupt handling to remove use of pqsignal to support PG 18 (Paul Ramsey)
-  - Add ST_CoverageClean to edge match and gap remove polygonal 
+  - Add ST_CoverageClean to edge match and gap remove polygonal
     coverages (Paul Ramsey) from GEOS 3.14 (Martin Davis)
   - Add ST_ReclassExact to quickly remap values in raster (Paul Ramsey)
 

commit 1fcce085b4f4be3f0f51c93d7b37514ae14ce91a
Author: Loïc Bartoletti <loic.bartoletti at oslandia.com>
Date:   Thu Jun 5 09:59:52 2025 +0200

    test(PolyhedralSurface): Add tests for NumGeometries and GeometryN

diff --git a/regress/core/polyhedralsurface.sql b/regress/core/polyhedralsurface.sql
index 7c05b3118..dc58cb92d 100644
--- a/regress/core/polyhedralsurface.sql
+++ b/regress/core/polyhedralsurface.sql
@@ -27,3 +27,14 @@ SELECT 'patchN_02', ST_AsEWKT(ST_patchN('POLYHEDRALSURFACE(((0 0,0 0,0 1,0 0)))'
 SELECT 'patchN_03', ST_AsEWKT(ST_patchN('POLYHEDRALSURFACE(((0 0,0 0,0 1,0 0)))'::geometry, 0));
 SELECT 'patchN_04', ST_AsEWKT(ST_patchN('POLYHEDRALSURFACE(((0 0,0 0,0 1,0 0)))'::geometry, 2));
 SELECT 'patchN_05', ST_AsEWKT(ST_patchN('POLYHEDRALSURFACE(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))'::geometry, 2));
+
+-- ST_NumGeometries
+SELECT 'numgeometries_01', ST_NumGeometries('POLYHEDRALSURFACE EMPTY'::geometry);
+SELECT 'numgeometries_02', ST_NumGeometries('POLYHEDRALSURFACE(((0 0,0 0,0 1,0 0)))'::geometry);
+SELECT 'numgeometries_03', ST_NumGeometries('POLYHEDRALSURFACE(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))'::geometry);
+
+-- ST_GeometryN
+SELECT 'geometryN_01', ST_AsEWKT(ST_GeometryN('POLYHEDRALSURFACE EMPTY'::geometry, 1));
+SELECT 'geometryN_02', ST_AsEWKT(ST_GeometryN('POLYHEDRALSURFACE(((0 0,0 0,0 1,0 0)))'::geometry, 1));
+SELECT 'geometryN_03', ST_AsEWKT(ST_GeometryN('POLYHEDRALSURFACE(((0 0,0 0,0 1,0 0)))'::geometry, 0));
+SELECT 'geometryN_04', ST_AsEWKT(ST_GeometryN('POLYHEDRALSURFACE(((0 0,0 0,0 1,0 0)))'::geometry, 2));
diff --git a/regress/core/polyhedralsurface_expected b/regress/core/polyhedralsurface_expected
index 7700c04b5..cbfcfa90d 100644
--- a/regress/core/polyhedralsurface_expected
+++ b/regress/core/polyhedralsurface_expected
@@ -14,3 +14,10 @@ patchN_02|POLYGON((0 0,0 0,0 1,0 0))
 patchN_03|
 patchN_04|
 patchN_05|POLYGON((0 0 0,0 1 0,1 0 0,0 0 0))
+numgeometries_01|0
+numgeometries_02|1
+numgeometries_03|1
+geometryN_01|
+geometryN_02|POLYHEDRALSURFACE(((0 0,0 0,0 1,0 0)))
+geometryN_03|
+geometryN_04|

commit 39601c33a64116dcb2447705e4276d957e9dfa01
Author: Loïc Bartoletti <loic.bartoletti at oslandia.com>
Date:   Thu Jun 5 09:59:26 2025 +0200

    fix(lwgeom_ogc): rewrite NumGeometries and GeometryN and add fuctions to NumPatches and PatchN
    
    TIN and PolyhedralSurface are now treated as unitary geometries:
    - ST_NumGeometries() returns 1 for non-empty TIN/PolyhedralSurface
    - ST_GeometryN() returns the whole geometry for index 1
    - ST_NumPatches() preserves original patch counting behavior
    - ST_PatchN() provides access to individual patches
    - Added lwgeom_has_patches() helper function

diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in
index c7f2633ed..847a1ff6e 100644
--- a/liblwgeom/liblwgeom.h.in
+++ b/liblwgeom/liblwgeom.h.in
@@ -907,6 +907,11 @@ extern int lwgeom_is_collection(const LWGEOM *lwgeom);
 */
 extern int lwgeom_is_unitary(const LWGEOM *geom);
 
+/*
+ * Check if geometry type contains patches
+ */
+extern int lwgeom_has_patches(const LWGEOM *geom);
+
 /**
 * Is this a type that has rings enclosing an area, but is
 * not a collection of areas? (triangle, polygon, curvepolygon)
diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c
index 1b26752ee..a40181423 100644
--- a/liblwgeom/lwgeom.c
+++ b/liblwgeom/lwgeom.c
@@ -1122,6 +1122,20 @@ lwgeom_is_unitary(const LWGEOM *geom)
 	}
 }
 
+int
+lwgeom_has_patches(const LWGEOM *geom)
+{
+	switch (geom->type)
+	{
+	case TINTYPE:
+	case POLYHEDRALSURFACETYPE:
+		return LW_TRUE;
+		break;
+	default:
+		return LW_FALSE;
+	}
+}
+
 int
 lwgeom_has_rings(const LWGEOM *geom)
 {
diff --git a/postgis/lwgeom_ogc.c b/postgis/lwgeom_ogc.c
index bf3b81424..6e9f26912 100644
--- a/postgis/lwgeom_ogc.c
+++ b/postgis/lwgeom_ogc.c
@@ -55,8 +55,12 @@ Datum geometry_geometrytype(PG_FUNCTION_ARGS);
 Datum LWGEOM_numpoints_linestring(PG_FUNCTION_ARGS);
 /* ---- NumGeometries(geometry) */
 Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS);
+/* ---- NumPatches(geometry) */
+Datum LWGEOM_numpatches(PG_FUNCTION_ARGS);
 /* ---- GeometryN(geometry, integer) */
 Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS);
+/* ---- PatchN(geometry, integer) */
+Datum LWGEOM_patchn(PG_FUNCTION_ARGS);
 /* ---- Dimension(geometry) */
 Datum LWGEOM_dimension(PG_FUNCTION_ARGS);
 /* ---- ExteriorRing(geometry) */
@@ -233,6 +237,42 @@ Datum LWGEOM_numpoints_linestring(PG_FUNCTION_ARGS)
 	PG_RETURN_INT32(count);
 }
 
+/*
+ * Count geometries with patches option
+ * patches_as_geometries = true: count patches as separate geometries (for ST_NumPatches)
+ * patches_as_geometries = false: treat TIN/PolyhedralSurface as unitary geometries (for ST_NumGeometries)
+ */
+static int32
+lwgeom_count_geometries(LWGEOM *lwgeom, bool patches_as_geometries)
+{
+	int32 ret = 0;
+
+	if (lwgeom_is_empty(lwgeom))
+	{
+		ret = 0;
+	}
+	else if (lwgeom_is_unitary(lwgeom))
+	{
+		/* If it's a TIN or PolyhedralSurface and we want to count patches */
+		if (lwgeom_has_patches(lwgeom) && patches_as_geometries)
+		{
+			LWCOLLECTION *col = lwgeom_as_lwcollection(lwgeom);
+			ret = col ? col->ngeoms : 1;
+		}
+		else
+		{
+			ret = 1;
+		}
+	}
+	else
+	{
+		LWCOLLECTION *col = lwgeom_as_lwcollection(lwgeom);
+		ret = col->ngeoms;
+	}
+
+	return ret;
+}
+
 PG_FUNCTION_INFO_V1(LWGEOM_numgeometries_collection);
 Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS)
 {
@@ -241,24 +281,93 @@ Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS)
 	int32 ret = 0;
 
 	lwgeom = lwgeom_from_gserialized(geom);
-	if (lwgeom_is_empty(lwgeom))
-	{
-		ret = 0;
-	}
-	else if (lwgeom_is_unitary(lwgeom))
-	{
-		ret = 1;
-	}
-	else
-	{
-		LWCOLLECTION *col = lwgeom_as_lwcollection(lwgeom);
-		ret = col->ngeoms;
-	}
+
+	/* TIN and PolyhedralSurface count as 1 geometry, not their patch count */
+	ret = lwgeom_count_geometries(lwgeom, false);
+
 	lwgeom_free(lwgeom);
 	PG_FREE_IF_COPY(geom, 0);
 	PG_RETURN_INT32(ret);
 }
 
+PG_FUNCTION_INFO_V1(LWGEOM_numpatches);
+Datum LWGEOM_numpatches(PG_FUNCTION_ARGS)
+{
+	GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
+	LWGEOM *lwgeom;
+	int32 ret = 0;
+
+	lwgeom = lwgeom_from_gserialized(geom);
+
+	if (!lwgeom_has_patches(lwgeom))
+	{
+		lwgeom_free(lwgeom);
+		PG_FREE_IF_COPY(geom, 0);
+		elog(ERROR, "ST_NumPatches only supports TIN and PolyhedralSurface geometries");
+	}
+
+	ret = lwgeom_count_geometries(lwgeom, true);
+
+	lwgeom_free(lwgeom);
+	PG_FREE_IF_COPY(geom, 0);
+	PG_RETURN_INT32(ret);
+}
+
+/*
+ * Extract geometry at given index with patches option
+ */
+static LWGEOM*
+lwgeom_extract_geometry_n(LWGEOM *lwgeom, int32 idx, bool patches_as_geometries)
+{
+	LWCOLLECTION *coll = NULL;
+	LWGEOM *subgeom = NULL;
+
+	/* Empty returns NULL */
+	if (lwgeom_is_empty(lwgeom))
+		return NULL;
+
+	/* Unitary geometries */
+	if (lwgeom_is_unitary(lwgeom))
+	{
+		/* If it's a TIN or PolyhedralSurface and we want to access patches */
+		if (lwgeom_has_patches(lwgeom) && patches_as_geometries)
+		{
+			coll = lwgeom_as_lwcollection(lwgeom);
+			if (!coll)
+			{
+				/* Single patch case */
+				if (idx == 1)
+					return lwgeom;
+				else
+					return NULL;
+			}
+		}
+		else
+		{
+			/* Standard unitary geometry handling */
+			if (idx == 1)
+				return lwgeom;
+			else
+				return NULL;
+		}
+	}
+	else
+	{
+		coll = lwgeom_as_lwcollection(lwgeom);
+	}
+
+	if (!coll)
+		return NULL;
+
+	/* Handle out-of-range index value */
+	idx -= 1;
+	if (idx < 0 || idx >= (int32) coll->ngeoms)
+		return NULL;
+
+	subgeom = coll->geoms[idx];
+	return subgeom;
+}
+
 /** 1-based offset */
 PG_FUNCTION_INFO_V1(LWGEOM_geometryn_collection);
 Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS)
@@ -267,36 +376,58 @@ Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS)
 	LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
 	GSERIALIZED *result = NULL;
 	int32 idx = PG_GETARG_INT32(1);
-	LWCOLLECTION *coll = NULL;
 	LWGEOM *subgeom = NULL;
 
-	/* Empty returns NULL */
-	if (lwgeom_is_empty(lwgeom))
+	/* TIN and PolyhedralSurface are treated as unitary geometries */
+	subgeom = lwgeom_extract_geometry_n(lwgeom, idx, false);
+
+	if (!subgeom)
 		PG_RETURN_NULL();
 
-	/* Unitary geometries just reflect back */
-	if (lwgeom_is_unitary(lwgeom))
+	/* If returning the original geometry */
+	if (subgeom == lwgeom)
+		PG_RETURN_POINTER(geom);
+
+	subgeom->srid = lwgeom->srid;
+	/* COMPUTE_BBOX==TAINTING */
+	if (lwgeom->bbox) lwgeom_add_bbox(subgeom);
+
+	result = geometry_serialize(subgeom);
+	lwgeom_free(lwgeom);
+	PG_FREE_IF_COPY(geom, 0);
+	PG_RETURN_POINTER(result);
+}
+
+/** 1-based offset */
+PG_FUNCTION_INFO_V1(LWGEOM_patchn);
+Datum LWGEOM_patchn(PG_FUNCTION_ARGS)
+{
+	GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
+	LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
+	GSERIALIZED *result = NULL;
+	int32 idx = PG_GETARG_INT32(1);
+	LWGEOM *subgeom = NULL;
+
+	if (!lwgeom_has_patches(lwgeom))
 	{
-		if ( idx == 1 )
-			PG_RETURN_POINTER(geom);
-		else
-			PG_RETURN_NULL();
+		lwgeom_free(lwgeom);
+		PG_FREE_IF_COPY(geom, 0);
+		elog(ERROR, "ST_PatchN only supports TIN and PolyhedralSurface geometries");
 	}
 
-	coll = lwgeom_as_lwcollection(lwgeom);
-	if (!coll)
-		elog(ERROR, "Unable to handle type %d in ST_GeometryN", lwgeom->type);
+	/* Access patches individually */
+	subgeom = lwgeom_extract_geometry_n(lwgeom, idx, true);
 
-	/* Handle out-of-range index value */
-	idx -= 1;
-	if ( idx < 0 || idx >= (int32) coll->ngeoms )
+	if (!subgeom)
 		PG_RETURN_NULL();
 
-	subgeom = coll->geoms[idx];
-	subgeom->srid = coll->srid;
+	/* If returning the original geometry */
+	if (subgeom == lwgeom)
+		PG_RETURN_POINTER(geom);
 
+	subgeom->srid = lwgeom->srid;
 	/* COMPUTE_BBOX==TAINTING */
-	if ( coll->bbox ) lwgeom_add_bbox(subgeom);
+	if (lwgeom->bbox) lwgeom_add_bbox(subgeom);
 
 	result = geometry_serialize(subgeom);
 	lwgeom_free(lwgeom);
diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in
index 6df42c397..38d009eac 100644
--- a/postgis/postgis.sql.in
+++ b/postgis/postgis.sql.in
@@ -5487,24 +5487,15 @@ CREATE OR REPLACE FUNCTION ST_PointN(geometry,integer)
 -- Availability: 2.0.0
 CREATE OR REPLACE FUNCTION ST_NumPatches(geometry)
 	RETURNS integer
-	AS '
-	SELECT CASE WHEN @extschema at .ST_GeometryType($1) in (''ST_PolyhedralSurface'', ''ST_Tin'')
-	THEN @extschema at .ST_NumGeometries($1)
-	ELSE NULL END
-	'
-	LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE
+	AS 'MODULE_PATHNAME', 'LWGEOM_numpatches'
+	LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE
 	_COST_LOW;
 
 -- Availability: 2.0.0
 CREATE OR REPLACE FUNCTION ST_PatchN(geometry, integer)
 	RETURNS geometry
-	AS '
-	SELECT CASE WHEN @extschema at .ST_GeometryType($1) in (''ST_PolyhedralSurface'', ''ST_Tin'')
-	THEN @extschema at .ST_GeometryN($1, $2)
-	ELSE NULL END
-	'
-	LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE
-	_COST_LOW;
+	AS 'MODULE_PATHNAME', 'LWGEOM_patchn'
+	LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE;
 
 -- PostGIS equivalent function of old StartPoint(geometry))
 CREATE OR REPLACE FUNCTION ST_StartPoint(geometry)

commit cf378d24aa3e89d1e628927ac42ecd534b6facc6
Author: Loïc Bartoletti <loic.bartoletti at oslandia.com>
Date:   Tue May 13 09:27:56 2025 +0200

    fix(Collection): PolyhedralSurface and TIN are not collections

diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c
index e7cea3de3..1b26752ee 100644
--- a/liblwgeom/lwgeom.c
+++ b/liblwgeom/lwgeom.c
@@ -1112,6 +1112,8 @@ lwgeom_is_unitary(const LWGEOM *geom)
 	case COMPOUNDTYPE:
 	case CIRCSTRINGTYPE:
 	case TRIANGLETYPE:
+	case POLYHEDRALSURFACETYPE:
+	case TINTYPE:
 		return LW_TRUE;
 		break;
 
@@ -1156,7 +1158,7 @@ lwtype_is_collection(uint8_t type)
 	case MULTICURVETYPE:
 	case MULTISURFACETYPE:
 	case POLYHEDRALSURFACETYPE:
-	case TINTYPE:
+  case TINTYPE:
 		return LW_TRUE;
 		break;
 

commit 54012ef1659aaab0b30e43823ddc6a34a6a6ce5d
Author: Loïc Bartoletti <loic.bartoletti at oslandia.com>
Date:   Tue May 13 07:17:08 2025 +0200

    fix(TIN): Add support for ST_NumPatches and ST_PatchN

diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in
index 51fba0988..6df42c397 100644
--- a/postgis/postgis.sql.in
+++ b/postgis/postgis.sql.in
@@ -5488,7 +5488,7 @@ CREATE OR REPLACE FUNCTION ST_PointN(geometry,integer)
 CREATE OR REPLACE FUNCTION ST_NumPatches(geometry)
 	RETURNS integer
 	AS '
-	SELECT CASE WHEN @extschema at .ST_GeometryType($1) = ''ST_PolyhedralSurface''
+	SELECT CASE WHEN @extschema at .ST_GeometryType($1) in (''ST_PolyhedralSurface'', ''ST_Tin'')
 	THEN @extschema at .ST_NumGeometries($1)
 	ELSE NULL END
 	'
@@ -5499,7 +5499,7 @@ CREATE OR REPLACE FUNCTION ST_NumPatches(geometry)
 CREATE OR REPLACE FUNCTION ST_PatchN(geometry, integer)
 	RETURNS geometry
 	AS '
-	SELECT CASE WHEN @extschema at .ST_GeometryType($1) = ''ST_PolyhedralSurface''
+	SELECT CASE WHEN @extschema at .ST_GeometryType($1) in (''ST_PolyhedralSurface'', ''ST_Tin'')
 	THEN @extschema at .ST_GeometryN($1, $2)
 	ELSE NULL END
 	'

-----------------------------------------------------------------------

Summary of changes:
 NEWS                                    |   4 +-
 liblwgeom/liblwgeom.h.in                |   5 +
 liblwgeom/lwgeom.c                      |  18 +++-
 postgis/lwgeom_ogc.c                    | 177 +++++++++++++++++++++++++++-----
 postgis/postgis.sql.in                  |  17 +--
 regress/core/polyhedralsurface.sql      |  11 ++
 regress/core/polyhedralsurface_expected |   7 ++
 7 files changed, 201 insertions(+), 38 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list