PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwgeom_dump.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 2001-2009 Refractions Research Inc.
22 *
23 **********************************************************************/
24
25
26#include <math.h>
27#include <float.h>
28#include <string.h>
29#include <stdio.h>
30#include <assert.h>
31
32#include "postgres.h"
33#include "fmgr.h"
34#include "utils/elog.h"
35#include "utils/array.h"
36#include "utils/geo_decls.h"
37#include "funcapi.h"
38
39#include "../postgis_config.h"
40#include "liblwgeom.h"
41#include "lwgeom_pg.h"
42
43
44Datum LWGEOM_dump(PG_FUNCTION_ARGS);
45Datum LWGEOM_dump_rings(PG_FUNCTION_ARGS);
46Datum ST_Subdivide(PG_FUNCTION_ARGS);
47
48typedef struct GEOMDUMPNODE_T
49{
50 uint32_t idx;
52}
54
55#define MAXDEPTH 32
63
64#define PUSH(x,y) ((x)->stack[(x)->stacklen++]=(y))
65#define LAST(x) ((x)->stack[(x)->stacklen-1])
66#define POP(x) (--((x)->stacklen))
67
68
70Datum LWGEOM_dump(PG_FUNCTION_ARGS)
71{
72 GSERIALIZED *pglwgeom;
73 LWCOLLECTION *lwcoll;
74 LWGEOM *lwgeom;
75 FuncCallContext *funcctx;
76 GEOMDUMPSTATE *state;
77 GEOMDUMPNODE *node;
78 TupleDesc tupdesc;
79 HeapTuple tuple;
80 MemoryContext oldcontext, newcontext;
81 Datum result;
82 char address[256];
83 char *ptr;
84 int i;
85 char *values[2];
86
87 if (SRF_IS_FIRSTCALL())
88 {
89 funcctx = SRF_FIRSTCALL_INIT();
90 newcontext = funcctx->multi_call_memory_ctx;
91
92 oldcontext = MemoryContextSwitchTo(newcontext);
93
94 pglwgeom = PG_GETARG_GSERIALIZED_P_COPY(0);
95 lwgeom = lwgeom_from_gserialized(pglwgeom);
96
97 /* Create function state */
98 state = lwalloc(sizeof(GEOMDUMPSTATE));
99 state->root = lwgeom;
100 state->stacklen=0;
101
102 if ( lwgeom_is_collection(lwgeom) )
103 {
104 /*
105 * Push a GEOMDUMPNODE on the state stack
106 */
107 node = lwalloc(sizeof(GEOMDUMPNODE));
108 node->idx=0;
109 node->geom = lwgeom;
110 PUSH(state, node);
111 }
112
113 funcctx->user_fctx = state;
114
115 /*
116 * Build a tuple description for an
117 * geometry_dump tuple
118 */
119 get_call_result_type(fcinfo, 0, &tupdesc);
120 BlessTupleDesc(tupdesc);
121
122 /*
123 * generate attribute metadata needed later to produce
124 * tuples from raw C strings
125 */
126 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);;
127
128 MemoryContextSwitchTo(oldcontext);
129 }
130
131 /* stuff done on every call of the function */
132 funcctx = SRF_PERCALL_SETUP();
133 newcontext = funcctx->multi_call_memory_ctx;
134
135 /* get state */
136 state = funcctx->user_fctx;
137
138 /* Handled simple geometries */
139 if ( ! state->root ) SRF_RETURN_DONE(funcctx);
140 /* Return nothing for empties */
141 if ( lwgeom_is_empty(state->root) ) SRF_RETURN_DONE(funcctx);
142 if ( ! lwgeom_is_collection(state->root) )
143 {
144 values[0] = "{}";
145 values[1] = lwgeom_to_hexwkb_buffer(state->root, WKB_EXTENDED);
146 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
147 result = HeapTupleGetDatum(tuple);
148
149 state->root = NULL;
150 SRF_RETURN_NEXT(funcctx, result);
151 }
152
153 while (1)
154 {
155 node = LAST(state);
156 lwcoll = (LWCOLLECTION*)node->geom;
157
158 if ( node->idx < lwcoll->ngeoms )
159 {
160 lwgeom = lwcoll->geoms[node->idx];
161 if ( ! lwgeom_is_collection(lwgeom) )
162 {
163 /* write address of current geom */
164 ptr=address;
165 *ptr++='{';
166 for (i=0; i<state->stacklen; i++)
167 {
168 if ( i ) ptr += sprintf(ptr, ",");
169 ptr += sprintf(ptr, "%d", state->stack[i]->idx+1);
170 }
171 *ptr++='}';
172 *ptr='\0';
173
174 break;
175 }
176
177 /*
178 * It's a collection, increment index
179 * of current node, push a new one on the
180 * stack
181 */
182
183 if (state->stacklen > MAXDEPTH)
184 elog(ERROR, "Unable to dump overly nested collection.");
185
186 oldcontext = MemoryContextSwitchTo(newcontext);
187
188 node = lwalloc(sizeof(GEOMDUMPNODE));
189 node->idx=0;
190 node->geom = lwgeom;
191 PUSH(state, node);
192
193 MemoryContextSwitchTo(oldcontext);
194
195 continue;
196 }
197
198 if ( ! POP(state) ) SRF_RETURN_DONE(funcctx);
199 LAST(state)->idx++;
200 }
201
202 lwgeom->srid = state->root->srid;
203
204 values[0] = address;
205 values[1] = lwgeom_to_hexwkb_buffer(lwgeom, WKB_EXTENDED);
206 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
207 result = TupleGetDatum(funcctx->slot, tuple);
208 node->idx++;
209 SRF_RETURN_NEXT(funcctx, result);
210}
211
213{
214 uint32_t ringnum;
216};
217
219Datum LWGEOM_dump_rings(PG_FUNCTION_ARGS)
220{
221 GSERIALIZED *pglwgeom;
222 LWGEOM *lwgeom;
223 FuncCallContext *funcctx;
224 struct POLYDUMPSTATE *state;
225 TupleDesc tupdesc;
226 HeapTuple tuple;
227 MemoryContext oldcontext, newcontext;
228 Datum result;
229 char address[256];
230 char *values[2];
231
232 if (SRF_IS_FIRSTCALL())
233 {
234 funcctx = SRF_FIRSTCALL_INIT();
235 newcontext = funcctx->multi_call_memory_ctx;
236
237 oldcontext = MemoryContextSwitchTo(newcontext);
238
239 pglwgeom = PG_GETARG_GSERIALIZED_P_COPY(0);
240 if ( gserialized_get_type(pglwgeom) != POLYGONTYPE )
241 {
242 elog(ERROR, "Input is not a polygon");
243 }
244
245 lwgeom = lwgeom_from_gserialized(pglwgeom);
246
247 /* Create function state */
248 state = lwalloc(sizeof(struct POLYDUMPSTATE));
249 state->poly = lwgeom_as_lwpoly(lwgeom);
250 assert (state->poly);
251 state->ringnum=0;
252
253 funcctx->user_fctx = state;
254
255 /*
256 * Build a tuple description for an
257 * geometry_dump tuple
258 */
259 get_call_result_type(fcinfo, 0, &tupdesc);
260 BlessTupleDesc(tupdesc);
261
262 /*
263 * generate attribute metadata needed later to produce
264 * tuples from raw C strings
265 */
266 funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);;
267
268 MemoryContextSwitchTo(oldcontext);
269 }
270
271 /* stuff done on every call of the function */
272 funcctx = SRF_PERCALL_SETUP();
273 newcontext = funcctx->multi_call_memory_ctx;
274
275 /* get state */
276 state = funcctx->user_fctx;
277
278 /* Loop through polygon rings */
279 while (state->ringnum < state->poly->nrings )
280 {
281 LWPOLY* poly = state->poly;
282 POINTARRAY *ring;
283 LWGEOM* ringgeom;
284
285 /* Switch to an appropriate memory context for POINTARRAY
286 * cloning and hexwkb allocation */
287 oldcontext = MemoryContextSwitchTo(newcontext);
288
289 /* We need a copy of input ring here */
290 ring = ptarray_clone_deep(poly->rings[state->ringnum]);
291
292 /* Construct another polygon with shell only */
293 ringgeom = (LWGEOM*)lwpoly_construct(
294 poly->srid,
295 NULL, /* TODO: could use input bounding box here */
296 1, /* one ring */
297 &ring);
298
299 /* Write path as ``{ <ringnum> }'' */
300 sprintf(address, "{%d}", state->ringnum);
301
302 values[0] = address;
303 values[1] = lwgeom_to_hexwkb_buffer(ringgeom, WKB_EXTENDED);
304
305 MemoryContextSwitchTo(oldcontext);
306
307 tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
308 result = HeapTupleGetDatum(tuple);
309 ++state->ringnum;
310 SRF_RETURN_NEXT(funcctx, result);
311 }
312
313 SRF_RETURN_DONE(funcctx);
314
315}
316
317
318/*
319* Break an object up into smaller objects of no more than N vertices
320*/
322Datum ST_Subdivide(PG_FUNCTION_ARGS)
323{
324 typedef struct
325 {
326 int nextgeom;
327 int numgeoms;
328 LWCOLLECTION *col;
329 } collection_fctx;
330
331 FuncCallContext *funcctx;
332 collection_fctx *fctx;
333 MemoryContext oldcontext;
334
335 /* stuff done only on the first call of the function */
336 if (SRF_IS_FIRSTCALL())
337 {
338 GSERIALIZED *gser;
339 LWGEOM *geom;
340 LWCOLLECTION *col;
341 /* default to maxvertices < page size */
342 int maxvertices = 128;
343 double gridSize = -1;
344
345 /* create a function context for cross-call persistence */
346 funcctx = SRF_FIRSTCALL_INIT();
347
348 /*
349 * switch to memory context appropriate for multiple function calls
350 */
351 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
352
353 /*
354 * Get the geometry value
355 */
356 gser = PG_GETARG_GSERIALIZED_P(0);
357 geom = lwgeom_from_gserialized(gser);
358
359 /*
360 * Get the max vertices value
361 */
362 if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
363 maxvertices = PG_GETARG_INT32(1);
364
365 /*
366 * Get the gridSize value
367 */
368 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
369 gridSize = PG_GETARG_FLOAT8(2);
370
371 /*
372 * Compute the subdivision of the geometry
373 */
374 col = lwgeom_subdivide_prec(geom, maxvertices, gridSize);
375
376 if ( ! col )
377 SRF_RETURN_DONE(funcctx);
378
379 /* allocate memory for user context */
380 fctx = (collection_fctx *) palloc(sizeof(collection_fctx));
381
382 /* initialize state */
383 fctx->nextgeom = 0;
384 fctx->numgeoms = col->ngeoms;
385 fctx->col = col;
386
387 /* save user context, switch back to function context */
388 funcctx->user_fctx = fctx;
389 MemoryContextSwitchTo(oldcontext);
390 }
391
392 /* stuff done on every call of the function */
393 funcctx = SRF_PERCALL_SETUP();
394 fctx = funcctx->user_fctx;
395
396 if (fctx->nextgeom < fctx->numgeoms)
397 {
398 GSERIALIZED *gpart = geometry_serialize(fctx->col->geoms[fctx->nextgeom]);
399 fctx->nextgeom++;
400 SRF_RETURN_NEXT(funcctx, PointerGetDatum(gpart));
401 }
402 else
403 {
404 /* do when there is no more left */
405 SRF_RETURN_DONE(funcctx);
406 }
407}
408
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
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,...
char * lwgeom_to_hexwkb_buffer(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:845
void * lwalloc(size_t size)
Definition lwutil.c:227
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:243
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM contains sub-geometries or not This basically just checks that the struct ...
Definition lwgeom.c:1125
#define POLYGONTYPE
Definition liblwgeom.h:104
#define WKB_EXTENDED
Definition liblwgeom.h:2212
LWPOLY * lwpoly_construct(int32_t srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition lwpoly.c:43
LWCOLLECTION * lwgeom_subdivide_prec(const LWGEOM *geom, uint32_t maxvertices, double gridSize)
Definition lwgeom.c:2619
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
Definition ptarray.c:643
This library is the generic geometry handling section of PostGIS.
#define MAXDEPTH
Definition lwgeom_dump.c:55
Datum ST_Subdivide(PG_FUNCTION_ARGS)
struct GEOMDUMPNODE_T GEOMDUMPNODE
#define PUSH(x, y)
Definition lwgeom_dump.c:64
#define LAST(x)
Definition lwgeom_dump.c:65
Datum LWGEOM_dump_rings(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(LWGEOM_dump)
Datum LWGEOM_dump(PG_FUNCTION_ARGS)
Definition lwgeom_dump.c:70
#define POP(x)
Definition lwgeom_dump.c:66
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition lwinline.h:199
LWGEOM * geom
Definition lwgeom_dump.c:51
LWGEOM * root
Definition lwgeom_dump.c:60
GEOMDUMPNODE * stack[MAXDEPTH]
Definition lwgeom_dump.c:59
uint32_t ngeoms
Definition liblwgeom.h:580
LWGEOM ** geoms
Definition liblwgeom.h:575
int32_t srid
Definition liblwgeom.h:460
POINTARRAY ** rings
Definition liblwgeom.h:519
uint32_t nrings
Definition liblwgeom.h:524
int32_t srid
Definition liblwgeom.h:520
uint32_t ringnum
LWPOLY * poly