LWGEOM* lwgeom_flip_coordinates(LWGEOM *in) { LWCOLLECTION *col; LWPOLY *poly; int i; LWDEBUGF(4, "lwgeom_flip_coordinates, got type: %s", lwtype_name(in->type)); switch (in->type) { case POINTTYPE: ptarray_flip_coordinates(lwgeom_as_lwpoint(in)->point); return in; case LINETYPE: ptarray_flip_coordinates(lwgeom_as_lwline(in)->points); return in; case CIRCSTRINGTYPE: ptarray_flip_coordinates(lwgeom_as_lwcircstring(in)->points); return in; case POLYGONTYPE: poly = (LWPOLY *) in; for (i=0; i<poly->nrings; i++) ptarray_flip_coordinates(poly->rings[i]); return in; case TRIANGLETYPE: ptarray_flip_coordinates(lwgeom_as_lwtriangle(in)->points); return in; case MULTIPOINTTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: case COLLECTIONTYPE: case COMPOUNDTYPE: case CURVEPOLYTYPE: case MULTISURFACETYPE: case MULTICURVETYPE: case POLYHEDRALSURFACETYPE: case TINTYPE: col = (LWCOLLECTION *) in; for (i=0; i<col->ngeoms; i++) lwgeom_flip_coordinates(col->geoms[i]); return in; default: lwerror("lwgeom_flip_coordinates: unsupported geometry type: %s", lwtype_name(in->type)); } return NULL; }
Datum LWGEOM_dumppoints(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; MemoryContext oldcontext, newcontext; GSERIALIZED *pglwgeom; LWCOLLECTION *lwcoll; LWGEOM *lwgeom; struct dumpstate *state; struct dumpnode *node; HeapTuple tuple; Datum pathpt[2]; /* used to construct the composite return value */ bool isnull[2] = {0,0}; /* needed to say neither value is null */ Datum result; /* the actual composite return value */ if (SRF_IS_FIRSTCALL()) { funcctx = SRF_FIRSTCALL_INIT(); newcontext = funcctx->multi_call_memory_ctx; oldcontext = MemoryContextSwitchTo(newcontext); /* get a local copy of what we're doing a dump points on */ pglwgeom = PG_GETARG_GSERIALIZED_P_COPY(0); lwgeom = lwgeom_from_gserialized(pglwgeom); /* return early if nothing to do */ if (!lwgeom || lwgeom_is_empty(lwgeom)) { MemoryContextSwitchTo(oldcontext); funcctx = SRF_PERCALL_SETUP(); SRF_RETURN_DONE(funcctx); } /* Create function state */ state = lwalloc(sizeof *state); state->root = lwgeom; state->stacklen = 0; state->pathlen = 0; state->pt = 0; state->ring = 0; funcctx->user_fctx = state; /* * Push a struct dumpnode on the state stack */ state->stack[0].idx = 0; state->stack[0].geom = lwgeom; state->stacklen++; /* * get tuple description for return type */ if (get_call_result_type(fcinfo, 0, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); } BlessTupleDesc(funcctx->tuple_desc); /* get and cache data for constructing int4 arrays */ get_typlenbyvalalign(INT4OID, &state->typlen, &state->byval, &state->align); MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); newcontext = funcctx->multi_call_memory_ctx; /* get state */ state = funcctx->user_fctx; while (1) { node = &state->stack[state->stacklen-1]; lwgeom = node->geom; /* need to return a point from this geometry */ if (!lwgeom_is_collection(lwgeom)) { /* either return a point, or pop the stack */ /* TODO use a union? would save a tiny amount of stack space. * probably not worth the bother */ LWLINE *line; LWCIRCSTRING *circ; LWPOLY *poly; LWTRIANGLE *tri; LWPOINT *lwpoint = NULL; POINT4D pt; /* * net result of switch should be to set lwpoint to the * next point to return, or leave at NULL if there * are no more points in the geometry */ switch(lwgeom->type) { case TRIANGLETYPE: tri = lwgeom_as_lwtriangle(lwgeom); if (state->pt == 0) { state->path[state->pathlen++] = Int32GetDatum(state->ring+1); } if (state->pt <= 3) { getPoint4d_p(tri->points, state->pt, &pt); lwpoint = lwpoint_make(tri->srid, FLAGS_GET_Z(tri->points->flags), FLAGS_GET_M(tri->points->flags), &pt); } if (state->pt > 3) { state->pathlen--; } break; case POLYGONTYPE: poly = lwgeom_as_lwpoly(lwgeom); if (state->pt == poly->rings[state->ring]->npoints) { state->pt = 0; state->ring++; state->pathlen--; } if (state->pt == 0 && state->ring < poly->nrings) { /* handle new ring */ state->path[state->pathlen] = Int32GetDatum(state->ring+1); state->pathlen++; } if (state->ring == poly->nrings) { } else { /* TODO should be able to directly get the point * into the point array of a fixed lwpoint */ /* can't get the point directly from the ptarray because * it might be aligned wrong, so at least one memcpy * seems unavoidable * It might be possible to pass it directly to gserialized * depending how that works, it might effectively be gserialized * though a brief look at the code indicates not */ getPoint4d_p(poly->rings[state->ring], state->pt, &pt); lwpoint = lwpoint_make(poly->srid, FLAGS_GET_Z(poly->rings[state->ring]->flags), FLAGS_GET_M(poly->rings[state->ring]->flags), &pt); } break; case POINTTYPE: if (state->pt == 0) lwpoint = lwgeom_as_lwpoint(lwgeom); break; case LINETYPE: line = lwgeom_as_lwline(lwgeom); if (line->points && state->pt <= line->points->npoints) { lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, state->pt); } break; case CIRCSTRINGTYPE: circ = lwgeom_as_lwcircstring(lwgeom); if (circ->points && state->pt <= circ->points->npoints) { lwpoint = lwcircstring_get_lwpoint((LWCIRCSTRING*)lwgeom, state->pt); } break; default: ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("Invalid Geometry type %d passed to ST_DumpPoints()", lwgeom->type))); } /* * At this point, lwpoint is either NULL, in which case * we need to pop the geometry stack and get the next * geometry, if amy, or lwpoint is set and we construct * a record type with the integer array of geometry * indexes and the point number, and the actual point * geometry itself */ if (!lwpoint) { /* no point, so pop the geom and look for more */ if (--state->stacklen == 0) SRF_RETURN_DONE(funcctx); state->pathlen--; continue; } else { /* write address of current geom/pt */ state->pt++; state->path[state->pathlen] = Int32GetDatum(state->pt); pathpt[0] = PointerGetDatum(construct_array(state->path, state->pathlen+1, INT4OID, state->typlen, state->byval, state->align)); pathpt[1] = PointerGetDatum(gserialized_from_lwgeom((LWGEOM*)lwpoint,0,0)); tuple = heap_form_tuple(funcctx->tuple_desc, pathpt, isnull); result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } } lwcoll = (LWCOLLECTION*)node->geom; /* if a collection and we have more geoms */ if (node->idx < lwcoll->ngeoms) { /* push the next geom on the path and the stack */ lwgeom = lwcoll->geoms[node->idx++]; state->path[state->pathlen++] = Int32GetDatum(node->idx); node = &state->stack[state->stacklen++]; node->idx = 0; node->geom = lwgeom; state->pt = 0; state->ring = 0; /* loop back to beginning, which will then check whatever node we just pushed */ continue; } /* no more geometries in the current collection */ if (--state->stacklen == 0) SRF_RETURN_DONE(funcctx); state->pathlen--; state->stack[state->stacklen-1].idx++; } }
Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *result; POINTARRAY *extring; LWGEOM *lwgeom; LWLINE *line; GBOX *bbox=NULL; int type = gserialized_get_type(geom); POSTGIS_DEBUG(2, "LWGEOM_exteriorring_polygon called."); if ( (type != POLYGONTYPE) && (type != CURVEPOLYTYPE) && (type != TRIANGLETYPE)) { elog(ERROR, "ExteriorRing: geom is not a polygon"); PG_RETURN_NULL(); } lwgeom = lwgeom_from_gserialized(geom); if( lwgeom_is_empty(lwgeom) ) { line = lwline_construct_empty(lwgeom->srid, lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom)); result = geometry_serialize(lwline_as_lwgeom(line)); } else if ( lwgeom->type == POLYGONTYPE ) { LWPOLY *poly = lwgeom_as_lwpoly(lwgeom); /* Ok, now we have a polygon. Here is its exterior ring. */ extring = poly->rings[0]; /* * This is a LWLINE constructed by exterior ring POINTARRAY * If the input geom has a bbox, use it for * the output geom, as exterior ring makes it up ! */ if ( poly->bbox ) bbox = gbox_copy(poly->bbox); line = lwline_construct(poly->srid, bbox, extring); result = geometry_serialize((LWGEOM *)line); lwgeom_release((LWGEOM *)line); } else if ( lwgeom->type == TRIANGLETYPE ) { LWTRIANGLE *triangle = lwgeom_as_lwtriangle(lwgeom); /* * This is a LWLINE constructed by exterior ring POINTARRAY * If the input geom has a bbox, use it for * the output geom, as exterior ring makes it up ! */ if ( triangle->bbox ) bbox = gbox_copy(triangle->bbox); line = lwline_construct(triangle->srid, bbox, triangle->points); result = geometry_serialize((LWGEOM *)line); lwgeom_release((LWGEOM *)line); } else { LWCURVEPOLY *curvepoly = lwgeom_as_lwcurvepoly(lwgeom); result = geometry_serialize(curvepoly->rings[0]); } lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }