PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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// ===============================================================================
40static 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// ===============================================================================
77Datum 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
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1246
#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:710
#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:723
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