Datum ST_LocateBetween(PG_FUNCTION_ARGS) { GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0); double from = PG_GETARG_FLOAT8(1); double to = PG_GETARG_FLOAT8(2); double offset = PG_GETARG_FLOAT8(3); LWCOLLECTION *geom_out = NULL; LWGEOM *line_in = NULL; static char ordinate = 'M'; /* M */ if ( ! gserialized_has_m(geom_in) ) { elog(ERROR,"This function only accepts geometries that have an M dimension."); PG_RETURN_NULL(); } /* This should be a call to ST_LocateAlong! */ if ( to == from ) { PG_RETURN_DATUM(DirectFunctionCall3(ST_LocateAlong, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1), PG_GETARG_DATUM(3))); } line_in = lwgeom_from_gserialized(geom_in); geom_out = lwgeom_clip_to_ordinate_range(line_in, ordinate, from, to, offset); lwgeom_free(line_in); PG_FREE_IF_COPY(geom_in, 0); if ( ! geom_out ) { elog(ERROR,"lwline_clip_to_ordinate_range returned null"); PG_RETURN_NULL(); } PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out)); }
Datum ST_InterpolatePoint(PG_FUNCTION_ARGS) { GSERIALIZED *gser_line = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *gser_point = PG_GETARG_GSERIALIZED_P(1); LWGEOM *lwline; LWPOINT *lwpoint; if ( gserialized_get_type(gser_line) != LINETYPE ) { elog(ERROR,"ST_InterpolatePoint: 1st argument isn't a line"); PG_RETURN_NULL(); } if ( gserialized_get_type(gser_point) != POINTTYPE ) { elog(ERROR,"ST_InterpolatePoint: 2st argument isn't a point"); PG_RETURN_NULL(); } error_if_srid_mismatch(gserialized_get_srid(gser_line), gserialized_get_srid(gser_point)); if ( ! gserialized_has_m(gser_line) ) { elog(ERROR,"ST_InterpolatePoint only accepts geometries that have an M dimension"); PG_RETURN_NULL(); } lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(gser_point)); lwline = lwgeom_from_gserialized(gser_line); PG_RETURN_FLOAT8(lwgeom_interpolate_point(lwline, lwpoint)); }
Datum LWGEOM_getTYPE(PG_FUNCTION_ARGS) { GSERIALIZED *lwgeom; char *text_ob; char *result; int32 size; uint8_t type; lwgeom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); text_ob = lwalloc(20+VARHDRSZ); result = text_ob+VARHDRSZ; type = gserialized_get_type(lwgeom); memset(VARDATA(text_ob), 0, 20); if (type == POINTTYPE) strcpy(result,"POINT"); else if (type == MULTIPOINTTYPE) strcpy(result,"MULTIPOINT"); else if (type == LINETYPE) strcpy(result,"LINESTRING"); else if (type == CIRCSTRINGTYPE) strcpy(result,"CIRCULARSTRING"); else if (type == COMPOUNDTYPE) strcpy(result, "COMPOUNDCURVE"); else if (type == MULTILINETYPE) strcpy(result,"MULTILINESTRING"); else if (type == MULTICURVETYPE) strcpy(result, "MULTICURVE"); else if (type == POLYGONTYPE) strcpy(result,"POLYGON"); else if (type == TRIANGLETYPE) strcpy(result,"TRIANGLE"); else if (type == CURVEPOLYTYPE) strcpy(result,"CURVEPOLYGON"); else if (type == MULTIPOLYGONTYPE) strcpy(result,"MULTIPOLYGON"); else if (type == MULTISURFACETYPE) strcpy(result, "MULTISURFACE"); else if (type == COLLECTIONTYPE) strcpy(result,"GEOMETRYCOLLECTION"); else if (type == POLYHEDRALSURFACETYPE) strcpy(result,"POLYHEDRALSURFACE"); else if (type == TINTYPE) strcpy(result,"TIN"); else strcpy(result,"UNKNOWN"); if ( gserialized_has_m(lwgeom) && ! gserialized_has_z(lwgeom) ) strcat(result, "M"); size = strlen(result) + VARHDRSZ ; SET_VARSIZE(text_ob, size); /* size of string */ PG_FREE_IF_COPY(lwgeom, 0); PG_RETURN_POINTER(text_ob); }
Datum LWGEOM_locate_between_m(PG_FUNCTION_ARGS) { GSERIALIZED *gin = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *gout; double start_measure = PG_GETARG_FLOAT8(1); double end_measure = PG_GETARG_FLOAT8(2); LWGEOM *lwin, *lwout; int hasz = gserialized_has_z(gin); int hasm = gserialized_has_m(gin); int type; elog(WARNING,"ST_Locate_Between_Measures and ST_Locate_Along_Measure were deprecated in 2.2.0. Please use ST_LocateAlong and ST_LocateBetween"); if ( end_measure < start_measure ) { lwpgerror("locate_between_m: 2nd arg must be bigger then 1st arg"); PG_RETURN_NULL(); } /* * Return error if input doesn't have a measure */ if ( ! hasm ) { lwpgerror("Geometry argument does not have an 'M' ordinate"); PG_RETURN_NULL(); } /* * Raise an error if input is a polygon, a multipolygon * or a collection */ type = gserialized_get_type(gin); if ( type == POLYGONTYPE || type == MULTIPOLYGONTYPE || type == COLLECTIONTYPE ) { lwpgerror("Areal or Collection types are not supported"); PG_RETURN_NULL(); } lwin = lwgeom_from_gserialized(gin); lwout = lwgeom_locate_between_m(lwin, start_measure, end_measure); lwgeom_free(lwin); if ( lwout == NULL ) { lwout = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, gserialized_get_srid(gin), hasz, hasm); } gout = geometry_serialize(lwout); lwgeom_free(lwout); PG_RETURN_POINTER(gout); }
Datum LWGEOM_getTYPE(PG_FUNCTION_ARGS) { GSERIALIZED *gser; text *text_ob; char *result; uint8_t type; static int maxtyplen = 20; gser = PG_GETARG_GSERIALIZED_P_SLICE(0, 0, gserialized_max_header_size()); text_ob = palloc0(VARHDRSZ + maxtyplen); result = VARDATA(text_ob); type = gserialized_get_type(gser); if (type == POINTTYPE) strcpy(result,"POINT"); else if (type == MULTIPOINTTYPE) strcpy(result,"MULTIPOINT"); else if (type == LINETYPE) strcpy(result,"LINESTRING"); else if (type == CIRCSTRINGTYPE) strcpy(result,"CIRCULARSTRING"); else if (type == COMPOUNDTYPE) strcpy(result, "COMPOUNDCURVE"); else if (type == MULTILINETYPE) strcpy(result,"MULTILINESTRING"); else if (type == MULTICURVETYPE) strcpy(result, "MULTICURVE"); else if (type == POLYGONTYPE) strcpy(result,"POLYGON"); else if (type == TRIANGLETYPE) strcpy(result,"TRIANGLE"); else if (type == CURVEPOLYTYPE) strcpy(result,"CURVEPOLYGON"); else if (type == MULTIPOLYGONTYPE) strcpy(result,"MULTIPOLYGON"); else if (type == MULTISURFACETYPE) strcpy(result, "MULTISURFACE"); else if (type == COLLECTIONTYPE) strcpy(result,"GEOMETRYCOLLECTION"); else if (type == POLYHEDRALSURFACETYPE) strcpy(result,"POLYHEDRALSURFACE"); else if (type == TINTYPE) strcpy(result,"TIN"); else strcpy(result,"UNKNOWN"); if ( gserialized_has_m(gser) && ! gserialized_has_z(gser) ) strcat(result, "M"); SET_VARSIZE(text_ob, strlen(result) + VARHDRSZ); /* size of string */ PG_FREE_IF_COPY(gser, 0); PG_RETURN_TEXT_P(text_ob); }
/** * Check the consistency of the metadata we want to enforce in the typmod: * srid, type and dimensionality. If things are inconsistent, shut down the query. */ GSERIALIZED* postgis_valid_typmod(GSERIALIZED *gser, int32_t typmod) { int32 geom_srid = gserialized_get_srid(gser); int32 geom_type = gserialized_get_type(gser); int32 geom_z = gserialized_has_z(gser); int32 geom_m = gserialized_has_m(gser); int32 typmod_srid = TYPMOD_GET_SRID(typmod); int32 typmod_type = TYPMOD_GET_TYPE(typmod); int32 typmod_z = TYPMOD_GET_Z(typmod); int32 typmod_m = TYPMOD_GET_M(typmod); POSTGIS_DEBUG(2, "Entered function"); /* No typmod (-1) => no preferences */ if (typmod < 0) return gser; POSTGIS_DEBUGF(3, "Got geom(type = %d, srid = %d, hasz = %d, hasm = %d)", geom_type, geom_srid, geom_z, geom_m); POSTGIS_DEBUGF(3, "Got typmod(type = %d, srid = %d, hasz = %d, hasm = %d)", typmod_type, typmod_srid, typmod_z, typmod_m); /* * #3031: If a user is handing us a MULTIPOINT EMPTY but trying to fit it into * a POINT geometry column, there's a strong chance the reason she has * a MULTIPOINT EMPTY because we gave it to her during data dump, * converting the internal POINT EMPTY into a EWKB MULTIPOINT EMPTY * (because EWKB doesn't have a clean way to represent POINT EMPTY). * In such a case, it makes sense to turn the MULTIPOINT EMPTY back into a * point EMPTY, rather than throwing an error. */ if ( typmod_type == POINTTYPE && geom_type == MULTIPOINTTYPE && gserialized_is_empty(gser) ) { LWPOINT *empty_point = lwpoint_construct_empty(geom_srid, geom_z, geom_m); geom_type = POINTTYPE; pfree(gser); if ( gserialized_is_geodetic(gser) ) gser = geography_serialize(lwpoint_as_lwgeom(empty_point)); else gser = geometry_serialize(lwpoint_as_lwgeom(empty_point)); } /* Typmod has a preference for SRID? Geometry SRID had better match. */ if ( typmod_srid > 0 && typmod_srid != geom_srid ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Geometry SRID (%d) does not match column SRID (%d)", geom_srid, typmod_srid) )); } /* Typmod has a preference for geometry type. */ if ( typmod_type > 0 && /* GEOMETRYCOLLECTION column can hold any kind of collection */ ((typmod_type == COLLECTIONTYPE && ! (geom_type == COLLECTIONTYPE || geom_type == MULTIPOLYGONTYPE || geom_type == MULTIPOINTTYPE || geom_type == MULTILINETYPE )) || /* Other types must be strictly equal. */ (typmod_type != geom_type)) ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Geometry type (%s) does not match column type (%s)", lwtype_name(geom_type), lwtype_name(typmod_type)) )); } /* Mismatched Z dimensionality. */ if ( typmod_z && ! geom_z ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Column has Z dimension but geometry does not" ))); } /* Mismatched Z dimensionality (other way). */ if ( geom_z && ! typmod_z ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Geometry has Z dimension but column does not" ))); } /* Mismatched M dimensionality. */ if ( typmod_m && ! geom_m ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Column has M dimension but geometry does not" ))); } /* Mismatched M dimensionality (other way). */ if ( geom_m && ! typmod_m ) { ereport(ERROR, ( errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Geometry has M dimension but column does not" ))); } return gser; }
Datum LWGEOM_line_interpolate_point(PG_FUNCTION_ARGS) { GSERIALIZED *gser = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *result; double distance = PG_GETARG_FLOAT8(1); LWLINE *line; LWGEOM *geom; LWPOINT *point; POINTARRAY *ipa, *opa; POINT4D pt; int nsegs, i; double length, slength, tlength; if ( distance < 0 || distance > 1 ) { elog(ERROR,"line_interpolate_point: 2nd arg isn't within [0,1]"); PG_RETURN_NULL(); } if ( gserialized_get_type(gser) != LINETYPE ) { elog(ERROR,"line_interpolate_point: 1st arg isn't a line"); PG_RETURN_NULL(); } /* Empty.InterpolatePoint == Point Empty */ if ( gserialized_is_empty(gser) ) { point = lwpoint_construct_empty(gserialized_get_srid(gser), gserialized_has_z(gser), gserialized_has_m(gser)); result = geometry_serialize(lwpoint_as_lwgeom(point)); lwpoint_free(point); PG_RETURN_POINTER(result); } geom = lwgeom_from_gserialized(gser); line = lwgeom_as_lwline(geom); ipa = line->points; /* If distance is one of the two extremes, return the point on that * end rather than doing any expensive computations */ if ( distance == 0.0 || distance == 1.0 ) { if ( distance == 0.0 ) getPoint4d_p(ipa, 0, &pt); else getPoint4d_p(ipa, ipa->npoints-1, &pt); opa = ptarray_construct(lwgeom_has_z(geom), lwgeom_has_m(geom), 1); ptarray_set_point4d(opa, 0, &pt); point = lwpoint_construct(line->srid, NULL, opa); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point))); } /* Interpolate a point on the line */ nsegs = ipa->npoints - 1; length = ptarray_length_2d(ipa); tlength = 0; for ( i = 0; i < nsegs; i++ ) { POINT4D p1, p2; POINT4D *p1ptr=&p1, *p2ptr=&p2; /* don't break * strict-aliasing rules */ getPoint4d_p(ipa, i, &p1); getPoint4d_p(ipa, i+1, &p2); /* Find the relative length of this segment */ slength = distance2d_pt_pt((POINT2D*)p1ptr, (POINT2D*)p2ptr)/length; /* If our target distance is before the total length we've seen * so far. create a new point some distance down the current * segment. */ if ( distance < tlength + slength ) { double dseg = (distance - tlength) / slength; interpolate_point4d(&p1, &p2, &pt, dseg); opa = ptarray_construct(lwgeom_has_z(geom), lwgeom_has_m(geom), 1); ptarray_set_point4d(opa, 0, &pt); point = lwpoint_construct(line->srid, NULL, opa); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point))); } tlength += slength; } /* Return the last point on the line. This shouldn't happen, but * could if there's some floating point rounding errors. */ getPoint4d_p(ipa, ipa->npoints-1, &pt); opa = ptarray_construct(lwgeom_has_z(geom), lwgeom_has_m(geom), 1); ptarray_set_point4d(opa, 0, &pt); point = lwpoint_construct(line->srid, NULL, opa); PG_FREE_IF_COPY(gser, 0); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point))); }