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

◆ LWGEOM_dumppoints()

Datum LWGEOM_dumppoints ( PG_FUNCTION_ARGS  )

Definition at line 75 of file lwgeom_dumppoints.c.

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

References dumpstate::align, dumpstate::byval, CIRCSTRINGTYPE, dumpnode::geom, geometry_serialize(), 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(), LWCOLLECTION::ngeoms, POINTARRAY::npoints, LWPOLY::nrings, dumpstate::path, dumpstate::pathlen, LWLINE::points, LWTRIANGLE::points, LWCIRCSTRING::points, POINTTYPE, POLYGONTYPE, dumpstate::pt, 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: