void lwgeom_add_bbox_deep(LWGEOM *lwgeom, GBOX *gbox) { if ( lwgeom_is_empty(lwgeom) ) return; FLAGS_SET_BBOX(lwgeom->flags, 1); if ( ! ( gbox || lwgeom->bbox ) ) { lwgeom->bbox = gbox_new(lwgeom->flags); lwgeom_calculate_gbox(lwgeom, lwgeom->bbox); } else if ( gbox && ! lwgeom->bbox ) { lwgeom->bbox = gbox_clone(gbox); } if ( lwgeom_is_collection(lwgeom) ) { int i; LWCOLLECTION *lwcol = (LWCOLLECTION*)lwgeom; for ( i = 0; i < lwcol->ngeoms; i++ ) { lwgeom_add_bbox_deep(lwcol->geoms[i], lwgeom->bbox); } } }
double lwgeom_perimeter_2d(const LWGEOM *geom) { int type = geom->type; if ( type == POLYGONTYPE ) return lwpoly_perimeter_2d((LWPOLY*)geom); else if ( type == CURVEPOLYTYPE ) return lwcurvepoly_perimeter_2d((LWCURVEPOLY*)geom); else if ( type == TRIANGLETYPE ) return lwtriangle_perimeter_2d((LWTRIANGLE*)geom); else if ( type == POLYHEDRALSURFACETYPE || type == TINTYPE ) { return tgeom_perimeter(tgeom_from_lwgeom(geom)); } else if ( lwgeom_is_collection(geom) ) { double perimeter = 0.0; int i; LWCOLLECTION *col = (LWCOLLECTION*)geom; for ( i = 0; i < col->ngeoms; i++ ) perimeter += lwgeom_perimeter_2d(col->geoms[i]); return perimeter; } else return 0.0; }
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom) { if ( lwgeom == NULL ) return NULL; if ( lwgeom_is_collection(lwgeom) ) return (LWCOLLECTION*)lwgeom; else return NULL; }
static size_t asx3d3_collection_buf(const LWCOLLECTION *col, char *srs, char *output, int precision, int opts, const char *defid) { char *ptr; int i; LWGEOM *subgeom; ptr = output; /* Open outmost tag */ if ( srs ) { ptr += sprintf(ptr, "<%sMultiGeometry srsName=\"%s\">", defid, srs); } else { ptr += sprintf(ptr, "<%sMultiGeometry>", defid); } for (i=0; i<col->ngeoms; i++) { subgeom = col->geoms[i]; ptr += sprintf(ptr, "<%sgeometryMember>", defid); if ( subgeom->type == POINTTYPE ) { ptr += asx3d3_point_buf((LWPOINT*)subgeom, 0, ptr, precision, opts, defid); } else if ( subgeom->type == LINETYPE ) { ptr += asx3d3_line_buf((LWLINE*)subgeom, 0, ptr, precision, opts, defid); } else if ( subgeom->type == POLYGONTYPE ) { ptr += asx3d3_poly_buf((LWPOLY*)subgeom, 0, ptr, precision, opts, 0, defid); } else if ( lwgeom_is_collection(subgeom) ) { if ( subgeom->type == COLLECTIONTYPE ) ptr += asx3d3_collection_buf((LWCOLLECTION*)subgeom, 0, ptr, precision, opts, defid); else ptr += asx3d3_multi_buf((LWCOLLECTION*)subgeom, 0, ptr, precision, opts, defid); } else lwerror("asx3d3_collection_buf: unknown geometry type"); ptr += sprintf(ptr, "</%sgeometryMember>", defid); } /* Close outmost tag */ ptr += sprintf(ptr, "</%sMultiGeometry>", defid); return (ptr-output); }
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine) { int type = geom->type; int i; switch(type) { /* Take advantage of fact tht pt/ln/circ/tri have same memory structure */ case POINTTYPE: case LINETYPE: case CIRCSTRINGTYPE: case TRIANGLETYPE: { LWLINE *l = (LWLINE*)geom; ptarray_affine(l->points, affine); break; } case POLYGONTYPE: { LWPOLY *p = (LWPOLY*)geom; for( i = 0; i < p->nrings; i++ ) ptarray_affine(p->rings[i], affine); break; } case CURVEPOLYTYPE: { LWCURVEPOLY *c = (LWCURVEPOLY*)geom; for( i = 0; i < c->nrings; i++ ) lwgeom_affine(c->rings[i], affine); break; } default: { if( lwgeom_is_collection(geom) ) { LWCOLLECTION *c = (LWCOLLECTION*)geom; for( i = 0; i < c->ngeoms; i++ ) { lwgeom_affine(c->geoms[i], affine); } } else { lwerror("lwgeom_affine: unable to handle type '%s'", lwtype_name(type)); } } } }
/** * Convert LWGEOM to a char* in TWKB format. Caller is responsible for freeing * the returned array. */ uint8_t* lwgeom_to_twkb_with_idlist(const LWGEOM *geom, int64_t *idlist, uint8_t variant, int8_t precision_xy, int8_t precision_z, int8_t precision_m, size_t *twkb_size) { LWDEBUGF(2, "Entered %s", __func__); LWDEBUGF(2, "variant value %x", variant); TWKB_GLOBALS tg; TWKB_STATE ts; uint8_t *twkb; memset(&ts, 0, sizeof(TWKB_STATE)); memset(&tg, 0, sizeof(TWKB_GLOBALS)); tg.variant = variant; tg.prec_xy = precision_xy; tg.prec_z = precision_z; tg.prec_m = precision_m; if ( idlist && ! lwgeom_is_collection(geom) ) { lwerror("Only collections can support ID lists"); return NULL; } if ( ! geom ) { LWDEBUG(4,"Cannot convert NULL into TWKB."); lwerror("Cannot convert NULL into TWKB"); return NULL; } ts.idlist = idlist; ts.header_buf = NULL; ts.geom_buf = bytebuffer_create(); lwgeom_write_to_buffer(geom, &tg, &ts); if ( twkb_size ) *twkb_size = bytebuffer_getlength(ts.geom_buf); twkb = ts.geom_buf->buf_start; lwfree(ts.geom_buf); return twkb; }
/** * Create a new LWGEOM of the appropriate MULTI* type. */ LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom) { LWGEOM **ogeoms; LWGEOM *ogeom = NULL; GBOX *box = NULL; int type; /* ** This funx is a no-op only if a bbox cache is already present ** in input. */ if ( lwgeom_is_collection(lwgeom) ) { return lwgeom_clone(lwgeom); } type = lwgeom->type; if ( ! MULTITYPE[type] ) return lwgeom_clone(lwgeom); if( lwgeom_is_empty(lwgeom) ) { ogeom = (LWGEOM *)lwcollection_construct_empty( MULTITYPE[type], lwgeom->srid, FLAGS_GET_Z(lwgeom->flags), FLAGS_GET_M(lwgeom->flags) ); } else { ogeoms = lwalloc(sizeof(LWGEOM*)); ogeoms[0] = lwgeom_clone(lwgeom); /* Sub-geometries are not allowed to have bboxes or SRIDs, move the bbox to the collection */ box = ogeoms[0]->bbox; ogeoms[0]->bbox = NULL; ogeoms[0]->srid = SRID_UNKNOWN; ogeom = (LWGEOM *)lwcollection_construct(MULTITYPE[type], lwgeom->srid, box, 1, ogeoms); } return ogeom; }
void lwgeom_set_srid(LWGEOM *geom, int32_t srid) { int i; LWDEBUGF(4,"entered with srid=%d",srid); geom->srid = srid; if ( lwgeom_is_collection(geom) ) { /* All the children are set to the unknown SRID value TODO: change this so the children have a known SRID? */ LWCOLLECTION *col = lwgeom_as_lwcollection(geom); for ( i = 0; i < col->ngeoms; i++ ) { lwgeom_set_srid(col->geoms[i], SRID_UNKNOWN); } } }
int lwgeom_is_closed(const LWGEOM *geom) { int type = geom->type; if( lwgeom_is_empty(geom) ) return LW_FALSE; /* Test linear types for closure */ switch (type) { case LINETYPE: return lwline_is_closed((LWLINE*)geom); case POLYGONTYPE: return lwpoly_is_closed((LWPOLY*)geom); case CIRCSTRINGTYPE: return lwcircstring_is_closed((LWCIRCSTRING*)geom); case COMPOUNDTYPE: return lwcompound_is_closed((LWCOMPOUND*)geom); case TINTYPE: return lwtin_is_closed((LWTIN*)geom); case POLYHEDRALSURFACETYPE: return lwpsurface_is_closed((LWPSURFACE*)geom); } /* Recurse into collections and see if anything is not closed */ if ( lwgeom_is_collection(geom) ) { LWCOLLECTION *col = lwgeom_as_lwcollection(geom); int i; int closed; for ( i = 0; i < col->ngeoms; i++ ) { closed = lwgeom_is_closed(col->geoms[i]); if ( ! closed ) return LW_FALSE; } return LW_TRUE; } /* All non-linear non-collection types we will call closed */ return LW_TRUE; }
Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); LWGEOM *lwgeom; int32 ret = 1; lwgeom = lwgeom_from_gserialized(geom); if ( lwgeom_is_empty(lwgeom) ) { ret = 0; } else if ( lwgeom_is_collection(lwgeom) ) { LWCOLLECTION *col = lwgeom_as_lwcollection(lwgeom); ret = col->ngeoms; } lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_INT32(ret); }
double lwgeom_length_2d(const LWGEOM *geom) { int type = geom->type; if ( type == LINETYPE ) return lwline_length_2d((LWLINE*)geom); else if ( type == CIRCSTRINGTYPE ) return lwcircstring_length_2d((LWCIRCSTRING*)geom); else if ( type == COMPOUNDTYPE ) return lwcompound_length_2d((LWCOMPOUND*)geom); else if ( lwgeom_is_collection(geom) ) { double length = 0.0; int i; LWCOLLECTION *col = (LWCOLLECTION*)geom; for ( i = 0; i < col->ngeoms; i++ ) length += lwgeom_length_2d(col->geoms[i]); return length; } else return 0.0; }
static size_t asx3d3_collection_size(const LWCOLLECTION *col, char *srs, int precision, int opts, const char *defid) { int i; size_t size; size_t defidlen = strlen(defid); LWGEOM *subgeom; size = sizeof("<MultiGeometry></MultiGeometry>") + defidlen*2; if ( srs ) size += strlen(srs) + sizeof(" srsName=.."); for (i=0; i<col->ngeoms; i++) { subgeom = col->geoms[i]; size += ( sizeof("<geometryMember>/") + defidlen ) * 2; if ( subgeom->type == POINTTYPE ) { size += asx3d3_point_size((LWPOINT*)subgeom, 0, precision, opts, defid); } else if ( subgeom->type == LINETYPE ) { size += asx3d3_line_size((LWLINE*)subgeom, 0, precision, opts, defid); } else if ( subgeom->type == POLYGONTYPE ) { size += asx3d3_poly_size((LWPOLY*)subgeom, 0, precision, opts, defid); } else if ( lwgeom_is_collection(subgeom) ) { size += asx3d3_multi_size((LWCOLLECTION*)subgeom, 0, precision, opts, defid); } else lwerror("asx3d3_collection_size: unknown geometry type"); } return size; }
double lwgeom_area(const LWGEOM *geom) { int type = geom->type; if ( type == POLYGONTYPE ) return lwpoly_area((LWPOLY*)geom); else if ( type == CURVEPOLYTYPE ) return lwcurvepoly_area((LWCURVEPOLY*)geom); else if (type == TRIANGLETYPE ) return lwtriangle_area((LWTRIANGLE*)geom); else if ( lwgeom_is_collection(geom) ) { double area = 0.0; int i; LWCOLLECTION *col = (LWCOLLECTION*)geom; for ( i = 0; i < col->ngeoms; i++ ) area += lwgeom_area(col->geoms[i]); return area; } else return 0.0; }
/* ** Given a generic geometry, return the "simplest" form. ** ** eg: ** LINESTRING() => LINESTRING() ** ** MULTILINESTRING(with a single line) => LINESTRING() ** ** GEOMETRYCOLLECTION(MULTILINESTRING()) => MULTILINESTRING() ** ** GEOMETRYCOLLECTION(MULTILINESTRING(), MULTILINESTRING(), POINT()) ** => GEOMETRYCOLLECTION(MULTILINESTRING(), POINT()) */ LWGEOM * lwgeom_homogenize(const LWGEOM *geom) { LWGEOM *hgeom; /* EMPTY Geometry */ if (lwgeom_is_empty(geom)) { if( lwgeom_is_collection(geom) ) { return lwcollection_as_lwgeom(lwcollection_construct_empty(geom->type, geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom))); } return lwgeom_clone(geom); } switch (geom->type) { /* Return simple geometries untouched */ case POINTTYPE: case LINETYPE: case CIRCSTRINGTYPE: case COMPOUNDTYPE: case TRIANGLETYPE: case CURVEPOLYTYPE: case POLYGONTYPE: return lwgeom_clone(geom); /* Process homogeneous geometries lightly */ case MULTIPOINTTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: case MULTICURVETYPE: case MULTISURFACETYPE: case POLYHEDRALSURFACETYPE: case TINTYPE: { LWCOLLECTION *col = (LWCOLLECTION*)geom; /* Strip single-entry multi-geometries down to singletons */ if ( col->ngeoms == 1 ) { hgeom = lwgeom_clone((LWGEOM*)(col->geoms[0])); hgeom->srid = geom->srid; if (geom->bbox) hgeom->bbox = gbox_copy(geom->bbox); return hgeom; } /* Return proper multigeometry untouched */ return lwgeom_clone(geom); } /* Work on anonymous collections separately */ case COLLECTIONTYPE: return lwcollection_homogenize((LWCOLLECTION *) geom); } /* Unknown type */ lwerror("lwgeom_homogenize: Geometry Type not supported (%i)", lwtype_name(geom->type)); return NULL; /* Never get here! */ }
LWGEOM* lwgeom_node(const LWGEOM* lwgeom_in) { #if POSTGIS_GEOS_VERSION < 33 lwerror("The GEOS version this postgis binary " "was compiled against (%d) doesn't support " "'GEOSUnaryUnion' function (3.3.0+ required)", POSTGIS_GEOS_VERSION); return NULL; #else /* POSTGIS_GEOS_VERSION >= 33 */ GEOSGeometry *g1, *gu, *gm; LWGEOM *ep, *lines; LWCOLLECTION *col, *tc; int pn, ln, np, nl; if ( lwgeom_dimension(lwgeom_in) != 1 ) { lwerror("Noding geometries of dimension != 1 is unsupported"); return NULL; } initGEOS(lwgeom_geos_error, lwgeom_geos_error); g1 = LWGEOM2GEOS(lwgeom_in); if ( ! g1 ) { lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg); return NULL; } ep = lwgeom_extract_unique_endpoints(lwgeom_in); if ( ! ep ) { GEOSGeom_destroy(g1); lwerror("Error extracting unique endpoints from input"); return NULL; } /* Unary union input to fully node */ gu = GEOSUnaryUnion(g1); GEOSGeom_destroy(g1); if ( ! gu ) { lwgeom_free(ep); lwerror("GEOSUnaryUnion: %s", lwgeom_geos_errmsg); return NULL; } /* Linemerge (in case of overlaps) */ gm = GEOSLineMerge(gu); GEOSGeom_destroy(gu); if ( ! gm ) { lwgeom_free(ep); lwerror("GEOSLineMerge: %s", lwgeom_geos_errmsg); return NULL; } lines = GEOS2LWGEOM(gm, FLAGS_GET_Z(lwgeom_in->flags)); GEOSGeom_destroy(gm); if ( ! lines ) { lwgeom_free(ep); lwerror("Error during GEOS2LWGEOM"); return NULL; } /* * Reintroduce endpoints from input, using split-line-by-point. * Note that by now we can be sure that each point splits at * most _one_ segment as any point shared by multiple segments * would already be a node. Also we can be sure that any of * the segments endpoints won't split any other segment. * We can use the above 2 assertions to early exit the loop. */ col = lwcollection_construct_empty(MULTILINETYPE, lwgeom_in->srid, FLAGS_GET_Z(lwgeom_in->flags), FLAGS_GET_M(lwgeom_in->flags)); np = lwgeom_ngeoms(ep); for (pn=0; pn<np; ++pn) { /* for each point */ const LWPOINT* p = (LWPOINT*)lwgeom_subgeom(ep, pn); nl = lwgeom_ngeoms(lines); for (ln=0; ln<nl; ++ln) { /* for each line */ const LWLINE* l = (LWLINE*)lwgeom_subgeom(lines, ln); int s = lwline_split_by_point_to(l, p, (LWMLINE*)col); if ( ! s ) continue; /* not on this line */ if ( s == 1 ) { /* found on this line, but not splitting it */ break; } /* splits this line */ /* replace this line with the two splits */ if ( lwgeom_is_collection(lines) ) { tc = (LWCOLLECTION*)lines; lwcollection_reserve(tc, nl + 1); while (nl > ln+1) { tc->geoms[nl] = tc->geoms[nl-1]; --nl; } lwgeom_free(tc->geoms[ln]); tc->geoms[ln] = col->geoms[0]; tc->geoms[ln+1] = col->geoms[1]; tc->ngeoms++; } else { lwgeom_free(lines); /* transfer ownership rather than cloning */ lines = (LWGEOM*)lwcollection_clone_deep(col); assert(col->ngeoms == 2); lwgeom_free(col->geoms[0]); lwgeom_free(col->geoms[1]); } /* reset the vector */ assert(col->ngeoms == 2); col->ngeoms = 0; break; } } lwgeom_free(ep); lwcollection_free(col); lines->srid = lwgeom_in->srid; return (LWGEOM*)lines; #endif /* POSTGIS_GEOS_VERSION >= 33 */ }
/** This is a recursive function delivering every possible combination of subgeometries */ int lw_dist3d_recursive(const LWGEOM *lwg1,const LWGEOM *lwg2, DISTPTS3D *dl) { int i, j; int n1=1; int n2=1; LWGEOM *g1 = NULL; LWGEOM *g2 = NULL; LWCOLLECTION *c1 = NULL; LWCOLLECTION *c2 = NULL; LWDEBUGF(2, "lw_dist3d_recursive is called with type1=%d, type2=%d", lwg1->type, lwg2->type); if (lwgeom_is_collection(lwg1)) { LWDEBUG(3, "First geometry is collection"); c1 = lwgeom_as_lwcollection(lwg1); n1 = c1->ngeoms; } if (lwgeom_is_collection(lwg2)) { LWDEBUG(3, "Second geometry is collection"); c2 = lwgeom_as_lwcollection(lwg2); n2 = c2->ngeoms; } for ( i = 0; i < n1; i++ ) { if (lwgeom_is_collection(lwg1)) { g1 = c1->geoms[i]; } else { g1 = (LWGEOM*)lwg1; } if (lwgeom_is_empty(g1)) return LW_TRUE; if (lwgeom_is_collection(g1)) { LWDEBUG(3, "Found collection inside first geometry collection, recursing"); if (!lw_dist3d_recursive(g1, lwg2, dl)) return LW_FALSE; continue; } for ( j = 0; j < n2; j++ ) { if (lwgeom_is_collection(lwg2)) { g2 = c2->geoms[j]; } else { g2 = (LWGEOM*)lwg2; } if (lwgeom_is_collection(g2)) { LWDEBUG(3, "Found collection inside second geometry collection, recursing"); if (!lw_dist3d_recursive(g1, g2, dl)) return LW_FALSE; continue; } /*If one of geometries is empty, return. True here only means continue searching. False would have stoped the process*/ if (lwgeom_is_empty(g1)||lwgeom_is_empty(g2)) return LW_TRUE; if (!lw_dist3d_distribute_bruteforce(g1, g2, dl)) return LW_FALSE; if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return LW_TRUE; /*just a check if the answer is already given*/ } } return LW_TRUE; }
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++; } }