Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS) { bytea *bytea_wkb = (bytea*)PG_GETARG_BYTEA_P(0); int32 srid = 0; GSERIALIZED *geom; LWGEOM *lwgeom; uint8_t *wkb = (uint8_t*)VARDATA(bytea_wkb); lwgeom = lwgeom_from_wkb(wkb, VARSIZE(bytea_wkb)-VARHDRSZ, LW_PARSER_CHECK_ALL); if ( lwgeom_needs_bbox(lwgeom) ) lwgeom_add_bbox(lwgeom); geom = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_FREE_IF_COPY(bytea_wkb, 0); if ( gserialized_get_srid(geom) != SRID_UNKNOWN ) { elog(WARNING, "OGC WKB expected, EWKB provided - use GeometryFromEWKB() for this"); } if ( PG_NARGS() > 1 ) { srid = PG_GETARG_INT32(1); if ( srid != gserialized_get_srid(geom) ) gserialized_set_srid(geom, srid); } PG_RETURN_POINTER(geom); }
Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS) { GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *result; int type = gserialized_get_type(geom); LWGEOM *in; LWGEOM *out; double dist; if ( type == POINTTYPE || type == MULTIPOINTTYPE ) PG_RETURN_POINTER(geom); dist = PG_GETARG_FLOAT8(1); in = lwgeom_from_gserialized(geom); out = lwgeom_simplify(in, dist); if ( ! out ) PG_RETURN_NULL(); /* COMPUTE_BBOX TAINTING */ if ( in->bbox ) lwgeom_add_bbox(out); result = geometry_serialize(out); lwgeom_free(out); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
Datum LWGEOM_SetEffectiveArea(PG_FUNCTION_ARGS) { GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *result; int type = gserialized_get_type(geom); LWGEOM *in; LWGEOM *out; double area=0; int set_area=0; if ( type == POINTTYPE || type == MULTIPOINTTYPE ) PG_RETURN_POINTER(geom); if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) ) area = PG_GETARG_FLOAT8(1); if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) ) set_area = PG_GETARG_INT32(2); in = lwgeom_from_gserialized(geom); out = lwgeom_set_effective_area(in,set_area, area); if ( ! out ) PG_RETURN_NULL(); /* COMPUTE_BBOX TAINTING */ if ( in->bbox ) lwgeom_add_bbox(out); result = geometry_serialize(out); lwgeom_free(out); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS) { GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0); double dist = PG_GETARG_FLOAT8(1); GSERIALIZED *result; int type = gserialized_get_type(geom); LWGEOM *in, *out; bool preserve_collapsed = false; /* Handle optional argument to preserve collapsed features */ if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) ) preserve_collapsed = true; /* Can't simplify points! */ if ( type == POINTTYPE || type == MULTIPOINTTYPE ) PG_RETURN_POINTER(geom); in = lwgeom_from_gserialized(geom); out = lwgeom_simplify(in, dist, preserve_collapsed); if ( ! out ) PG_RETURN_NULL(); /* COMPUTE_BBOX TAINTING */ if ( in->bbox ) lwgeom_add_bbox(out); result = geometry_serialize(out); lwgeom_free(out); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
const GBOX * lwgeom_get_bbox(const LWGEOM *lwg) { /* add it if not already there */ lwgeom_add_bbox((LWGEOM *)lwg); return lwg->bbox; }
Datum LWGEOM_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); int32 geom_typmod = -1; GSERIALIZED *geom; LWGEOM *lwgeom; if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) ) { geom_typmod = PG_GETARG_INT32(2); } lwgeom = lwgeom_from_wkb((uint8_t*)buf->data, buf->len, LW_PARSER_CHECK_ALL); if ( lwgeom_needs_bbox(lwgeom) ) lwgeom_add_bbox(lwgeom); /* Set cursor to the end of buffer (so the backend is happy) */ buf->cursor = buf->len; geom = geometry_serialize(lwgeom); lwgeom_free(lwgeom); if ( geom_typmod >= 0 ) { postgis_valid_typmod(geom, geom_typmod); POSTGIS_DEBUG(3, "typmod and geometry were consistent"); } else { POSTGIS_DEBUG(3, "typmod was -1"); } PG_RETURN_POINTER(geom); }
Datum transform(PG_FUNCTION_ARGS) { GSERIALIZED *geom; GSERIALIZED *result=NULL; LWGEOM *lwgeom; projPJ input_pj, output_pj; int32 output_srid, input_srid; output_srid = PG_GETARG_INT32(1); if (output_srid == SRID_UNKNOWN) { elog(ERROR,"%d is an invalid target SRID",SRID_UNKNOWN); PG_RETURN_NULL(); } geom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)); input_srid = gserialized_get_srid(geom); if ( input_srid == SRID_UNKNOWN ) { PG_FREE_IF_COPY(geom, 0); elog(ERROR,"Input geometry has unknown (%d) SRID",SRID_UNKNOWN); PG_RETURN_NULL(); } /* * If input SRID and output SRID are equal, return geometry * without transform it */ if ( input_srid == output_srid ) PG_RETURN_POINTER(PG_GETARG_DATUM(0)); if ( GetProjectionsUsingFCInfo(fcinfo, input_srid, output_srid, &input_pj, &output_pj) == LW_FAILURE ) { PG_FREE_IF_COPY(geom, 0); elog(ERROR,"Failure reading projections from spatial_ref_sys."); PG_RETURN_NULL(); } /* now we have a geometry, and input/output PJ structs. */ lwgeom = lwgeom_from_gserialized(geom); lwgeom_transform(lwgeom, input_pj, output_pj); lwgeom->srid = output_srid; /* Re-compute bbox if input had one (COMPUTE_BBOX TAINTING) */ if ( lwgeom->bbox ) { lwgeom_drop_bbox(lwgeom); lwgeom_add_bbox(lwgeom); } result = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); /* new geometry */ }
/* * Note: input will be changed, make sure you have permissions for this. */ void lwline_setPoint4d(LWLINE *line, unsigned int index, POINT4D *newpoint) { setPoint4d(line->points, index, newpoint); /* Update the box, if there is one to update */ if( line->bbox ) { lwgeom_drop_bbox((LWGEOM*)line); lwgeom_add_bbox((LWGEOM*)line); } }
Datum LWGEOM_snaptogrid(PG_FUNCTION_ARGS) { Datum datum; GSERIALIZED *in_geom; LWGEOM *in_lwgeom; GSERIALIZED *out_geom = NULL; LWGEOM *out_lwgeom; gridspec grid; /* BOX3D box3d; */ if ( PG_ARGISNULL(0) ) PG_RETURN_NULL(); datum = PG_GETARG_DATUM(0); in_geom = (GSERIALIZED *)PG_DETOAST_DATUM(datum); if ( PG_ARGISNULL(1) ) PG_RETURN_NULL(); grid.ipx = PG_GETARG_FLOAT8(1); if ( PG_ARGISNULL(2) ) PG_RETURN_NULL(); grid.ipy = PG_GETARG_FLOAT8(2); if ( PG_ARGISNULL(3) ) PG_RETURN_NULL(); grid.xsize = PG_GETARG_FLOAT8(3); if ( PG_ARGISNULL(4) ) PG_RETURN_NULL(); grid.ysize = PG_GETARG_FLOAT8(4); /* Do not support gridding Z and M values for now */ grid.ipz=grid.ipm=grid.zsize=grid.msize=0; /* Return input geometry if grid is null */ if ( grid_isNull(&grid) ) { PG_RETURN_POINTER(in_geom); } in_lwgeom = lwgeom_from_gserialized(in_geom); POSTGIS_DEBUGF(3, "SnapToGrid got a %s", lwtype_name(in_lwgeom->type)); out_lwgeom = lwgeom_grid(in_lwgeom, &grid); if ( out_lwgeom == NULL ) PG_RETURN_NULL(); /* COMPUTE_BBOX TAINTING */ if ( in_lwgeom->bbox ) lwgeom_add_bbox(out_lwgeom); POSTGIS_DEBUGF(3, "SnapToGrid made a %s", lwtype_name(out_lwgeom->type)); out_geom = geometry_serialize(out_lwgeom); PG_RETURN_POINTER(out_geom); }
/* Conversion from SFCGAL::Geometry to GSERIALIZED */ GSERIALIZED* SFCGALGeometry2POSTGIS(const sfcgal_geometry_t* geom, int force3D, int SRID) { GSERIALIZED *result; LWGEOM* lwgeom = SFCGAL2LWGEOM(geom, force3D, SRID); if (lwgeom_needs_bbox(lwgeom) == LW_TRUE) lwgeom_add_bbox(lwgeom); result = geometry_serialize(lwgeom); lwgeom_free(lwgeom); return result; }
Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *result; LWGEOM *lwgeom; lwgeom = lwgeom_from_gserialized(geom); lwgeom_add_bbox(lwgeom); result = geometry_serialize(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
Datum geography_from_geometry(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); LWGEOM *lwgeom = NULL; GSERIALIZED *g_ser = NULL; geography_valid_type(gserialized_get_type(geom)); lwgeom = lwgeom_from_gserialized(geom); /* Force default SRID */ if ( (int)lwgeom->srid <= 0 ) { lwgeom->srid = SRID_DEFAULT; } /* Error on any SRID != default */ if ( lwgeom->srid != SRID_DEFAULT ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Only SRID %d is currently supported in geography.", SRID_DEFAULT))); } /* Check if the geography has valid coordinate range. */ if ( lwgeom_check_geodetic(lwgeom) == LW_FALSE ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Coordinate values are out of range [-180 -90, 180 90] for GEOGRAPHY type" ))); } /* ** Serialize our lwgeom and set the geodetic flag so subsequent ** functions do the right thing. */ lwgeom_set_geodetic(lwgeom, true); /* Recalculate the boxes after re-setting the geodetic bit */ lwgeom_drop_bbox(lwgeom); lwgeom_add_bbox(lwgeom); g_ser = geography_serialize(lwgeom); /* ** Replace the unaligned lwgeom with a new aligned one based on GSERIALIZED. */ lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(g_ser); }
/** * Clip an input MULTIPOINT between two values, on any ordinate input. */ LWCOLLECTION* lwmpoint_clip_to_ordinate_range(const LWMPOINT *mpoint, char ordinate, double from, double to) { LWCOLLECTION *lwgeom_out = NULL; char hasz, hasm; int i; /* Nothing to do with NULL */ if ( ! mpoint ) lwerror("Null input geometry."); /* Ensure 'from' is less than 'to'. */ if ( to < from ) { double t = from; from = to; to = t; } /* Read Z/M info */ hasz = lwgeom_has_z(lwmpoint_as_lwgeom(mpoint)); hasm = lwgeom_has_m(lwmpoint_as_lwgeom(mpoint)); /* Prepare return object */ lwgeom_out = lwcollection_construct_empty(MULTIPOINTTYPE, mpoint->srid, hasz, hasm); /* For each point, is its ordinate value between from and to? */ for ( i = 0; i < mpoint->ngeoms; i ++ ) { POINT4D p4d; double ordinate_value; lwpoint_getPoint4d_p(mpoint->geoms[i], &p4d); ordinate_value = lwpoint_get_ordinate(&p4d, ordinate); if ( from <= ordinate_value && to >= ordinate_value ) { LWPOINT *lwp = lwpoint_clone(mpoint->geoms[i]); lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(lwp)); } } /* Set the bbox */ lwgeom_drop_bbox((LWGEOM*)lwgeom_out); lwgeom_add_bbox((LWGEOM*)lwgeom_out); return lwgeom_out; }
Datum geography_from_geometry(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)); LWGEOM *lwgeom = NULL; GSERIALIZED *g_ser = NULL; geography_valid_type(gserialized_get_type(geom)); lwgeom = lwgeom_from_gserialized(geom); /* Force default SRID */ if ( (int)lwgeom->srid <= 0 ) { lwgeom->srid = SRID_DEFAULT; } /* Error on any SRID != default */ srid_is_latlong(fcinfo, lwgeom->srid); /* Force the geometry to have valid geodetic coordinate range. */ lwgeom_nudge_geodetic(lwgeom); if ( lwgeom_force_geodetic(lwgeom) == LW_TRUE ) { ereport(NOTICE, ( errmsg_internal("Coordinate values were coerced into range [-180 -90, 180 90] for GEOGRAPHY" )) ); } /* ** Serialize our lwgeom and set the geodetic flag so subsequent ** functions do the right thing. */ lwgeom_set_geodetic(lwgeom, true); /* Recalculate the boxes after re-setting the geodetic bit */ lwgeom_drop_bbox(lwgeom); lwgeom_add_bbox(lwgeom); g_ser = geography_serialize(lwgeom); /* ** Replace the unaligned lwgeom with a new aligned one based on GSERIALIZED. */ lwgeom_free(lwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(g_ser); }
Datum LWGEOM_snaptogrid(PG_FUNCTION_ARGS) { LWGEOM *in_lwgeom; GSERIALIZED *out_geom = NULL; LWGEOM *out_lwgeom; gridspec grid; GSERIALIZED *in_geom = PG_GETARG_GSERIALIZED_P(0); /* Set grid values to zero to start */ memset(&grid, 0, sizeof(gridspec)); grid.ipx = PG_GETARG_FLOAT8(1); grid.ipy = PG_GETARG_FLOAT8(2); grid.xsize = PG_GETARG_FLOAT8(3); grid.ysize = PG_GETARG_FLOAT8(4); /* Return input geometry if input geometry is empty */ if ( gserialized_is_empty(in_geom) ) { PG_RETURN_POINTER(in_geom); } /* Return input geometry if input grid is meaningless */ if ( grid.xsize==0 && grid.ysize==0 && grid.zsize==0 && grid.msize==0 ) { PG_RETURN_POINTER(in_geom); } in_lwgeom = lwgeom_from_gserialized(in_geom); POSTGIS_DEBUGF(3, "SnapToGrid got a %s", lwtype_name(in_lwgeom->type)); out_lwgeom = lwgeom_grid(in_lwgeom, &grid); if ( out_lwgeom == NULL ) PG_RETURN_NULL(); /* COMPUTE_BBOX TAINTING */ if ( in_lwgeom->bbox ) lwgeom_add_bbox(out_lwgeom); POSTGIS_DEBUGF(3, "SnapToGrid made a %s", lwtype_name(out_lwgeom->type)); out_geom = geometry_serialize(out_lwgeom); PG_RETURN_POINTER(out_geom); }
Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *result; int type = gserialized_get_type(geom); int32 idx; LWCOLLECTION *coll; LWGEOM *subgeom; POSTGIS_DEBUG(2, "LWGEOM_geometryn_collection called."); /* elog(NOTICE, "GeometryN called"); */ idx = PG_GETARG_INT32(1); idx -= 1; /* index is 1-based */ /* call is valid on multi* geoms only */ if (type==POINTTYPE || type==LINETYPE || type==CIRCSTRINGTYPE || type==COMPOUNDTYPE || type==POLYGONTYPE || type==CURVEPOLYTYPE || type==TRIANGLETYPE) { if ( idx == 0 ) PG_RETURN_POINTER(geom); PG_RETURN_NULL(); } coll = lwgeom_as_lwcollection(lwgeom_from_gserialized(geom)); if ( idx < 0 ) PG_RETURN_NULL(); if ( idx >= coll->ngeoms ) PG_RETURN_NULL(); subgeom = coll->geoms[idx]; subgeom->srid = coll->srid; /* COMPUTE_BBOX==TAINTING */ if ( coll->bbox ) lwgeom_add_bbox(subgeom); result = geometry_serialize(subgeom); lwcollection_free(coll); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *result; LWGEOM *in = lwgeom_from_gserialized(geom); LWGEOM *out; double dist = PG_GETARG_FLOAT8(1); out = lwgeom_simplify(in, dist); if ( ! out ) PG_RETURN_NULL(); /* COMPUTE_BBOX TAINTING */ if ( in->bbox ) lwgeom_add_bbox(out); result = geometry_serialize(out); lwgeom_free(out); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS) { PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); PG_LWGEOM *result; int type = lwgeom_getType(geom->type); int32 idx; LWCOLLECTION *coll; LWGEOM *subgeom; POSTGIS_DEBUG(2, "LWGEOM_geometryn_collection called."); /* elog(NOTICE, "GeometryN called"); */ /* call is valid on multi* geoms only */ if (type==POINTTYPE || type==LINETYPE || type==CIRCSTRINGTYPE || type==COMPOUNDTYPE || type==POLYGONTYPE || type==CURVEPOLYTYPE) { /* elog(NOTICE, "geometryn: geom is of type %d, requires >=4", type); */ PG_RETURN_NULL(); } idx = PG_GETARG_INT32(1); idx -= 1; /* index is 1-based */ coll = (LWCOLLECTION *)lwgeom_deserialize(SERIALIZED_FORM(geom)); if ( idx < 0 ) PG_RETURN_NULL(); if ( idx >= coll->ngeoms ) PG_RETURN_NULL(); subgeom = coll->geoms[idx]; subgeom->SRID = coll->SRID; /* COMPUTE_BBOX==TAINTING */ if ( coll->bbox ) lwgeom_add_bbox(subgeom); result = pglwgeom_serialize(subgeom); lwgeom_release((LWGEOM *)coll); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
/** * Clip an input POINT between two values, on any ordinate input. */ LWCOLLECTION* lwpoint_clip_to_ordinate_range(const LWPOINT *point, char ordinate, double from, double to) { LWCOLLECTION *lwgeom_out = NULL; char hasz, hasm; POINT4D p4d; double ordinate_value; /* Nothing to do with NULL */ if ( ! point ) lwerror("Null input geometry."); /* Ensure 'from' is less than 'to'. */ if ( to < from ) { double t = from; from = to; to = t; } /* Read Z/M info */ hasz = lwgeom_has_z(lwpoint_as_lwgeom(point)); hasm = lwgeom_has_m(lwpoint_as_lwgeom(point)); /* Prepare return object */ lwgeom_out = lwcollection_construct_empty(MULTIPOINTTYPE, point->srid, hasz, hasm); /* Test if ordinate is in range */ lwpoint_getPoint4d_p(point, &p4d); ordinate_value = lwpoint_get_ordinate(&p4d, ordinate); if ( from <= ordinate_value && to >= ordinate_value ) { LWPOINT *lwp = lwpoint_clone(point); lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(lwp)); } /* Set the bbox */ lwgeom_drop_bbox((LWGEOM*)lwgeom_out); lwgeom_add_bbox((LWGEOM*)lwgeom_out); return lwgeom_out; }
LWPOLY * lwpoly_construct_envelope(int srid, double x1, double y1, double x2, double y2) { POINT4D p1, p2, p3, p4; LWPOLY *poly; p1.x = x1; p1.y = y1; p2.x = x1; p2.y = y2; p3.x = x2; p3.y = y2; p4.x = x2; p4.y = y1; poly = lwpoly_construct_rectangle(0, 0, &p1, &p2, &p3, &p4); lwgeom_set_srid(lwpoly_as_lwgeom(poly), srid); lwgeom_add_bbox(lwpoly_as_lwgeom(poly)); return poly; }
Datum geometry_from_geography(PG_FUNCTION_ARGS) { LWGEOM *lwgeom = NULL; GSERIALIZED *ret = NULL; GSERIALIZED *g_ser = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); lwgeom = lwgeom_from_gserialized(g_ser); /* Recalculate the boxes after re-setting the geodetic bit */ lwgeom_set_geodetic(lwgeom, false); lwgeom_drop_bbox(lwgeom); lwgeom_add_bbox(lwgeom); /* We want "geometry" to think all our "geography" has an SRID, and the implied SRID is the default, so we fill that in if our SRID is actually unknown. */ if ( (int)lwgeom->srid <= 0 ) lwgeom->srid = SRID_DEFAULT; ret = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_RETURN_POINTER(ret); }
Datum LWGEOMFromWKB(PG_FUNCTION_ARGS) { bytea *bytea_wkb = (bytea*)PG_GETARG_BYTEA_P(0); int32 srid = 0; GSERIALIZED *geom; LWGEOM *lwgeom; uint8_t *wkb = (uint8_t*)VARDATA(bytea_wkb); lwgeom = lwgeom_from_wkb(wkb, VARSIZE(bytea_wkb)-VARHDRSZ, LW_PARSER_CHECK_ALL); if ( ( PG_NARGS()>1) && ( ! PG_ARGISNULL(1) )) { srid = PG_GETARG_INT32(1); lwgeom_set_srid(lwgeom, srid); } if ( lwgeom_needs_bbox(lwgeom) ) lwgeom_add_bbox(lwgeom); geom = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_FREE_IF_COPY(bytea_wkb, 0); PG_RETURN_POINTER(geom); }
Datum geom_from_geojson(PG_FUNCTION_ARGS) { #ifndef HAVE_LIBJSON elog(ERROR, "You need JSON-C for ST_GeomFromGeoJSON"); PG_RETURN_NULL(); #else /* HAVE_LIBJSON */ GSERIALIZED *geom; LWGEOM *lwgeom; text *geojson_input; int geojson_size; char *geojson; int root_srid=0; bool hasz=true; json_tokener* jstok = NULL; json_object* poObj = NULL; json_object* poObjSrs = NULL; /* Get the geojson stream */ if (PG_ARGISNULL(0)) PG_RETURN_NULL(); geojson_input = PG_GETARG_TEXT_P(0); geojson = text2cstring(geojson_input); geojson_size = VARSIZE(geojson_input) - VARHDRSZ; /* Begin to Parse json */ jstok = json_tokener_new(); poObj = json_tokener_parse_ex(jstok, geojson, -1); if( jstok->err != json_tokener_success) { char err[256]; snprintf(err, 256, "%s (at offset %d)", json_tokener_errors[jstok->err], jstok->char_offset); json_tokener_free(jstok); geojson_lwerror(err, 1); } json_tokener_free(jstok); poObjSrs = findMemberByName( poObj, "crs" ); if (poObjSrs != NULL) { json_object* poObjSrsType = findMemberByName( poObjSrs, "type" ); if (poObjSrsType != NULL) { json_object* poObjSrsProps = findMemberByName( poObjSrs, "properties" ); json_object* poNameURL = findMemberByName( poObjSrsProps, "name" ); const char* pszName = json_object_get_string( poNameURL ); root_srid = getSRIDbySRS(pszName); POSTGIS_DEBUGF(3, "getSRIDbySRS returned root_srid = %d.", root_srid ); } } lwgeom = parse_geojson(poObj, &hasz, &root_srid); lwgeom_add_bbox(lwgeom); if (root_srid && lwgeom->srid == -1) lwgeom->srid = root_srid; if (!hasz) { LWGEOM *tmp = lwgeom_force_2d(lwgeom); lwgeom_free(lwgeom); lwgeom = tmp; POSTGIS_DEBUG(2, "geom_from_geojson called."); } geom = geometry_serialize(lwgeom); lwgeom_free(lwgeom); PG_RETURN_POINTER(geom); #endif }
Datum LWGEOM_in(PG_FUNCTION_ARGS) { char *input = PG_GETARG_CSTRING(0); int32 geom_typmod = -1; char *str = input; LWGEOM_PARSER_RESULT lwg_parser_result; LWGEOM *lwgeom; GSERIALIZED *ret; int srid = 0; if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) ) { geom_typmod = PG_GETARG_INT32(2); } lwgeom_parser_result_init(&lwg_parser_result); /* Empty string. */ if ( str[0] == '\0' ) ereport(ERROR,(errmsg("parse error - invalid geometry"))); /* Starts with "SRID=" */ if( strncasecmp(str,"SRID=",5) == 0 ) { /* Roll forward to semi-colon */ char *tmp = str; while ( tmp && *tmp != ';' ) tmp++; /* Check next character to see if we have WKB */ if ( tmp && *(tmp+1) == '0' ) { /* Null terminate the SRID= string */ *tmp = '\0'; /* Set str to the start of the real WKB */ str = tmp + 1; /* Move tmp to the start of the numeric part */ tmp = input + 5; /* Parse out the SRID number */ srid = atoi(tmp); } } /* WKB? Let's find out. */ if ( str[0] == '0' ) { size_t hexsize = strlen(str); unsigned char *wkb = bytes_from_hexbytes(str, hexsize); /* TODO: 20101206: No parser checks! This is inline with current 1.5 behavior, but needs discussion */ lwgeom = lwgeom_from_wkb(wkb, hexsize/2, LW_PARSER_CHECK_NONE); /* If we picked up an SRID at the head of the WKB set it manually */ if ( srid ) lwgeom_set_srid(lwgeom, srid); /* Add a bbox if necessary */ if ( lwgeom_needs_bbox(lwgeom) ) lwgeom_add_bbox(lwgeom); pfree(wkb); ret = geometry_serialize(lwgeom); lwgeom_free(lwgeom); } /* WKT then. */ else { if ( lwgeom_parse_wkt(&lwg_parser_result, str, LW_PARSER_CHECK_ALL) == LW_FAILURE ) { PG_PARSER_ERROR(lwg_parser_result); } lwgeom = lwg_parser_result.geom; if ( lwgeom_needs_bbox(lwgeom) ) lwgeom_add_bbox(lwgeom); ret = geometry_serialize(lwgeom); lwgeom_parser_result_free(&lwg_parser_result); } if ( geom_typmod >= 0 ) { postgis_valid_typmod(ret, geom_typmod); POSTGIS_DEBUG(3, "typmod and geometry were consistent"); } else { POSTGIS_DEBUG(3, "typmod was -1"); } /* Don't free the parser result (and hence lwgeom) until we have done */ /* the typemod check with lwgeom */ PG_RETURN_POINTER(ret); }
LWGEOM* lwgeom_flip_coordinates(LWGEOM *in) { LWCOLLECTION *col; LWPOLY *poly; int i; if ( (!in) || lwgeom_is_empty(in) ) return in; 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); break; case LINETYPE: ptarray_flip_coordinates(lwgeom_as_lwline(in)->points); break; case CIRCSTRINGTYPE: ptarray_flip_coordinates(lwgeom_as_lwcircstring(in)->points); break; case POLYGONTYPE: poly = (LWPOLY *) in; for (i=0; i<poly->nrings; i++) { ptarray_flip_coordinates(poly->rings[i]); } break; case TRIANGLETYPE: ptarray_flip_coordinates(lwgeom_as_lwtriangle(in)->points); break; 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]); } break; default: lwerror("lwgeom_flip_coordinates: unsupported geometry type: %s", lwtype_name(in->type)); return NULL; } lwgeom_drop_bbox(in); lwgeom_add_bbox(in); return in; }
Datum LWGEOM_snaptogrid_pointoff(PG_FUNCTION_ARGS) { Datum datum; GSERIALIZED *in_geom, *in_point; LWGEOM *in_lwgeom; LWPOINT *in_lwpoint; GSERIALIZED *out_geom = NULL; LWGEOM *out_lwgeom; gridspec grid; /* BOX3D box3d; */ POINT4D offsetpoint; if ( PG_ARGISNULL(0) ) PG_RETURN_NULL(); datum = PG_GETARG_DATUM(0); in_geom = (GSERIALIZED *)PG_DETOAST_DATUM(datum); if ( PG_ARGISNULL(1) ) PG_RETURN_NULL(); datum = PG_GETARG_DATUM(1); in_point = (GSERIALIZED *)PG_DETOAST_DATUM(datum); in_lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(in_point)); if ( in_lwpoint == NULL ) { lwerror("Offset geometry must be a point"); } if ( PG_ARGISNULL(2) ) PG_RETURN_NULL(); grid.xsize = PG_GETARG_FLOAT8(2); if ( PG_ARGISNULL(3) ) PG_RETURN_NULL(); grid.ysize = PG_GETARG_FLOAT8(3); if ( PG_ARGISNULL(4) ) PG_RETURN_NULL(); grid.zsize = PG_GETARG_FLOAT8(4); if ( PG_ARGISNULL(5) ) PG_RETURN_NULL(); grid.msize = PG_GETARG_FLOAT8(5); /* Take offsets from point geometry */ getPoint4d_p(in_lwpoint->point, 0, &offsetpoint); grid.ipx = offsetpoint.x; grid.ipy = offsetpoint.y; if (FLAGS_GET_Z(in_lwpoint->flags) ) grid.ipz = offsetpoint.z; else grid.ipz=0; if (FLAGS_GET_M(in_lwpoint->flags) ) grid.ipm = offsetpoint.m; else grid.ipm=0; #if POSTGIS_DEBUG_LEVEL >= 4 grid_print(&grid); #endif /* Return input geometry if grid is null */ if ( grid_isNull(&grid) ) { PG_RETURN_POINTER(in_geom); } in_lwgeom = lwgeom_from_gserialized(in_geom); POSTGIS_DEBUGF(3, "SnapToGrid got a %s", lwtype_name(in_lwgeom->type)); out_lwgeom = lwgeom_grid(in_lwgeom, &grid); if ( out_lwgeom == NULL ) PG_RETURN_NULL(); /* COMPUTE_BBOX TAINTING */ if ( in_lwgeom->bbox ) lwgeom_add_bbox(out_lwgeom); POSTGIS_DEBUGF(3, "SnapToGrid made a %s", lwtype_name(out_lwgeom->type)); out_geom = geometry_serialize(out_lwgeom); PG_RETURN_POINTER(out_geom); }
Datum geom_from_kml(PG_FUNCTION_ARGS) { GSERIALIZED *geom; LWGEOM *lwgeom, *hlwgeom; xmlDocPtr xmldoc; text *xml_input; int xml_size; char *xml; bool hasz=true; xmlNodePtr xmlroot=NULL; /* Get the KML stream */ if (PG_ARGISNULL(0)) PG_RETURN_NULL(); xml_input = PG_GETARG_TEXT_P(0); xml = text2cstring(xml_input); xml_size = VARSIZE(xml_input) - VARHDRSZ; /* Begin to Parse XML doc */ xmlInitParser(); xmldoc = xmlParseMemory(xml, xml_size); if (!xmldoc || (xmlroot = xmlDocGetRootElement(xmldoc)) == NULL) { xmlFreeDoc(xmldoc); xmlCleanupParser(); lwerror("invalid KML representation"); } lwgeom = parse_kml(xmlroot, &hasz); /* Homogenize geometry result if needed */ if (lwgeom->type == COLLECTIONTYPE) { hlwgeom = lwgeom_homogenize(lwgeom); lwgeom_release(lwgeom); lwgeom = hlwgeom; } lwgeom_add_bbox(lwgeom); /* KML geometries could be either 2 or 3D * * So we deal with 3D in all structures allocation, and flag hasz * to false if we met once a missing Z dimension * In this case, we force recursive 2D. */ if (!hasz) { LWGEOM *tmp = lwgeom_force_2d(lwgeom); lwgeom_free(lwgeom); lwgeom = tmp; } geom = geometry_serialize(lwgeom); lwgeom_free(lwgeom); xmlFreeDoc(xmldoc); xmlCleanupParser(); PG_RETURN_POINTER(geom); }
GSERIALIZED* gserialized_from_lwgeom(LWGEOM *geom, int is_geodetic, size_t *size) { size_t expected_size = 0; size_t return_size = 0; uint8_t *serialized = NULL; uint8_t *ptr = NULL; GSERIALIZED *g = NULL; assert(geom); /* ** See if we need a bounding box, add one if we don't have one. */ if ( (! geom->bbox) && lwgeom_needs_bbox(geom) && (!lwgeom_is_empty(geom)) ) { lwgeom_add_bbox(geom); } /* ** Harmonize the flags to the state of the lwgeom */ if ( geom->bbox ) FLAGS_SET_BBOX(geom->flags, 1); /* Set up the uint8_t buffer into which we are going to write the serialized geometry. */ expected_size = gserialized_from_lwgeom_size(geom); serialized = lwalloc(expected_size); ptr = serialized; /* Move past size, srid and flags. */ ptr += 8; /* Write in the serialized form of the gbox, if necessary. */ if ( geom->bbox ) ptr += gserialized_from_gbox(geom->bbox, ptr); /* Write in the serialized form of the geometry. */ ptr += gserialized_from_lwgeom_any(geom, ptr); /* Calculate size as returned by data processing functions. */ return_size = ptr - serialized; if ( expected_size != return_size ) /* Uh oh! */ { lwerror("Return size (%d) not equal to expected size (%d)!", return_size, expected_size); return NULL; } if ( size ) /* Return the output size to the caller if necessary. */ *size = return_size; g = (GSERIALIZED*)serialized; /* ** We are aping PgSQL code here, PostGIS code should use ** VARSIZE to set this for real. */ g->size = return_size << 2; /* Set the SRID! */ gserialized_set_srid(g, geom->srid); g->flags = geom->flags; return g; }
/** * Take in a LINESTRING and return a MULTILINESTRING of those portions of the * LINESTRING between the from/to range for the specified ordinate (XYZM) */ LWCOLLECTION* lwline_clip_to_ordinate_range(const LWLINE *line, char ordinate, double from, double to) { POINTARRAY *pa_in = NULL; LWCOLLECTION *lwgeom_out = NULL; POINTARRAY *dp = NULL; int i, rv; int added_last_point = 0; POINT4D *p = NULL, *q = NULL, *r = NULL; double ordinate_value_p = 0.0, ordinate_value_q = 0.0; char hasz = lwgeom_has_z(lwline_as_lwgeom(line)); char hasm = lwgeom_has_m(lwline_as_lwgeom(line)); char dims = FLAGS_NDIMS(line->flags); /* Null input, nothing we can do. */ if ( ! line ) { lwerror("Null input geometry."); return NULL; } /* Ensure 'from' is less than 'to'. */ if ( to < from ) { double t = from; from = to; to = t; } LWDEBUGF(4, "from = %g, to = %g, ordinate = %c", from, to, ordinate); LWDEBUGF(4, "%s", lwgeom_to_ewkt((LWGEOM*)line)); /* Asking for an ordinate we don't have. Error. */ if ( (ordinate == 'Z' && ! hasz) || (ordinate == 'M' && ! hasm) ) { lwerror("Cannot clip on ordinate %d in a %d-d geometry.", ordinate, dims); return NULL; } /* Prepare our working point objects. */ p = lwalloc(sizeof(POINT4D)); q = lwalloc(sizeof(POINT4D)); r = lwalloc(sizeof(POINT4D)); /* Construct a collection to hold our outputs. */ lwgeom_out = lwcollection_construct_empty(MULTILINETYPE, line->srid, hasz, hasm); /* Get our input point array */ pa_in = line->points; for ( i = 0; i < pa_in->npoints; i++ ) { LWDEBUGF(4, "Point #%d", i); LWDEBUGF(4, "added_last_point %d", added_last_point); if ( i > 0 ) { *q = *p; ordinate_value_q = ordinate_value_p; } rv = getPoint4d_p(pa_in, i, p); ordinate_value_p = lwpoint_get_ordinate(p, ordinate); LWDEBUGF(4, " ordinate_value_p %g (current)", ordinate_value_p); LWDEBUGF(4, " ordinate_value_q %g (previous)", ordinate_value_q); /* Is this point inside the ordinate range? Yes. */ if ( ordinate_value_p >= from && ordinate_value_p <= to ) { LWDEBUGF(4, " inside ordinate range (%g, %g)", from, to); if ( ! added_last_point ) { LWDEBUG(4," new ptarray required"); /* We didn't add the previous point, so this is a new segment. * Make a new point array. */ dp = ptarray_construct_empty(hasz, hasm, 32); /* We're transiting into the range so add an interpolated * point at the range boundary. * If we're on a boundary and crossing from the far side, * we also need an interpolated point. */ if ( i > 0 && ( /* Don't try to interpolate if this is the first point */ ( ordinate_value_p > from && ordinate_value_p < to ) || /* Inside */ ( ordinate_value_p == from && ordinate_value_q > to ) || /* Hopping from above */ ( ordinate_value_p == to && ordinate_value_q < from ) ) ) /* Hopping from below */ { double interpolation_value; (ordinate_value_q > to) ? (interpolation_value = to) : (interpolation_value = from); rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, "[0] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } } /* Add the current vertex to the point array. */ rv = ptarray_append_point(dp, p, LW_FALSE); if ( ordinate_value_p == from || ordinate_value_p == to ) { added_last_point = 2; /* Added on boundary. */ } else { added_last_point = 1; /* Added inside range. */ } } /* Is this point inside the ordinate range? No. */ else { LWDEBUGF(4, " added_last_point (%d)", added_last_point); if ( added_last_point == 1 ) { /* We're transiting out of the range, so add an interpolated point * to the point array at the range boundary. */ double interpolation_value; (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from); rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, " [1] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } else if ( added_last_point == 2 ) { /* We're out and the last point was on the boundary. * If the last point was the near boundary, nothing to do. * If it was the far boundary, we need an interpolated point. */ if ( from != to && ( (ordinate_value_q == from && ordinate_value_p > from) || (ordinate_value_q == to && ordinate_value_p < to) ) ) { double interpolation_value; (ordinate_value_p > to) ? (interpolation_value = to) : (interpolation_value = from); rv = point_interpolate(q, p, r, hasz, hasm, ordinate, interpolation_value); rv = ptarray_append_point(dp, r, LW_FALSE); LWDEBUGF(4, " [2] interpolating between (%g, %g) with interpolation point (%g)", ordinate_value_q, ordinate_value_p, interpolation_value); } } else if ( i && ordinate_value_q < from && ordinate_value_p > to ) { /* We just hopped over the whole range, from bottom to top, * so we need to add *two* interpolated points! */ dp = ptarray_construct(hasz, hasm, 2); /* Interpolate lower point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, from); ptarray_set_point4d(dp, 0, r); /* Interpolate upper point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, to); ptarray_set_point4d(dp, 1, r); } else if ( i && ordinate_value_q > to && ordinate_value_p < from ) { /* We just hopped over the whole range, from top to bottom, * so we need to add *two* interpolated points! */ dp = ptarray_construct(hasz, hasm, 2); /* Interpolate upper point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, to); ptarray_set_point4d(dp, 0, r); /* Interpolate lower point. */ rv = point_interpolate(p, q, r, hasz, hasm, ordinate, from); ptarray_set_point4d(dp, 1, r); } /* We have an extant point-array, save it out to a multi-line. */ if ( dp ) { LWDEBUG(4, "saving pointarray to multi-line (1)"); /* Only one point, so we have to make an lwpoint to hold this * and set the overall output type to a generic collection. */ if ( dp->npoints == 1 ) { LWPOINT *opoint = lwpoint_construct(line->srid, NULL, dp); lwgeom_out->type = COLLECTIONTYPE; lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(opoint)); } else { LWLINE *oline = lwline_construct(line->srid, NULL, dp); lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwline_as_lwgeom(oline)); } /* Pointarray is now owned by lwgeom_out, so drop reference to it */ dp = NULL; } added_last_point = 0; } } /* Still some points left to be saved out. */ if ( dp && dp->npoints > 0 ) { LWDEBUG(4, "saving pointarray to multi-line (2)"); LWDEBUGF(4, "dp->npoints == %d", dp->npoints); LWDEBUGF(4, "lwgeom_out->ngeoms == %d", lwgeom_out->ngeoms); if ( dp->npoints == 1 ) { LWPOINT *opoint = lwpoint_construct(line->srid, NULL, dp); lwgeom_out->type = COLLECTIONTYPE; lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwpoint_as_lwgeom(opoint)); } else { LWLINE *oline = lwline_construct(line->srid, NULL, dp); lwgeom_out = lwcollection_add_lwgeom(lwgeom_out, lwline_as_lwgeom(oline)); } /* Pointarray is now owned by lwgeom_out, so drop reference to it */ dp = NULL; } lwfree(p); lwfree(q); lwfree(r); if ( lwgeom_out->ngeoms > 0 ) { lwgeom_drop_bbox((LWGEOM*)lwgeom_out); lwgeom_add_bbox((LWGEOM*)lwgeom_out); } return lwgeom_out; }
/** * Clip an input MULTILINESTRING between two values, on any ordinate input. */ LWCOLLECTION* lwmline_clip_to_ordinate_range(const LWMLINE *mline, char ordinate, double from, double to) { LWCOLLECTION *lwgeom_out = NULL; if ( ! mline ) { lwerror("Null input geometry."); return NULL; } if ( mline->ngeoms == 1) { lwgeom_out = lwline_clip_to_ordinate_range(mline->geoms[0], ordinate, from, to); } else { LWCOLLECTION *col; char hasz = lwgeom_has_z(lwmline_as_lwgeom(mline)); char hasm = lwgeom_has_m(lwmline_as_lwgeom(mline)); int i, j; char homogeneous = 1; size_t geoms_size = 0; lwgeom_out = lwcollection_construct_empty(MULTILINETYPE, mline->srid, hasz, hasm); FLAGS_SET_Z(lwgeom_out->flags, hasz); FLAGS_SET_M(lwgeom_out->flags, hasm); for ( i = 0; i < mline->ngeoms; i ++ ) { col = lwline_clip_to_ordinate_range(mline->geoms[i], ordinate, from, to); if ( col ) { /* Something was left after the clip. */ if ( lwgeom_out->ngeoms + col->ngeoms > geoms_size ) { geoms_size += 16; if ( lwgeom_out->geoms ) { lwgeom_out->geoms = lwrealloc(lwgeom_out->geoms, geoms_size * sizeof(LWGEOM*)); } else { lwgeom_out->geoms = lwalloc(geoms_size * sizeof(LWGEOM*)); } } for ( j = 0; j < col->ngeoms; j++ ) { lwgeom_out->geoms[lwgeom_out->ngeoms] = col->geoms[j]; lwgeom_out->ngeoms++; } if ( col->type != mline->type ) { homogeneous = 0; } /* Shallow free the struct, leaving the geoms behind. */ if ( col->bbox ) lwfree(col->bbox); lwfree(col->geoms); lwfree(col); } } lwgeom_drop_bbox((LWGEOM*)lwgeom_out); lwgeom_add_bbox((LWGEOM*)lwgeom_out); if ( ! homogeneous ) { lwgeom_out->type = COLLECTIONTYPE; } } if ( ! lwgeom_out || lwgeom_out->ngeoms == 0 ) /* Nothing left after clip. */ { return NULL; } return lwgeom_out; }