LWGEOM* lwmpoint_remove_repeated_points(const LWMPOINT *mpoint, double tolerance) { uint32_t nnewgeoms; uint32_t i, j; LWGEOM **newgeoms; LWGEOM *lwpt1, *lwpt2; newgeoms = lwalloc(sizeof(LWGEOM *)*mpoint->ngeoms); nnewgeoms = 0; for (i=0; i<mpoint->ngeoms; ++i) { lwpt1 = (LWGEOM*)mpoint->geoms[i]; /* Brute force, may be optimized by building an index */ int seen=0; for (j=0; j<nnewgeoms; ++j) { lwpt2 = (LWGEOM*)newgeoms[j]; if ( lwgeom_mindistance2d(lwpt1, lwpt2) <= tolerance ) { seen=1; break; } } if ( seen ) continue; newgeoms[nnewgeoms++] = lwgeom_clone_deep(lwpt1); } return (LWGEOM*)lwcollection_construct(mpoint->type, mpoint->srid, mpoint->bbox ? gbox_copy(mpoint->bbox) : NULL, nnewgeoms, newgeoms); }
LWGEOM* lwmpoint_remove_repeated_points(LWMPOINT *mpoint) { uint32_t nnewgeoms; uint32_t i, j; LWGEOM **newgeoms; newgeoms = lwalloc(sizeof(LWGEOM *)*mpoint->ngeoms); nnewgeoms = 0; for (i=0; i<mpoint->ngeoms; ++i) { /* Brute force, may be optimized by building an index */ int seen=0; for (j=0; j<nnewgeoms; ++j) { if ( lwpoint_same((LWPOINT*)newgeoms[j], (LWPOINT*)mpoint->geoms[i]) ) { seen=1; break; } } if ( seen ) continue; newgeoms[nnewgeoms++] = (LWGEOM*)lwpoint_clone(mpoint->geoms[i]); } return (LWGEOM*)lwcollection_construct(mpoint->type, mpoint->srid, mpoint->bbox ? gbox_copy(mpoint->bbox) : NULL, nnewgeoms, newgeoms); }
Datum BOX2D_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); int nitems; double tmp; GBOX box; gbox_init(&box); if (strstr(str,"BOX(") != str ) { elog(ERROR,"box2d parser - doesnt start with BOX("); PG_RETURN_NULL(); } nitems = sscanf(str,"BOX(%lf %lf,%lf %lf)", &box.xmin, &box.ymin, &box.xmax, &box.ymax); if (nitems != 4) { elog(ERROR,"box2d parser - couldnt parse. It should look like: BOX(xmin ymin,xmax ymax)"); PG_RETURN_NULL(); } if (box.xmin > box.xmax) { tmp = box.xmin; box.xmin = box.xmax; box.xmax = tmp; } if (box.ymin > box.ymax) { tmp = box.ymin; box.ymin = box.ymax; box.ymax = tmp; } PG_RETURN_POINTER(gbox_copy(&box)); }
Datum BOX2D_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); int nitems; double tmp; GBOX box; int i; gbox_init(&box); for(i = 0; str[i]; i++) { str[i] = tolower(str[i]); } nitems = sscanf(str,"box(%lf %lf,%lf %lf)", &box.xmin, &box.ymin, &box.xmax, &box.ymax); if (nitems != 4) { elog(ERROR,"box2d parser - couldnt parse. It should look like: BOX(xmin ymin,xmax ymax)"); PG_RETURN_NULL(); } if (box.xmin > box.xmax) { tmp = box.xmin; box.xmin = box.xmax; box.xmax = tmp; } if (box.ymin > box.ymax) { tmp = box.ymin; box.ymin = box.ymax; box.ymax = tmp; } PG_RETURN_POINTER(gbox_copy(&box)); }
LWGEOM* lwgeom_from_gserialized(const GSERIALIZED *g) { uint8_t g_flags = 0; int32_t g_srid = 0; uint32_t g_type = 0; uint8_t *data_ptr = NULL; LWGEOM *lwgeom = NULL; GBOX bbox; size_t g_size = 0; assert(g); g_srid = gserialized_get_srid(g); g_flags = g->flags; g_type = gserialized_get_type(g); LWDEBUGF(4, "Got type %d (%s), srid=%d", g_type, lwtype_name(g_type), g_srid); data_ptr = (uint8_t*)g->data; if ( FLAGS_GET_BBOX(g_flags) ) data_ptr += gbox_serialized_size(g_flags); lwgeom = lwgeom_from_gserialized_buffer(data_ptr, g_flags, &g_size); if ( ! lwgeom ) lwerror("lwgeom_from_gserialized: unable create geometry"); /* Ooops! */ lwgeom->type = g_type; lwgeom->flags = g_flags; if ( gserialized_read_gbox_p(g, &bbox) == LW_SUCCESS ) { lwgeom->bbox = gbox_copy(&bbox); } else if ( lwgeom_needs_bbox(lwgeom) && (lwgeom_calculate_gbox(lwgeom, &bbox) == LW_SUCCESS) ) { lwgeom->bbox = gbox_copy(&bbox); } else { lwgeom->bbox = NULL; } lwgeom_set_srid(lwgeom, g_srid); return lwgeom; }
/* @brief Clone LWLINE object. Serialized point lists are not copied. * * @see ptarray_clone */ LWPOLY * lwpoly_clone(const LWPOLY *g) { int i; LWPOLY *ret = lwalloc(sizeof(LWPOLY)); memcpy(ret, g, sizeof(LWPOLY)); ret->rings = lwalloc(sizeof(POINTARRAY *)*g->nrings); for ( i = 0; i < g->nrings; i++ ) { ret->rings[i] = ptarray_clone(g->rings[i]); } if ( g->bbox ) ret->bbox = gbox_copy(g->bbox); return ret; }
/* @brief Clone LWPOINT object. Serialized point lists are not copied. * * @see ptarray_clone */ LWPOINT * lwpoint_clone(const LWPOINT *g) { LWPOINT *ret = lwalloc(sizeof(LWPOINT)); LWDEBUG(2, "lwpoint_clone called"); memcpy(ret, g, sizeof(LWPOINT)); ret->point = ptarray_clone(g->point); if ( g->bbox ) ret->bbox = gbox_copy(g->bbox); return ret; }
/* Deep clone LWPOLY object. POINTARRAY are copied, as is ring array */ LWPOLY * lwpoly_clone_deep(const LWPOLY *g) { int i; LWPOLY *ret = lwalloc(sizeof(LWPOLY)); memcpy(ret, g, sizeof(LWPOLY)); if ( g->bbox ) ret->bbox = gbox_copy(g->bbox); ret->rings = lwalloc(sizeof(POINTARRAY *)*g->nrings); for ( i = 0; i < ret->nrings; i++ ) { ret->rings[i] = ptarray_clone_deep(g->rings[i]); } FLAGS_SET_READONLY(ret->flags,0); return ret; }
Datum LWGEOM_to_BOX2DF(PG_FUNCTION_ARGS) { GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0); GBOX gbox; if ( gserialized_get_gbox_p(geom, &gbox) == LW_FAILURE ) PG_RETURN_NULL(); /* Strip out higher dimensions */ FLAGS_SET_Z(gbox.flags, 0); FLAGS_SET_M(gbox.flags, 0); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(gbox_copy(&gbox)); }
LWGEOM* lwcollection_remove_repeated_points(LWCOLLECTION *coll) { uint32_t i; LWGEOM **newgeoms; newgeoms = lwalloc(sizeof(LWGEOM *)*coll->ngeoms); for (i=0; i<coll->ngeoms; i++) { newgeoms[i] = lwgeom_remove_repeated_points(coll->geoms[i]); } return (LWGEOM*)lwcollection_construct(coll->type, coll->srid, coll->bbox ? gbox_copy(coll->bbox) : NULL, coll->ngeoms, newgeoms); }
LWGEOM* lwpoly_remove_repeated_points(LWPOLY *poly) { uint32_t i; POINTARRAY **newrings; newrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings); for (i=0; i<poly->nrings; i++) { newrings[i] = ptarray_remove_repeated_points(poly->rings[i]); } return (LWGEOM*)lwpoly_construct(poly->srid, poly->bbox ? gbox_copy(poly->bbox) : NULL, poly->nrings, newrings); }
Datum LWGEOM_to_BOX2D(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); LWGEOM *lwgeom = lwgeom_from_gserialized(geom); GBOX gbox; /* Cannot box empty! */ if ( lwgeom_is_empty(lwgeom) ) PG_RETURN_NULL(); /* Cannot calculate box? */ if ( lwgeom_calculate_gbox(lwgeom, &gbox) == LW_FAILURE ) PG_RETURN_NULL(); /* Strip out higher dimensions */ FLAGS_SET_Z(gbox.flags, 0); FLAGS_SET_M(gbox.flags, 0); PG_RETURN_POINTER(gbox_copy(&gbox)); }
/** * @brief Deep clone #LWCOLLECTION object. #POINTARRAY are copied. */ LWCOLLECTION * lwcollection_clone_deep(const LWCOLLECTION *g) { uint32_t i; LWCOLLECTION *ret = lwalloc(sizeof(LWCOLLECTION)); memcpy(ret, g, sizeof(LWCOLLECTION)); if ( g->ngeoms > 0 ) { ret->geoms = lwalloc(sizeof(LWGEOM *)*g->ngeoms); for (i=0; i<g->ngeoms; i++) { ret->geoms[i] = lwgeom_clone_deep(g->geoms[i]); } if ( g->bbox ) ret->bbox = gbox_copy(g->bbox); } else { ret->bbox = NULL; /* empty collection */ ret->geoms = NULL; } return ret; }
/** * Takes a potentially heterogeneous collection and returns a homogeneous * collection consisting only of the specified type. */ LWCOLLECTION* lwcollection_extract(LWCOLLECTION *col, int type) { int i = 0; LWGEOM **geomlist; LWCOLLECTION *outcol; int geomlistsize = 16; int geomlistlen = 0; uint8_t outtype; if ( ! col ) return NULL; switch (type) { case POINTTYPE: outtype = MULTIPOINTTYPE; break; case LINETYPE: outtype = MULTILINETYPE; break; case POLYGONTYPE: outtype = MULTIPOLYGONTYPE; break; default: lwerror("Only POLYGON, LINESTRING and POINT are supported by lwcollection_extract. %s requested.", lwtype_name(type)); return NULL; } geomlist = lwalloc(sizeof(LWGEOM*) * geomlistsize); /* Process each sub-geometry */ for ( i = 0; i < col->ngeoms; i++ ) { int subtype = col->geoms[i]->type; /* Don't bother adding empty sub-geometries */ if ( lwgeom_is_empty(col->geoms[i]) ) { continue; } /* Copy our sub-types into the output list */ if ( subtype == type ) { /* We've over-run our buffer, double the memory segment */ if ( geomlistlen == geomlistsize ) { geomlistsize *= 2; geomlist = lwrealloc(geomlist, sizeof(LWGEOM*) * geomlistsize); } geomlist[geomlistlen] = lwgeom_clone(col->geoms[i]); geomlistlen++; } /* Recurse into sub-collections */ if ( lwtype_is_collection( subtype ) ) { int j = 0; LWCOLLECTION *tmpcol = lwcollection_extract((LWCOLLECTION*)col->geoms[i], type); for ( j = 0; j < tmpcol->ngeoms; j++ ) { /* We've over-run our buffer, double the memory segment */ if ( geomlistlen == geomlistsize ) { geomlistsize *= 2; geomlist = lwrealloc(geomlist, sizeof(LWGEOM*) * geomlistsize); } geomlist[geomlistlen] = tmpcol->geoms[j]; geomlistlen++; } lwfree(tmpcol); } } if ( geomlistlen > 0 ) { GBOX gbox; outcol = lwcollection_construct(outtype, col->srid, NULL, geomlistlen, geomlist); lwgeom_calculate_gbox((LWGEOM *) outcol, &gbox); outcol->bbox = gbox_copy(&gbox); } else { lwfree(geomlist); outcol = lwcollection_construct_empty(outtype, col->srid, FLAGS_GET_Z(col->flags), FLAGS_GET_M(col->flags)); } return outcol; }
/* ** 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! */ }
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); }