PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ LWGEOM_dumppoints()

Datum LWGEOM_dumppoints ( PG_FUNCTION_ARGS  )

Definition at line 76 of file lwgeom_dumppoints.c.

76 {
77 FuncCallContext *funcctx;
78 MemoryContext oldcontext, newcontext;
79
80 GSERIALIZED *pglwgeom;
81 LWCOLLECTION *lwcoll;
82 LWGEOM *lwgeom;
83 struct dumpstate *state;
84 struct dumpnode *node;
85
86 HeapTuple tuple;
87 Datum pathpt[2]; /* used to construct the composite return value */
88 bool isnull[2] = {0,0}; /* needed to say neither value is null */
89 Datum result; /* the actual composite return value */
90
91 if (SRF_IS_FIRSTCALL()) {
92 funcctx = SRF_FIRSTCALL_INIT();
93
94 newcontext = funcctx->multi_call_memory_ctx;
95 oldcontext = MemoryContextSwitchTo(newcontext);
96
97 /* get a local copy of what we're doing a dump points on */
98 pglwgeom = PG_GETARG_GSERIALIZED_P_COPY(0);
99 lwgeom = lwgeom_from_gserialized(pglwgeom);
100
101 /* return early if nothing to do */
102 if (!lwgeom || lwgeom_is_empty(lwgeom)) {
103 MemoryContextSwitchTo(oldcontext);
104 funcctx = SRF_PERCALL_SETUP();
105 SRF_RETURN_DONE(funcctx);
106 }
107
108 /* Create function state */
109 state = lwalloc(sizeof *state);
110 state->root = lwgeom;
111 state->stacklen = 0;
112 state->pathlen = 0;
113 state->pt = 0;
114 state->ring = 0;
115
116 funcctx->user_fctx = state;
117
118 /*
119 * Push a struct dumpnode on the state stack
120 */
121
122 state->stack[0].idx = 0;
123 state->stack[0].geom = lwgeom;
124 state->stacklen++;
125
126 /*
127 * get tuple description for return type
128 */
129 if (get_call_result_type(fcinfo, 0, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE) {
130 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
131 errmsg("set-valued function called in context that cannot accept a set")));
132 }
133
134 BlessTupleDesc(funcctx->tuple_desc);
135
136 /* get and cache data for constructing int4 arrays */
137 get_typlenbyvalalign(INT4OID, &state->typlen, &state->byval, &state->align);
138
139 MemoryContextSwitchTo(oldcontext);
140 }
141
142 /* stuff done on every call of the function */
143 funcctx = SRF_PERCALL_SETUP();
144 newcontext = funcctx->multi_call_memory_ctx;
145
146 /* get state */
147 state = funcctx->user_fctx;
148
149 while (1) {
150 node = &state->stack[state->stacklen-1];
151 lwgeom = node->geom;
152
153 /* need to return a point from this geometry */
154 if (!lwgeom_is_collection(lwgeom) ) {
155 /* either return a point, or pop the stack */
156 /* TODO use a union? would save a tiny amount of stack space.
157 * probably not worth the bother
158 */
159 LWLINE *line;
160 LWCIRCSTRING *circ;
161 LWPOLY *poly;
162 LWTRIANGLE *tri;
163 LWPOINT *lwpoint = NULL;
164 POINT4D pt;
165
166 if ( !lwgeom_is_empty(lwgeom) ) {
167 /*
168 * net result of switch should be to set lwpoint to the
169 * next point to return, or leave at NULL if there
170 * are no more points in the geometry
171 */
172 switch(lwgeom->type) {
173 case TRIANGLETYPE:
174 tri = lwgeom_as_lwtriangle(lwgeom);
175 if (state->pt == 0) {
176 state->path[state->pathlen++] = Int32GetDatum(state->ring+1);
177 }
178 if (state->pt <= 3) {
179 getPoint4d_p(tri->points, state->pt, &pt);
180 lwpoint = lwpoint_make(tri->srid,
181 lwgeom_has_z(lwgeom),
182 lwgeom_has_m(lwgeom),
183 &pt);
184 }
185 if (state->pt > 3) {
186 state->pathlen--;
187 }
188 break;
189 case POLYGONTYPE:
190 poly = lwgeom_as_lwpoly(lwgeom);
191 if (state->pt == poly->rings[state->ring]->npoints) {
192 state->pt = 0;
193 state->ring++;
194 state->pathlen--;
195 }
196 if (state->pt == 0 && state->ring < poly->nrings) {
197 /* handle new ring */
198 state->path[state->pathlen] = Int32GetDatum(state->ring+1);
199 state->pathlen++;
200 }
201 if (state->ring == poly->nrings) {
202 } else {
203 /* TODO should be able to directly get the point
204 * into the point array of a fixed lwpoint
205 */
206 /* can't get the point directly from the ptarray because
207 * it might be aligned wrong, so at least one memcpy
208 * seems unavoidable
209 * It might be possible to pass it directly to gserialized
210 * depending how that works, it might effectively be gserialized
211 * though a brief look at the code indicates not
212 */
213 getPoint4d_p(poly->rings[state->ring], state->pt, &pt);
214 lwpoint = lwpoint_make(poly->srid,
215 lwgeom_has_z(lwgeom),
216 lwgeom_has_m(lwgeom),
217 &pt);
218 }
219 break;
220 case POINTTYPE:
221 if (state->pt == 0) lwpoint = lwgeom_as_lwpoint(lwgeom);
222 break;
223 case LINETYPE:
224 line = lwgeom_as_lwline(lwgeom);
225 if (line->points && state->pt <= line->points->npoints) {
226 lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, state->pt);
227 }
228 break;
229 case CIRCSTRINGTYPE:
230 circ = lwgeom_as_lwcircstring(lwgeom);
231 if (circ->points && state->pt <= circ->points->npoints) {
232 lwpoint = lwcircstring_get_lwpoint((LWCIRCSTRING*)lwgeom, state->pt);
233 }
234 break;
235 default:
236 ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
237 errmsg("Invalid Geometry type %d passed to ST_DumpPoints()", lwgeom->type)));
238 }
239 }
240
241 /*
242 * At this point, lwpoint is either NULL, in which case
243 * we need to pop the geometry stack and get the next
244 * geometry, if any, or lwpoint is set and we construct
245 * a record type with the integer array of geometry
246 * indexes and the point number, and the actual point
247 * geometry itself
248 */
249
250 if (!lwpoint) {
251 /* no point, so pop the geom and look for more */
252 if (--state->stacklen == 0) SRF_RETURN_DONE(funcctx);
253 state->pathlen--;
254 continue;
255 } else {
256 /* write address of current geom/pt */
257 state->pt++;
258
259 state->path[state->pathlen] = Int32GetDatum(state->pt);
260 pathpt[0] = PointerGetDatum(construct_array(state->path, state->pathlen+1,
261 INT4OID, state->typlen, state->byval, state->align));
262
263 pathpt[1] = PointerGetDatum(geometry_serialize((LWGEOM*)lwpoint));
264
265 tuple = heap_form_tuple(funcctx->tuple_desc, pathpt, isnull);
266 result = HeapTupleGetDatum(tuple);
267 SRF_RETURN_NEXT(funcctx, result);
268 }
269 }
270
271 lwcoll = (LWCOLLECTION*)node->geom;
272
273 /* if a collection and we have more geoms */
274 if (node->idx < lwcoll->ngeoms) {
275
276 if(state->stacklen >= MAXDEPTH)
277 elog(ERROR, "Unable to dump overly nested collection");
278
279 /* push the next geom on the path and the stack */
280 lwgeom = lwcoll->geoms[node->idx++];
281 state->path[state->pathlen++] = Int32GetDatum(node->idx);
282
283 node = &state->stack[state->stacklen++];
284 node->idx = 0;
285 node->geom = lwgeom;
286
287 state->pt = 0;
288 state->ring = 0;
289
290 /* loop back to beginning, which will then check whatever node we just pushed */
291 continue;
292 }
293
294 /* no more geometries in the current collection */
295 if (--state->stacklen == 0) SRF_RETURN_DONE(funcctx);
296 state->pathlen--;
297 }
298}
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.
LWPOINT * lwline_get_lwpoint(const LWLINE *line, uint32_t where)
Returns freshly allocated LWPOINT that corresponds to the index where.
Definition lwline.c:319
#define LINETYPE
Definition liblwgeom.h:103
LWPOINT * lwcircstring_get_lwpoint(const LWCIRCSTRING *circ, uint32_t where)
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition lwgeom.c:962
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:102
void * lwalloc(size_t size)
Definition lwutil.c:227
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:243
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition lwgeom.c:252
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
LWCIRCSTRING * lwgeom_as_lwcircstring(const LWGEOM *lwgeom)
Definition lwgeom.c:216
#define CIRCSTRINGTYPE
Definition liblwgeom.h:109
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition lwgeom_api.c:125
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition lwgeom.c:207
LWPOINT * lwpoint_make(int32_t srid, int hasz, int hasm, const POINT4D *p)
Definition lwpoint.c:206
#define TRIANGLETYPE
Definition liblwgeom.h:115
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:969
#define MAXDEPTH
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition lwinline.h:127
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
POINTARRAY * points
Definition liblwgeom.h:507
uint32_t ngeoms
Definition liblwgeom.h:580
LWGEOM ** geoms
Definition liblwgeom.h:575
uint8_t type
Definition liblwgeom.h:462
POINTARRAY * points
Definition liblwgeom.h:483
POINTARRAY ** rings
Definition liblwgeom.h:519
uint32_t nrings
Definition liblwgeom.h:524
int32_t srid
Definition liblwgeom.h:520
int32_t srid
Definition liblwgeom.h:496
POINTARRAY * points
Definition liblwgeom.h:495
uint32_t npoints
Definition liblwgeom.h:427
LWGEOM * geom
Datum path[34]
struct dumpnode stack[MAXDEPTH]

References dumpstate::align, dumpstate::byval, CIRCSTRINGTYPE, dumpnode::geom, LWCOLLECTION::geoms, getPoint4d_p(), dumpnode::idx, LINETYPE, lwalloc(), lwcircstring_get_lwpoint(), lwgeom_as_lwcircstring(), lwgeom_as_lwline(), lwgeom_as_lwpoint(), lwgeom_as_lwpoly(), lwgeom_as_lwtriangle(), lwgeom_from_gserialized(), lwgeom_has_m(), lwgeom_has_z(), lwgeom_is_collection(), lwgeom_is_empty(), lwline_get_lwpoint(), lwpoint_make(), MAXDEPTH, LWCOLLECTION::ngeoms, POINTARRAY::npoints, LWPOLY::nrings, dumpstate::path, dumpstate::pathlen, LWLINE::points, LWTRIANGLE::points, LWCIRCSTRING::points, POINTTYPE, POLYGONTYPE, dumpstate::pt, result, dumpstate::ring, LWPOLY::rings, dumpstate::root, LWTRIANGLE::srid, LWPOLY::srid, dumpstate::stack, dumpstate::stacklen, TRIANGLETYPE, LWGEOM::type, and dumpstate::typlen.

Here is the call graph for this function: