[SCM] PostGIS branch master updated. 3.6.0rc2-626-gbdf4f5727
git at osgeo.org
git at osgeo.org
Fri Jun 19 13:14: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 bdf4f57279395f82cc323c14f828cbd50b678444 (commit)
from 9aee37109ed245fc322dfec6b1ac7bb1227eb942 (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 bdf4f57279395f82cc323c14f828cbd50b678444
Author: Darafei Praliaskouski <me at komzpa.net>
Date: Sat Jun 20 00:13:39 2026 +0400
postgis: support curved rings in ST_MakePolygon
Allow ST_MakePolygon to accept closed CircularString, CompoundCurve, and NURBSCurve rings, returning CurvePolygon when any input ring is curved.
References #1291
Closes https://github.com/postgis/postgis/pull/961
diff --git a/NEWS b/NEWS
index f0c449087..4012eedcf 100644
--- a/NEWS
+++ b/NEWS
@@ -47,6 +47,7 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
- GH-839, ST_Multi support for TIN and surfaces (Loïc Bartoletti)
- #4398, Add ST_CatmullSmoothing smoothes but retains original vertices (Paul Ramsey)
- #4560, ST_3DInterpolatePoint for M interpolation from XYZ inputs (Paul Ramsey)
+ - #1291, ST_MakePolygon support for curved rings (Darafei Praliaskouski)
- GT-270, Add NURBSCurve (Loïc Bartoletti)
- #2863, Add ST_XSize, ST_YSize, ST_ZSize, and ST_MSize dimension helpers
(Darafei Praliaskouski)
diff --git a/doc/reference_constructor.xml b/doc/reference_constructor.xml
index 66fbb8b7c..1786be337 100644
--- a/doc/reference_constructor.xml
+++ b/doc/reference_constructor.xml
@@ -529,7 +529,7 @@ result
<refnamediv>
<refname>ST_MakePolygon</refname>
- <refpurpose>Creates a Polygon from a shell and optional list of holes.</refpurpose>
+ <refpurpose>Creates a Polygon or CurvePolygon from a shell and optional list of holes.</refpurpose>
</refnamediv>
<refsynopsisdiv>
@@ -551,12 +551,14 @@ result
<refsection>
<title>Description</title>
- <para>Creates a Polygon formed by the given shell and optional array of holes.
- Input geometries must be closed LineStrings (rings).</para>
+ <para>Creates a Polygon or CurvePolygon formed by the given shell and optional array of holes.
+ Input geometries must be closed LineStrings, CircularStrings, CompoundCurves, or NURBSCurves (rings).
+ If any input ring is curved, the result is a CurvePolygon.
+ </para>
- <para><emphasis role="bold">Variant 1:</emphasis> Accepts one shell LineString.</para>
- <para><emphasis role="bold">Variant 2:</emphasis> Accepts a shell LineString and an array of
- inner (hole) LineStrings. A geometry array can be constructed using the PostgreSQL array_agg(), ARRAY[] or
+ <para><emphasis role="bold">Variant 1:</emphasis> Accepts one shell ring.</para>
+ <para><emphasis role="bold">Variant 2:</emphasis> Accepts a shell ring and an array of
+ inner (hole) rings. A geometry array can be constructed using the PostgreSQL array_agg(), ARRAY[] or
ARRAY() constructs.</para>
<note><para>This function does not accept MultiLineStrings.
@@ -564,6 +566,7 @@ result
</note>
<para>&Z_support;</para>
+ <para role="enhanced" conformance="3.7.0">Enhanced: 3.7.0 - Support for curved input rings was introduced.</para>
</refsection>
<refsection>
@@ -596,6 +599,15 @@ SELECT ST_AsEWKT( ST_MakePolygon( 'LINESTRINGM(75.15 29.53 1,77 29 1,77.6 29.5 2
st_asewkt
----------
POLYGONM((75.15 29.53 1,77 29 1,77.6 29.5 2,75.15 29.53 2))
+</programlisting>
+
+<para>Create a CurvePolygon from a CircularString shell.</para>
+<programlisting>
+SELECT ST_AsText( ST_MakePolygon( 'CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0)' ));
+
+ st_astext
+----------------------------------------------------
+ CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0))
</programlisting>
</refsection>
<refsection>
diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c
index ec8b3ca18..f12b04b5c 100644
--- a/postgis/lwgeom_functions_basic.c
+++ b/postgis/lwgeom_functions_basic.c
@@ -20,6 +20,7 @@
*
* Copyright 2001-2006 Refractions Research Inc.
* Copyright 2017-2018 Daniel Baston <dbaston at gmail.com>
+ * Copyright 2026 Darafei Praliaskouski <me at komzpa.net>
*
**********************************************************************/
@@ -128,6 +129,23 @@ Datum ST_PointZM(PG_FUNCTION_ARGS);
/*------------------------------------------------------------------*/
+static int
+lwgeom_is_makepoly_ring_type(uint8_t type)
+{
+ return type == LINETYPE || type == CIRCSTRINGTYPE || type == COMPOUNDTYPE || type == NURBSCURVETYPE;
+}
+
+static void
+lwgeom_makepoly_validate_curve_ring(const LWGEOM *ring, const char *label)
+{
+ uint32_t vertices_needed = ring->type == LINETYPE ? 4 : 3;
+
+ if (lwgeom_count_vertices(ring) < vertices_needed)
+ lwerror("%s must have at least %d points", label, vertices_needed);
+ if (!lwgeom_is_closed(ring))
+ lwerror("%s must be closed", label);
+}
+
/** find the size of geometry */
PG_FUNCTION_INFO_V1(LWGEOM_mem_size);
Datum LWGEOM_mem_size(PG_FUNCTION_ARGS)
@@ -1559,28 +1577,39 @@ Datum LWGEOM_makepoly(PG_FUNCTION_ARGS)
GSERIALIZED *pglwg1;
ArrayType *array = NULL;
GSERIALIZED *result = NULL;
- const LWLINE *shell = NULL;
+ LWGEOM *shell = NULL;
+ LWGEOM **rings = NULL;
const LWLINE **holes = NULL;
LWPOLY *outpoly;
+ LWCURVEPOLY *outcurvepoly;
uint32 nholes = 0;
uint32 i;
size_t offset = 0;
+ int has_curve_ring = LW_FALSE;
+ int32_t srid;
+ int has_z;
+ int has_m;
POSTGIS_DEBUG(2, "LWGEOM_makepoly called.");
/* Get input shell */
pglwg1 = PG_GETARG_GSERIALIZED_P(0);
- if (gserialized_get_type(pglwg1) != LINETYPE)
+ if (!lwgeom_is_makepoly_ring_type(gserialized_get_type(pglwg1)))
{
lwpgerror("Shell is not a line");
}
- shell = lwgeom_as_lwline(lwgeom_from_gserialized(pglwg1));
+ shell = lwgeom_from_gserialized(pglwg1);
+ has_curve_ring = shell->type != LINETYPE;
+ srid = shell->srid;
+ has_z = FLAGS_GET_Z(shell->flags);
+ has_m = FLAGS_GET_M(shell->flags);
/* Get input holes if any */
if (PG_NARGS() > 1)
{
array = PG_GETARG_ARRAYTYPE_P(1);
nholes = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
+ rings = lwalloc(sizeof(LWGEOM *) * (nholes + 1));
holes = lwalloc(sizeof(LWLINE *) * nholes);
for (i = 0; i < nholes; i++)
{
@@ -1592,28 +1621,65 @@ Datum LWGEOM_makepoly(PG_FUNCTION_ARGS)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop
#endif
- LWLINE *hole;
+ LWGEOM *hole;
offset += INTALIGN(VARSIZE(g));
- if (gserialized_get_type(g) != LINETYPE)
+ if (!lwgeom_is_makepoly_ring_type(gserialized_get_type(g)))
{
lwpgerror("Hole %d is not a line", i);
}
- hole = lwgeom_as_lwline(lwgeom_from_gserialized(g));
- holes[i] = hole;
+ hole = lwgeom_from_gserialized(g);
+ has_curve_ring |= hole->type != LINETYPE;
+ rings[i + 1] = hole;
+ holes[i] = lwgeom_as_lwline(hole);
}
}
- outpoly = lwpoly_from_lwlines(shell, nholes, holes);
- POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM *)outpoly, 0));
- result = geometry_serialize((LWGEOM *)outpoly);
+ if (has_curve_ring)
+ {
+ if (!rings)
+ rings = lwalloc(sizeof(LWGEOM *));
+ rings[0] = shell;
+ outcurvepoly = lwcurvepoly_construct_empty(srid, FLAGS_GET_Z(shell->flags), FLAGS_GET_M(shell->flags));
- lwline_free((LWLINE *)shell);
+ for (i = 0; i <= nholes; i++)
+ {
+ if (rings[i]->srid != srid)
+ lwerror("lwgeom_makepoly: mixed SRIDs in input rings");
+ if (FLAGS_GET_Z(rings[i]->flags) != has_z || FLAGS_GET_M(rings[i]->flags) != has_m)
+ lwerror("lwgeom_makepoly: mixed dimensioned rings");
+ lwgeom_makepoly_validate_curve_ring(rings[i], i == 0 ? "Shell" : "Hole");
+ if (LW_FAILURE == lwcurvepoly_add_ring(outcurvepoly, rings[i]))
+ lwerror("lwgeom_makepoly: could not add ring %d to curve polygon", i);
+ if (i == 0)
+ shell = NULL;
+ rings[i] = NULL;
+ }
+
+ POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM *)outcurvepoly, 0));
+ result = geometry_serialize((LWGEOM *)outcurvepoly);
+ lwgeom_free((LWGEOM *)outcurvepoly);
+ }
+ else
+ {
+ outpoly = lwpoly_from_lwlines(lwgeom_as_lwline(shell), nholes, holes);
+ POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM *)outpoly, 0));
+ result = geometry_serialize((LWGEOM *)outpoly);
+ lwpoly_free(outpoly);
+ }
+
+ if (shell)
+ lwgeom_free(shell);
PG_FREE_IF_COPY(pglwg1, 0);
for (i = 0; i < nholes; i++)
{
- lwline_free((LWLINE *)holes[i]);
+ if (rings && rings[i + 1])
+ lwgeom_free(rings[i + 1]);
}
+ if (rings)
+ lwfree(rings);
+ if (holes)
+ lwfree(holes);
PG_RETURN_POINTER(result);
}
diff --git a/regress/core/ctors.sql b/regress/core/ctors.sql
index d4038d44e..2b74d19a1 100644
--- a/regress/core/ctors.sql
+++ b/regress/core/ctors.sql
@@ -44,3 +44,30 @@ FROM (
('MULTILINESTRING((1 1, 2 2), (2 2, 3 3))'),
('MULTILINESTRING(EMPTY, (4 4, 5 5))')
) AS geoms(geom);
+
+SELECT 'ST_MakePolygonLine', ST_AsText(ST_MakePolygon(
+ 'LINESTRING(0 0, 4 0, 4 4, 0 4, 0 0)'::geometry));
+
+SELECT 'ST_MakePolygonCurveShell', ST_AsText(ST_MakePolygon(
+ 'CIRCULARSTRING(0 0, 1 1, 2 0, 1 -1, 0 0)'::geometry));
+
+SELECT 'ST_MakePolygonCurveHole', ST_AsText(ST_MakePolygon(
+ 'LINESTRING(0 0, 4 0, 4 4, 0 4, 0 0)'::geometry,
+ ARRAY['CIRCULARSTRING(1 1, 2 2, 3 1, 2 0, 1 1)'::geometry]));
+
+SELECT 'ST_MakePolygonNurbsShell', ST_AsText(ST_MakePolygon(
+ 'NURBSCURVE(2, (0 0, 5 10, 10 0, 5 -10, 0 0))'::geometry));
+
+SELECT 'ST_MakePolygonNurbsHole', ST_AsText(ST_MakePolygon(
+ 'LINESTRING(0 0, 4 0, 4 4, 0 4, 0 0)'::geometry,
+ ARRAY['NURBSCURVE(2, (1 1, 2 2, 3 1, 2 0, 1 1))'::geometry]));
+
+SELECT ST_MakePolygon('CIRCULARSTRING(0 0, 1 1, 2 0)'::geometry);
+
+SELECT ST_MakePolygon(
+ 'CIRCULARSTRING Z (0 0 0, 1 1 0, 2 0 0, 1 -1 0, 0 0 0)'::geometry,
+ ARRAY['CIRCULARSTRING M (1 1 7, 2 2 7, 3 1 7, 2 0 7, 1 1 7)'::geometry]);
+
+SELECT ST_MakePolygon(
+ 'CIRCULARSTRING M (0 0 0, 1 1 0, 2 0 0, 1 -1 0, 0 0 0)'::geometry,
+ ARRAY['CIRCULARSTRING Z (1 1 7, 2 2 7, 3 1 7, 2 0 7, 1 1 7)'::geometry]);
diff --git a/regress/core/ctors_expected b/regress/core/ctors_expected
index d18c7100c..bcdf4a5e7 100644
--- a/regress/core/ctors_expected
+++ b/regress/core/ctors_expected
@@ -10,3 +10,11 @@ ERROR: BOX2D_construct: Operation on mixed SRID geometries (Point, 0) != (Point
BOX3D(0 0 0,1 1 0)
ERROR: BOX3D_construct: Operation on mixed SRID geometries (Point, 0) != (Point, 3)
ST_MakeLine2|LINESTRING(0 0,1 1,2 2,3 3,4 4,5 5)
+ST_MakePolygonLine|POLYGON((0 0,4 0,4 4,0 4,0 0))
+ST_MakePolygonCurveShell|CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0))
+ST_MakePolygonCurveHole|CURVEPOLYGON((0 0,4 0,4 4,0 4,0 0),CIRCULARSTRING(1 1,2 2,3 1,2 0,1 1))
+ST_MakePolygonNurbsShell|CURVEPOLYGON(NURBSCURVE(DEGREE 2,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 10),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(10 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(5 -10),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(0 0),WEIGHT 1)),KNOTS (KNOT(0,3),KNOT(0.333333333333333,1),KNOT(0.666666666666667,1),KNOT(1,3))))
+ST_MakePolygonNurbsHole|CURVEPOLYGON((0 0,4 0,4 4,0 4,0 0),NURBSCURVE(DEGREE 2,CONTROLPOINTS(NURBSPOINT(WEIGHTEDPOINT(1 1),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2 2),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(3 1),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(2 0),WEIGHT 1),NURBSPOINT(WEIGHTEDPOINT(1 1),WEIGHT 1)),KNOTS (KNOT(0,3),KNOT(0.333333333333333,1),KNOT(0.666666666666667,1),KNOT(1,3))))
+ERROR: Shell must be closed
+ERROR: lwgeom_makepoly: mixed dimensioned rings
+ERROR: lwgeom_makepoly: mixed dimensioned rings
-----------------------------------------------------------------------
Summary of changes:
NEWS | 1 +
doc/reference_constructor.xml | 24 ++++++++---
postgis/lwgeom_functions_basic.c | 90 ++++++++++++++++++++++++++++++++++------
regress/core/ctors.sql | 27 ++++++++++++
regress/core/ctors_expected | 8 ++++
5 files changed, 132 insertions(+), 18 deletions(-)
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list