[SCM] PostGIS branch master updated. 3.7.0alpha1-615-gdd49506ad

git at osgeo.org git at osgeo.org
Sat Jul 18 14:11:45 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  dd49506ad52fda156b7dee8caacabbfc414f577c (commit)
       via  2d3e766eacf6a315103adc560ca696487410ac0d (commit)
       via  c7f11e50cb6476a04bfcf57b4527dae9feee11ae (commit)
       via  9c9625e9baf55cb25b2c5d6c144371e3dd5f112f (commit)
       via  4692dcc9010d2bde584ac9a3174bbcd530b992ae (commit)
       via  133840adde9a3da79c7255f7b4acf665e959230c (commit)
       via  8e790242494987283ebe2e43b3757c7a42d3631c (commit)
       via  df75dd4a035198383831ebfb597f2817721e0a65 (commit)
       via  9171580784d079adc0bbf7b59768a553b61b693d (commit)
      from  fe789eb49efa9ffae30b7491cfb42563b4b9bb64 (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 dd49506ad52fda156b7dee8caacabbfc414f577c
Merge: fe789eb49 2d3e766ea
Author: Darafei Praliaskouski <komzpa at gmail.com>
Date:   Sat Jul 18 14:11:44 2026 -0700

    Merge pull request 'Rasterize curved geometry inputs' (!369) from Komzpa/postgis:codex/ticket-1168-asraster-curves into master
    
    Reviewed-on: https://gitea.osgeo.org/postgis/postgis/pulls/369


commit 2d3e766eacf6a315103adc560ca696487410ac0d
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Sat Jul 18 21:02:00 2026 +0400

    Preserve extent padding for native GDAL curves
    
    Map GDAL 3.14 curve line types to their linear counterparts when deciding whether ST_AsRaster needs extent padding. This keeps native curve rasterization aligned with the pre-3.14 PostGIS fallback.
    
    Extend the raster regression with CircularString, CompoundCurve, and MultiCurve metadata parity checks against ST_CurveToLine.
    
    References #1168

diff --git a/raster/rt_core/rt_raster.c b/raster/rt_core/rt_raster.c
index 3ce611261..1c2bbb9f2 100644
--- a/raster/rt_core/rt_raster.c
+++ b/raster/rt_core/rt_raster.c
@@ -4,6 +4,7 @@
  * http://trac.osgeo.org/postgis/wiki/WKTRaster
  *
  * Copyright (C) 2013 Bborie Park <dustymugs at gmail.com>
+ * Copyright (C) 2026 Darafei Praliaskouski <me at komzpa.net>
  * Copyright (C) 2011-2013 Regents of the University of California
  *   <bkpark at ucdavis.edu>
  * Copyright (C) 2010-2011 Jorge Arevalo <jorge.arevalo at deimos-space.com>
@@ -2414,6 +2415,14 @@ rt_raster_gdal_rasterize(
 		compatibility with GDAL 1.6, 1.7 and 1.8.  1.9+ works fine with half-pixel.
 	*/
 	wkbtype = wkbFlatten(OGR_G_GetGeometryType(src_geom));
+#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 14, 0)
+	/*
+	 * GDAL 3.14 rasterizes curve line types as their linear counterparts. Use
+	 * the same type mapping for extent padding so native and pre-linearized
+	 * curves receive identical bounds.
+	 */
+	wkbtype = wkbFlatten(OGR_GT_GetLinear(wkbtype));
+#endif
 	if ((
 			(wkbtype == wkbPoint) ||
 			(wkbtype == wkbMultiPoint) ||
diff --git a/raster/test/regress/rt_asraster.sql b/raster/test/regress/rt_asraster.sql
index 6fe825325..405985832 100644
--- a/raster/test/regress/rt_asraster.sql
+++ b/raster/test/regress/rt_asraster.sql
@@ -544,6 +544,35 @@ WITH cases(label, geom) AS (
 )
 SELECT * FROM stats ORDER BY label;
 
+WITH lineal_curves(label, geom) AS (
+	VALUES
+	(
+		'#1168-CircularStringMatchesCurveToLine',
+		'CIRCULARSTRING(0 0, 5 5, 10 0)'::geometry
+	),
+	(
+		'#1168-CompoundCurveMatchesCurveToLine',
+		'COMPOUNDCURVE((0 0, 2 0), CIRCULARSTRING(2 0, 4 2, 6 0))'::geometry
+	),
+	(
+		'#1168-MultiCurveMatchesCurveToLine',
+		'MULTICURVE(CIRCULARSTRING(0 0, 5 5, 10 0))'::geometry
+	)
+), rasters AS (
+	SELECT
+		label,
+		ST_AsRaster(geom, 1.0, -1.0, '8BUI', 7, 0) AS curved_rast,
+		ST_AsRaster(ST_CurveToLine(geom), 1.0, -1.0, '8BUI', 7, 0) AS linear_rast
+	FROM lineal_curves
+)
+SELECT
+	label,
+	ST_SameAlignment(curved_rast, linear_rast) AS same_alignment,
+	(ST_MetaData(curved_rast)).width = (ST_MetaData(linear_rast)).width AS same_width,
+	(ST_MetaData(curved_rast)).height = (ST_MetaData(linear_rast)).height AS same_height
+FROM rasters
+ORDER BY label;
+
 WITH linearized_rasters(label, geom) AS (
 	VALUES
 	(
diff --git a/raster/test/regress/rt_asraster_expected b/raster/test/regress/rt_asraster_expected
index 32fff1d6e..c1cafe2f4 100644
--- a/raster/test/regress/rt_asraster_expected
+++ b/raster/test/regress/rt_asraster_expected
@@ -69,5 +69,8 @@ NOTICE:  The rasters have different scales on the X axis
 #1168-CurvePolygon|t|t|t|t
 #1168-CurvePolygonStraight|t|t|t|t
 #1168-NURBSCurve|t|t|t|t
+#1168-CircularStringMatchesCurveToLine|t|t|t
+#1168-CompoundCurveMatchesCurveToLine|t|t|t
+#1168-MultiCurveMatchesCurveToLine|t|t|t
 #1168-GeometryCollectionCurveStraight|t|t|t|t
 #1168-NURBSCurveMatchesCurveToLine|t|t|t|t

commit c7f11e50cb6476a04bfcf57b4527dae9feee11ae
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Sat Jul 18 20:34:08 2026 +0400

    Use native GDAL curve rasterization when available
    
    Keep the PostGIS curve linearizer for GDAL versions before 3.14 and for NURBSCurve inputs that OGR cannot represent. Let GDAL 3.14 and newer linearize supported OGR curve types inside GDALRasterizeGeometries.
    
    References #1168

diff --git a/NEWS b/NEWS
index 11a7e2253..1e1b9878b 100644
--- a/NEWS
+++ b/NEWS
@@ -58,8 +58,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
           (Darafei Praliaskouski)
  - #2557, #2805, Document ST_MapAlgebra callback argument
           signatures and return semantics (Darafei Praliaskouski)
- - #1168, [raster] Linearize curved geometry inputs with the PostGIS
-          curve linearizer for ST_AsRaster (Darafei Praliaskouski)
+ - #1168, [raster] Support curved geometry inputs in ST_AsRaster
+          (Darafei Praliaskouski)
 
 
 PostGIS 3.7.0dev
diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c
index 97ab6f1db..474aa62b7 100644
--- a/raster/rt_pg/rtpg_geometry.c
+++ b/raster/rt_pg/rtpg_geometry.c
@@ -65,7 +65,16 @@ rtpg_lwgeom_needs_curve_linearize(const LWGEOM *geom)
 	uint32_t i;
 	const LWCOLLECTION *collection;
 
+	/*
+	 * GDAL 3.14 linearizes OGR curve geometries in
+	 * GDALRasterizeGeometries(). Older versions ignore them. NURBSCURVE is
+	 * not an OGR geometry type, so it must always be linearized here.
+	 */
+#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 14, 0)
+	if (geom->type == NURBSCURVETYPE)
+#else
 	if (lwgeom_type_arc(geom))
+#endif
 		return LW_TRUE;
 
 	if (!lwgeom_is_collection(geom))

commit 9c9625e9baf55cb25b2c5d6c144371e3dd5f112f
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Wed Jul 8 23:49:21 2026 +0400

    Avoid cloning linear ST_AsRaster inputs
    
    Guard curve linearization with a cheap type-tree walk before calling lwcurve_linearize. The guard uses liblwgeom's lwgeom_type_arc() predicate and only recurses through collection wrappers, so already-linear inputs avoid an unnecessary deep clone while nested curve containers still get linearized before WKB serialization.
    
    References #1168

diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c
index bd1aa381b..97ab6f1db 100644
--- a/raster/rt_pg/rtpg_geometry.c
+++ b/raster/rt_pg/rtpg_geometry.c
@@ -59,6 +59,28 @@ Datum RASTER_getPolygon(PG_FUNCTION_ARGS);
 /* rasterize a geometry */
 Datum RASTER_asRaster(PG_FUNCTION_ARGS);
 
+static int
+rtpg_lwgeom_needs_curve_linearize(const LWGEOM *geom)
+{
+	uint32_t i;
+	const LWCOLLECTION *collection;
+
+	if (lwgeom_type_arc(geom))
+		return LW_TRUE;
+
+	if (!lwgeom_is_collection(geom))
+		return LW_FALSE;
+
+	collection = (const LWCOLLECTION *)geom;
+	for (i = 0; i < collection->ngeoms; i++)
+	{
+		if (rtpg_lwgeom_needs_curve_linearize(collection->geoms[i]))
+			return LW_TRUE;
+	}
+
+	return LW_FALSE;
+}
+
 /* ---------------------------------------------------------------- */
 /*  Raster envelope                                                 */
 /* ---------------------------------------------------------------- */
@@ -1124,11 +1146,7 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
 		geom = geom2d;
 	}
 
-	/*
-	 * Follow the same liblwgeom path as ST_CurveToLine. It returns a
-	 * cloned geometry for already-linear inputs, and recursively handles
-	 * curved members inside geometry collections before WKB serialization.
-	 */
+	if (rtpg_lwgeom_needs_curve_linearize(geom))
 	{
 		LWGEOM *linearized = lwcurve_linearize(geom, 32, LW_LINEARIZE_TOLERANCE_TYPE_SEGS_PER_QUAD, 0);
 		if (linearized == NULL)

commit 4692dcc9010d2bde584ac9a3174bbcd530b992ae
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Wed Jul 8 23:40:44 2026 +0400

    Use ST_CurveToLine idiom for raster curve linearization
    
    Call lwcurve_linearize directly before serializing ST_AsRaster inputs to WKB, matching the liblwgeom path used by ST_CurveToLine. This removes the raster-local recursive curve-type predicate while still handling curved members inside geometry collections.

diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c
index 63f7cac5c..bd1aa381b 100644
--- a/raster/rt_pg/rtpg_geometry.c
+++ b/raster/rt_pg/rtpg_geometry.c
@@ -59,34 +59,6 @@ Datum RASTER_getPolygon(PG_FUNCTION_ARGS);
 /* rasterize a geometry */
 Datum RASTER_asRaster(PG_FUNCTION_ARGS);
 
-static bool
-rtpg_lwgeom_is_curve_type(const LWGEOM *geom)
-{
-	uint32_t i;
-
-	switch (geom->type)
-	{
-	case CIRCSTRINGTYPE:
-	case COMPOUNDTYPE:
-	case CURVEPOLYTYPE:
-	case MULTICURVETYPE:
-	case MULTISURFACETYPE:
-	case NURBSCURVETYPE:
-		return true;
-	case COLLECTIONTYPE: {
-		const LWCOLLECTION *collection = (const LWCOLLECTION *)geom;
-		for (i = 0; i < collection->ngeoms; i++)
-		{
-			if (rtpg_lwgeom_is_curve_type(collection->geoms[i]))
-				return true;
-		}
-		return false;
-	}
-	default:
-		return false;
-	}
-}
-
 /* ---------------------------------------------------------------- */
 /*  Raster envelope                                                 */
 /* ---------------------------------------------------------------- */
@@ -1152,7 +1124,11 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
 		geom = geom2d;
 	}
 
-	if (lwgeom_has_arc(geom) || rtpg_lwgeom_is_curve_type(geom))
+	/*
+	 * Follow the same liblwgeom path as ST_CurveToLine. It returns a
+	 * cloned geometry for already-linear inputs, and recursively handles
+	 * curved members inside geometry collections before WKB serialization.
+	 */
 	{
 		LWGEOM *linearized = lwcurve_linearize(geom, 32, LW_LINEARIZE_TOLERANCE_TYPE_SEGS_PER_QUAD, 0);
 		if (linearized == NULL)

commit 133840adde9a3da79c7255f7b4acf665e959230c
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Wed Jul 8 23:30:39 2026 +0400

    Use PostGIS linearizer for ST_AsRaster curves
    
    Linearize curve inputs in the raster SQL bridge before serializing to WKB, instead of relying on GDAL-side curve handling. This keeps the rasterizer on SFSQL WKB and lets PostGIS-only curve types such as NURBSCurve reach GDAL as ordinary linear geometries.
    
    Extend rt_asraster regression coverage with a direct NURBSCurve case and a parity check against ST_CurveToLine.

diff --git a/NEWS b/NEWS
index 08ba6ac1a..11a7e2253 100644
--- a/NEWS
+++ b/NEWS
@@ -58,8 +58,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
           (Darafei Praliaskouski)
  - #2557, #2805, Document ST_MapAlgebra callback argument
           signatures and return semantics (Darafei Praliaskouski)
- - #1168, [raster] Linearize curved geometry inputs with GDAL for ST_AsRaster
-          rasterization (Darafei Praliaskouski)
+ - #1168, [raster] Linearize curved geometry inputs with the PostGIS
+          curve linearizer for ST_AsRaster (Darafei Praliaskouski)
 
 
 PostGIS 3.7.0dev
diff --git a/doc/reference_raster.xml b/doc/reference_raster.xml
index 61bc5f96c..b95d865e3 100644
--- a/doc/reference_raster.xml
+++ b/doc/reference_raster.xml
@@ -1728,7 +1728,7 @@ FROM ST_BandMetaData(ST_AddBand(ST_MakeEmptyRaster(10, 10, 0, 0, 1, -1, 0, 0, 0)
                     with <xref linkend="RT_ST_AsPNG"/> and other <xref linkend="RT_ST_AsGDALRaster"/> family of functions.</para>
                  <para role="availability" conformance="2.0.0">Availability: 2.0.0 - requires GDAL >= 1.6.0. </para>
 
-                 <para>Curved geometry inputs are linearized with GDAL before rasterization. TIN and PolyhedralSurface inputs are not supported.</para>
+                 <para>Curved geometry inputs are linearized before rasterization, including NURBSCurve inputs handled by PostGIS. TIN and PolyhedralSurface inputs are not supported.</para>
             </refsection>
 
             <refsection>
diff --git a/raster/rt_core/rt_raster.c b/raster/rt_core/rt_raster.c
index 3d23219bb..3ce611261 100644
--- a/raster/rt_core/rt_raster.c
+++ b/raster/rt_core/rt_raster.c
@@ -2319,23 +2319,6 @@ rt_raster_gdal_rasterize(
 		return NULL;
 	}
 
-	if (OGR_G_HasCurveGeometry(src_geom, FALSE)) {
-		/*
-		 * GDAL can read curved OGR geometries, but GDALRasterizeGeometries()
-		 * does not burn direct curve inputs reliably without an explicit
-		 * linearization step.
-		 */
-		OGRGeometryH linearized_geom = OGR_G_GetLinearGeometry(src_geom, 0.0, NULL);
-		if (linearized_geom == NULL) {
-			OGR_G_DestroyGeometry(src_geom);
-			_rti_rasterize_arg_destroy(arg);
-			rterror("rt_raster_gdal_rasterize: Could not linearize OGR Geometry");
-			return NULL;
-		}
-		OGR_G_DestroyGeometry(src_geom);
-		src_geom = linearized_geom;
-	}
-
 	/* OGR Geometry is empty */
 	if (OGR_G_IsEmpty(src_geom)) {
 		rtinfo("Geometry provided is empty. Returning empty raster");
diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c
index 509b093f3..63f7cac5c 100644
--- a/raster/rt_pg/rtpg_geometry.c
+++ b/raster/rt_pg/rtpg_geometry.c
@@ -59,6 +59,34 @@ Datum RASTER_getPolygon(PG_FUNCTION_ARGS);
 /* rasterize a geometry */
 Datum RASTER_asRaster(PG_FUNCTION_ARGS);
 
+static bool
+rtpg_lwgeom_is_curve_type(const LWGEOM *geom)
+{
+	uint32_t i;
+
+	switch (geom->type)
+	{
+	case CIRCSTRINGTYPE:
+	case COMPOUNDTYPE:
+	case CURVEPOLYTYPE:
+	case MULTICURVETYPE:
+	case MULTISURFACETYPE:
+	case NURBSCURVETYPE:
+		return true;
+	case COLLECTIONTYPE: {
+		const LWCOLLECTION *collection = (const LWCOLLECTION *)geom;
+		for (i = 0; i < collection->ngeoms; i++)
+		{
+			if (rtpg_lwgeom_is_curve_type(collection->geoms[i]))
+				return true;
+		}
+		return false;
+	}
+	default:
+		return false;
+	}
+}
+
 /* ---------------------------------------------------------------- */
 /*  Raster envelope                                                 */
 /* ---------------------------------------------------------------- */
@@ -1051,7 +1079,7 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
 	rt_pgraster *pgrast = NULL;
 
 	lwvarlena_t *wkb;
-	unsigned char variant = WKB_ISO;
+	unsigned char variant = WKB_SFSQL;
 
 	double scale[2] = {0};
 	double *scale_x = NULL;
@@ -1124,6 +1152,20 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
 		geom = geom2d;
 	}
 
+	if (lwgeom_has_arc(geom) || rtpg_lwgeom_is_curve_type(geom))
+	{
+		LWGEOM *linearized = lwcurve_linearize(geom, 32, LW_LINEARIZE_TOLERANCE_TYPE_SEGS_PER_QUAD, 0);
+		if (linearized == NULL)
+		{
+			lwgeom_free(geom);
+			PG_FREE_IF_COPY(gser, 0);
+			elog(ERROR, "RASTER_asRaster: Could not linearize geometry");
+			PG_RETURN_NULL();
+		}
+		lwgeom_free(geom);
+		geom = linearized;
+	}
+
 	/* empty geometry, return empty raster */
 	if (lwgeom_is_empty(geom)) {
 		POSTGIS_RT_DEBUG(3, "Input geometry is empty. Returning empty raster");
diff --git a/raster/test/regress/rt_asraster.sql b/raster/test/regress/rt_asraster.sql
index 844c4db91..6fe825325 100644
--- a/raster/test/regress/rt_asraster.sql
+++ b/raster/test/regress/rt_asraster.sql
@@ -523,6 +523,10 @@ WITH cases(label, geom) AS (
 	(
 		'#1168-CurvePolygonStraight',
 		'CURVEPOLYGON(COMPOUNDCURVE((0 0, 4 0, 4 4, 0 4, 0 0)))'::geometry
+	),
+	(
+		'#1168-NURBSCurve',
+		ST_MakeNurbsCurve(2, 'LINESTRING(0 0, 5 10, 10 0)'::geometry)
 	)
 ), rasters AS (
 	SELECT
@@ -540,19 +544,31 @@ WITH cases(label, geom) AS (
 )
 SELECT * FROM stats ORDER BY label;
 
-WITH collection_rasters AS (
+WITH linearized_rasters(label, geom) AS (
+	VALUES
+	(
+		'#1168-GeometryCollectionCurveStraight',
+		'GEOMETRYCOLLECTION(COMPOUNDCURVE((0 0, 4 0, 4 4)))'::geometry
+	),
+	(
+		'#1168-NURBSCurveMatchesCurveToLine',
+		ST_MakeNurbsCurve(2, 'LINESTRING(0 0, 5 10, 10 0)'::geometry)
+	)
+), rasters AS (
 	SELECT
+		label,
 		ST_AsRaster(geom, 1.0, -1.0, '8BUI', 7, 0) AS curved_rast,
 		ST_AsRaster(ST_CurveToLine(geom), 1.0, -1.0, '8BUI', 7, 0) AS linear_rast
-	FROM (SELECT 'GEOMETRYCOLLECTION(COMPOUNDCURVE((0 0, 4 0, 4 4)))'::geometry AS geom) g
+	FROM linearized_rasters
 )
 SELECT
-	'#1168-GeometryCollectionCurveStraight',
+	label,
 	ST_SameAlignment(curved_rast, linear_rast) AS same_alignment,
 	(ST_MetaData(curved_rast)).width = (ST_MetaData(linear_rast)).width AS same_width,
 	(ST_MetaData(curved_rast)).height = (ST_MetaData(linear_rast)).height AS same_height,
 	(ST_SummaryStats(curved_rast)).count IS NOT DISTINCT FROM (ST_SummaryStats(linear_rast)).count AS same_count
-FROM collection_rasters;
+FROM rasters
+ORDER BY label;
 
 DELETE FROM "spatial_ref_sys" WHERE srid = 992163;
 DELETE FROM "spatial_ref_sys" WHERE srid = 993309;
diff --git a/raster/test/regress/rt_asraster_expected b/raster/test/regress/rt_asraster_expected
index 471f64450..32fff1d6e 100644
--- a/raster/test/regress/rt_asraster_expected
+++ b/raster/test/regress/rt_asraster_expected
@@ -68,4 +68,6 @@ NOTICE:  The rasters have different scales on the X axis
 #1168-CompoundCurveStraight|t|t|t|t
 #1168-CurvePolygon|t|t|t|t
 #1168-CurvePolygonStraight|t|t|t|t
+#1168-NURBSCurve|t|t|t|t
 #1168-GeometryCollectionCurveStraight|t|t|t|t
+#1168-NURBSCurveMatchesCurveToLine|t|t|t|t

commit 8e790242494987283ebe2e43b3757c7a42d3631c
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Wed Jul 8 15:27:20 2026 +0400

    Use GDAL to linearize ST_AsRaster curves

diff --git a/NEWS b/NEWS
index ad182c51d..08ba6ac1a 100644
--- a/NEWS
+++ b/NEWS
@@ -62,8 +62,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
           rasterization (Darafei Praliaskouski)
 
 
-PostGIS 3.7.0alpha1
-2026/07/05
+PostGIS 3.7.0dev
+2026/xx/xx
 
 This version requires GEOS 3.10+, PostgreSQL 14-19beta1, Proj 6.1+, libgmp.
 To take advantage of all features postgis extension features, GEOS 3.15+ is needed.
diff --git a/doc/reference_raster.xml b/doc/reference_raster.xml
index 98028ef3b..61bc5f96c 100644
--- a/doc/reference_raster.xml
+++ b/doc/reference_raster.xml
@@ -1728,7 +1728,7 @@ FROM ST_BandMetaData(ST_AddBand(ST_MakeEmptyRaster(10, 10, 0, 0, 1, -1, 0, 0, 0)
                     with <xref linkend="RT_ST_AsPNG"/> and other <xref linkend="RT_ST_AsGDALRaster"/> family of functions.</para>
                  <para role="availability" conformance="2.0.0">Availability: 2.0.0 - requires GDAL >= 1.6.0. </para>
 
-                 <para>Curved geometry inputs are linearized before rasterization. TIN and PolyhedralSurface inputs are not supported.</para>
+                 <para>Curved geometry inputs are linearized with GDAL before rasterization. TIN and PolyhedralSurface inputs are not supported.</para>
             </refsection>
 
             <refsection>
diff --git a/raster/rt_core/rt_raster.c b/raster/rt_core/rt_raster.c
index 3ce611261..3d23219bb 100644
--- a/raster/rt_core/rt_raster.c
+++ b/raster/rt_core/rt_raster.c
@@ -2319,6 +2319,23 @@ rt_raster_gdal_rasterize(
 		return NULL;
 	}
 
+	if (OGR_G_HasCurveGeometry(src_geom, FALSE)) {
+		/*
+		 * GDAL can read curved OGR geometries, but GDALRasterizeGeometries()
+		 * does not burn direct curve inputs reliably without an explicit
+		 * linearization step.
+		 */
+		OGRGeometryH linearized_geom = OGR_G_GetLinearGeometry(src_geom, 0.0, NULL);
+		if (linearized_geom == NULL) {
+			OGR_G_DestroyGeometry(src_geom);
+			_rti_rasterize_arg_destroy(arg);
+			rterror("rt_raster_gdal_rasterize: Could not linearize OGR Geometry");
+			return NULL;
+		}
+		OGR_G_DestroyGeometry(src_geom);
+		src_geom = linearized_geom;
+	}
+
 	/* OGR Geometry is empty */
 	if (OGR_G_IsEmpty(src_geom)) {
 		rtinfo("Geometry provided is empty. Returning empty raster");
diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c
index f0630cd71..509b093f3 100644
--- a/raster/rt_pg/rtpg_geometry.c
+++ b/raster/rt_pg/rtpg_geometry.c
@@ -59,34 +59,6 @@ Datum RASTER_getPolygon(PG_FUNCTION_ARGS);
 /* rasterize a geometry */
 Datum RASTER_asRaster(PG_FUNCTION_ARGS);
 
-static bool
-rtpg_lwgeom_is_curve_type(const LWGEOM *geom)
-{
-	uint32_t i;
-
-	switch (geom->type)
-	{
-	case CIRCSTRINGTYPE:
-	case COMPOUNDTYPE:
-	case CURVEPOLYTYPE:
-	case MULTICURVETYPE:
-	case MULTISURFACETYPE:
-	case NURBSCURVETYPE:
-		return true;
-	case COLLECTIONTYPE: {
-		const LWCOLLECTION *collection = (const LWCOLLECTION *)geom;
-		for (i = 0; i < collection->ngeoms; i++)
-		{
-			if (rtpg_lwgeom_is_curve_type(collection->geoms[i]))
-				return true;
-		}
-		return false;
-	}
-	default:
-		return false;
-	}
-}
-
 /* ---------------------------------------------------------------- */
 /*  Raster envelope                                                 */
 /* ---------------------------------------------------------------- */
@@ -1079,7 +1051,7 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
 	rt_pgraster *pgrast = NULL;
 
 	lwvarlena_t *wkb;
-	unsigned char variant = WKB_SFSQL;
+	unsigned char variant = WKB_ISO;
 
 	double scale[2] = {0};
 	double *scale_x = NULL;
@@ -1152,20 +1124,6 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
 		geom = geom2d;
 	}
 
-	if (lwgeom_has_arc(geom) || rtpg_lwgeom_is_curve_type(geom))
-	{
-		LWGEOM *linearized = lwgeom_stroke(geom, 32);
-		if (!linearized)
-		{
-			lwgeom_free(geom);
-			PG_FREE_IF_COPY(gser, 0);
-			elog(ERROR, "RASTER_asRaster: Could not linearize geometry");
-			PG_RETURN_NULL();
-		}
-		lwgeom_free(geom);
-		geom = linearized;
-	}
-
 	/* empty geometry, return empty raster */
 	if (lwgeom_is_empty(geom)) {
 		POSTGIS_RT_DEBUG(3, "Input geometry is empty. Returning empty raster");
diff --git a/raster/test/regress/rt_asraster.sql b/raster/test/regress/rt_asraster.sql
index 00722dcc1..844c4db91 100644
--- a/raster/test/regress/rt_asraster.sql
+++ b/raster/test/regress/rt_asraster.sql
@@ -523,29 +523,37 @@ WITH cases(label, geom) AS (
 	(
 		'#1168-CurvePolygonStraight',
 		'CURVEPOLYGON(COMPOUNDCURVE((0 0, 4 0, 4 4, 0 4, 0 0)))'::geometry
-	),
-	(
-		'#1168-GeometryCollectionCurveStraight',
-		'GEOMETRYCOLLECTION(COMPOUNDCURVE((0 0, 4 0, 4 4)))'::geometry
 	)
 ), rasters AS (
 	SELECT
 		label,
-		ST_AsRaster(geom, 1.0, -1.0, '8BUI', 7, 0) AS curved_rast,
-		ST_AsRaster(ST_CurveToLine(geom), 1.0, -1.0, '8BUI', 7, 0) AS linear_rast
+		ST_AsRaster(geom, 1.0, -1.0, '8BUI', 7, 0) AS rast
 	FROM cases
 ), stats AS (
 	SELECT
 		label,
-		ST_SameAlignment(curved_rast, linear_rast) AS same_alignment,
-		(ST_MetaData(curved_rast)).width = (ST_MetaData(linear_rast)).width AS same_width,
-		(ST_MetaData(curved_rast)).height = (ST_MetaData(linear_rast)).height AS same_height,
-		(ST_SummaryStats(curved_rast)).count IS NOT DISTINCT FROM (ST_SummaryStats(linear_rast)).count AS same_count,
-		(ST_SummaryStats(curved_rast)).sum IS NOT DISTINCT FROM (ST_SummaryStats(linear_rast)).sum AS same_sum
+		(ST_MetaData(rast)).width > 0 AS has_width,
+		(ST_MetaData(rast)).height > 0 AS has_height,
+		(ST_SummaryStats(rast)).count > 0 AS has_pixels,
+		(ST_SummaryStats(rast)).sum > 0 AS has_burned_pixels
 	FROM rasters
 )
 SELECT * FROM stats ORDER BY label;
 
+WITH collection_rasters AS (
+	SELECT
+		ST_AsRaster(geom, 1.0, -1.0, '8BUI', 7, 0) AS curved_rast,
+		ST_AsRaster(ST_CurveToLine(geom), 1.0, -1.0, '8BUI', 7, 0) AS linear_rast
+	FROM (SELECT 'GEOMETRYCOLLECTION(COMPOUNDCURVE((0 0, 4 0, 4 4)))'::geometry AS geom) g
+)
+SELECT
+	'#1168-GeometryCollectionCurveStraight',
+	ST_SameAlignment(curved_rast, linear_rast) AS same_alignment,
+	(ST_MetaData(curved_rast)).width = (ST_MetaData(linear_rast)).width AS same_width,
+	(ST_MetaData(curved_rast)).height = (ST_MetaData(linear_rast)).height AS same_height,
+	(ST_SummaryStats(curved_rast)).count IS NOT DISTINCT FROM (ST_SummaryStats(linear_rast)).count AS same_count
+FROM collection_rasters;
+
 DELETE FROM "spatial_ref_sys" WHERE srid = 992163;
 DELETE FROM "spatial_ref_sys" WHERE srid = 993309;
 DELETE FROM "spatial_ref_sys" WHERE srid = 993310;
diff --git a/raster/test/regress/rt_asraster_expected b/raster/test/regress/rt_asraster_expected
index 2a58dd628..471f64450 100644
--- a/raster/test/regress/rt_asraster_expected
+++ b/raster/test/regress/rt_asraster_expected
@@ -63,9 +63,9 @@ NOTICE:  The rasters have different scales on the X axis
 4.8|993310|142|88|1|1000.000|-1000.000|0.000|0.000|-176000.000|115000.000|16BUI|0.000|t|13.000|13.000|f
 4.9|993310|142|88|1|1000.000|-1000.000|0.000|0.000|-176453.000|115987.000|16BUI|0.000|t|13.000|13.000|f
 #5084|10
-#1168-CircularString|t|t|t|t|t
-#1168-CompoundCurve|t|t|t|t|t
-#1168-CompoundCurveStraight|t|t|t|t|t
-#1168-CurvePolygon|t|t|t|t|t
-#1168-CurvePolygonStraight|t|t|t|t|t
-#1168-GeometryCollectionCurveStraight|t|t|t|t|t
+#1168-CircularString|t|t|t|t
+#1168-CompoundCurve|t|t|t|t
+#1168-CompoundCurveStraight|t|t|t|t
+#1168-CurvePolygon|t|t|t|t
+#1168-CurvePolygonStraight|t|t|t|t
+#1168-GeometryCollectionCurveStraight|t|t|t|t

commit df75dd4a035198383831ebfb597f2817721e0a65
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Mon Jul 6 17:45:51 2026 +0400

    NEWS: move entry to 3.7.0beta1

diff --git a/NEWS b/NEWS
index 08c503313..ad182c51d 100644
--- a/NEWS
+++ b/NEWS
@@ -58,10 +58,12 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
           (Darafei Praliaskouski)
  - #2557, #2805, Document ST_MapAlgebra callback argument
           signatures and return semantics (Darafei Praliaskouski)
+ - #1168, [raster] Linearize curved geometry inputs with GDAL for ST_AsRaster
+          rasterization (Darafei Praliaskouski)
 
 
-PostGIS 3.7.0dev
-2026/xx/xx
+PostGIS 3.7.0alpha1
+2026/07/05
 
 This version requires GEOS 3.10+, PostgreSQL 14-19beta1, Proj 6.1+, libgmp.
 To take advantage of all features postgis extension features, GEOS 3.15+ is needed.
@@ -126,8 +128,6 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
 
 * Enhancements *
 
- - #1168, [raster] Linearize curved geometry inputs before ST_AsRaster
-          rasterization (Darafei Praliaskouski)
  - #2045, pgsql2shp query dumps no longer require temporary table
           privileges (Darafei Praliaskouski)
  - #1577, [loader] Report unsupported .zip archive input before trying

commit 9171580784d079adc0bbf7b59768a553b61b693d
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Mon Jun 22 03:56:23 2026 +0400

    Rasterize curved geometry inputs
    
    ST_AsRaster now linearizes curved geometry inputs before passing WKB to GDAL rasterization. This enables curved line and curved polygon inputs while leaving TIN and PolyhedralSurface rasterization unsupported.
    
    References #1168

diff --git a/NEWS b/NEWS
index 1e6959eaf..08c503313 100644
--- a/NEWS
+++ b/NEWS
@@ -126,6 +126,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
 
 * Enhancements *
 
+ - #1168, [raster] Linearize curved geometry inputs before ST_AsRaster
+          rasterization (Darafei Praliaskouski)
  - #2045, pgsql2shp query dumps no longer require temporary table
           privileges (Darafei Praliaskouski)
  - #1577, [loader] Report unsupported .zip archive input before trying
diff --git a/doc/reference_raster.xml b/doc/reference_raster.xml
index bc5b1a359..98028ef3b 100644
--- a/doc/reference_raster.xml
+++ b/doc/reference_raster.xml
@@ -1728,8 +1728,7 @@ FROM ST_BandMetaData(ST_AddBand(ST_MakeEmptyRaster(10, 10, 0, 0, 1, -1, 0, 0, 0)
                     with <xref linkend="RT_ST_AsPNG"/> and other <xref linkend="RT_ST_AsGDALRaster"/> family of functions.</para>
                  <para role="availability" conformance="2.0.0">Availability: 2.0.0 - requires GDAL >= 1.6.0. </para>
 
-                 <note><para>Not yet capable of rendering complex geometry types such as curves, TINS, and PolyhedralSurfaces, but should be
-                 able too once GDAL can.</para></note>
+                 <para>Curved geometry inputs are linearized before rasterization. TIN and PolyhedralSurface inputs are not supported.</para>
             </refsection>
 
             <refsection>
diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c
index 6a006f5f2..f0630cd71 100644
--- a/raster/rt_pg/rtpg_geometry.c
+++ b/raster/rt_pg/rtpg_geometry.c
@@ -59,6 +59,34 @@ Datum RASTER_getPolygon(PG_FUNCTION_ARGS);
 /* rasterize a geometry */
 Datum RASTER_asRaster(PG_FUNCTION_ARGS);
 
+static bool
+rtpg_lwgeom_is_curve_type(const LWGEOM *geom)
+{
+	uint32_t i;
+
+	switch (geom->type)
+	{
+	case CIRCSTRINGTYPE:
+	case COMPOUNDTYPE:
+	case CURVEPOLYTYPE:
+	case MULTICURVETYPE:
+	case MULTISURFACETYPE:
+	case NURBSCURVETYPE:
+		return true;
+	case COLLECTIONTYPE: {
+		const LWCOLLECTION *collection = (const LWCOLLECTION *)geom;
+		for (i = 0; i < collection->ngeoms; i++)
+		{
+			if (rtpg_lwgeom_is_curve_type(collection->geoms[i]))
+				return true;
+		}
+		return false;
+	}
+	default:
+		return false;
+	}
+}
+
 /* ---------------------------------------------------------------- */
 /*  Raster envelope                                                 */
 /* ---------------------------------------------------------------- */
@@ -1124,6 +1152,20 @@ Datum RASTER_asRaster(PG_FUNCTION_ARGS)
 		geom = geom2d;
 	}
 
+	if (lwgeom_has_arc(geom) || rtpg_lwgeom_is_curve_type(geom))
+	{
+		LWGEOM *linearized = lwgeom_stroke(geom, 32);
+		if (!linearized)
+		{
+			lwgeom_free(geom);
+			PG_FREE_IF_COPY(gser, 0);
+			elog(ERROR, "RASTER_asRaster: Could not linearize geometry");
+			PG_RETURN_NULL();
+		}
+		lwgeom_free(geom);
+		geom = linearized;
+	}
+
 	/* empty geometry, return empty raster */
 	if (lwgeom_is_empty(geom)) {
 		POSTGIS_RT_DEBUG(3, "Input geometry is empty. Returning empty raster");
diff --git a/raster/test/regress/rt_asraster.sql b/raster/test/regress/rt_asraster.sql
index 6a25fd448..00722dcc1 100644
--- a/raster/test/regress/rt_asraster.sql
+++ b/raster/test/regress/rt_asraster.sql
@@ -502,6 +502,50 @@ FROM (
 SELECT '#5084' As ticket, count(dp.geom)
 FROM ST_DumpAsPolygons(ST_AsRaster('LINESTRING(986015.7 6720291.2,986024.3 6720347,986028 6720417.4,986025.6 6720474.3)'::geometry, 2::double precision, 2, 0, 0)) AS dp;
 
+WITH cases(label, geom) AS (
+	VALUES
+	(
+		'#1168-CircularString',
+		'CIRCULARSTRING(0 0, 5 5, 10 0)'::geometry
+	),
+	(
+		'#1168-CompoundCurve',
+		'COMPOUNDCURVE((0 0, 2 0), CIRCULARSTRING(2 0, 4 2, 6 0))'::geometry
+	),
+	(
+		'#1168-CompoundCurveStraight',
+		'COMPOUNDCURVE((0 0, 4 0, 4 4))'::geometry
+	),
+	(
+		'#1168-CurvePolygon',
+		'CURVEPOLYGON(CIRCULARSTRING(0 0, 5 5, 10 0, 5 -5, 0 0))'::geometry
+	),
+	(
+		'#1168-CurvePolygonStraight',
+		'CURVEPOLYGON(COMPOUNDCURVE((0 0, 4 0, 4 4, 0 4, 0 0)))'::geometry
+	),
+	(
+		'#1168-GeometryCollectionCurveStraight',
+		'GEOMETRYCOLLECTION(COMPOUNDCURVE((0 0, 4 0, 4 4)))'::geometry
+	)
+), rasters AS (
+	SELECT
+		label,
+		ST_AsRaster(geom, 1.0, -1.0, '8BUI', 7, 0) AS curved_rast,
+		ST_AsRaster(ST_CurveToLine(geom), 1.0, -1.0, '8BUI', 7, 0) AS linear_rast
+	FROM cases
+), stats AS (
+	SELECT
+		label,
+		ST_SameAlignment(curved_rast, linear_rast) AS same_alignment,
+		(ST_MetaData(curved_rast)).width = (ST_MetaData(linear_rast)).width AS same_width,
+		(ST_MetaData(curved_rast)).height = (ST_MetaData(linear_rast)).height AS same_height,
+		(ST_SummaryStats(curved_rast)).count IS NOT DISTINCT FROM (ST_SummaryStats(linear_rast)).count AS same_count,
+		(ST_SummaryStats(curved_rast)).sum IS NOT DISTINCT FROM (ST_SummaryStats(linear_rast)).sum AS same_sum
+	FROM rasters
+)
+SELECT * FROM stats ORDER BY label;
+
 DELETE FROM "spatial_ref_sys" WHERE srid = 992163;
 DELETE FROM "spatial_ref_sys" WHERE srid = 993309;
 DELETE FROM "spatial_ref_sys" WHERE srid = 993310;
diff --git a/raster/test/regress/rt_asraster_expected b/raster/test/regress/rt_asraster_expected
index 50110cee8..2a58dd628 100644
--- a/raster/test/regress/rt_asraster_expected
+++ b/raster/test/regress/rt_asraster_expected
@@ -63,3 +63,9 @@ NOTICE:  The rasters have different scales on the X axis
 4.8|993310|142|88|1|1000.000|-1000.000|0.000|0.000|-176000.000|115000.000|16BUI|0.000|t|13.000|13.000|f
 4.9|993310|142|88|1|1000.000|-1000.000|0.000|0.000|-176453.000|115987.000|16BUI|0.000|t|13.000|13.000|f
 #5084|10
+#1168-CircularString|t|t|t|t|t
+#1168-CompoundCurve|t|t|t|t|t
+#1168-CompoundCurveStraight|t|t|t|t|t
+#1168-CurvePolygon|t|t|t|t|t
+#1168-CurvePolygonStraight|t|t|t|t|t
+#1168-GeometryCollectionCurveStraight|t|t|t|t|t

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

Summary of changes:
 NEWS                                     |  2 +
 doc/reference_raster.xml                 |  3 +-
 raster/rt_core/rt_raster.c               |  9 +++
 raster/rt_pg/rtpg_geometry.c             | 45 +++++++++++++++
 raster/test/regress/rt_asraster.sql      | 97 ++++++++++++++++++++++++++++++++
 raster/test/regress/rt_asraster_expected | 11 ++++
 6 files changed, 165 insertions(+), 2 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list