[postgis-tickets] [SCM] PostGIS branch master updated. 3.1.0rc1-127-gd7b7763

git at osgeo.org git at osgeo.org
Tue Apr 6 13:09:51 PDT 2021


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  d7b7763fb4ac3ef12b31c9b728f7dbb81f31ed2c (commit)
       via  fa6a25ffa8be606285dc9f380bbdc676e017337f (commit)
       via  2744a0994ec1ab69ad8bf2aa4e835d944733eb84 (commit)
       via  acd8f4ae2830a08b33f5b97d5f1ece073eb528f1 (commit)
      from  91f887f5cc5a675beaa9c54870115346fa754c48 (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 d7b7763fb4ac3ef12b31c9b728f7dbb81f31ed2c
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Tue Apr 6 23:07:04 2021 +0300

    ST_Boundary: formatting and polish
    
    Closes #4401
    Closes #3779

diff --git a/NEWS b/NEWS
index 7fcff87..2d92e2d 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ PostGIS 3.2.0
            (Sandro Santilli)
   - #4827, Allow NaN coordinates in WKT input (Paul Ramsey)
   - #4870, Allow open options to be passed to GDAL drivers (Paul Ramsey)
+  - #3778, #4401, ST_Boundary now works for TIN and does not linearize curves (Aliaksandr Kalenik)
 
  * New features*
   - #4841, FindTopology to quickly get a topology record (Sandro Santilli)
diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c
index 58264bf..99d45be 100644
--- a/liblwgeom/lwgeom.c
+++ b/liblwgeom/lwgeom.c
@@ -2547,19 +2547,15 @@ lwgeom_boundary(LWGEOM *lwgeom)
 	switch (lwgeom->type)
 	{
 	case POINTTYPE: {
-		lwresult = (LWGEOM *)lwpoint_construct_empty(srid, hasz, hasm);
-		break;
+		return (LWGEOM *)lwpoint_construct_empty(srid, hasz, hasm);
 	}
 	case MULTIPOINTTYPE: {
-		lwresult = (LWGEOM *)lwmpoint_construct_empty(srid, hasz, hasm);
-		break;
+		return (LWGEOM *)lwmpoint_construct_empty(srid, hasz, hasm);
 	}
 	case LINETYPE:
 	case CIRCSTRINGTYPE: {
 		if (lwgeom_is_closed(lwgeom))
-		{
-			lwresult = (LWGEOM *)lwmpoint_construct_empty(srid, hasz, hasm);
-		}
+			return (LWGEOM *)lwmpoint_construct_empty(srid, hasz, hasm);
 		else
 		{
 			LWLINE *lwline = (LWLINE *)lwgeom;
@@ -2570,68 +2566,55 @@ lwgeom_boundary(LWGEOM *lwgeom)
 			getPoint4d_p(lwline->points, lwline->points->npoints - 1, &pt);
 			lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &pt));
 
-			lwresult = (LWGEOM *)lwmpoint;
+			return (LWGEOM *)lwmpoint;
 		}
-
-		break;
 	}
 	case MULTILINETYPE:
 	case MULTICURVETYPE: {
 		LWMLINE *lwmline = (LWMLINE *)lwgeom;
 		POINT4D *out = lwalloc(sizeof(POINT4D) * lwmline->ngeoms * 2);
 		uint32_t n = 0;
-		uint32_t i, j, k;
-		for (i = 0; i < lwmline->ngeoms; i++)
+
+		for (uint32_t i = 0; i < lwmline->ngeoms; i++)
 		{
 			LWMPOINT *points = lwgeom_as_lwmpoint(lwgeom_boundary((LWGEOM *)lwmline->geoms[i]));
 			if (!points)
 				continue;
 
-			for (k = 0; k < points->ngeoms; k++)
+			for (uint32_t k = 0; k < points->ngeoms; k++)
 			{
-				POINT4D pt;
-				getPoint4d_p(points->geoms[k]->point, 0, &pt);
+				POINT4D pt = getPoint4d(points->geoms[k]->point, 0);
 
-				int seen = LW_FALSE;
-				for (j = 0; j < n; j++)
+				uint8_t seen = LW_FALSE;
+				for (uint32_t j = 0; j < n; j++)
 				{
 					if (memcmp(&(out[j]), &pt, sizeof(POINT4D)) == 0)
 					{
 						seen = LW_TRUE;
-						memcpy(&(out[j]), &(out[n - 1]), sizeof(POINT4D));
-						n--;
+						out[j] = out[--n];
 						break;
 					}
 				}
-
 				if (!seen)
-				{
-					memcpy(&(out[n]), &pt, sizeof(POINT4D));
-					n++;
-				}
+					out[n++] = pt;
 			}
 
-			if (points)
-				lwgeom_free((LWGEOM *)points);
+			lwgeom_free((LWGEOM *)points);
 		}
 
 		LWMPOINT *lwmpoint = lwmpoint_construct_empty(srid, hasz, hasm);
-		for (i = 0; i < n; i++)
-		{
+
+		for (uint32_t i = 0; i < n; i++)
 			lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &(out[i])));
-		}
 
 		lwfree(out);
 
-		lwresult = (LWGEOM *)lwmpoint;
-
-		break;
+		return (LWGEOM *)lwmpoint;
 	}
 	case TRIANGLETYPE: {
 		LWTRIANGLE *lwtriangle = (LWTRIANGLE *)lwgeom;
 		POINTARRAY *points = ptarray_clone_deep(lwtriangle->points);
-		lwresult = (LWGEOM *)lwline_construct(srid, 0, points);
-		break;
+		return (LWGEOM *)lwline_construct(srid, 0, points);
 	}
 	case POLYGONTYPE: {
 		LWPOLY *lwpoly = (LWPOLY *)lwgeom;
@@ -2639,7 +2622,7 @@ lwgeom_boundary(LWGEOM *lwgeom)
 		if (lwpoly->nrings == 1)
 		{
 			POINTARRAY *ring = ptarray_clone_deep(lwpoly->rings[0]);
-			lwresult = (LWGEOM *)lwline_construct(srid, 0, ring);
+			return (LWGEOM *)lwline_construct(srid, 0, ring);
 		}
 		else
 		{
@@ -2650,48 +2633,30 @@ lwgeom_boundary(LWGEOM *lwgeom)
 				lwmline_add_lwline(lwmline, lwline_construct(srid, 0, ring));
 			}
 
-			lwresult = (LWGEOM *)lwmline;
+			return (LWGEOM *)lwmline;
 		}
-
-		break;
 	}
 	case CURVEPOLYTYPE: {
 		LWCURVEPOLY *lwcurvepoly = (LWCURVEPOLY *)lwgeom;
 		LWCOLLECTION *lwcol = lwcollection_construct_empty(MULTICURVETYPE, srid, hasz, hasm);
+
 		for (uint32_t i = 0; i < lwcurvepoly->nrings; i++)
-		{
 			lwcol = lwcollection_add_lwgeom(lwcol, lwgeom_clone_deep(lwcurvepoly->rings[i]));
-		}
-
-		lwresult = (LWGEOM *)lwcol;
 
-		break;
+		return (LWGEOM *)lwcol;
 	}
 	case MULTIPOLYGONTYPE:
 	case TINTYPE: {
 		LWCOLLECTION *lwcol = (LWCOLLECTION *)lwgeom;
+		LWCOLLECTION *lwcol_boundary = lwcollection_construct_empty(MULTILINETYPE, srid, hasz, hasm);
 
-		if (lwcol->ngeoms == 1)
-		{
-			lwresult = lwgeom_boundary(lwcol->geoms[0]);
-		}
-		else
-		{
-			LWCOLLECTION *lwcol_boundary = lwcollection_construct_empty(MULTILINETYPE, srid, hasz, hasm);
-			for (uint32_t i = 0; i < lwcol->ngeoms; i++)
-			{
-				lwcollection_add_lwgeom(lwcol_boundary, lwgeom_boundary(lwcol->geoms[i]));
-			}
-
-			lwresult = (LWGEOM *)lwcol_boundary;
-		}
+		for (uint32_t i = 0; i < lwcol->ngeoms; i++)
+			lwcollection_add_lwgeom(lwcol_boundary, lwgeom_boundary(lwcol->geoms[i]));
 
-		break;
+		return (LWGEOM *)lwcol_boundary;
 	}
 	default:
-		lwerror("lwgeom_boundary: unsupported geometry type: %s", lwtype_name(lwgeom->type));
+		lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(lwgeom->type));
 		return NULL;
 	}
-
-	return lwresult;
-}
\ No newline at end of file
+}
diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c
index e50914e..1f7b1f6 100644
--- a/postgis/lwgeom_functions_basic.c
+++ b/postgis/lwgeom_functions_basic.c
@@ -3184,20 +3184,13 @@ Datum boundary(PG_FUNCTION_ARGS)
 
 	geom1 = PG_GETARG_GSERIALIZED_P(0);
 
-	/* Empty.Boundary() == Empty */
-	if (gserialized_is_empty(geom1))
-		PG_RETURN_POINTER(geom1);
+	/* Empty.Boundary() == Empty, but of other dimension, so can't shortcut */
 
 	lwgeom = lwgeom_from_gserialized(geom1);
-	if (!lwgeom)
-	{
-		lwpgerror("POSTGIS2GEOS: unable to deserialize input");
-		PG_RETURN_NULL();
-	}
-
 	lwresult = lwgeom_boundary(lwgeom);
-	if (lwresult == NULL)
+	if (!lwresult)
 	{
+		lwgeom_free(lwgeom);
 		PG_RETURN_NULL();
 	}
 
diff --git a/regress/core/boundary.sql b/regress/core/boundary.sql
index e99ca76..806de1a 100644
--- a/regress/core/boundary.sql
+++ b/regress/core/boundary.sql
@@ -1,16 +1,16 @@
-SELECT ST_AsText(ST_Boundary(ST_GeomFromText('POINT(0 1)')));
-SELECT ST_AsText(ST_Boundary(ST_GeomFromText('MULTIPOINT(0 0, 1 1)')));
-SELECT ST_AsText(ST_Boundary(ST_GeomFromText('LINESTRING(1 1,0 0, -1 1)')));
-SELECT ST_AsText(ST_Boundary(ST_GeomFromText('LINESTRING(1 1,0 0, 1 1)')));
-SELECT ST_AsText(ST_Boundary(ST_GeomFromText('POLYGON((1 1,0 0, -1 1, 1 1))')));
-SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('POLYGON((1 1 1,0 0 1, -1 1 1, 1 1 1))')));
-SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('POLYGON((1 1 1,0 0 1, -1 1 1, 1 1 1),(1 1 1,0 0 1, -1 1 1, 1 1 1))')));
-SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTILINESTRING((1 1 1,0 0 0.5, -1 1 1),(1 1 0.5,0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
-SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTILINESTRING((1 1 1,0 0 0.5, -1 1 1),(-1 1 1,0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
-SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTILINESTRING((1 1 1,0 0 0.5, 1 1 1),(1 1 0.5,0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
-SELECT ST_AsText(ST_Boundary(ST_GeomFromText('TRIANGLE((1 1,0 0, -1 1, 1 1))')));
-SELECT ST_AsText(ST_Boundary(ST_GeomFromText('MULTIPOLYGON(((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)), ((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))')));
-SELECT ST_AsText(ST_Boundary(ST_GeomFromEWKT('TIN(((0 0,0 -1,-1 1,0 0)),((0 0,1 0,0 -1,0 0)))')));
-SELECT ST_AsText(ST_Boundary(ST_GeomFromEWKT('TIN(((0 0,0 -1,-1 1,0 0)))')));
-SELECT ST_AsText(ST_Boundary(ST_GeomFromEWKT('CURVEPOLYGON(CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0),(1 1, 3 3, 3 1, 1 1))')));
-SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTICURVE((1 1 1,0 0 0.5, -1 1 1),(1 1 0.5,0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
+SELECT 'boundary01', ST_AsText(ST_Boundary(ST_GeomFromText('POINT(0 1)')));
+SELECT 'boundary02', ST_AsText(ST_Boundary(ST_GeomFromText('MULTIPOINT(0 0, 1 1)')));
+SELECT 'boundary03', ST_AsText(ST_Boundary(ST_GeomFromText('LINESTRING(1 1,0 0, -1 1)')));
+SELECT 'boundary04', ST_AsText(ST_Boundary(ST_GeomFromText('LINESTRING(1 1,0 0, 1 1)')));
+SELECT 'boundary05', ST_AsText(ST_Boundary(ST_GeomFromText('POLYGON((1 1,0 0, -1 1, 1 1))')));
+SELECT 'boundary06', ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('POLYGON((1 1 1,0 0 1, -1 1 1, 1 1 1))')));
+SELECT 'boundary07', ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('POLYGON((1 1 1,0 0 1, -1 1 1, 1 1 1),(1 1 1,0 0 1, -1 1 1, 1 1 1))')));
+SELECT 'boundary08', ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTILINESTRING((1 1 1,0 0 0.5, -1 1 1),(1 1 0.5, 0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
+SELECT 'boundary09', ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTILINESTRING((1 1 1,0 0 0.5, -1 1 1),(-1 1 1, 0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
+SELECT 'boundary10', ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTILINESTRING((1 1 1,0 0 0.5, 1 1 1),(1 1 0.5, 0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
+SELECT 'boundary11', ST_AsText(ST_Boundary(ST_GeomFromText('TRIANGLE((1 1,0 0, -1 1, 1 1))')));
+SELECT 'boundary12', ST_AsText(ST_Boundary(ST_GeomFromText('MULTIPOLYGON(((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)), ((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))')));
+SELECT 'boundary13', ST_AsText(ST_Boundary(ST_GeomFromEWKT('TIN(((0 0,0 -1,-1 1,0 0)),((0 0,1 0,0 -1,0 0)))')));
+SELECT 'boundary14', ST_AsText(ST_Boundary(ST_GeomFromEWKT('TIN(((0 0,0 -1,-1 1,0 0)))')));
+SELECT 'boundary15', ST_AsText(ST_Boundary(ST_GeomFromEWKT('CURVEPOLYGON(CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0),(1 1, 3 3, 3 1, 1 1))')));
+SELECT 'boundary16', ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTICURVE((1 1 1,0 0 0.5, -1 1 1),(1 1 0.5,0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
diff --git a/regress/core/boundary_expected b/regress/core/boundary_expected
index 988e85d..973bf46 100644
--- a/regress/core/boundary_expected
+++ b/regress/core/boundary_expected
@@ -1,16 +1,16 @@
-POINT EMPTY
-MULTIPOINT EMPTY
-MULTIPOINT(1 1,-1 1)
-MULTIPOINT EMPTY
-LINESTRING(1 1,0 0,-1 1,1 1)
-LINESTRING(1 1 1,0 0 1,-1 1 1,1 1 1)
-MULTILINESTRING((1 1 1,0 0 1,-1 1 1,1 1 1),(1 1 1,0 0 1,-1 1 1,1 1 1))
-MULTIPOINT(1 1 1,-1 1 1)
-MULTIPOINT(1 1 1,1 1 0.5)
-MULTIPOINT EMPTY
-LINESTRING(1 1,0 0,-1 1,1 1)
-MULTILINESTRING((30 20,45 40,10 40,30 20),(15 5,40 10,10 20,5 10,15 5),(30 20,45 40,10 40,30 20),(15 5,40 10,10 20,5 10,15 5))
-MULTILINESTRING((0 0,0 -1,-1 1,0 0),(0 0,1 0,0 -1,0 0))
-LINESTRING(0 0,0 -1,-1 1,0 0)
-MULTICURVE(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1))
-MULTIPOINT(1 1 1,-1 1 1)
+boundary01|POINT EMPTY
+boundary02|MULTIPOINT EMPTY
+boundary03|MULTIPOINT(1 1,-1 1)
+boundary04|MULTIPOINT EMPTY
+boundary05|LINESTRING(1 1,0 0,-1 1,1 1)
+boundary06|LINESTRING(1 1 1,0 0 1,-1 1 1,1 1 1)
+boundary07|MULTILINESTRING((1 1 1,0 0 1,-1 1 1,1 1 1),(1 1 1,0 0 1,-1 1 1,1 1 1))
+boundary08|MULTIPOINT(1 1 1,-1 1 1)
+boundary09|MULTIPOINT(1 1 1,1 1 0.5)
+boundary10|MULTIPOINT EMPTY
+boundary11|LINESTRING(1 1,0 0,-1 1,1 1)
+boundary12|MULTILINESTRING((30 20,45 40,10 40,30 20),(15 5,40 10,10 20,5 10,15 5),(30 20,45 40,10 40,30 20),(15 5,40 10,10 20,5 10,15 5))
+boundary13|MULTILINESTRING((0 0,0 -1,-1 1,0 0),(0 0,1 0,0 -1,0 0))
+boundary14|MULTILINESTRING((0 0,0 -1,-1 1,0 0))
+boundary15|MULTICURVE(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1))
+boundary16|MULTIPOINT(1 1 1,-1 1 1)

commit fa6a25ffa8be606285dc9f380bbdc676e017337f
Merge: 91f887f 2744a09
Author: kalenikaliaksandr <45686940+kalenikaliaksandr at users.noreply.github.com>
Date:   Sun Apr 4 23:36:03 2021 +0000

    Merge 2744a0994ec1ab69ad8bf2aa4e835d944733eb84 into 91f887f5cc5a675beaa9c54870115346fa754c48


commit 2744a0994ec1ab69ad8bf2aa4e835d944733eb84
Author: kalenikaliaksandr <kalenik.aliaksandr at gmail.com>
Date:   Mon Apr 5 02:35:49 2021 +0300

    free tmp lwgeom

diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c
index 9403fdf..58264bf 100644
--- a/liblwgeom/lwgeom.c
+++ b/liblwgeom/lwgeom.c
@@ -2610,6 +2610,9 @@ lwgeom_boundary(LWGEOM *lwgeom)
 					n++;
 				}
 			}
+
+			if (points)
+				lwgeom_free((LWGEOM *)points);
 		}
 
 		LWMPOINT *lwmpoint = lwmpoint_construct_empty(srid, hasz, hasm);

commit acd8f4ae2830a08b33f5b97d5f1ece073eb528f1
Author: kalenikaliaksandr <kalenik.aliaksandr at gmail.com>
Date:   Sun Apr 4 17:45:08 2021 +0300

    ST_Boundary refactoring

diff --git a/doc/reference_accessor.xml b/doc/reference_accessor.xml
index 20118d4..227b810 100644
--- a/doc/reference_accessor.xml
+++ b/doc/reference_accessor.xml
@@ -122,6 +122,7 @@
 		<para>&sqlmm_compliant; SQL-MM 3: 5.1.14</para>
 		<para>&Z_support;</para>
 		<para>Enhanced: 2.1.0 support for Triangle was introduced</para>
+		<para>Changed: 3.2.0 support for TIN, does not use geos, does not linearize curves</para>
 	  </refsection>
 
 	  <refsection>
diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in
index 805ea7c..30d2646 100644
--- a/liblwgeom/liblwgeom.h.in
+++ b/liblwgeom/liblwgeom.h.in
@@ -2274,6 +2274,8 @@ extern lwvarlena_t* lwgeom_to_twkb_with_idlist(const LWGEOM *geom, int64_t *idli
  */
 extern void lwgeom_trim_bits_in_place(LWGEOM *geom, int32_t prec_x, int32_t prec_y, int32_t prec_z, int32_t prec_m);
 
+extern LWGEOM* lwgeom_boundary(LWGEOM* lwgeom);
+
 /*******************************************************************************
  * SQLMM internal functions
  ******************************************************************************/
diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c
index a2d3d7f..9403fdf 100644
--- a/liblwgeom/lwgeom.c
+++ b/liblwgeom/lwgeom.c
@@ -2534,3 +2534,161 @@ void lwgeom_trim_bits_in_place(LWGEOM* geom, int32_t prec_x, int32_t prec_y, int
 
 	lwpointiterator_destroy(it);
 }
+
+LWGEOM *
+lwgeom_boundary(LWGEOM *lwgeom)
+{
+	LWGEOM *lwresult;
+
+	int32_t srid = lwgeom_get_srid(lwgeom);
+	uint8_t hasz = lwgeom_has_z(lwgeom);
+	uint8_t hasm = lwgeom_has_m(lwgeom);
+
+	switch (lwgeom->type)
+	{
+	case POINTTYPE: {
+		lwresult = (LWGEOM *)lwpoint_construct_empty(srid, hasz, hasm);
+		break;
+	}
+	case MULTIPOINTTYPE: {
+		lwresult = (LWGEOM *)lwmpoint_construct_empty(srid, hasz, hasm);
+		break;
+	}
+	case LINETYPE:
+	case CIRCSTRINGTYPE: {
+		if (lwgeom_is_closed(lwgeom))
+		{
+			lwresult = (LWGEOM *)lwmpoint_construct_empty(srid, hasz, hasm);
+		}
+		else
+		{
+			LWLINE *lwline = (LWLINE *)lwgeom;
+			LWMPOINT *lwmpoint = lwmpoint_construct_empty(srid, hasz, hasm);
+			POINT4D pt;
+			getPoint4d_p(lwline->points, 0, &pt);
+			lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &pt));
+			getPoint4d_p(lwline->points, lwline->points->npoints - 1, &pt);
+			lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &pt));
+
+			lwresult = (LWGEOM *)lwmpoint;
+		}
+
+		break;
+	}
+	case MULTILINETYPE:
+	case MULTICURVETYPE: {
+		LWMLINE *lwmline = (LWMLINE *)lwgeom;
+		POINT4D *out = lwalloc(sizeof(POINT4D) * lwmline->ngeoms * 2);
+		uint32_t n = 0;
+		uint32_t i, j, k;
+		for (i = 0; i < lwmline->ngeoms; i++)
+		{
+			LWMPOINT *points = lwgeom_as_lwmpoint(lwgeom_boundary((LWGEOM *)lwmline->geoms[i]));
+			if (!points)
+				continue;
+
+			for (k = 0; k < points->ngeoms; k++)
+			{
+				POINT4D pt;
+				getPoint4d_p(points->geoms[k]->point, 0, &pt);
+
+				int seen = LW_FALSE;
+				for (j = 0; j < n; j++)
+				{
+					if (memcmp(&(out[j]), &pt, sizeof(POINT4D)) == 0)
+					{
+						seen = LW_TRUE;
+						memcpy(&(out[j]), &(out[n - 1]), sizeof(POINT4D));
+						n--;
+						break;
+					}
+				}
+
+				if (!seen)
+				{
+					memcpy(&(out[n]), &pt, sizeof(POINT4D));
+					n++;
+				}
+			}
+		}
+
+		LWMPOINT *lwmpoint = lwmpoint_construct_empty(srid, hasz, hasm);
+		for (i = 0; i < n; i++)
+		{
+			lwmpoint_add_lwpoint(lwmpoint, lwpoint_make(srid, hasz, hasm, &(out[i])));
+		}
+
+		lwfree(out);
+
+		lwresult = (LWGEOM *)lwmpoint;
+
+		break;
+	}
+	case TRIANGLETYPE: {
+		LWTRIANGLE *lwtriangle = (LWTRIANGLE *)lwgeom;
+		POINTARRAY *points = ptarray_clone_deep(lwtriangle->points);
+		lwresult = (LWGEOM *)lwline_construct(srid, 0, points);
+		break;
+	}
+	case POLYGONTYPE: {
+		LWPOLY *lwpoly = (LWPOLY *)lwgeom;
+
+		if (lwpoly->nrings == 1)
+		{
+			POINTARRAY *ring = ptarray_clone_deep(lwpoly->rings[0]);
+			lwresult = (LWGEOM *)lwline_construct(srid, 0, ring);
+		}
+		else
+		{
+			LWMLINE *lwmline = lwmline_construct_empty(srid, hasz, hasm);
+			for (uint32_t i = 0; i < lwpoly->nrings; i++)
+			{
+				POINTARRAY *ring = ptarray_clone_deep(lwpoly->rings[i]);
+				lwmline_add_lwline(lwmline, lwline_construct(srid, 0, ring));
+			}
+
+			lwresult = (LWGEOM *)lwmline;
+		}
+
+		break;
+	}
+	case CURVEPOLYTYPE: {
+		LWCURVEPOLY *lwcurvepoly = (LWCURVEPOLY *)lwgeom;
+		LWCOLLECTION *lwcol = lwcollection_construct_empty(MULTICURVETYPE, srid, hasz, hasm);
+		for (uint32_t i = 0; i < lwcurvepoly->nrings; i++)
+		{
+			lwcol = lwcollection_add_lwgeom(lwcol, lwgeom_clone_deep(lwcurvepoly->rings[i]));
+		}
+
+		lwresult = (LWGEOM *)lwcol;
+
+		break;
+	}
+	case MULTIPOLYGONTYPE:
+	case TINTYPE: {
+		LWCOLLECTION *lwcol = (LWCOLLECTION *)lwgeom;
+
+		if (lwcol->ngeoms == 1)
+		{
+			lwresult = lwgeom_boundary(lwcol->geoms[0]);
+		}
+		else
+		{
+			LWCOLLECTION *lwcol_boundary = lwcollection_construct_empty(MULTILINETYPE, srid, hasz, hasm);
+			for (uint32_t i = 0; i < lwcol->ngeoms; i++)
+			{
+				lwcollection_add_lwgeom(lwcol_boundary, lwgeom_boundary(lwcol->geoms[i]));
+			}
+
+			lwresult = (LWGEOM *)lwcol_boundary;
+		}
+
+		break;
+	}
+	default:
+		lwerror("lwgeom_boundary: unsupported geometry type: %s", lwtype_name(lwgeom->type));
+		return NULL;
+	}
+
+	return lwresult;
+}
\ No newline at end of file
diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c
index 43b236b..e50914e 100644
--- a/postgis/lwgeom_functions_basic.c
+++ b/postgis/lwgeom_functions_basic.c
@@ -3174,3 +3174,37 @@ Datum LWGEOM_FilterByM(PG_FUNCTION_ARGS)
 	lwgeom_free(lwgeom_out);
 	PG_RETURN_POINTER(geom_out);
 }
+
+PG_FUNCTION_INFO_V1(boundary);
+Datum boundary(PG_FUNCTION_ARGS)
+{
+	GSERIALIZED *geom1;
+	GSERIALIZED *result;
+	LWGEOM *lwgeom, *lwresult;
+
+	geom1 = PG_GETARG_GSERIALIZED_P(0);
+
+	/* Empty.Boundary() == Empty */
+	if (gserialized_is_empty(geom1))
+		PG_RETURN_POINTER(geom1);
+
+	lwgeom = lwgeom_from_gserialized(geom1);
+	if (!lwgeom)
+	{
+		lwpgerror("POSTGIS2GEOS: unable to deserialize input");
+		PG_RETURN_NULL();
+	}
+
+	lwresult = lwgeom_boundary(lwgeom);
+	if (lwresult == NULL)
+	{
+		PG_RETURN_NULL();
+	}
+
+	result = geometry_serialize(lwresult);
+
+	lwgeom_free(lwgeom);
+	lwgeom_free(lwresult);
+
+	PG_RETURN_POINTER(result);
+}
diff --git a/postgis/lwgeom_geos.c b/postgis/lwgeom_geos.c
index 1bfa150..117ddf0 100644
--- a/postgis/lwgeom_geos.c
+++ b/postgis/lwgeom_geos.c
@@ -40,6 +40,7 @@
 #include "lwgeom_functions_analytic.h" /* for point_in_polygon */
 #include "lwgeom_geos.h"
 #include "liblwgeom.h"
+#include "liblwgeom_internal.h"
 #include "lwgeom_rtree.h"
 #include "lwgeom_geos_prepared.h"
 #include "lwgeom_accum.h"
@@ -822,79 +823,6 @@ Datum ST_SymDifference(PG_FUNCTION_ARGS)
 	PG_RETURN_POINTER(result);
 }
 
-
-PG_FUNCTION_INFO_V1(boundary);
-Datum boundary(PG_FUNCTION_ARGS)
-{
-	GSERIALIZED	*geom1;
-	GEOSGeometry *g1, *g3;
-	GSERIALIZED *result;
-	LWGEOM *lwgeom;
-	int32_t srid;
-
-	geom1 = PG_GETARG_GSERIALIZED_P(0);
-
-	/* Empty.Boundary() == Empty */
-	if ( gserialized_is_empty(geom1) )
-		PG_RETURN_POINTER(geom1);
-
-	srid = gserialized_get_srid(geom1);
-
-	lwgeom = lwgeom_from_gserialized(geom1);
-	if ( ! lwgeom ) {
-		lwpgerror("POSTGIS2GEOS: unable to deserialize input");
-		PG_RETURN_NULL();
-	}
-
-	/* GEOS doesn't do triangle type, so we special case that here */
-	if (lwgeom->type == TRIANGLETYPE)
-	{
-		lwgeom->type = LINETYPE;
-		result = geometry_serialize(lwgeom);
-		lwgeom_free(lwgeom);
-		PG_RETURN_POINTER(result);
-	}
-
-	initGEOS(lwpgnotice, lwgeom_geos_error);
-
-	g1 = LWGEOM2GEOS(lwgeom, 0);
-	lwgeom_free(lwgeom);
-
-	if (!g1)
-		HANDLE_GEOS_ERROR("First argument geometry could not be converted to GEOS");
-
-	g3 = GEOSBoundary(g1);
-
-	if (!g3)
-	{
-		GEOSGeom_destroy(g1);
-		HANDLE_GEOS_ERROR("GEOSBoundary");
-	}
-
-	POSTGIS_DEBUGF(3, "result: %s", GEOSGeomToWKT(g3));
-
-	GEOSSetSRID(g3, srid);
-
-	result = GEOS2POSTGIS(g3, gserialized_has_z(geom1));
-
-	if (!result)
-	{
-		GEOSGeom_destroy(g1);
-		GEOSGeom_destroy(g3);
-		elog(NOTICE,
-		     "GEOS2POSTGIS threw an error (result postgis geometry "
-		     "formation)!");
-		PG_RETURN_NULL(); /* never get here */
-	}
-
-	GEOSGeom_destroy(g1);
-	GEOSGeom_destroy(g3);
-
-	PG_FREE_IF_COPY(geom1, 0);
-
-	PG_RETURN_POINTER(result);
-}
-
 PG_FUNCTION_INFO_V1(convexhull);
 Datum convexhull(PG_FUNCTION_ARGS)
 {
diff --git a/regress/core/boundary.sql b/regress/core/boundary.sql
index 68dc883..e99ca76 100644
--- a/regress/core/boundary.sql
+++ b/regress/core/boundary.sql
@@ -1,5 +1,16 @@
+SELECT ST_AsText(ST_Boundary(ST_GeomFromText('POINT(0 1)')));
+SELECT ST_AsText(ST_Boundary(ST_GeomFromText('MULTIPOINT(0 0, 1 1)')));
 SELECT ST_AsText(ST_Boundary(ST_GeomFromText('LINESTRING(1 1,0 0, -1 1)')));
+SELECT ST_AsText(ST_Boundary(ST_GeomFromText('LINESTRING(1 1,0 0, 1 1)')));
 SELECT ST_AsText(ST_Boundary(ST_GeomFromText('POLYGON((1 1,0 0, -1 1, 1 1))')));
 SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('POLYGON((1 1 1,0 0 1, -1 1 1, 1 1 1))')));
+SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('POLYGON((1 1 1,0 0 1, -1 1 1, 1 1 1),(1 1 1,0 0 1, -1 1 1, 1 1 1))')));
 SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTILINESTRING((1 1 1,0 0 0.5, -1 1 1),(1 1 0.5,0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
+SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTILINESTRING((1 1 1,0 0 0.5, -1 1 1),(-1 1 1,0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
+SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTILINESTRING((1 1 1,0 0 0.5, 1 1 1),(1 1 0.5,0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
 SELECT ST_AsText(ST_Boundary(ST_GeomFromText('TRIANGLE((1 1,0 0, -1 1, 1 1))')));
+SELECT ST_AsText(ST_Boundary(ST_GeomFromText('MULTIPOLYGON(((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)), ((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))')));
+SELECT ST_AsText(ST_Boundary(ST_GeomFromEWKT('TIN(((0 0,0 -1,-1 1,0 0)),((0 0,1 0,0 -1,0 0)))')));
+SELECT ST_AsText(ST_Boundary(ST_GeomFromEWKT('TIN(((0 0,0 -1,-1 1,0 0)))')));
+SELECT ST_AsText(ST_Boundary(ST_GeomFromEWKT('CURVEPOLYGON(CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0),(1 1, 3 3, 3 1, 1 1))')));
+SELECT ST_AsEWKT(ST_Boundary(ST_GeomFromEWKT('MULTICURVE((1 1 1,0 0 0.5, -1 1 1),(1 1 0.5,0 0 0.5, -1 1 0.5, 1 1 0.5) )')));
diff --git a/regress/core/boundary_expected b/regress/core/boundary_expected
index 8105f0b..988e85d 100644
--- a/regress/core/boundary_expected
+++ b/regress/core/boundary_expected
@@ -1,5 +1,16 @@
+POINT EMPTY
+MULTIPOINT EMPTY
 MULTIPOINT(1 1,-1 1)
+MULTIPOINT EMPTY
 LINESTRING(1 1,0 0,-1 1,1 1)
 LINESTRING(1 1 1,0 0 1,-1 1 1,1 1 1)
-MULTIPOINT(-1 1 1,1 1 0.75)
+MULTILINESTRING((1 1 1,0 0 1,-1 1 1,1 1 1),(1 1 1,0 0 1,-1 1 1,1 1 1))
+MULTIPOINT(1 1 1,-1 1 1)
+MULTIPOINT(1 1 1,1 1 0.5)
+MULTIPOINT EMPTY
 LINESTRING(1 1,0 0,-1 1,1 1)
+MULTILINESTRING((30 20,45 40,10 40,30 20),(15 5,40 10,10 20,5 10,15 5),(30 20,45 40,10 40,30 20),(15 5,40 10,10 20,5 10,15 5))
+MULTILINESTRING((0 0,0 -1,-1 1,0 0),(0 0,1 0,0 -1,0 0))
+LINESTRING(0 0,0 -1,-1 1,0 0)
+MULTICURVE(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1))
+MULTIPOINT(1 1 1,-1 1 1)

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

Summary of changes:
 NEWS                             |   1 +
 doc/reference_accessor.xml       |   1 +
 liblwgeom/liblwgeom.h.in         |   2 +
 liblwgeom/lwgeom.c               | 126 +++++++++++++++++++++++++++++++++++++++
 postgis/lwgeom_functions_basic.c |  27 +++++++++
 postgis/lwgeom_geos.c            |  74 +----------------------
 regress/core/boundary.sql        |  21 +++++--
 regress/core/boundary_expected   |  21 +++++--
 8 files changed, 190 insertions(+), 83 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list