PostGIS  2.5.7dev-r@@SVN_REVISION@@

◆ 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  FLAGS_GET_Z(tri->points->flags),
181  FLAGS_GET_M(tri->points->flags),
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  FLAGS_GET_Z(poly->rings[state->ring]->flags),
215  FLAGS_GET_M(poly->rings[state->ring]->flags),
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(gserialized_from_lwgeom((LWGEOM*)lwpoint,0));
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.
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:170
LWPOINT * lwcircstring_get_lwpoint(const LWCIRCSTRING *circ, uint32_t where)
Definition: lwcircstring.c:293
#define LINETYPE
Definition: liblwgeom.h:86
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
Definition: liblwgeom.h:140
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:161
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition: lwgeom.c:215
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM can contain sub-geometries or not.
Definition: lwgeom.c:1085
#define POLYGONTYPE
Definition: liblwgeom.h:87
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:92
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:141
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwgeom.c:1393
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:123
#define TRIANGLETYPE
Definition: liblwgeom.h:98
void * lwalloc(size_t size)
Definition: lwutil.c:229
LWCIRCSTRING * lwgeom_as_lwcircstring(const LWGEOM *lwgeom)
Definition: lwgeom.c:179
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:206
LWPOINT * lwpoint_make(int srid, int hasz, int hasm, const POINT4D *p)
Definition: lwpoint.c:206
LWPOINT * lwline_get_lwpoint(const LWLINE *line, uint32_t where)
Returns freshly allocated LWPOINT that corresponds to the index where.
Definition: lwline.c:318
if(!(yy_init))
POINTARRAY * points
Definition: liblwgeom.h:447
uint32_t ngeoms
Definition: liblwgeom.h:510
LWGEOM ** geoms
Definition: liblwgeom.h:512
uint8_t type
Definition: liblwgeom.h:399
POINTARRAY * points
Definition: liblwgeom.h:425
POINTARRAY ** rings
Definition: liblwgeom.h:460
uint32_t nrings
Definition: liblwgeom.h:458
int32_t srid
Definition: liblwgeom.h:457
int32_t srid
Definition: liblwgeom.h:435
POINTARRAY * points
Definition: liblwgeom.h:436
uint32_t npoints
Definition: liblwgeom.h:374
uint8_t flags
Definition: liblwgeom.h:372
uint32_t idx
LWGEOM * geom
Datum path[34]
LWGEOM * root
struct dumpnode stack[MAXDEPTH]
uint32_t ring

References dumpstate::align, dumpstate::byval, CIRCSTRINGTYPE, POINTARRAY::flags, FLAGS_GET_M, FLAGS_GET_Z, dumpnode::geom, LWCOLLECTION::geoms, getPoint4d_p(), gserialized_from_lwgeom(), dumpnode::idx, if(), LINETYPE, lwalloc(), lwcircstring_get_lwpoint(), lwgeom_as_lwcircstring(), lwgeom_as_lwline(), lwgeom_as_lwpoint(), lwgeom_as_lwpoly(), lwgeom_as_lwtriangle(), lwgeom_from_gserialized(), 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: