Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS) { PG_LWGEOM *geom; LWGEOM_INSPECTED *inspected; LWLINE *line = NULL; POINTARRAY *pts; LWPOINT *point; PG_LWGEOM *result; int i, type; POSTGIS_DEBUG(2, "LWGEOM_startpoint_linestring called."); geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); /* * Curved polygons and compound curves are both collections * that should not be traversed looking for linestrings. */ type = lwgeom_getType((uchar)SERIALIZED_FORM(geom)[0]); if (type == CURVEPOLYTYPE || type == COMPOUNDTYPE) { PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } inspected = lwgeom_inspect(SERIALIZED_FORM(geom)); for (i=0; i<inspected->ngeometries; i++) { line = lwgeom_getline_inspected(inspected, i); if ( line ) break; } if ( line == NULL ) { PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } /* Ok, now we have a line. */ /* Construct a point array */ pts = pointArray_construct(getPoint_internal(line->points, 0), TYPE_HASZ(line->type), TYPE_HASM(line->type), 1); lwgeom_release((LWGEOM *)line); /* Construct an LWPOINT */ point = lwpoint_construct(pglwgeom_getSRID(geom), NULL, pts); /* Construct a PG_LWGEOM */ result = pglwgeom_serialize((LWGEOM *)point); lwgeom_release((LWGEOM *)point); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
LWCURVEPOLY * lwcurvepoly_deserialize(uchar *srl) { LWCURVEPOLY *result; LWGEOM_INSPECTED *insp; int type = lwgeom_getType(srl[0]); int i; LWDEBUG(3, "lwcurvepoly_deserialize called."); if (type != CURVEPOLYTYPE) { lwerror("lwcurvepoly_deserialize called on NON curvepoly: %d", type); return NULL; } insp = lwgeom_inspect(srl); result = lwalloc(sizeof(LWCURVEPOLY)); result->type = insp->type; result->SRID = insp->SRID; result->nrings = insp->ngeometries; result->rings = lwalloc(sizeof(LWGEOM *)*insp->ngeometries); if (lwgeom_hasBBOX(srl[0])) { result->bbox = lwalloc(sizeof(BOX2DFLOAT4)); memcpy(result->bbox, srl + 1, sizeof(BOX2DFLOAT4)); } else result->bbox = NULL; for (i = 0; i < insp->ngeometries; i++) { result->rings[i] = lwgeom_deserialize(insp->sub_geoms[i]); if (lwgeom_getType(result->rings[i]->type) != CIRCSTRINGTYPE && lwgeom_getType(result->rings[i]->type) != LINETYPE && lwgeom_getType(result->rings[i]->type) != COMPOUNDTYPE) { lwerror("Only Circular curves, Linestrings and Compound curves are supported as rings, not %s (%d)", lwgeom_typename(result->rings[i]->type), result->rings[i]->type); lwfree(result); lwfree(insp); return NULL; } if (TYPE_NDIMS(result->rings[i]->type) != TYPE_NDIMS(result->type)) { lwerror("Mixed dimensions (curvepoly %d, ring %d)", TYPE_NDIMS(result->type), i, TYPE_NDIMS(result->rings[i]->type)); lwfree(result); lwfree(insp); return NULL; } } return result; }
Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS) { PG_LWGEOM *geom; LWGEOM_INSPECTED *inspected; LWLINE *line = NULL; POINTARRAY *pts; LWGEOM *point; PG_LWGEOM *result; int i, type; POSTGIS_DEBUG(2, "LWGEOM_endpoint_linestring called."); geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); type = lwgeom_getType((uchar)SERIALIZED_FORM(geom)[0]); if (type == CURVEPOLYTYPE || type == COMPOUNDTYPE) { PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } inspected = lwgeom_inspect(SERIALIZED_FORM(geom)); for (i=0; i<inspected->ngeometries; i++) { line = lwgeom_getline_inspected(inspected, i); if ( line ) break; } lwinspected_release(inspected); if ( line == NULL ) { PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } /* Ok, now we have a line. */ /* Construct a point array */ pts = pointArray_construct( getPoint_internal(line->points, line->points->npoints-1), TYPE_HASZ(line->type), TYPE_HASM(line->type), 1); lwgeom_release((LWGEOM *)line); /* Construct an LWPOINT */ point = (LWGEOM *)lwpoint_construct(pglwgeom_getSRID(geom), NULL, pts); /* Serialize an PG_LWGEOM */ result = pglwgeom_serialize(point); lwgeom_release(point); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
LWMPOLY * lwmpoly_deserialize(uchar *srl) { LWMPOLY *result; LWGEOM_INSPECTED *insp; int type = lwgeom_getType(srl[0]); int i; LWDEBUG(2, "lwmpoly_deserialize called"); if ( type != MULTIPOLYGONTYPE ) { lwerror("lwmpoly_deserialize called on NON multipoly: %d", type); return NULL; } insp = lwgeom_inspect(srl); result = lwalloc(sizeof(LWMPOLY)); result->type = insp->type; result->SRID = insp->SRID; result->ngeoms = insp->ngeometries; if ( insp->ngeometries ) { result->geoms = lwalloc(sizeof(LWPOLY *)*insp->ngeometries); } else { result->geoms = NULL; } if (lwgeom_hasBBOX(srl[0])) { result->bbox = lwalloc(sizeof(BOX2DFLOAT4)); memcpy(result->bbox, srl+1, sizeof(BOX2DFLOAT4)); } else result->bbox = NULL; for (i=0; i<insp->ngeometries; i++) { result->geoms[i] = lwpoly_deserialize(insp->sub_geoms[i]); if ( TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type) ) { lwerror("Mixed dimensions (multipoly:%d, poly%d:%d)", TYPE_NDIMS(result->type), i, TYPE_NDIMS(result->geoms[i]->type) ); return NULL; } } return result; }
LWCOMPOUND * lwcompound_deserialize(uchar *serialized) { LWCOMPOUND *result; LWGEOM_INSPECTED *insp; int type = lwgeom_getType(serialized[0]); int i; if(type != COMPOUNDTYPE) { lwerror("lwcompound_deserialize called on non compound: %d", type); return NULL; } insp = lwgeom_inspect(serialized); result = lwalloc(sizeof(LWCOMPOUND)); result->type = insp->type; result->SRID = insp->SRID; result->ngeoms = insp->ngeometries; result->geoms = lwalloc(sizeof(LWGEOM *)*insp->ngeometries); if(lwgeom_hasBBOX(serialized[0])) { result->bbox = lwalloc(sizeof(BOX2DFLOAT4)); memcpy(result->bbox, serialized + 1, sizeof(BOX2DFLOAT4)); } else result->bbox = NULL; for(i = 0; i < insp->ngeometries; i++) { if(lwgeom_getType(insp->sub_geoms[i][0]) == LINETYPE) result->geoms[i] = (LWGEOM *)lwline_deserialize(insp->sub_geoms[i]); else result->geoms[i] = (LWGEOM *)lwcircstring_deserialize(insp->sub_geoms[i]); if(TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type)) { lwerror("Mixed dimensions (compound: %d, line/circularstring %d:%d)", TYPE_NDIMS(result->type), i, TYPE_NDIMS(result->geoms[i]->type) ); lwfree(result); return NULL; } } return result; }
Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS) { PG_LWGEOM *geom; int32 wanted_index; LWGEOM_INSPECTED *inspected; LWLINE *line = NULL; LWCIRCSTRING *curve = NULL; LWGEOM *tmp = NULL; POINTARRAY *pts; LWPOINT *point; uchar *serializedpoint; PG_LWGEOM *result; int i, type; wanted_index = PG_GETARG_INT32(1); if ( wanted_index < 1 ) PG_RETURN_NULL(); /* index out of range */ geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); type = lwgeom_getType((uchar)SERIALIZED_FORM(geom)[0]); if (type == COMPOUNDTYPE || type == CURVEPOLYTYPE) { PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } else { inspected = lwgeom_inspect(SERIALIZED_FORM(geom)); for (i=0; i<inspected->ngeometries; i++) { tmp = lwgeom_getgeom_inspected(inspected, i); if (lwgeom_getType(tmp->type) == LINETYPE || lwgeom_getType(tmp->type) == CIRCSTRINGTYPE) break; } if ( tmp == NULL ) { lwinspected_release(inspected); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } if (lwgeom_getType(tmp->type) == CIRCSTRINGTYPE) { curve = (LWCIRCSTRING *)tmp; if (wanted_index > curve->points->npoints) { lwinspected_release(inspected); PG_FREE_IF_COPY(geom, 0); lwgeom_release(tmp); PG_RETURN_NULL(); } lwinspected_release(inspected); pts = pointArray_construct(getPoint_internal( curve->points, wanted_index-1), TYPE_HASZ(curve->type), TYPE_HASM(curve->type), 1); } else if (lwgeom_getType(tmp->type) == LINETYPE) { line = (LWLINE *)tmp; /* Ok, now we have a line. Let's see if it has enough points. */ if ( wanted_index > line->points->npoints ) { lwinspected_release(inspected); PG_FREE_IF_COPY(geom, 0); lwgeom_release(tmp); PG_RETURN_NULL(); } lwinspected_release(inspected); /* Construct a point array */ pts = pointArray_construct(getPoint_internal(line->points, wanted_index-1), TYPE_HASZ(line->type), TYPE_HASM(line->type), 1); } else { lwinspected_release(inspected); PG_FREE_IF_COPY(geom, 0); lwgeom_release(tmp); PG_RETURN_NULL(); } } /* Construct an LWPOINT */ point = lwpoint_construct(pglwgeom_getSRID(geom), NULL, pts); /* Serialized the point */ serializedpoint = lwpoint_serialize(point); /* And we construct the line * TODO: use serialize_buf above, instead .. */ result = PG_LWGEOM_construct(serializedpoint, pglwgeom_getSRID(geom), 0); pfree(point); pfree(serializedpoint); PG_FREE_IF_COPY(geom, 0); lwgeom_release(tmp); PG_RETURN_POINTER(result); }
Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS) { PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); LWGEOM_INSPECTED *inspected = NULL; LWGEOM *tmp = NULL; LWPOLY *poly = NULL; LWCURVEPOLY *curvepoly = NULL; int32 result; int i; POSTGIS_DEBUG(2, "LWGEOM_numinteriorrings called."); if (lwgeom_getType((uchar)SERIALIZED_FORM(geom)[0]) == CURVEPOLYTYPE) { tmp = (LWGEOM *)lwcurvepoly_deserialize(SERIALIZED_FORM(geom)); } else { inspected = lwgeom_inspect(SERIALIZED_FORM(geom)); for (i=0; i<inspected->ngeometries; i++) { tmp = lwgeom_getgeom_inspected(inspected, i); if (lwgeom_getType(tmp->type) == POLYGONTYPE || lwgeom_getType(tmp->type) == CURVEPOLYTYPE) break; } } if ( tmp == NULL ) { PG_FREE_IF_COPY(geom, 0); lwinspected_release(inspected); PG_RETURN_NULL(); } POSTGIS_DEBUGF(3, "Geometry of type %d found.", lwgeom_getType(tmp->type)); if (lwgeom_getType(tmp->type) == POLYGONTYPE) { poly = (LWPOLY *)tmp; /* Ok, now we have a polygon. Here is its number of holes */ result = poly->nrings-1; } else if (lwgeom_getType(tmp->type) == CURVEPOLYTYPE) { POSTGIS_DEBUG(3, "CurvePolygon found."); curvepoly = (LWCURVEPOLY *)tmp; result = curvepoly->nrings-1; } else { PG_FREE_IF_COPY(geom, 0); lwinspected_release(inspected); PG_RETURN_NULL(); } PG_FREE_IF_COPY(geom, 0); if (inspected != NULL) lwinspected_release(inspected); lwgeom_release((LWGEOM *)tmp); PG_RETURN_INT32(result); }
/** * @brief returns 0 for points, 1 for lines, 2 for polygons. * returns max dimension for a collection. * returns -1 for the empty geometry (TODO) * returns -2 on error */ static int32 lwgeom_dimension_recursive(const uchar *serialized) { LWGEOM_INSPECTED *inspected; int ret = -1; int i; /** @todo * This has the unfortunate habit of traversing the CURVEPOLYTYPe * geoms and returning 1, as all contained geoms are linear. * Here we preempt this problem. * TODO: This should handle things a bit better. Only * GEOMETRYCOLLECTION should ever need to be traversed. */ if (lwgeom_getType(serialized[0]) == CURVEPOLYTYPE) return 2; inspected = lwgeom_inspect(serialized); for (i=0; i<inspected->ngeometries; i++) { uchar *subgeom; char typeflags = lwgeom_getsubtype_inspected(inspected, i); int type = lwgeom_getType(typeflags); int dims=-1; LWDEBUGF(3, "lwgeom_dimension_recursive: type %d", type); if ( type == POINTTYPE ) dims = 0; else if ( type == MULTIPOINTTYPE ) dims=0; else if ( type == LINETYPE ) dims=1; else if ( type == CIRCSTRINGTYPE ) dims=1; else if ( type == COMPOUNDTYPE ) dims=1; else if ( type == MULTILINETYPE ) dims=1; else if ( type == MULTICURVETYPE ) dims=1; else if ( type == POLYGONTYPE ) dims=2; else if ( type == CURVEPOLYTYPE ) dims=2; else if ( type == MULTIPOLYGONTYPE ) dims=2; else if ( type == MULTISURFACETYPE ) dims=2; else if ( type == COLLECTIONTYPE ) { subgeom = lwgeom_getsubgeometry_inspected(inspected, i); if ( subgeom == NULL ) { lwinspected_release(inspected); return -2; } dims = lwgeom_dimension_recursive(subgeom); } if ( dims == 2 ) { /* nothing can be higher */ lwinspected_release(inspected); return 2; } if ( dims > ret ) ret = dims; } lwinspected_release(inspected); return ret; }
/** * Find first linestring in serialized geometry and return * the number of points in it. If no linestrings are found * return -1. */ static int32 lwgeom_numpoints_linestring_recursive(const uchar *serialized) { LWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized); int i; LWDEBUG(2, "lwgeom_numpoints_linestring_recursive called."); /* * CURVEPOLY and COMPOUND have no concept of numpoints but look like * collections once inspected. Fast-fail on these here. */ if (lwgeom_getType(inspected->type) == COMPOUNDTYPE || lwgeom_getType(inspected->type) == CURVEPOLYTYPE) { return -1; } for (i=0; i<inspected->ngeometries; i++) { int32 npoints; int type; LWGEOM *geom=NULL; uchar *subgeom; geom = lwgeom_getgeom_inspected(inspected, i); LWDEBUGF(3, "numpoints_recursive: type=%d", lwgeom_getType(geom->type)); if (lwgeom_getType(geom->type) == LINETYPE) { return ((LWLINE *)geom)->points->npoints; } else if (lwgeom_getType(geom->type) == CIRCSTRINGTYPE) { return ((LWCIRCSTRING *)geom)->points->npoints; } subgeom = lwgeom_getsubgeometry_inspected(inspected, i); if ( subgeom == NULL ) { elog(ERROR, "What ? lwgeom_getsubgeometry_inspected returned NULL??"); } type = lwgeom_getType(subgeom[0]); /* MULTILINESTRING && GEOMETRYCOLLECTION are worth checking */ if ( type != MULTILINETYPE && type != COLLECTIONTYPE ) continue; npoints = lwgeom_numpoints_linestring_recursive(subgeom); if ( npoints == -1 ) continue; lwinspected_release(inspected); return npoints; } lwinspected_release(inspected); return -1; }
Datum LWGEOM_isclosed_linestring(PG_FUNCTION_ARGS) { PG_LWGEOM *geom; LWGEOM_INSPECTED *inspected; LWGEOM *sub = NULL; LWCOMPOUND *compound = NULL; int linesfound=0; int i; POSTGIS_DEBUG(2, "LWGEOM_isclosed_linestring called."); geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); if (lwgeom_getType((uchar)SERIALIZED_FORM(geom)[0]) == COMPOUNDTYPE) { compound = lwcompound_deserialize(SERIALIZED_FORM(geom)); if (compound_is_closed(compound)) { lwgeom_release((LWGEOM *)compound); PG_FREE_IF_COPY(geom, 0); PG_RETURN_BOOL(TRUE); } else { lwgeom_release((LWGEOM *)compound); PG_FREE_IF_COPY(geom, 0); PG_RETURN_BOOL(FALSE); } } inspected = lwgeom_inspect(SERIALIZED_FORM(geom)); for (i=0; i<inspected->ngeometries; i++) { sub = lwgeom_getgeom_inspected(inspected, i); if ( sub == NULL ) continue; else if (lwgeom_getType(sub->type) == LINETYPE && !line_is_closed((LWLINE *)sub)) { lwgeom_release(sub); lwinspected_release(inspected); PG_FREE_IF_COPY(geom, 0); PG_RETURN_BOOL(FALSE); } else if (lwgeom_getType(sub->type) == CIRCSTRINGTYPE && !circstring_is_closed((LWCIRCSTRING *)sub)) { lwgeom_release(sub); lwinspected_release(inspected); PG_FREE_IF_COPY(geom, 0); PG_RETURN_BOOL(FALSE); } else if (lwgeom_getType(sub->type) == COMPOUNDTYPE && !compound_is_closed((LWCOMPOUND *)sub)) { lwgeom_release(sub); lwinspected_release(inspected); PG_FREE_IF_COPY(geom, 0); PG_RETURN_BOOL(FALSE); } lwgeom_release(sub); linesfound++; } lwinspected_release(inspected); if ( ! linesfound ) { PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } PG_FREE_IF_COPY(geom, 0); PG_RETURN_BOOL(TRUE); }
LWMCURVE * lwmcurve_deserialize(uchar *srl) { LWMCURVE *result; LWGEOM_INSPECTED *insp; int stype; int type = lwgeom_getType(srl[0]); int i; if (type != MULTICURVETYPE) { lwerror("lwmcurve_deserialize called on NON multicurve: %d", type); return NULL; } insp = lwgeom_inspect(srl); result = lwalloc(sizeof(LWMCURVE)); result->type = insp->type; result->SRID = insp->SRID; result->ngeoms = insp->ngeometries; if ( insp->ngeometries ) { result->geoms = lwalloc(sizeof(LWGEOM *)*insp->ngeometries); } else { result->geoms = NULL; } if (lwgeom_hasBBOX(srl[0])) { result->bbox = lwalloc(sizeof(BOX2DFLOAT4)); memcpy(result->bbox, srl+1, sizeof(BOX2DFLOAT4)); } else result->bbox = NULL; for (i = 0; i < insp->ngeometries; i++) { stype = lwgeom_getType(insp->sub_geoms[i][0]); if (stype == CIRCSTRINGTYPE) { result->geoms[i] = (LWGEOM *)lwcircstring_deserialize(insp->sub_geoms[i]); } else if (stype == LINETYPE) { result->geoms[i] = (LWGEOM *)lwline_deserialize(insp->sub_geoms[i]); } else if (stype == COMPOUNDTYPE) { result->geoms[i] = (LWGEOM *)lwcompound_deserialize(insp->sub_geoms[i]); } else { lwerror("Only Circular strings, Line strings or Compound curves are permitted in a MultiCurve."); lwfree(result); lwfree(insp); return NULL; } if (TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type)) { lwerror("Mixed dimensions (multicurve: %d, curve %d:%d)", TYPE_NDIMS(result->type), i, TYPE_NDIMS(result->geoms[i]->type)); lwfree(result); lwfree(insp); return NULL; } } return result; }
LWMSURFACE * lwmsurface_deserialize(uchar *srl) { LWMSURFACE *result; LWGEOM_INSPECTED *insp; int stype; int type = lwgeom_getType(srl[0]); int i; LWDEBUG(2, "lwmsurface_deserialize called"); if (type != MULTISURFACETYPE) { lwerror("lwmsurface_deserialize called on a non-multisurface: %d", type); return NULL; } insp = lwgeom_inspect(srl); result = lwalloc(sizeof(LWMSURFACE)); result->type = insp->type; result->SRID = insp->SRID; result->ngeoms = insp->ngeometries; if ( insp->ngeometries ) { result->geoms = lwalloc(sizeof(LWPOLY *)*insp->ngeometries); } else { result->geoms = NULL; } if (lwgeom_hasBBOX(srl[0])) { result->bbox = lwalloc(sizeof(BOX2DFLOAT4)); memcpy(result->bbox, srl + 1, sizeof(BOX2DFLOAT4)); } else result->bbox = NULL; for (i = 0; i < insp->ngeometries; i++) { stype = lwgeom_getType(insp->sub_geoms[i][0]); if (stype == POLYGONTYPE) { result->geoms[i] = (LWGEOM *)lwpoly_deserialize(insp->sub_geoms[i]); } else if (stype == CURVEPOLYTYPE) { result->geoms[i] = (LWGEOM *)lwcurvepoly_deserialize(insp->sub_geoms[i]); } else { lwerror("Only Polygons and Curved Polygons are supported in a MultiSurface."); lwfree(result); lwfree(insp); return NULL; } if (TYPE_NDIMS(result->geoms[i]->type) != TYPE_NDIMS(result->type)) { lwerror("Mixed dimensions (multisurface: %d, surface %d:%d", TYPE_NDIMS(result->type), i, TYPE_NDIMS(result->geoms[i]->type)); lwfree(result); lwfree(insp); return NULL; } } return result; }