PostGIS  3.7.0dev-r@@SVN_REVISION@@
lwgeom_remove_small_parts.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright (C) 2024 Sam Peters <gluser1357@gmx.de>
22  *
23  **********************************************************************/
24 
25 #include "postgres.h"
26 #include "funcapi.h"
27 #include "utils/array.h"
28 #include "utils/builtins.h"
29 #include "utils/lsyscache.h"
30 #include "utils/numeric.h"
31 #include "access/htup_details.h"
32 
33 #include "liblwgeom.h"
34 #include "liblwgeom_internal.h"
35 
36 // ===============================================================================
37 // helper function for polygon and polyline POINTARRAY's
38 // which removes small parts given by dx and dy.
39 // ===============================================================================
40 static void ptarray_remove_dim_helper(POINTARRAY *points, double mindx, double mindy) {
41 
42  int r;
43  double xmin = 0, ymin = 0, xmax = 0, ymax = 0;
44  double x, y;
45  POINT4D point;
46 
47  int npoints = points->npoints;
48  for (r=0; r < npoints; r++) {
49 
50  getPoint4d_p(points, r, &point);
51 
52  x = point.x;
53  y = point.y;
54 
55  if (mindx > 0) {
56  if (!r || xmin > x) xmin = x;
57  if (!r || xmax < x) xmax = x;
58  }
59  if (mindy > 0) {
60  if (!r || ymin > y) ymin = y;
61  if (!r || ymax < y) ymax = y;
62  }
63  }
64 
65  if ((mindx > 0 && xmax - xmin < mindx) ||
66  (mindy > 0 && ymax - ymin < mindy)) {
67  // skip part
68  points->npoints = 0;
69  }
70 }
71 
72 // ===============================================================================
73 // remove small (sub-)geometries being smaller than given dimensions.
74 // 2D-(MULTI)POLYGONs and (MULTI)LINESTRINGs are evaluated, others keep untouched.
75 // ===============================================================================
77 Datum ST_RemoveSmallParts(PG_FUNCTION_ARGS) {
78 
79  double mindx = 0, mindy = 0;
80  unsigned int i, j, iw, jw;
81 
82  GSERIALIZED *serialized_in;
83  GSERIALIZED *serialized_out;
84 
85  LWGEOM *geom;
86 
87  // geom input check
88  if (PG_GETARG_POINTER(0) == NULL) {
89  PG_RETURN_NULL();
90  }
91 
92  serialized_in = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
93 
94  if (PG_NARGS() == 3) {
95 
96  if (PG_ARGISNULL(1) || PG_ARGISNULL(2)) {
97  // no valid args given, leave untouched
98  PG_RETURN_POINTER(serialized_in);
99  }
100 
101  mindx = PG_GETARG_FLOAT8(1);
102  mindy = PG_GETARG_FLOAT8(2);
103  if (mindx <= 0 && mindy <= 0) {
104  // nothing to do
105  PG_RETURN_POINTER(serialized_in);
106  }
107 
108  // type check (only polygon and line types are supported yet)
109  if (gserialized_get_type(serialized_in) != POLYGONTYPE &&
110  gserialized_get_type(serialized_in) != MULTIPOLYGONTYPE &&
111  gserialized_get_type(serialized_in) != LINETYPE &&
112  gserialized_get_type(serialized_in) != MULTILINETYPE) {
113 
114  // no (multi)polygon or (multi)linetype, leave untouched
115  PG_RETURN_POINTER(serialized_in);
116  }
117 
118  }
119 
120  else {
121  // unknown params, leave untouched
122  PG_RETURN_POINTER(serialized_in);
123  }
124 
125  // deserialize geom and copy coordinates (no clone_deep)
126  geom = lwgeom_from_gserialized(serialized_in);
127 
128  if (geom->type == LINETYPE) {
129 
130  LWLINE* line = (LWLINE*)geom;
131  ptarray_remove_dim_helper(line->points, mindx, mindy);
132  }
133 
134  if (geom->type == MULTILINETYPE) {
135 
136  LWMLINE* mline = (LWMLINE*)geom;
137  iw = 0;
138  for (i=0; i<mline->ngeoms; i++) {
139  LWLINE* line = mline->geoms[i];
140  ptarray_remove_dim_helper(line->points, mindx, mindy);
141 
142  if (line->points->npoints) {
143  // keep (reduced) line
144  mline->geoms[iw++] = line;
145  }
146  else {
147  // discard current line
148  lwfree(line);
149  }
150  }
151  mline->ngeoms = iw;
152  }
153 
154  if (geom->type == POLYGONTYPE) {
155 
156  LWPOLY* polygon = (LWPOLY*)geom;
157  iw = 0;
158  for (i=0; i<polygon->nrings; i++) {
159  ptarray_remove_dim_helper(polygon->rings[i], mindx, mindy);
160 
161  if (polygon->rings[i]->npoints) {
162  // keep (reduced) ring
163  polygon->rings[iw++] = polygon->rings[i];
164  }
165  else {
166  if (!i) {
167  // exterior ring too small, free and skip all rings
168  unsigned int k;
169  for (k=0; k<polygon->nrings; k++) {
170  lwfree(polygon->rings[k]);
171  }
172  break;
173  }
174  else {
175  // free and remove current interior ring
176  lwfree(polygon->rings[i]);
177  }
178  }
179  }
180  polygon->nrings = iw;
181  }
182 
183  if (geom->type == MULTIPOLYGONTYPE) {
184 
185  LWMPOLY* mpolygon = (LWMPOLY*)geom;
186  jw = 0;
187  for (j=0; j<mpolygon->ngeoms; j++) {
188 
189  LWPOLY* polygon = mpolygon->geoms[j];
190  iw = 0;
191  for (i=0; i<polygon->nrings; i++) {
192  ptarray_remove_dim_helper(polygon->rings[i], mindx, mindy);
193 
194  if (polygon->rings[i]->npoints) {
195  // keep (reduced) ring
196  polygon->rings[iw++] = polygon->rings[i];
197  }
198  else {
199  if (!i) {
200  // exterior ring too small, free and skip all rings
201  unsigned int k;
202  for (k=0; k<polygon->nrings; k++) {
203  lwfree(polygon->rings[k]);
204  }
205  break;
206  }
207  else {
208  // free and remove current interior ring
209  lwfree(polygon->rings[i]);
210  }
211  }
212  }
213  polygon->nrings = iw;
214 
215  if (iw) {
216  mpolygon->geoms[jw++] = polygon;
217  }
218  else {
219  // free and remove polygon from multipolygon
220  lwfree(polygon);
221  }
222  }
223  mpolygon->ngeoms = jw;
224  }
225 
226  // recompute bbox if computed previously (may result in NULL)
227  lwgeom_drop_bbox(geom);
228  lwgeom_add_bbox(geom);
229 
230  serialized_out = gserialized_from_lwgeom(geom, 0);
231  lwgeom_free(geom);
232 
233  PG_FREE_IF_COPY(serialized_in, 0);
234  PG_RETURN_POINTER(serialized_out);
235 }
char * r
Definition: cu_in_wkt.c:24
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:268
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
Definition: gserialized.c:118
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
Definition: gserialized.c:251
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1218
#define MULTILINETYPE
Definition: liblwgeom.h:106
#define LINETYPE
Definition: liblwgeom.h:103
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
Definition: lwgeom.c:682
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:107
void lwfree(void *mem)
Definition: lwutil.c:248
#define POLYGONTYPE
Definition: liblwgeom.h:104
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:125
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:695
This library is the generic geometry handling section of PostGIS.
static void ptarray_remove_dim_helper(POINTARRAY *points, double mindx, double mindy)
PG_FUNCTION_INFO_V1(ST_RemoveSmallParts)
Datum ST_RemoveSmallParts(PG_FUNCTION_ARGS)
uint8_t type
Definition: liblwgeom.h:462
POINTARRAY * points
Definition: liblwgeom.h:483
LWLINE ** geoms
Definition: liblwgeom.h:547
uint32_t ngeoms
Definition: liblwgeom.h:552
uint32_t ngeoms
Definition: liblwgeom.h:566
LWPOLY ** geoms
Definition: liblwgeom.h:561
POINTARRAY ** rings
Definition: liblwgeom.h:519
uint32_t nrings
Definition: liblwgeom.h:524
double x
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414
uint32_t npoints
Definition: liblwgeom.h:427