[SCM] PostGIS branch master updated. 3.4.0rc1-1141-ga1922ae9d

git at osgeo.org git at osgeo.org
Sun Jun 2 01:40:40 PDT 2024


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  a1922ae9d3d8a00b431c35ef39c6bbc04d4c5fa3 (commit)
       via  e1785e5bca139fac2be3df309a76c4982e489be1 (commit)
       via  3dfa59f318945883a9f94c7dd7e8efe078142a92 (commit)
      from  4903c6f76a29750e53d0ad923f9f67a6f4029c02 (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 a1922ae9d3d8a00b431c35ef39c6bbc04d4c5fa3
Author: Regina Obe <lr at pcorp.us>
Date:   Sun Jun 2 04:28:16 2024 -0400

    Additional changes to ST_RemoveSmallParts
    
     - Add To NEWS ST_RemoveSmallParts, and cleanup prior NEWS commit
     - Move ST_RemoveIrrelevantPointsForView before ST_RemoveSmallParts
     - Mark ST_RemoveSmallParts as IMMUTABLE and add costing
     - References https://github.com/postgis/postgis/pull/768
     - References #5706

diff --git a/NEWS b/NEWS
index ab90a927a..f28a02d90 100644
--- a/NEWS
+++ b/NEWS
@@ -66,8 +66,8 @@ Andreas Schild (German Team)
             CG_3DDistance, CG_Distance (Loïc Bartoletti)
   - #5687, Don't rely on search_path to determine postgis schema
            Fix for PG17 security change (Regina Obe)
-  - #5705, GH-767, Remove irrelevant points for view (Sam Peters)
-  - #5706, GH-768, Remove small parts (Sam Peters)
+  - #5705, GH-767, Remove irrelevant points for view: ST_RemoveIrrelevantPointsForView  (Sam Peters)
+  - #5706, GH-768, Remove small parts: ST_RemoveSmallParts (Sam Peters)
 
 * Enhancements *
 
diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in
index 75134caca..c8f0ed48b 100644
--- a/postgis/postgis.sql.in
+++ b/postgis/postgis.sql.in
@@ -6967,17 +6967,6 @@ CREATE OR REPLACE FUNCTION ST_3DLineInterpolatePoint(geometry, float8)
 #include "postgis_spgist.sql.in"
 #include "postgis_letters.sql"
 
-
------------------------------------------------------------------------
--- ST_RemoveSmallParts
------------------------------------------------------------------------
--- Availability: 3.5.0
-CREATE OR REPLACE FUNCTION ST_RemoveSmallParts(geometry, double precision, double precision)
-RETURNS geometry
-AS 'MODULE_PATHNAME','ST_RemoveSmallParts'
-LANGUAGE 'c' VOLATILE STRICT; 
-
-
 -----------------------------------------------------------------------
 -- ST_RemoveIrrelevantPointsForView
 -----------------------------------------------------------------------
@@ -6988,4 +6977,14 @@ AS 'MODULE_PATHNAME','ST_RemoveIrrelevantPointsForView'
 	LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE
 	_COST_MEDIUM;
 
+-----------------------------------------------------------------------
+-- ST_RemoveSmallParts
+-----------------------------------------------------------------------
+-- Availability: 3.5.0
+CREATE OR REPLACE FUNCTION ST_RemoveSmallParts(geometry, double precision, double precision)
+RETURNS geometry
+AS 'MODULE_PATHNAME','ST_RemoveSmallParts'
+LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE
+	_COST_MEDIUM;
+
 COMMIT;

commit e1785e5bca139fac2be3df309a76c4982e489be1
Author: Regina Obe <lr at pcorp.us>
Date:   Sun Jun 2 04:26:51 2024 -0400

    Add Remove small parts feature to news

diff --git a/NEWS b/NEWS
index da043ec6a..ab90a927a 100644
--- a/NEWS
+++ b/NEWS
@@ -67,6 +67,7 @@ Andreas Schild (German Team)
   - #5687, Don't rely on search_path to determine postgis schema
            Fix for PG17 security change (Regina Obe)
   - #5705, GH-767, Remove irrelevant points for view (Sam Peters)
+  - #5706, GH-768, Remove small parts (Sam Peters)
 
 * Enhancements *
 

commit 3dfa59f318945883a9f94c7dd7e8efe078142a92
Author: Regina Obe <lr at pcorp.us>
Date:   Sun Jun 2 04:24:26 2024 -0400

    Remove small parts
    
    - Closes https://github.com/postgis/postgis/pull/768
    - Closes #5706
    
    Author: Sam Peters

diff --git a/doc/html/images/static/st_removesmallparts.png b/doc/html/images/static/st_removesmallparts.png
new file mode 100644
index 000000000..2b2a7e06e
Binary files /dev/null and b/doc/html/images/static/st_removesmallparts.png differ
diff --git a/doc/reference_editor.xml b/doc/reference_editor.xml
index b19080547..415c0da1c 100644
--- a/doc/reference_editor.xml
+++ b/doc/reference_editor.xml
@@ -1856,6 +1856,101 @@ SELECT ST_AsText( ST_RemoveRepeatedPoints( 'LINESTRING (0 0, 0 0, 1 1, 5 5, 1 1,
 
 	</refentry>
 
+	<refentry xml:id="ST_RemoveSmallParts">
+	  <refnamediv>
+		<refname>ST_RemoveSmallParts</refname>
+		<refpurpose>Removes small parts (polygon rings or linestrings) of a geometry.</refpurpose>
+	  </refnamediv>
+
+	  <refsynopsisdiv>
+		<funcsynopsis>
+		  <funcprototype>
+			<funcdef>geometry <function>ST_RemoveSmallParts</function></funcdef>
+			<paramdef><type>geometry </type> <parameter>geom</parameter></paramdef>
+			<paramdef><type>double precision </type> <parameter>minSizeX</parameter></paramdef>
+			<paramdef><type>double precision </type> <parameter>minSizeY</parameter></paramdef>
+		  </funcprototype>
+		</funcsynopsis>
+	  </refsynopsisdiv>
+
+	  <refsection>
+		<title>Description</title>
+
+		<para>Returns a <xref linkend="geometry"/> without small parts (exterior or interior polygon rings, or linestrings).</para>
+		<para>This function can be used as preprocessing step for creating simplified maps, e. g. to remove small islands or holes.</para>
+		<para>It evaluates only geometries of type (MULTI)POLYGON and (MULTI)LINESTRING. Other geometries remain unchanged.</para>
+		<para>If <parameter>minSizeX</parameter> is greater than 0, parts are sorted out if their width is smaller than <parameter>minSizeX</parameter>.</para>
+		<para>If <parameter>minSizeY</parameter> is greater than 0, parts are sorted out if their height is smaller than <parameter>minSizeY</parameter>.</para>
+		<para>Both <parameter>minSizeX</parameter> and <parameter>minSizeY</parameter> are measured in coordinate system units of the geometry.</para>
+		<para>For polygon types, evaluation is done separately for each ring which can lead to one of the following results:
+            <itemizedlist>
+            <listitem><para>the original geometry,</para></listitem>
+			<listitem><para>a POLYGON with all rings with less vertices,</para></listitem>
+			<listitem><para>a POLYGON with a reduced number of interior rings (having possibly less vertices),</para></listitem> 
+			<listitem><para>a POLYGON EMPTY, or</para></listitem>
+			<listitem><para>a MULTIPOLYGON with a reduced number of polygons (having possibly less interior rings or vertices), or</para></listitem>
+			<listitem><para>a MULTIPOLYGON EMPTY.</para></listitem>
+			</itemizedlist>
+		</para>
+		<para>For linestring types, evaluation is done for each linestring which can lead to one of the following results:
+            <itemizedlist>
+            <listitem><para>the original geometry,</para></listitem>
+			<listitem><para>a LINESTRING with a reduced number of vertices,</para></listitem>
+			<listitem><para>a LINESTRING EMPTY,</para></listitem>
+			<listitem><para>a MULTILINESTRING with a reduced number of linestrings (having possibly less vertices), or</para></listitem>
+			<listitem><para>a MULTILINESTRING EMPTY.</para></listitem>
+			</itemizedlist>
+		</para>
+
+        <para>
+            <informalfigure>
+                <mediaobject>
+                    <imageobject>
+                        <imagedata fileref="images/st_removesmallparts.png"/>
+                    </imageobject>
+                    <caption>
+                        <para>Example: ST_RemoveSmallParts() applied to a multi-polygon. Blue parts remain.</para>
+                    </caption>
+                </mediaobject>
+            </informalfigure>
+        </para>
+
+		<para role="availability" conformance="3.5.0">Availability: 3.5.0</para>
+		
+	  </refsection>
+
+	  <refsection>
+		<title>Examples</title>
+
+		<programlisting>
+			SELECT ST_AsText(
+			ST_RemoveSmallParts(
+			ST_GeomFromText('MULTIPOLYGON(
+				((60 160, 120 160, 120 220, 60 220, 60 160), (70 170, 70 210, 110 210, 110 170, 70 170)),
+				((85 75, 155 75, 155 145, 85 145, 85 75)),
+				((50 110, 70 110, 70 130, 50 130, 50 110)))'),
+				50, 50));
+		
+		st_astext
+		---------
+			MULTIPOLYGON(((60 160,120 160,120 220,60 220,60 160)),((85 75,155 75,155 145,85 145,85 75)))
+		</programlisting>
+
+		<programlisting>
+			SELECT ST_AsText(
+			ST_RemoveSmallParts(
+			ST_GeomFromText('LINESTRING(10 10, 20 20)'),
+				50, 50));
+		
+		st_astext
+		---------
+			LINESTRING EMPTY
+		</programlisting>
+			
+	  </refsection>
+
+	</refentry>
+
 	<refentry xml:id="ST_Reverse">
 	  <refnamediv>
 		<refname>ST_Reverse</refname>
diff --git a/postgis/Makefile.in b/postgis/Makefile.in
index 780287b1b..15a69d2d4 100644
--- a/postgis/Makefile.in
+++ b/postgis/Makefile.in
@@ -131,6 +131,7 @@ PG_OBJS= \
 	lwgeom_in_flatgeobuf.o \
 	lwgeom_out_flatgeobuf.o \
 	lwgeom_remove_irrelevant_points_for_view.o \
+	lwgeom_remove_small_parts.o \
 	postgis_legacy.o
 
 # Objects to build using PGXS
diff --git a/postgis/lwgeom_remove_small_parts.c b/postgis/lwgeom_remove_small_parts.c
new file mode 100644
index 000000000..94192c023
--- /dev/null
+++ b/postgis/lwgeom_remove_small_parts.c
@@ -0,0 +1,235 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.net
+ *
+ * PostGIS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * PostGIS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with PostGIS.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ **********************************************************************
+ *
+ * Copyright (C) 2024 Sam Peters <gluser1357 at gmx.de>
+ *
+ **********************************************************************/
+
+#include "postgres.h"
+#include "funcapi.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/numeric.h"
+#include "access/htup_details.h"
+
+#include "liblwgeom.h"
+#include "liblwgeom_internal.h"
+
+// ===============================================================================
+// helper function for polygon and polyline POINTARRAY's
+// which removes small parts given by dx and dy.
+// ===============================================================================
+static void ptarray_remove_dim_helper(POINTARRAY *points, double mindx, double mindy) {
+
+	int r;
+	double xmin = 0, ymin = 0, xmax = 0, ymax = 0;
+	double x, y;
+	POINT4D point;
+
+	int npoints = points->npoints;
+	for (r=0; r < npoints; r++) {
+
+		getPoint4d_p(points, r, &point);
+
+		x = point.x;
+		y = point.y;
+
+		if (mindx > 0) {
+			if (!r || xmin > x) xmin = x;
+			if (!r || xmax < x) xmax = x;
+		}
+		if (mindy > 0) {
+			if (!r || ymin > y) ymin = y;
+			if (!r || ymax < y) ymax = y;
+		}
+	}
+
+	if ((mindx > 0 && xmax - xmin < mindx) ||
+		(mindy > 0 && ymax - ymin < mindy)) {
+		// skip part
+		points->npoints = 0;
+	}
+}
+
+// ===============================================================================
+// remove small (sub-)geometries being smaller than given dimensions.
+// 2D-(MULTI)POLYGONs and (MULTI)LINESTRINGs are evaluated, others keep untouched.
+// ===============================================================================
+PG_FUNCTION_INFO_V1(ST_RemoveSmallParts);
+Datum ST_RemoveSmallParts(PG_FUNCTION_ARGS) {
+
+	double mindx = 0, mindy = 0;
+	unsigned int i, j, iw, jw;
+
+	GSERIALIZED *serialized_in;
+	GSERIALIZED *serialized_out;
+
+	LWGEOM *geom;
+
+	// geom input check
+	if (PG_GETARG_POINTER(0) == NULL) {
+		PG_RETURN_NULL();
+	}
+
+	serialized_in = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
+
+	if (PG_NARGS() == 3) {
+
+		if (PG_ARGISNULL(1) || PG_ARGISNULL(2)) {
+			// no valid args given, leave untouched
+			PG_RETURN_POINTER(serialized_in);
+		}
+
+		mindx = PG_GETARG_FLOAT8(1);
+		mindy = PG_GETARG_FLOAT8(2);
+		if (mindx <= 0 && mindy <= 0) {
+			// nothing to do
+			PG_RETURN_POINTER(serialized_in);
+		}
+
+		// type check (only polygon and line types are supported yet)
+		if (gserialized_get_type(serialized_in) != POLYGONTYPE &&
+			gserialized_get_type(serialized_in) != MULTIPOLYGONTYPE &&
+			gserialized_get_type(serialized_in) != LINETYPE &&
+			gserialized_get_type(serialized_in) != MULTILINETYPE) {
+
+			// no (multi)polygon or (multi)linetype, leave untouched
+			PG_RETURN_POINTER(serialized_in);
+		}
+
+	}
+
+	else {
+		// unknown params, leave untouched
+		PG_RETURN_POINTER(serialized_in);
+	}
+
+	// deserialize geom and copy coordinates (no clone_deep)
+	geom = lwgeom_from_gserialized(serialized_in);
+
+	if (geom->type == LINETYPE) {
+
+		LWLINE* line = (LWLINE*)geom;
+		ptarray_remove_dim_helper(line->points, mindx, mindy);
+	}
+
+	if (geom->type == MULTILINETYPE) {
+
+		LWMLINE* mline = (LWMLINE*)geom;
+		iw = 0;
+		for (i=0; i<mline->ngeoms; i++) {
+			LWLINE* line = mline->geoms[i];
+			ptarray_remove_dim_helper(line->points, mindx, mindy);
+
+			if (line->points->npoints) {
+				// keep (reduced) line
+				mline->geoms[iw++] = line;
+			}
+			else {
+				// discard current line
+				lwfree(line);
+			}
+		}
+		mline->ngeoms = iw;
+	}
+
+	if (geom->type == POLYGONTYPE) {
+
+		LWPOLY* polygon = (LWPOLY*)geom;
+		iw = 0;
+		for (i=0; i<polygon->nrings; i++) {
+			ptarray_remove_dim_helper(polygon->rings[i], mindx, mindy);
+
+			if (polygon->rings[i]->npoints) {
+				// keep (reduced) ring
+				polygon->rings[iw++] = polygon->rings[i];
+			}
+			else {
+				if (!i) {
+					// exterior ring too small, free and skip all rings
+					unsigned int k;
+					for (k=0; k<polygon->nrings; k++) {
+						lwfree(polygon->rings[k]);
+					}
+					break;
+				}
+				else {
+					// free and remove current interior ring
+					lwfree(polygon->rings[i]);
+				}
+			}
+		}
+		polygon->nrings = iw;
+	}
+
+	if (geom->type == MULTIPOLYGONTYPE) {
+
+		LWMPOLY* mpolygon = (LWMPOLY*)geom;
+		jw = 0;
+		for (j=0; j<mpolygon->ngeoms; j++) {
+
+			LWPOLY* polygon = mpolygon->geoms[j];
+			iw = 0;
+			for (i=0; i<polygon->nrings; i++) {
+				ptarray_remove_dim_helper(polygon->rings[i], mindx, mindy);
+
+				if (polygon->rings[i]->npoints) {
+					// keep (reduced) ring
+					polygon->rings[iw++] = polygon->rings[i];
+				}
+				else {
+					if (!i) {
+						// exterior ring too small, free and skip all rings
+						unsigned int k;
+						for (k=0; k<polygon->nrings; k++) {
+							lwfree(polygon->rings[k]);
+						}
+						break;
+					}
+					else {
+						// free and remove current interior ring
+						lwfree(polygon->rings[i]);
+					}
+				}
+			}
+			polygon->nrings = iw;
+
+			if (iw) {
+				mpolygon->geoms[jw++] = polygon;
+			}
+			else {
+				// free and remove polygon from multipolygon
+				lwfree(polygon);
+			}
+		}
+		mpolygon->ngeoms = jw;
+	}
+
+	// recompute bbox if computed previously (may result in NULL)
+	lwgeom_drop_bbox(geom);
+	lwgeom_add_bbox(geom);
+
+	serialized_out = gserialized_from_lwgeom(geom, 0);
+	lwgeom_free(geom);
+
+	PG_FREE_IF_COPY(serialized_in, 0);
+	PG_RETURN_POINTER(serialized_out);
+}
diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in
index 67f63c98b..75134caca 100644
--- a/postgis/postgis.sql.in
+++ b/postgis/postgis.sql.in
@@ -6968,6 +6968,16 @@ CREATE OR REPLACE FUNCTION ST_3DLineInterpolatePoint(geometry, float8)
 #include "postgis_letters.sql"
 
 
+-----------------------------------------------------------------------
+-- ST_RemoveSmallParts
+-----------------------------------------------------------------------
+-- Availability: 3.5.0
+CREATE OR REPLACE FUNCTION ST_RemoveSmallParts(geometry, double precision, double precision)
+RETURNS geometry
+AS 'MODULE_PATHNAME','ST_RemoveSmallParts'
+LANGUAGE 'c' VOLATILE STRICT; 
+
+
 -----------------------------------------------------------------------
 -- ST_RemoveIrrelevantPointsForView
 -----------------------------------------------------------------------
diff --git a/regress/core/remove_small_parts.sql b/regress/core/remove_small_parts.sql
new file mode 100644
index 000000000..3e5474b67
--- /dev/null
+++ b/regress/core/remove_small_parts.sql
@@ -0,0 +1,17 @@
+SELECT 0, ST_AsText(
+    ST_RemoveSmallParts(
+    ST_GeomFromText('MULTIPOLYGON(
+	((60 160, 120 160, 120 220, 60 220, 60 160), (70 170, 70 210, 110 210, 110 170, 70 170)),
+	((85 75, 155 75, 155 145, 85 145, 85 75)),
+	((50 110, 70 110, 70 130, 50 130, 50 110)))'),
+	50, 50));
+
+SELECT 1, ST_AsText(
+    ST_RemoveSmallParts(
+    ST_GeomFromText('LINESTRING(10 10, 20 20)'),
+    50, 50));
+
+SELECT 2, ST_AsText(
+    ST_RemoveSmallParts(
+    ST_GeomFromText('LINESTRING(10 10 10, 20 20 20)'),
+    50, 50));
diff --git a/regress/core/remove_small_parts_expected b/regress/core/remove_small_parts_expected
new file mode 100644
index 000000000..f669c483c
--- /dev/null
+++ b/regress/core/remove_small_parts_expected
@@ -0,0 +1,3 @@
+0|MULTIPOLYGON(((60 160,120 160,120 220,60 220,60 160)),((85 75,155 75,155 145,85 145,85 75)))
+1|LINESTRING EMPTY
+2|LINESTRING Z EMPTY
diff --git a/regress/core/tests.mk.in b/regress/core/tests.mk.in
index 7182db0c0..d2dfe71a7 100644
--- a/regress/core/tests.mk.in
+++ b/regress/core/tests.mk.in
@@ -96,6 +96,7 @@ TESTS += \
 	$(top_srcdir)/regress/core/relate \
 	$(top_srcdir)/regress/core/remove_irrelevant_points_for_view \
 	$(top_srcdir)/regress/core/remove_repeated_points \
+	$(top_srcdir)/regress/core/remove_small_parts \
 	$(top_srcdir)/regress/core/removepoint \
 	$(top_srcdir)/regress/core/reverse \
 	$(top_srcdir)/regress/core/scroll \

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

Summary of changes:
 NEWS                                           |   3 +-
 doc/html/images/static/st_removesmallparts.png | Bin 0 -> 11314 bytes
 doc/reference_editor.xml                       |  95 ++++++++++
 postgis/Makefile.in                            |   1 +
 postgis/lwgeom_remove_small_parts.c            | 235 +++++++++++++++++++++++++
 postgis/postgis.sql.in                         |  11 +-
 regress/core/remove_small_parts.sql            |  17 ++
 regress/core/remove_small_parts_expected       |   3 +
 regress/core/tests.mk.in                       |   1 +
 9 files changed, 364 insertions(+), 2 deletions(-)
 create mode 100644 doc/html/images/static/st_removesmallparts.png
 create mode 100644 postgis/lwgeom_remove_small_parts.c
 create mode 100644 regress/core/remove_small_parts.sql
 create mode 100644 regress/core/remove_small_parts_expected


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list