[SCM] PostGIS branch master updated. 3.7.0alpha1-606-gfe789eb49

git at osgeo.org git at osgeo.org
Sat Jul 18 14:10:26 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  fe789eb49efa9ffae30b7491cfb42563b4b9bb64 (commit)
       via  19e655fd8d9661b5bfc85a048a477734c192845c (commit)
       via  5991739dacc8a9fba2f12028a138da245a010441 (commit)
       via  f6bd3d6e68d401ffcb1266e83cefdc434d449527 (commit)
       via  c16851a1ef16f6f30ef48f501ae21bca975a4b63 (commit)
      from  eda5443251a236dcbcc4e8caef70ef837ba2f518 (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 fe789eb49efa9ffae30b7491cfb42563b4b9bb64
Merge: eda544325 19e655fd8
Author: Darafei Praliaskouski <komzpa at gmail.com>
Date:   Sat Jul 18 14:10:25 2026 -0700

    Merge pull request 'Support curved GML input' (!368) from Komzpa/postgis:codex/ticket-1986-gml-curves into master
    
    Reviewed-on: https://gitea.osgeo.org/postgis/postgis/pulls/368


commit 19e655fd8d9661b5bfc85a048a477734c192845c
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Sat Jul 18 23:23:44 2026 +0400

    Complete curved GML collection handling
    
    Accept direct MultiSurface members emitted by ST_AsGML, reuse curved ring parsing for PolygonPatch, and validate closure in the effective ring dimension.
    
    Closes #1986

diff --git a/postgis/lwgeom_in_gml.c b/postgis/lwgeom_in_gml.c
index 80401aff0..4075e81d1 100644
--- a/postgis/lwgeom_in_gml.c
+++ b/postgis/lwgeom_in_gml.c
@@ -1382,11 +1382,13 @@ static LWGEOM* parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid
  * Parse GML Polygon (2.1.2, 3.1.1)
  */
 static void
-gml_validate_ring_geom(LWGEOM *ring, int error_code)
+gml_validate_ring_geom(LWGEOM *ring, bool hasz, int error_code)
 {
+	POINT4D first, last;
 	uint32_t vertices_needed = ring->type == LINETYPE ? 4 : 3;
 
-	if (lwgeom_count_vertices(ring) < vertices_needed || !lwgeom_is_closed(ring))
+	if (lwgeom_count_vertices(ring) < vertices_needed || lwgeom_startpoint(ring, &first) == LW_FAILURE ||
+	    gml_curve_endpoint(ring, &last) == LW_FAILURE || !gml_curve_points_equal(&first, &last, hasz))
 		gml_lwpgerror("invalid GML representation", error_code);
 }
 
@@ -1404,7 +1406,7 @@ parse_gml_linearring_as_lwgeom(xmlNodePtr xnode, bool *hasz, int *root_srid)
 		gml_reproject_lwgeom(ring, srs.srid, *root_srid);
 	ring->srid = *root_srid;
 
-	gml_validate_ring_geom(ring, 43);
+	gml_validate_ring_geom(ring, *hasz, 43);
 
 	return ring;
 }
@@ -1462,7 +1464,7 @@ parse_gml_ring(xmlNodePtr xnode, bool *hasz, int *root_srid)
 	ring = gml_curve_segments_to_lwgeom(segments, nsegments, hasz, root_srid);
 	lwfree(segments);
 
-	gml_validate_ring_geom(ring, 43);
+	gml_validate_ring_geom(ring, *hasz, 43);
 
 	return ring;
 }
@@ -1649,12 +1651,8 @@ static LWGEOM* parse_gml_triangle(xmlNodePtr xnode, bool *hasz, int *root_srid)
  */
 static LWGEOM* parse_gml_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
 {
-	xmlChar *interpolation=NULL;
-	POINTARRAY **ppa=NULL;
-	LWGEOM *geom=NULL;
-	xmlNodePtr xa, xb;
-	int i, ring=0;
-	gmlSrs srs;
+	xmlChar *interpolation = NULL;
+	LWGEOM *geom;
 
 	/* PolygonPatch */
 	if (!is_gml_element(xnode, "PolygonPatch"))
@@ -1669,76 +1667,9 @@ static LWGEOM* parse_gml_patch(xmlNodePtr xnode, bool *hasz, int *root_srid)
 		xmlFree(interpolation);
 	}
 
-	parse_gml_srs(xnode, &srs);
-
-	/* PolygonPatch/exterior */
-	for (xa = xnode->children ; xa != NULL ; xa = xa->next)
-	{
-		if (!is_gml_namespace(xa, false)) continue;
-		if (!is_gml_element(xa, "exterior")) continue;
-
-		/* PolygonPatch/exterior/LinearRing */
-		for (xb = xa->children ; xb != NULL ; xb = xb->next)
-		{
-			if (xb->type != XML_ELEMENT_NODE) continue;
-			if (!is_gml_namespace(xb, false)) continue;
-			if (!is_gml_element(xb, "LinearRing")) continue;
-
-			ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
-			ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
-
-			if (ppa[0]->npoints < 4
-			        || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
-			        ||  (*hasz && !ptarray_is_closed_3d(ppa[0])))
-				gml_lwpgerror("invalid GML representation", 48);
-
-			if (srs.reverse_axis)
-				ppa[0] = ptarray_flip_coordinates(ppa[0]);
-		}
-	}
-
-	/* Interior but no Exterior ! */
-	if ( ! ppa )
-	 	gml_lwpgerror("invalid GML representation", 48);
-
-	/* PolygonPatch/interior */
-	for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
-	{
-		if (xa->type != XML_ELEMENT_NODE) continue;
-		if (!is_gml_namespace(xa, false)) continue;
-		if (!is_gml_element(xa, "interior")) continue;
-
-		/* PolygonPatch/interior/LinearRing */
-		for (xb = xa->children ; xb != NULL ; xb = xb->next)
-		{
-			if (xb->type != XML_ELEMENT_NODE) continue;
-			if (!is_gml_element(xb, "LinearRing")) continue;
-
-			ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
-			                               sizeof(POINTARRAY*) * (ring + 1));
-			ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
-
-			if (ppa[ring]->npoints < 4
-			        || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
-			        || ( *hasz && !ptarray_is_closed_3d(ppa[ring])))
-				gml_lwpgerror("invalid GML representation", 49);
-
-			if (srs.reverse_axis)
-				ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
-
-			ring++;
-		}
-	}
-
-	/* Exterior Ring is mandatory */
-	if (ppa == NULL || ppa[0] == NULL) gml_lwpgerror("invalid GML representation", 50);
-
-	if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
-	{
-		for (i=0 ; i < ring ; i++)
-			gml_reproject_pa(ppa[i], srs.srid, *root_srid);
-	}
-	geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
+	geom = parse_gml_polygon(xnode, hasz, root_srid);
+	if (lwgeom_is_empty(geom))
+		gml_lwpgerror("invalid GML representation", 50);
 
 	return geom;
 }
@@ -2094,6 +2025,15 @@ static LWGEOM* parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
 					has_curve = true;
 			}
 		}
+		else if (is_gml_element(xa, "Polygon") || is_gml_element(xa, "CurvePolygon"))
+		{
+			LWGEOM *member = parse_gml(xa, hasz, root_srid);
+			geoms = ngeoms == 0 ? (LWGEOM **)lwalloc(sizeof(LWGEOM *))
+					    : (LWGEOM **)lwrealloc(geoms, sizeof(LWGEOM *) * (ngeoms + 1));
+			geoms[ngeoms++] = member;
+			if (member->type != POLYGONTYPE)
+				has_curve = true;
+		}
 		else if (is_gml_element(xa, "surfaceMember"))
 		{
 			if (xa->children != NULL)
diff --git a/regress/core/in_gml.sql b/regress/core/in_gml.sql
index d60a60ac3..bd0af0f06 100644
--- a/regress/core/in_gml.sql
+++ b/regress/core/in_gml.sql
@@ -173,6 +173,9 @@ SELECT 'polygon_24', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http
 -- ERROR mismatched Z between a Ring member and a nested compound Curve
 SELECT 'polygon_25', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:LineString><gml:posList srsDimension="3">0 0 0 1 0 0</gml:posList></gml:LineString></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList srsDimension="3">1 0 99 2 0 99</gml:posList></gml:LineStringSegment><gml:ArcString><gml:posList srsDimension="3">2 0 99 3 1 99 4 0 99</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:LineString><gml:posList srsDimension="3">4 0 99 0 0 0</gml:posList></gml:LineString></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon>'));
 
+-- Mixed dimensions make the whole curved ring 2D before closure validation
+SELECT 'polygon_26', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:pos srsDimension="3">0 0 5</gml:pos><gml:pos>1 1</gml:pos><gml:pos>0 0</gml:pos></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon>'));
+
 -- ERROR open curved ring
 SELECT 'polygon_22', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:Polygon>'));
 SELECT 'polygon_23', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http://www.opengis.net/gml/3.2" srsName="urn:ogc:def:crs:EPSG::4326"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>1 2 3 4 5 6 7 8 1 2</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon>'));
@@ -299,6 +302,8 @@ SELECT 'surface_22', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:Po
 -- ERROR: interior but no exterior
 SELECT 'surface_23', ST_AsEWKT(ST_GeomFromGML('<gml:Surface><gml:patches><gml:PolygonPatch><gml:interior><gml:LinearRing><gml:coordinates>1,2 3,4 5,6 1,2</gml:coordinates></gml:LinearRing></gml:interior></gml:PolygonPatch></gml:patches></gml:Surface>'));
 
+SELECT 'surface_24', ST_AsEWKT(ST_GeomFromGML('<gml:Surface xmlns:gml="http://www.opengis.net/gml/3.2"><gml:patches><gml:PolygonPatch><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0 1 -1 0 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:PolygonPatch></gml:patches></gml:Surface>'));
+
 --
 -- MultiPoint
 --
@@ -467,6 +472,8 @@ SELECT 'msurface_12', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface><gml:surfaceMe
 
 SELECT 'msurface_13', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface xmlns:gml="http://www.opengis.net/gml/3.2"><gml:surfaceMember><gml:CurvePolygon><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0 1 -1 0 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon></gml:surfaceMember></gml:MultiSurface>'));
 
+SELECT 'msurface_14', ST_AsEWKT(ST_GeomFromGML(ST_AsGML(3, ST_GeomFromEWKT('MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0)),((10 10,11 10,11 11,10 10)))'))));
+
 --
 -- PolyhedralSurface
 --
diff --git a/regress/core/in_gml_expected b/regress/core/in_gml_expected
index 4cd4999e5..a2f83b3ad 100644
--- a/regress/core/in_gml_expected
+++ b/regress/core/in_gml_expected
@@ -57,6 +57,7 @@ polygon_20|CURVEPOLYGON(COMPOUNDCURVE((0 0,1 0),CIRCULARSTRING(1 0,2 1,3 0),(3 0
 polygon_21|CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0))
 polygon_24|CURVEPOLYGON(COMPOUNDCURVE((0 0,1 0),(1 0,2 0),CIRCULARSTRING(2 0,3 1,4 0),(4 0,0 0)))
 ERROR:  invalid GML representation
+polygon_26|CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,0 0))
 ERROR:  invalid GML representation
 polygon_23|SRID=4326;CURVEPOLYGON(CIRCULARSTRING(2 1,4 3,6 5,8 7,2 1))
 linearring_1|POLYGON((1 2,3 4,5 6,1 2))
@@ -101,6 +102,7 @@ ERROR:  invalid GML representation
 surface_21|POLYGON((1 2,3 4,5 6,1 2))
 ERROR:  invalid GML representation
 ERROR:  invalid GML representation
+surface_24|CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0))
 mpoint_1|MULTIPOINT(1 2)
 mpoint_2|MULTIPOINT(1 2,3 4)
 mpoint_3|SRID=4326;MULTIPOINT(1 2)
@@ -156,6 +158,7 @@ msurface_10|MULTIPOLYGON(((1 2,3 4,5 6,1 2)))
 msurface_11|MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))
 msurface_12|MULTIPOLYGON EMPTY
 msurface_13|MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0)))
+msurface_14|MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0)),((10 10,11 10,11 11,10 10)))
 polyhedralsurface_1|POLYHEDRALSURFACE(((1 2 3,4 5 6,7 8 9,1 2 3)))
 polyhedralsurface_2|SRID=4326;POLYHEDRALSURFACE(((1 2 3,4 5 6,7 8 9,1 2 3)))
 ERROR:  invalid GML representation

commit 5991739dacc8a9fba2f12028a138da245a010441
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Sat Jul 18 23:09:52 2026 +0400

    Validate nested curved GML ring continuity
    
    Apply the full-dimensional component check while flattening nested compound curves, and cover a Z-discontinuous Ring member.
    
    Restore the 3.7 documentation note and keep the release entry under the existing Enhancements section.
    
    Closes #1986

diff --git a/NEWS b/NEWS
index a80b4d893..80f942b64 100644
--- a/NEWS
+++ b/NEWS
@@ -47,12 +47,10 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
             (Bas Couwenberg)
 
 * Enhancements *
-* New Features *
 
  - #1986, ST_GeomFromGML support for GML ArcString and curved polygon rings
           (Darafei Praliaskouski)
 
-
  - GH-1161, Render manual geometry examples as build-time SVG in HTML
           and PDF (Darafei Praliaskouski)
  - #4749, Use point-in-polygon predicate fast paths for point-only
diff --git a/doc/reference_input.xml b/doc/reference_input.xml
index 1e427ebd3..fd5f20113 100644
--- a/doc/reference_input.xml
+++ b/doc/reference_input.xml
@@ -1570,6 +1570,7 @@ precision 6 | POLYGON((-115.1806640625 36.112060546875,-115.1806640625 36.117553
 		<para role="availability" conformance="1.5">Availability: 1.5, requires libxml2 1.6+</para>
 		<para role="enhanced" conformance="2.0.0">Enhanced: 2.0.0 support for Polyhedral surfaces and TIN was introduced.</para>
 		<para role="enhanced" conformance="2.0.0">Enhanced: 2.0.0 default srid optional parameter added.</para>
+		<para role="enhanced" conformance="3.7.0">Enhanced: 3.7.0 support for GML ArcString, curved Ring, and CurvePolygon geometries was introduced.</para>
 		<para>&Z_support;</para>
 		<para>&P_support;</para>
 		<para>&T_support;</para>
@@ -1578,10 +1579,6 @@ precision 6 | POLYGON((-115.1806640625 36.112060546875,-115.1806640625 36.117553
 		<para>GML support mixed SRS inside the same MultiGeometry. As PostGIS geometries don't, ST_GeomFromGML, in this case, reproject all subgeometries to the SRS root node. If no srsName attribute available for the GML root node, the function throw an error.</para>
 
 		<para>ST_GeomFromGML function is not pedantic about an explicit GML namespace. You could avoid to mention it explicitly for common usages. But you need it if you want to use XLink feature inside GML.</para>
-		<note>
-			<para>ST_GeomFromGML function not support SQL/MM curves geometries.</para>
-		</note>
-
 	  </refsection>
 
 	  <refsection>
@@ -1851,6 +1848,7 @@ SELECT ST_AsEWKT(ST_GeomFromGML('
 			<para role="availability" conformance="1.5">Availability: 1.5, requires libxml2 1.6+</para>
 		        <para role="enhanced" conformance="2.0.0">Enhanced: 2.0.0 support for Polyhedral surfaces and TIN was introduced.</para>
 		        <para role="enhanced" conformance="2.0.0">Enhanced: 2.0.0 default srid optional parameter added.</para>
+		        <para role="enhanced" conformance="3.7.0">Enhanced: 3.7.0 support for GML ArcString, curved Ring, and CurvePolygon geometries was introduced.</para>
 		  </refsection>
 		  <refsection>
 			<title>See Also</title>
diff --git a/postgis/lwgeom_in_gml.c b/postgis/lwgeom_in_gml.c
index b1d5dc872..80401aff0 100644
--- a/postgis/lwgeom_in_gml.c
+++ b/postgis/lwgeom_in_gml.c
@@ -1211,10 +1211,7 @@ gml_compound_add_curve_component(LWCOMPOUND *compound, LWGEOM *segment)
 		LWCOMPOUND *nested = (LWCOMPOUND *)segment;
 
 		for (uint32_t i = 0; i < nested->ngeoms; i++)
-		{
-			if (lwcompound_add_lwgeom(compound, nested->geoms[i]) == LW_FAILURE)
-				gml_lwpgerror("invalid GML representation", 41);
-		}
+			gml_compound_add_curve_component(compound, nested->geoms[i]);
 
 		nested->ngeoms = 0;
 		lwgeom_free(segment);
diff --git a/regress/core/in_gml.sql b/regress/core/in_gml.sql
index 4f4043abc..d60a60ac3 100644
--- a/regress/core/in_gml.sql
+++ b/regress/core/in_gml.sql
@@ -170,6 +170,9 @@ SELECT 'polygon_20', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon xmlns:gml="http://ww
 SELECT 'polygon_21', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0 1 -1 0 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon>'));
 SELECT 'polygon_24', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:LineString><gml:posList>0 0 1 0</gml:posList></gml:LineString></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>1 0 2 0</gml:posList></gml:LineStringSegment><gml:ArcString><gml:posList>2 0 3 1 4 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:LineString><gml:posList>4 0 0 0</gml:posList></gml:LineString></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon>'));
 
+-- ERROR mismatched Z between a Ring member and a nested compound Curve
+SELECT 'polygon_25', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:LineString><gml:posList srsDimension="3">0 0 0 1 0 0</gml:posList></gml:LineString></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList srsDimension="3">1 0 99 2 0 99</gml:posList></gml:LineStringSegment><gml:ArcString><gml:posList srsDimension="3">2 0 99 3 1 99 4 0 99</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:LineString><gml:posList srsDimension="3">4 0 99 0 0 0</gml:posList></gml:LineString></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon>'));
+
 -- ERROR open curved ring
 SELECT 'polygon_22', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:Polygon>'));
 SELECT 'polygon_23', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http://www.opengis.net/gml/3.2" srsName="urn:ogc:def:crs:EPSG::4326"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>1 2 3 4 5 6 7 8 1 2</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon>'));
diff --git a/regress/core/in_gml_expected b/regress/core/in_gml_expected
index 54b91812c..4cd4999e5 100644
--- a/regress/core/in_gml_expected
+++ b/regress/core/in_gml_expected
@@ -57,6 +57,7 @@ polygon_20|CURVEPOLYGON(COMPOUNDCURVE((0 0,1 0),CIRCULARSTRING(1 0,2 1,3 0),(3 0
 polygon_21|CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0))
 polygon_24|CURVEPOLYGON(COMPOUNDCURVE((0 0,1 0),(1 0,2 0),CIRCULARSTRING(2 0,3 1,4 0),(4 0,0 0)))
 ERROR:  invalid GML representation
+ERROR:  invalid GML representation
 polygon_23|SRID=4326;CURVEPOLYGON(CIRCULARSTRING(2 1,4 3,6 5,8 7,2 1))
 linearring_1|POLYGON((1 2,3 4,5 6,1 2))
 linearring_2|SRID=4326;POLYGON((1 2,3 4,5 6,1 2))

commit f6bd3d6e68d401ffcb1266e83cefdc434d449527
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Mon Jul 6 17:46:18 2026 +0400

    NEWS: move entry to 3.7.0beta1
    
    Closes #1986

diff --git a/NEWS b/NEWS
index f3c33facc..a80b4d893 100644
--- a/NEWS
+++ b/NEWS
@@ -47,6 +47,11 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
             (Bas Couwenberg)
 
 * Enhancements *
+* New Features *
+
+ - #1986, ST_GeomFromGML support for GML ArcString and curved polygon rings
+          (Darafei Praliaskouski)
+
 
  - GH-1161, Render manual geometry examples as build-time SVG in HTML
           and PDF (Darafei Praliaskouski)
@@ -116,8 +121,6 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
  - #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)
- - #1986, ST_GeomFromGML support for GML ArcString and curved polygon 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)

commit c16851a1ef16f6f30ef48f501ae21bca975a4b63
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Sun Jun 21 03:47:09 2026 +0400

    Support curved GML input
    
    Add ST_GeomFromGML support for GML ArcString segments, curved Ring boundaries, CurvePolygon input, and curved members in MultiCurve/MultiSurface collections.
    
    Closes #1986

diff --git a/NEWS b/NEWS
index 1e6959eaf..f3c33facc 100644
--- a/NEWS
+++ b/NEWS
@@ -116,6 +116,8 @@ To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed
  - #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)
+ - #1986, ST_GeomFromGML support for GML ArcString and curved polygon 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_input.xml b/doc/reference_input.xml
index f0a29c6f2..1e427ebd3 100644
--- a/doc/reference_input.xml
+++ b/doc/reference_input.xml
@@ -1847,7 +1847,7 @@ SELECT ST_AsEWKT(ST_GeomFromGML('
 		  <refsection>
 			<title>Description</title>
 			<para>This function is an alias for <xref linkend="ST_GeomFromGML"/> and provides the same signatures.</para>
-			<para>&sqlmm_compliant; SQL-MM 3: 5.1.50 (except for curves support).</para>
+			<para>&sqlmm_compliant; SQL-MM 3: 5.1.50.</para>
 			<para role="availability" conformance="1.5">Availability: 1.5, requires libxml2 1.6+</para>
 		        <para role="enhanced" conformance="2.0.0">Enhanced: 2.0.0 support for Polyhedral surfaces and TIN was introduced.</para>
 		        <para role="enhanced" conformance="2.0.0">Enhanced: 2.0.0 default srid optional parameter added.</para>
diff --git a/postgis/lwgeom_in_gml.c b/postgis/lwgeom_in_gml.c
index 5f3a5acb6..b1d5dc872 100644
--- a/postgis/lwgeom_in_gml.c
+++ b/postgis/lwgeom_in_gml.c
@@ -370,6 +370,43 @@ gml_reproject_pa(POINTARRAY *pa, int32_t epsg_in, int32_t epsg_out)
 	return pa;
 }
 
+static LWGEOM *
+gml_reproject_lwgeom(LWGEOM *geom, int32_t epsg_in, int32_t epsg_out)
+{
+	LWPROJ *lwp;
+	char text_in[16];
+	char text_out[16];
+
+	if (epsg_in == SRID_UNKNOWN)
+		return geom;
+
+	if (epsg_out == SRID_UNKNOWN)
+	{
+		gml_lwpgerror("invalid GML representation", 3);
+		return NULL;
+	}
+
+	snprintf(text_in, 16, "EPSG:%d", epsg_in);
+	snprintf(text_out, 16, "EPSG:%d", epsg_out);
+
+	lwp = lwproj_from_str(text_in, text_out);
+	if (!lwp)
+	{
+		gml_lwpgerror("Could not create LWPROJ*", 57);
+		return NULL;
+	}
+
+	if (lwgeom_transform(geom, lwp) == LW_FAILURE)
+	{
+		elog(ERROR, "gml_reproject_lwgeom: reprojection failed");
+		return NULL;
+	}
+	proj_destroy(lwp->pj);
+	pfree(lwp);
+
+	return geom;
+}
+
 /**
  * Return 1 if the SRS definition from the authority has a GIS friendly order,
  * that is easting,northing. This is typically true for most projected CRS
@@ -1090,6 +1127,165 @@ static LWGEOM* parse_gml_line(xmlNodePtr xnode, bool *hasz, int *root_srid)
 /**
  * Parse GML Curve (3.1.1)
  */
+static LWGEOM *
+parse_gml_curve_segment(xmlNodePtr xnode, bool *hasz, int *root_srid)
+{
+	POINTARRAY *pa;
+	xmlChar *interpolation = NULL;
+
+	if (is_gml_element(xnode, "LineStringSegment"))
+	{
+		interpolation = gmlGetProp(xnode, "interpolation");
+		if (interpolation != NULL)
+		{
+			if (strcmp((char *)interpolation, "linear"))
+				gml_lwpgerror("invalid GML representation", 38);
+			xmlFree(interpolation);
+		}
+
+		pa = parse_gml_data(xnode->children, hasz, root_srid);
+		if (pa->npoints < 2)
+			gml_lwpgerror("invalid GML representation", 39);
+		return lwline_as_lwgeom(lwline_construct(SRID_UNKNOWN, NULL, pa));
+	}
+
+	if (is_gml_element(xnode, "ArcString"))
+	{
+		interpolation = gmlGetProp(xnode, "interpolation");
+		if (interpolation != NULL)
+		{
+			if (strcmp((char *)interpolation, "circularArc3Points"))
+				gml_lwpgerror("invalid GML representation", 38);
+			xmlFree(interpolation);
+		}
+
+		pa = parse_gml_data(xnode->children, hasz, root_srid);
+		if (pa->npoints < 3 || pa->npoints % 2 == 0)
+			gml_lwpgerror("invalid GML representation", 39);
+		return lwcircstring_as_lwgeom(lwcircstring_construct(SRID_UNKNOWN, NULL, pa));
+	}
+
+	return NULL;
+}
+
+static int
+gml_curve_endpoint(const LWGEOM *geom, POINT4D *pt)
+{
+	if (!geom || lwgeom_is_empty(geom))
+		return LW_FAILURE;
+
+	if (geom->type == COMPOUNDTYPE)
+	{
+		const LWCOMPOUND *compound = (const LWCOMPOUND *)geom;
+		return gml_curve_endpoint(compound->geoms[compound->ngeoms - 1], pt);
+	}
+
+	if (geom->type == LINETYPE || geom->type == CIRCSTRINGTYPE)
+	{
+		const LWLINE *line = (const LWLINE *)geom;
+		if (!line->points || line->points->npoints < 1)
+			return LW_FAILURE;
+		return getPoint4d_p(line->points, line->points->npoints - 1, pt) ? LW_SUCCESS : LW_FAILURE;
+	}
+
+	return LW_FAILURE;
+}
+
+static int
+gml_curve_points_equal(const POINT4D *a, const POINT4D *b, bool hasz)
+{
+	if (a->x != b->x || a->y != b->y)
+		return LW_FALSE;
+
+	if (hasz && a->z != b->z)
+		return LW_FALSE;
+
+	return LW_TRUE;
+}
+
+static void
+gml_compound_add_curve_component(LWCOMPOUND *compound, LWGEOM *segment)
+{
+	if (segment->type == COMPOUNDTYPE)
+	{
+		LWCOMPOUND *nested = (LWCOMPOUND *)segment;
+
+		for (uint32_t i = 0; i < nested->ngeoms; i++)
+		{
+			if (lwcompound_add_lwgeom(compound, nested->geoms[i]) == LW_FAILURE)
+				gml_lwpgerror("invalid GML representation", 41);
+		}
+
+		nested->ngeoms = 0;
+		lwgeom_free(segment);
+		return;
+	}
+
+	if (compound->ngeoms > 0)
+	{
+		POINT4D first, last;
+		bool hasz = lwgeom_has_z(lwcompound_as_lwgeom(compound));
+
+		if (lwgeom_startpoint(segment, &first) == LW_FAILURE ||
+		    gml_curve_endpoint(compound->geoms[compound->ngeoms - 1], &last) == LW_FAILURE ||
+		    !gml_curve_points_equal(&first, &last, hasz))
+			gml_lwpgerror("invalid GML representation", 41);
+	}
+
+	if (lwcompound_add_lwgeom(compound, segment) == LW_FAILURE)
+		gml_lwpgerror("invalid GML representation", 41);
+}
+
+static LWGEOM *
+gml_curve_segments_to_lwgeom(LWGEOM **segments, size_t nsegments, bool *hasz, int *root_srid)
+{
+	bool has_curve = false;
+
+	if (nsegments == 0)
+		gml_lwpgerror("invalid GML representation", 40);
+
+	for (size_t i = 0; i < nsegments; i++)
+	{
+		if (segments[i]->type != LINETYPE)
+		{
+			has_curve = true;
+			break;
+		}
+	}
+
+	if (nsegments == 1)
+		return segments[0];
+
+	if (!has_curve)
+	{
+		LWLINE *line = (LWLINE *)segments[0];
+		POINTARRAY *pa = ptarray_clone_deep(line->points);
+		size_t point_size = *hasz ? sizeof(POINT3D) : sizeof(POINT2D);
+
+		for (size_t i = 1; i < nsegments; i++)
+		{
+			LWLINE *next = (LWLINE *)segments[i];
+			if (memcmp(
+				getPoint_internal(pa, pa->npoints - 1), getPoint_internal(next->points, 0), point_size))
+				gml_lwpgerror("invalid GML representation", 41);
+			if (ptarray_append_ptarray(pa, next->points, 0.0) == LW_FAILURE)
+				gml_lwpgerror("invalid GML representation", 41);
+			lwgeom_free(segments[i]);
+		}
+		lwgeom_free(segments[0]);
+
+		return lwline_as_lwgeom(lwline_construct(*root_srid, NULL, pa));
+	}
+	else
+	{
+		LWCOMPOUND *compound = lwcompound_construct_empty(*root_srid, *hasz, 0);
+		for (size_t i = 0; i < nsegments; i++)
+			gml_compound_add_curve_component(compound, segments[i]);
+
+		return lwcompound_as_lwgeom(compound);
+	}
+}
+
 static LWGEOM* parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
 {
 	xmlNodePtr xa;
@@ -1097,10 +1293,7 @@ static LWGEOM* parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
 	bool found=false;
 	gmlSrs srs;
 	LWGEOM *geom=NULL;
-	POINTARRAY *pa=NULL;
-	POINTARRAY **ppa=NULL;
-	uint32 npoints=0;
-	xmlChar *interpolation=NULL;
+	LWGEOM **segments = NULL;
 
 	if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
 	if (xnode == NULL)
@@ -1119,83 +1312,36 @@ static LWGEOM* parse_gml_curve(xmlNodePtr xnode, bool *hasz, int *root_srid)
 	}
 	if (!found) gml_lwpgerror("invalid GML representation", 37);
 
-	ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
+	segments = (LWGEOM **)lwalloc(sizeof(LWGEOM *));
 
-	/* Processing each gml:LineStringSegment */
+	/* Processing each gml:LineStringSegment or gml:ArcString */
 	for (xa = xa->children, lss=0; xa != NULL ; xa = xa->next)
 	{
+		LWGEOM *segment;
+
 		if (xa->type != XML_ELEMENT_NODE) continue;
 		if (!is_gml_namespace(xa, false)) continue;
 
-		if (!is_gml_element(xa, "LineStringSegment")) continue;
+		segment = parse_gml_curve_segment(xa, hasz, root_srid);
+		if (segment == NULL)
+			continue;
 
-		/* GML SF is restricted to linear interpolation  */
-		interpolation = gmlGetProp(xa, "interpolation");
-		if (interpolation != NULL)
-		{
-			if (strcmp((char *) interpolation, "linear"))
-				gml_lwpgerror("invalid GML representation", 38);
-			xmlFree(interpolation);
-		}
-
-		if (lss > 0) ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
-			                   sizeof(POINTARRAY*) * (lss + 1));
-
-		ppa[lss] = parse_gml_data(xa->children, hasz, root_srid);
-		npoints += ppa[lss]->npoints;
-		if (ppa[lss]->npoints < 2)
-			gml_lwpgerror("invalid GML representation", 39);
+		if (lss > 0)
+			segments = lwrealloc(segments, sizeof(LWGEOM *) * (lss + 1));
+		segments[lss] = segment;
 		lss++;
 	}
 	if (lss == 0) gml_lwpgerror("invalid GML representation", 40);
 
-	/* Most common case, a single segment */
-	if (lss == 1) pa = ppa[0];
-
-	if (lss > 1)
-	{
-		/*
-		 * "The curve segments are connected to one another, with the end point
-		 *  of each segment except the last being the start point of the next
-		 *  segment"  from  ISO 19107:2003 -> 6.3.16.1 (p43)
-		 *
-		 * So we must aggregate all the segments into a single one and avoid
-		 * to copy the redundant points
-		 */
-		size_t cp_point_size = sizeof(POINT3D); /* All internals are done with 3D */
-		size_t final_point_size = *hasz ? sizeof(POINT3D) : sizeof(POINT2D);
-		pa = ptarray_construct(1, 0, npoints - lss + 1);
-
-		/* Copy the first linestring fully */
-		memcpy(getPoint_internal(pa, 0), getPoint_internal(ppa[0], 0), cp_point_size * (ppa[0]->npoints));
-		npoints = ppa[0]->npoints;
-		lwfree(ppa[0]);
-
-		/* For the rest of linestrings, ensure the first point matches the
-		 * last point of the previous one, and copy all points except the
-		 * first one (since it'd be repeated)
-		 */
-		for (size_t i = 1; i < lss; i++)
-		{
-			if (memcmp(getPoint_internal(pa, npoints - 1), getPoint_internal(ppa[i], 0), final_point_size))
-				gml_lwpgerror("invalid GML representation", 41);
-
-			memcpy(getPoint_internal(pa, npoints),
-			       getPoint_internal(ppa[i], 1),
-			       cp_point_size * (ppa[i]->npoints - 1));
-
-			npoints += ppa[i]->npoints - 1;
-			lwfree(ppa[i]);
-		}
-	}
-
-	lwfree(ppa);
+	geom = gml_curve_segments_to_lwgeom(segments, lss, hasz, root_srid);
+	lwfree(segments);
 
 	parse_gml_srs(xnode, &srs);
-	if (srs.reverse_axis) pa = ptarray_flip_coordinates(pa);
+	if (srs.reverse_axis)
+		lwgeom_swap_ordinates(geom, LWORD_X, LWORD_Y);
 	if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
-		gml_reproject_pa(pa, srs.srid, *root_srid);
-	geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
+		gml_reproject_lwgeom(geom, srs.srid, *root_srid);
+	geom->srid = *root_srid;
 
 	return geom;
 }
@@ -1238,13 +1384,100 @@ static LWGEOM* parse_gml_linearring(xmlNodePtr xnode, bool *hasz, int *root_srid
 /**
  * Parse GML Polygon (2.1.2, 3.1.1)
  */
+static void
+gml_validate_ring_geom(LWGEOM *ring, int error_code)
+{
+	uint32_t vertices_needed = ring->type == LINETYPE ? 4 : 3;
+
+	if (lwgeom_count_vertices(ring) < vertices_needed || !lwgeom_is_closed(ring))
+		gml_lwpgerror("invalid GML representation", error_code);
+}
+
+static LWGEOM *
+parse_gml_linearring_as_lwgeom(xmlNodePtr xnode, bool *hasz, int *root_srid)
+{
+	gmlSrs srs;
+	POINTARRAY *pa = parse_gml_data(xnode->children, hasz, root_srid);
+	LWGEOM *ring = lwline_as_lwgeom(lwline_construct(SRID_UNKNOWN, NULL, pa));
+
+	parse_gml_srs(xnode, &srs);
+	if (srs.reverse_axis)
+		lwgeom_swap_ordinates(ring, LWORD_X, LWORD_Y);
+	if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
+		gml_reproject_lwgeom(ring, srs.srid, *root_srid);
+	ring->srid = *root_srid;
+
+	gml_validate_ring_geom(ring, 43);
+
+	return ring;
+}
+
+static LWGEOM *
+parse_gml_ring(xmlNodePtr xnode, bool *hasz, int *root_srid)
+{
+	xmlNodePtr xa, xb;
+	LWGEOM **segments = NULL;
+	size_t nsegments = 0;
+	LWGEOM *ring;
+
+	if (is_xlink(xnode))
+		xnode = get_xlink_node(xnode);
+	if (xnode == NULL)
+		gml_lwpgerror("invalid GML representation", 30);
+
+	segments = (LWGEOM **)lwalloc(sizeof(LWGEOM *));
+
+	for (xa = xnode->children; xa != NULL; xa = xa->next)
+	{
+		if (xa->type != XML_ELEMENT_NODE)
+			continue;
+		if (!is_gml_namespace(xa, false))
+			continue;
+
+		if (is_gml_element(xa, "curveMembers"))
+		{
+			for (xb = xa->children; xb != NULL; xb = xb->next)
+			{
+				if (xb->type != XML_ELEMENT_NODE)
+					continue;
+				if (!is_gml_namespace(xb, false))
+					continue;
+
+				if (nsegments > 0)
+					segments = lwrealloc(segments, sizeof(LWGEOM *) * (nsegments + 1));
+				segments[nsegments++] = parse_gml(xb, hasz, root_srid);
+			}
+		}
+		else if (is_gml_element(xa, "curveMember"))
+		{
+			if (xa->children != NULL)
+			{
+				if (nsegments > 0)
+					segments = lwrealloc(segments, sizeof(LWGEOM *) * (nsegments + 1));
+				segments[nsegments++] = parse_gml(xa->children, hasz, root_srid);
+			}
+		}
+	}
+
+	if (nsegments == 0)
+		gml_lwpgerror("invalid GML representation", 43);
+
+	ring = gml_curve_segments_to_lwgeom(segments, nsegments, hasz, root_srid);
+	lwfree(segments);
+
+	gml_validate_ring_geom(ring, 43);
+
+	return ring;
+}
+
 static LWGEOM* parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
 {
 	gmlSrs srs;
-	int i, ring;
+	int ring;
 	LWGEOM *geom;
 	xmlNodePtr xa, xb;
-	POINTARRAY **ppa = NULL;
+	LWGEOM **rings = NULL;
+	bool has_curve_ring = false;
 
 	if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
 	if (xnode == NULL)
@@ -1269,22 +1502,19 @@ static LWGEOM* parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
 		{
 			if (xb->type != XML_ELEMENT_NODE) continue;
 			if (!is_gml_namespace(xb, false)) continue;
-			if (!is_gml_element(xb, "LinearRing")) continue;
+			if (!(is_gml_element(xb, "LinearRing") || is_gml_element(xb, "Ring")))
+				continue;
 
-			ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
-			ppa[0] = parse_gml_data(xb->children, hasz, root_srid);
-
-			if (ppa[0]->npoints < 4
-			        || (!*hasz && !ptarray_is_closed_2d(ppa[0]))
-			        ||  (*hasz && !ptarray_is_closed_3d(ppa[0])))
-				gml_lwpgerror("invalid GML representation", 43);
-
-			if (srs.reverse_axis) ppa[0] = ptarray_flip_coordinates(ppa[0]);
+			rings = (LWGEOM **)lwalloc(sizeof(LWGEOM *));
+			rings[0] = is_gml_element(xb, "Ring") ? parse_gml_ring(xb, hasz, root_srid)
+							      : parse_gml_linearring_as_lwgeom(xb, hasz, root_srid);
+			if (rings[0]->type != LINETYPE)
+				has_curve_ring = true;
 		}
 	}
 
 	/* Found an <exterior> or <outerBoundaryIs> but no rings?!? We're outa here! */
-	if ( ! ppa )
+	if (!rings)
 		gml_lwpgerror("invalid GML representation", 43);
 
 	for (ring=1, xa = xnode->children ; xa != NULL ; xa = xa->next)
@@ -1301,31 +1531,48 @@ static LWGEOM* parse_gml_polygon(xmlNodePtr xnode, bool *hasz, int *root_srid)
 		{
 			if (xb->type != XML_ELEMENT_NODE) continue;
 			if (!is_gml_namespace(xb, false)) continue;
-			if (!is_gml_element(xb, "LinearRing")) continue;
+			if (!(is_gml_element(xb, "LinearRing") || is_gml_element(xb, "Ring")))
+				continue;
 
-			ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa,
-			                               sizeof(POINTARRAY*) * (ring + 1));
-			ppa[ring] = parse_gml_data(xb->children, hasz, root_srid);
-
-			if (ppa[ring]->npoints < 4
-			        || (!*hasz && !ptarray_is_closed_2d(ppa[ring]))
-			        ||  (*hasz && !ptarray_is_closed_3d(ppa[ring])))
-				gml_lwpgerror("invalid GML representation", 43);
-
-			if (srs.reverse_axis) ppa[ring] = ptarray_flip_coordinates(ppa[ring]);
+			rings = lwrealloc(rings, sizeof(LWGEOM *) * (ring + 1));
+			rings[ring] = is_gml_element(xb, "Ring") ? parse_gml_ring(xb, hasz, root_srid)
+								 : parse_gml_linearring_as_lwgeom(xb, hasz, root_srid);
+			if (rings[ring]->type != LINETYPE)
+				has_curve_ring = true;
 			ring++;
 		}
 	}
 
 	/* Exterior Ring is mandatory */
-	if (ppa == NULL || ppa[0] == NULL) gml_lwpgerror("invalid GML representation", 44);
+	if (rings == NULL || rings[0] == NULL)
+		gml_lwpgerror("invalid GML representation", 44);
 
-	if (srs.srid != *root_srid && *root_srid != SRID_UNKNOWN)
+	if (has_curve_ring)
 	{
-		for (i=0 ; i < ring ; i++)
-			gml_reproject_pa(ppa[i], srs.srid, *root_srid);
+		LWCURVEPOLY *curvepoly =
+		    lwcurvepoly_construct_empty(*root_srid, FLAGS_GET_Z(rings[0]->flags), FLAGS_GET_M(rings[0]->flags));
+
+		for (int i = 0; i < ring; i++)
+		{
+			if (lwcurvepoly_add_ring(curvepoly, rings[i]) == LW_FAILURE)
+				gml_lwpgerror("invalid GML representation", 43);
+		}
+		lwfree(rings);
+		geom = lwcurvepoly_as_lwgeom(curvepoly);
+	}
+	else
+	{
+		POINTARRAY **ppa = (POINTARRAY **)lwalloc(sizeof(POINTARRAY *) * ring);
+
+		for (int i = 0; i < ring; i++)
+		{
+			LWLINE *line = (LWLINE *)rings[i];
+			ppa[i] = ptarray_clone_deep(line->points);
+			lwgeom_free(rings[i]);
+		}
+		lwfree(rings);
+		geom = (LWGEOM *)lwpoly_construct(*root_srid, NULL, ring, ppa);
 	}
-	geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
 
 	return geom;
 }
@@ -1699,7 +1946,9 @@ static LWGEOM* parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
 {
 	gmlSrs srs;
 	xmlNodePtr xa, xb;
-	LWGEOM *geom = NULL;
+	LWGEOM **geoms = NULL;
+	uint32_t ngeoms = 0;
+	bool has_curve = false;
 
 	if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
 	if (xnode == NULL)
@@ -1709,10 +1958,8 @@ static LWGEOM* parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
 	if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
 		*root_srid = srs.srid;
 
-	geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
-
 	if (xnode->children == NULL)
-		return geom;
+		return (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
 
 	for (xa = xnode->children ; xa != NULL ; xa = xa->next)
 	{
@@ -1724,20 +1971,47 @@ static LWGEOM* parse_gml_mcurve(xmlNodePtr xnode, bool *hasz, int *root_srid)
 		{
 			for (xb = xa->children ; xb != NULL ; xb = xb->next)
 			{
-				if (xb != NULL)
-					geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
-				                                       (LWLINE*)parse_gml(xb, hasz, root_srid));
+				LWGEOM *member;
+				if (xb->type != XML_ELEMENT_NODE)
+					continue;
+				if (!is_gml_namespace(xb, false))
+					continue;
+
+				member = parse_gml(xb, hasz, root_srid);
+				geoms = ngeoms == 0 ? (LWGEOM **)lwalloc(sizeof(LWGEOM *))
+						    : (LWGEOM **)lwrealloc(geoms, sizeof(LWGEOM *) * (ngeoms + 1));
+				geoms[ngeoms++] = member;
+				if (member->type != LINETYPE)
+					has_curve = true;
 			}
 		}
 		else if (is_gml_element(xa, "curveMember"))
 		{
 			if (xa->children != NULL)
-				geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
-				                                   (LWLINE*)parse_gml(xa->children, hasz, root_srid));
+			{
+				LWGEOM *member = parse_gml(xa->children, hasz, root_srid);
+				geoms = ngeoms == 0 ? (LWGEOM **)lwalloc(sizeof(LWGEOM *))
+						    : (LWGEOM **)lwrealloc(geoms, sizeof(LWGEOM *) * (ngeoms + 1));
+				geoms[ngeoms++] = member;
+				if (member->type != LINETYPE)
+					has_curve = true;
+			}
 		}
 	}
 
-	return geom;
+	if (ngeoms == 0)
+		return (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
+	else
+	{
+		LWCOLLECTION *col = lwcollection_construct_empty(has_curve ? MULTICURVETYPE : MULTILINETYPE,
+								 *root_srid,
+								 FLAGS_GET_Z(geoms[0]->flags),
+								 FLAGS_GET_M(geoms[0]->flags));
+		for (uint32_t i = 0; i < ngeoms; i++)
+			lwcollection_add_lwgeom(col, geoms[i]);
+		lwfree(geoms);
+		return (LWGEOM *)col;
+	}
 }
 
 
@@ -1785,7 +2059,9 @@ static LWGEOM* parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
 {
 	gmlSrs srs;
 	xmlNodePtr xa, xb;
-	LWGEOM *geom = NULL;
+	LWGEOM **geoms = NULL;
+	uint32_t ngeoms = 0;
+	bool has_curve = false;
 
 	if (is_xlink(xnode)) xnode = get_xlink_node(xnode);
 	if (xnode == NULL)
@@ -1795,10 +2071,8 @@ static LWGEOM* parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
 	if (*root_srid == SRID_UNKNOWN && srs.srid != SRID_UNKNOWN)
 		*root_srid = srs.srid;
 
-	geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
-
 	if (xnode->children == NULL)
-		return geom;
+		return (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
 
 	for (xa = xnode->children ; xa != NULL ; xa = xa->next)
 	{
@@ -1809,20 +2083,47 @@ static LWGEOM* parse_gml_msurface(xmlNodePtr xnode, bool *hasz, int *root_srid)
 		{
 			for (xb = xa->children ; xb != NULL ; xb = xb->next)
 			{
-				if (xb != NULL)
-					geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
-				                                       (LWPOLY*)parse_gml(xb, hasz, root_srid));
+				LWGEOM *member;
+				if (xb->type != XML_ELEMENT_NODE)
+					continue;
+				if (!is_gml_namespace(xb, false))
+					continue;
+
+				member = parse_gml(xb, hasz, root_srid);
+				geoms = ngeoms == 0 ? (LWGEOM **)lwalloc(sizeof(LWGEOM *))
+						    : (LWGEOM **)lwrealloc(geoms, sizeof(LWGEOM *) * (ngeoms + 1));
+				geoms[ngeoms++] = member;
+				if (member->type != POLYGONTYPE)
+					has_curve = true;
 			}
 		}
 		else if (is_gml_element(xa, "surfaceMember"))
 		{
 			if (xa->children != NULL)
-				geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
-				                                   (LWPOLY*)parse_gml(xa->children, hasz, root_srid));
+			{
+				LWGEOM *member = parse_gml(xa->children, hasz, root_srid);
+				geoms = ngeoms == 0 ? (LWGEOM **)lwalloc(sizeof(LWGEOM *))
+						    : (LWGEOM **)lwrealloc(geoms, sizeof(LWGEOM *) * (ngeoms + 1));
+				geoms[ngeoms++] = member;
+				if (member->type != POLYGONTYPE)
+					has_curve = true;
+			}
 		}
 	}
 
-	return geom;
+	if (ngeoms == 0)
+		return (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
+	else
+	{
+		LWCOLLECTION *col = lwcollection_construct_empty(has_curve ? MULTISURFACETYPE : MULTIPOLYGONTYPE,
+								 *root_srid,
+								 FLAGS_GET_Z(geoms[0]->flags),
+								 FLAGS_GET_M(geoms[0]->flags));
+		for (uint32_t i = 0; i < ngeoms; i++)
+			lwcollection_add_lwgeom(col, geoms[i]);
+		lwfree(geoms);
+		return (LWGEOM *)col;
+	}
 }
 
 
@@ -2018,7 +2319,7 @@ static LWGEOM* parse_gml(xmlNodePtr xnode, bool *hasz, int *root_srid)
 	if (is_gml_element(xa, "LinearRing"))
 		return parse_gml_linearring(xa, hasz, root_srid);
 
-	if (is_gml_element(xa, "Polygon"))
+	if (is_gml_element(xa, "Polygon") || is_gml_element(xa, "CurvePolygon"))
 		return parse_gml_polygon(xa, hasz, root_srid);
 
 	if (is_gml_element(xa, "Triangle"))
diff --git a/regress/core/in_gml.sql b/regress/core/in_gml.sql
index d676ef688..4f4043abc 100644
--- a/regress/core/in_gml.sql
+++ b/regress/core/in_gml.sql
@@ -97,6 +97,21 @@ SELECT 'curve_14', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineS
 SELECT 'curve_15', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList srsDimension="3">1 2 3 4 5 6</gml:posList></gml:LineStringSegment><gml:LineStringSegment><gml:posList srsDimension="2">4 5 7 8</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
 SELECT 'curve_16', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList srsDimension="2">1 2 3 4</gml:posList></gml:LineStringSegment><gml:LineStringSegment><gml:posList srsDimension="3">3 4 5 6 7 8</gml:posList></gml:LineStringSegment></gml:segments></gml:Curve>'));
 
+-- ArcString
+SELECT 'curve_17', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0</gml:posList></gml:ArcString></gml:segments></gml:Curve>'));
+SELECT 'curve_18', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>0 0 1 0</gml:posList></gml:LineStringSegment><gml:ArcString><gml:posList>1 0 2 1 3 0</gml:posList></gml:ArcString></gml:segments></gml:Curve>'));
+
+-- ERROR malformed ArcString
+SELECT 'curve_19', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1</gml:posList></gml:ArcString></gml:segments></gml:Curve>'));
+
+-- ERROR disjoint compound curve components
+SELECT 'curve_20', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>0 0 1 0</gml:posList></gml:LineStringSegment><gml:ArcString><gml:posList>2 0 3 1 4 0</gml:posList></gml:ArcString></gml:segments></gml:Curve>'));
+
+SELECT 'curve_21', ST_AsEWKT(ST_GeomFromGML('<gml:Curve srsName="urn:ogc:def:crs:EPSG::4326"><gml:segments><gml:ArcString><gml:posList>1 2 3 4 5 6</gml:posList></gml:ArcString></gml:segments></gml:Curve>'));
+
+-- ERROR mismatched Z compound curve components
+SELECT 'curve_22', ST_AsEWKT(ST_GeomFromGML('<gml:Curve><gml:segments><gml:LineStringSegment><gml:posList srsDimension="3">0 0 0 1 0 0</gml:posList></gml:LineStringSegment><gml:ArcString><gml:posList srsDimension="3">1 0 99 2 1 99 3 0 99</gml:posList></gml:ArcString></gml:segments></gml:Curve>'));
+
 --
 -- Polygon
 --
@@ -150,6 +165,15 @@ SELECT 'polygon_17', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:exterior><gml:L
 SELECT 'polygon_18', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:exterior><gml:LinearRing><gml:posList srsDimension="3">1 2 3 4 5 6 7 8 9 1 2 3</gml:posList></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:posList srsDimension="2">10 11 12 13 14 15 10 11</gml:posList></gml:LinearRing></gml:interior></gml:Polygon>'));
 SELECT 'polygon_19', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon><gml:exterior><gml:LinearRing><gml:posList srsDimension="2">1 2 3 4 5 6 1 2</gml:posList></gml:LinearRing></gml:exterior><gml:interior><gml:LinearRing><gml:posList srsDimension="3">7 8 9 10 11 12 13 14 15 7 8 9</gml:posList></gml:LinearRing></gml:interior></gml:Polygon>'));
 
+-- GML 3.2 Ring with curve members
+SELECT 'polygon_20', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:LineString><gml:posList>0 0 1 0</gml:posList></gml:LineString></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>1 0 2 1 3 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:LineString><gml:posList>3 0 0 0</gml:posList></gml:LineString></gml:curveMember></gml:Ring></gml:exterior><gml:interior><gml:LinearRing><gml:posList>0.5 0.1 0.75 0.2 0.5 0.3 0.5 0.1</gml:posList></gml:LinearRing></gml:interior></gml:Polygon>'));
+SELECT 'polygon_21', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0 1 -1 0 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon>'));
+SELECT 'polygon_24', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:LineString><gml:posList>0 0 1 0</gml:posList></gml:LineString></gml:curveMember><gml:curveMember><gml:Curve><gml:segments><gml:LineStringSegment><gml:posList>1 0 2 0</gml:posList></gml:LineStringSegment><gml:ArcString><gml:posList>2 0 3 1 4 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember><gml:curveMember><gml:LineString><gml:posList>4 0 0 0</gml:posList></gml:LineString></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon>'));
+
+-- ERROR open curved ring
+SELECT 'polygon_22', ST_AsEWKT(ST_GeomFromGML('<gml:Polygon xmlns:gml="http://www.opengis.net/gml/3.2"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:Polygon>'));
+SELECT 'polygon_23', ST_AsEWKT(ST_GeomFromGML('<gml:CurvePolygon xmlns:gml="http://www.opengis.net/gml/3.2" srsName="urn:ogc:def:crs:EPSG::4326"><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>1 2 3 4 5 6 7 8 1 2</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon>'));
+
 --
 -- LinearRing
 --
@@ -368,6 +392,11 @@ SELECT 'mcurve_11', ST_AsEWKT(ST_GeomFromGML('<gml:MultiCurve><gml:curveMembers>
 
 SELECT 'mcurve_12', ST_AsEWKT(ST_GeomFromGML('<gml:MultiCurve><gml:curveMembers></gml:curveMembers></gml:MultiCurve>'));
 
+SELECT 'mcurve_13', ST_AsEWKT(ST_GeomFromGML('<gml:MultiCurve><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve>'));
+
+WITH g AS (SELECT ST_GeomFromGML('<gml:MultiCurve srsName="EPSG:27582"><gml:curveMember><gml:Curve srsName="EPSG:27562"><gml:segments><gml:ArcString><gml:coordinates>400000,5000000 400010,5000010 400020,5000000</gml:coordinates></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:MultiCurve>') as g)
+SELECT 'mcurve_14', ST_SRID(g.g), ST_AsText(g.g, 8) FROM g;
+
 --
 -- MultiPolygon
 --
@@ -433,6 +462,8 @@ SELECT 'msurface_11', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface><gml:surfaceMe
 -- Empty surfaceMembers
 SELECT 'msurface_12', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface><gml:surfaceMembers></gml:surfaceMembers></gml:MultiSurface>'));
 
+SELECT 'msurface_13', ST_AsEWKT(ST_GeomFromGML('<gml:MultiSurface xmlns:gml="http://www.opengis.net/gml/3.2"><gml:surfaceMember><gml:CurvePolygon><gml:exterior><gml:Ring><gml:curveMember><gml:Curve><gml:segments><gml:ArcString><gml:posList>0 0 1 1 2 0 1 -1 0 0</gml:posList></gml:ArcString></gml:segments></gml:Curve></gml:curveMember></gml:Ring></gml:exterior></gml:CurvePolygon></gml:surfaceMember></gml:MultiSurface>'));
+
 --
 -- PolyhedralSurface
 --
diff --git a/regress/core/in_gml_expected b/regress/core/in_gml_expected
index 5b5257ec2..54b91812c 100644
--- a/regress/core/in_gml_expected
+++ b/regress/core/in_gml_expected
@@ -28,6 +28,12 @@ ERROR:  invalid GML representation
 ERROR:  invalid GML representation
 curve_15|LINESTRING(1 2,4 5,7 8)
 curve_16|LINESTRING(1 2,3 4,6 7)
+curve_17|CIRCULARSTRING(0 0,1 1,2 0)
+curve_18|COMPOUNDCURVE((0 0,1 0),CIRCULARSTRING(1 0,2 1,3 0))
+ERROR:  invalid GML representation
+ERROR:  invalid GML representation
+curve_21|SRID=4326;CIRCULARSTRING(2 1,4 3,6 5)
+ERROR:  invalid GML representation
 polygon_1|POLYGON((1 2,3 4,5 6,1 2))
 polygon_2|SRID=4326;POLYGON((1 2,3 4,5 6,1 2))
 ERROR:  invalid GML representation
@@ -47,6 +53,11 @@ polygon_16|POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8),(13 14,15 16,17 18,13
 polygon_17|POLYGON((1 2,3 4,5 6,1 2),(7 8,9 10,11 12,7 8))
 polygon_18|POLYGON((1 2,4 5,7 8,1 2),(10 11,12 13,14 15,10 11))
 polygon_19|POLYGON((1 2,3 4,5 6,1 2),(7 8,10 11,13 14,7 8))
+polygon_20|CURVEPOLYGON(COMPOUNDCURVE((0 0,1 0),CIRCULARSTRING(1 0,2 1,3 0),(3 0,0 0)),(0.5 0.1,0.75 0.2,0.5 0.3,0.5 0.1))
+polygon_21|CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0))
+polygon_24|CURVEPOLYGON(COMPOUNDCURVE((0 0,1 0),(1 0,2 0),CIRCULARSTRING(2 0,3 1,4 0),(4 0,0 0)))
+ERROR:  invalid GML representation
+polygon_23|SRID=4326;CURVEPOLYGON(CIRCULARSTRING(2 1,4 3,6 5,8 7,2 1))
 linearring_1|POLYGON((1 2,3 4,5 6,1 2))
 linearring_2|SRID=4326;POLYGON((1 2,3 4,5 6,1 2))
 ERROR:  invalid GML representation
@@ -120,6 +131,8 @@ mcurve_9|27582|MULTILINESTRING((1 2,3 4),(400000 7000000,400010 7000010))
 mcurve_10|MULTILINESTRING((1 2,3 4))
 mcurve_11|MULTILINESTRING((1 2,3 4),(5 6,7 8))
 mcurve_12|MULTILINESTRING EMPTY
+mcurve_13|MULTICURVE(CIRCULARSTRING(0 0,1 1,2 0))
+mcurve_14|27582|MULTICURVE(CIRCULARSTRING(400000 7000000,400010 7000010,400020 7000000))
 mpoly_1|MULTIPOLYGON(((1 2,3 4,5 6,1 2)))
 mpoly_2|MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))
 mpoly_3|SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))
@@ -141,6 +154,7 @@ msurface_9|MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((400000 7000000,400010 7000010,4000
 msurface_10|MULTIPOLYGON(((1 2,3 4,5 6,1 2)))
 msurface_11|MULTIPOLYGON(((1 2,3 4,5 6,1 2)),((7 8,9 10,11 12,7 8)))
 msurface_12|MULTIPOLYGON EMPTY
+msurface_13|MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0,1 1,2 0,1 -1,0 0)))
 polyhedralsurface_1|POLYHEDRALSURFACE(((1 2 3,4 5 6,7 8 9,1 2 3)))
 polyhedralsurface_2|SRID=4326;POLYHEDRALSURFACE(((1 2 3,4 5 6,7 8 9,1 2 3)))
 ERROR:  invalid GML representation
diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected
index 1daac1d93..c580547f4 100644
--- a/regress/core/tickets_expected
+++ b/regress/core/tickets_expected
@@ -220,7 +220,7 @@ NOTICE:  SRID value -1 converted to the officially unknown SRID value 0
 #1776|POLYGON((0 0,10 0,10 10,0 0))|POLYGON((0 0,10 0,10 10,0 0))
 #1780|t
 ERROR:  ST_Segmentize: invalid max_distance 0 (must be >= 0)
-ERROR:  invalid GML representation
+CURVEPOLYGON(COMPOUNDCURVE((1070163.61 711540.35,1070166.54 711523.82,1070164.14 711521.3,1070162.44 711519.52,1070164.62 711518.57,1070824.94 712154.47),CIRCULARSTRING(1070824.94 712154.47,1070826.04 712154.98,1070827.22 712154.41),(1070827.22 712154.41,1070837.07 712160.31,1070835.36 712160.92,1071007.95 712207.89),CIRCULARSTRING(1071007.95 712207.89,1071005.59 712207.48,1071001.28 712208.38),(1071001.28 712208.38,1070949.67 712228.74,1070936.15 712233.98,1070788.72 712124.93),CIRCULARSTRING(1070788.72 712124.93,1070785.87 712124.28,1070783.38 712124.63),(1070783.38 712124.63,1070764.12 712141.04,1070757.01 712146.6,1070163.61 711540.35)),(1070354.46 713061.62,1070335.12 713053.59,1070315.92 713049.58,1070298.33 713049.65,1070354.46 713061.62))
 #1957|1
 #1978|3.1416
 #1996|{"type":"Point","coordinates":[]}

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

Summary of changes:
 NEWS                          |   3 +
 doc/reference_input.xml       |   8 +-
 postgis/lwgeom_in_gml.c       | 628 +++++++++++++++++++++++++++++-------------
 regress/core/in_gml.sql       |  41 +++
 regress/core/in_gml_expected  |  18 ++
 regress/core/tickets_expected |   2 +-
 6 files changed, 499 insertions(+), 201 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list