Datum ST_LineCrossingDirection(PG_FUNCTION_ARGS) { int type1, type2, rv; LWLINE *l1 = NULL; LWLINE *l2 = NULL; GSERIALIZED *geom1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *geom2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2)); type1 = gserialized_get_type(geom1); type2 = gserialized_get_type(geom2); if ( type1 != LINETYPE || type2 != LINETYPE ) { elog(ERROR,"This function only accepts LINESTRING as arguments."); PG_RETURN_NULL(); } l1 = lwgeom_as_lwline(lwgeom_from_gserialized(geom1)); l2 = lwgeom_as_lwline(lwgeom_from_gserialized(geom2)); rv = lwline_crossing_direction(l1, l2); PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); PG_RETURN_INT32(rv); }
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_line_locate_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1); LWLINE *lwline; LWPOINT *lwpoint; POINTARRAY *pa; POINT4D p, p_proj; double ret; if ( gserialized_get_type(geom1) != LINETYPE ) { elog(ERROR,"line_locate_point: 1st arg isn't a line"); PG_RETURN_NULL(); } if ( gserialized_get_type(geom2) != POINTTYPE ) { elog(ERROR,"line_locate_point: 2st arg isn't a point"); PG_RETURN_NULL(); } error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2)); lwline = lwgeom_as_lwline(lwgeom_from_gserialized(geom1)); lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2)); pa = lwline->points; lwpoint_getPoint4d_p(lwpoint, &p); ret = ptarray_locate_point(pa, &p, NULL, &p_proj); PG_RETURN_FLOAT8(ret); }
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_from_WKB(PG_FUNCTION_ARGS) { GSERIALIZED *geom; int32 srid; GSERIALIZED *result = NULL; geom = (GSERIALIZED *)DatumGetPointer(DirectFunctionCall1( LWGEOMFromWKB, PG_GETARG_DATUM(0))); if ( gserialized_get_srid(geom) != SRID_UNKNOWN ) { elog(WARNING, "OGC WKB expected, EWKB provided - use GeometryFromEWKB() for this"); } /* read user-requested SRID if any */ if ( PG_NARGS() > 1 ) { srid = PG_GETARG_INT32(1); if ( srid != gserialized_get_srid(geom) ) gserialized_set_srid(geom, srid); } if ( ! result ) result = geom; PG_RETURN_POINTER(result); }
Datum lwgeom_gt(PG_FUNCTION_ARGS) { GSERIALIZED *geom1 = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *geom2 = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); GBOX box1; GBOX box2; POSTGIS_DEBUG(2, "lwgeom_gt called"); if (gserialized_get_srid(geom1) != gserialized_get_srid(geom2)) { elog(BTREE_SRID_MISMATCH_SEVERITY, "Operation on two GEOMETRIES with different SRIDs\n"); PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); PG_RETURN_NULL(); } gserialized_get_gbox_p(geom1, &box1); gserialized_get_gbox_p(geom2, &box2); PG_FREE_IF_COPY(geom1, 0); PG_FREE_IF_COPY(geom2, 1); if ( ! FPeq(box1.xmin , box2.xmin) ) { if (box1.xmin > box2.xmin) { PG_RETURN_BOOL(TRUE); } } if ( ! FPeq(box1.ymin , box2.ymin) ) { if (box1.ymin > box2.ymin) { PG_RETURN_BOOL(TRUE); } } if ( ! FPeq(box1.xmax , box2.xmax) ) { if (box1.xmax > box2.xmax) { PG_RETURN_BOOL(TRUE); } } if ( ! FPeq(box1.ymax , box2.ymax) ) { if (box1.ymax > box2.ymax) { PG_RETURN_BOOL(TRUE); } } PG_RETURN_BOOL(FALSE); }
Datum geometry_distance_spheroid(PG_FUNCTION_ARGS) { GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0); GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1); SPHEROID *sphere = (SPHEROID *)PG_GETARG_POINTER(2); int type1 = gserialized_get_type(geom1); int type2 = gserialized_get_type(geom2); bool use_spheroid = PG_GETARG_BOOL(3); LWGEOM *lwgeom1, *lwgeom2; double distance; /* Calculate some other parameters on the spheroid */ spheroid_init(sphere, sphere->a, sphere->b); /* Catch sphere special case and re-jig spheroid appropriately */ if ( ! use_spheroid ) { sphere->a = sphere->b = sphere->radius; } if ( ! ( type1 == POINTTYPE || type1 == LINETYPE || type1 == POLYGONTYPE || type1 == MULTIPOINTTYPE || type1 == MULTILINETYPE || type1 == MULTIPOLYGONTYPE )) { elog(ERROR, "geometry_distance_spheroid: Only point/line/polygon supported.\n"); PG_RETURN_NULL(); } if ( ! ( type2 == POINTTYPE || type2 == LINETYPE || type2 == POLYGONTYPE || type2 == MULTIPOINTTYPE || type2 == MULTILINETYPE || type2 == MULTIPOLYGONTYPE )) { elog(ERROR, "geometry_distance_spheroid: Only point/line/polygon supported.\n"); PG_RETURN_NULL(); } if (gserialized_get_srid(geom1) != gserialized_get_srid(geom2)) { elog(ERROR, "geometry_distance_spheroid: Operation on two GEOMETRIES with different SRIDs\n"); PG_RETURN_NULL(); } /* Get #LWGEOM structures */ lwgeom1 = lwgeom_from_gserialized(geom1); lwgeom2 = lwgeom_from_gserialized(geom2); /* We are going to be calculating geodetic distances */ lwgeom_set_geodetic(lwgeom1, LW_TRUE); lwgeom_set_geodetic(lwgeom2, LW_TRUE); distance = lwgeom_distance_spheroid(lwgeom1, lwgeom2, sphere, 0.0); PG_RETURN_FLOAT8(distance); }
Datum sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS) { #if POSTGIS_SFCGAL_VERSION < 12 lwpgerror("The SFCGAL version this PostGIS binary " "was compiled against (%d) doesn't support " "'sfcgal_geometry_approximate_medial_axis' function (1.2.0+ required)", POSTGIS_SFCGAL_VERSION); PG_RETURN_NULL(); #else /* POSTGIS_SFCGAL_VERSION >= 12 */ GSERIALIZED *input, *output; sfcgal_geometry_t *geom; sfcgal_geometry_t *result; srid_t srid; sfcgal_postgis_init(); input = PG_GETARG_GSERIALIZED_P(0); srid = gserialized_get_srid(input); geom = POSTGIS2SFCGALGeometry(input); PG_FREE_IF_COPY(input, 0); result = sfcgal_geometry_approximate_medial_axis(geom); sfcgal_geometry_delete(geom); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); PG_RETURN_POINTER(output); #endif /* POSTGIS_SFCGAL_VERSION >= 12 */ }
Datum sfcgal_union3D(PG_FUNCTION_ARGS) { GSERIALIZED *input0, *input1, *output; sfcgal_geometry_t *geom0, *geom1; sfcgal_geometry_t *result; srid_t srid; sfcgal_postgis_init(); input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); srid = gserialized_get_srid(input0); input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); geom0 = POSTGIS2SFCGALGeometry(input0); PG_FREE_IF_COPY(input0, 0); geom1 = POSTGIS2SFCGALGeometry(input1); PG_FREE_IF_COPY(input1, 1); result = sfcgal_geometry_union_3d(geom0, geom1); sfcgal_geometry_delete(geom0); sfcgal_geometry_delete(geom1); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); PG_RETURN_POINTER(output); }
Datum LWGEOM_get_srid(PG_FUNCTION_ARGS) { GSERIALIZED *geom=(GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); int srid = gserialized_get_srid (geom); PG_FREE_IF_COPY(geom,0); PG_RETURN_INT32(srid); }
Datum LWGEOM_get_srid(PG_FUNCTION_ARGS) { GSERIALIZED *geom=PG_GETARG_GSERIALIZED_P(0); int srid = gserialized_get_srid (geom); PG_FREE_IF_COPY(geom,0); PG_RETURN_INT32(srid); }
Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS) { GSERIALIZED *input0, *input1, *output; sfcgal_geometry_t *geom0, *geom1; sfcgal_geometry_t *result; srid_t srid; sfcgal_postgis_init(); input0 = PG_GETARG_GSERIALIZED_P(0); srid = gserialized_get_srid(input0); input1 = PG_GETARG_GSERIALIZED_P(1); geom0 = POSTGIS2SFCGALGeometry(input0); PG_FREE_IF_COPY(input0, 0); geom1 = POSTGIS2SFCGALGeometry(input1); PG_FREE_IF_COPY(input1, 1); result = sfcgal_geometry_minkowski_sum(geom0, geom1); sfcgal_geometry_delete(geom0); sfcgal_geometry_delete(geom1); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); PG_RETURN_POINTER(output); }
Datum sfcgal_extrude(PG_FUNCTION_ARGS) { GSERIALIZED *input, *output; sfcgal_geometry_t *geom; sfcgal_geometry_t *result; double dx, dy, dz; srid_t srid; sfcgal_postgis_init(); input = PG_GETARG_GSERIALIZED_P(0); srid = gserialized_get_srid(input); geom = POSTGIS2SFCGALGeometry(input); PG_FREE_IF_COPY(input, 0); dx = PG_GETARG_FLOAT8(1); dy = PG_GETARG_FLOAT8(2); dz = PG_GETARG_FLOAT8(3); result = sfcgal_geometry_extrude(geom, dx, dy, dz); sfcgal_geometry_delete(geom); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); PG_RETURN_POINTER(output); }
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 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 */ }
Datum LWGEOM_line_locate_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); GSERIALIZED *geom2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); LWLINE *lwline; LWPOINT *lwpoint; POINTARRAY *pa; POINT2D p; double ret; if ( gserialized_get_type(geom1) != LINETYPE ) { elog(ERROR,"line_locate_point: 1st arg isnt a line"); PG_RETURN_NULL(); } if ( gserialized_get_type(geom2) != POINTTYPE ) { elog(ERROR,"line_locate_point: 2st arg isnt a point"); PG_RETURN_NULL(); } if ( gserialized_get_srid(geom1) != gserialized_get_srid(geom2) ) { elog(ERROR, "Operation on two geometries with different SRIDs"); PG_RETURN_NULL(); } lwline = lwgeom_as_lwline(lwgeom_from_gserialized(geom1)); lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom2)); pa = lwline->points; lwpoint_getPoint2d_p(lwpoint, &p); ret = ptarray_locate_point(pa, &p, NULL); PG_RETURN_FLOAT8(ret); }
/* Conversion from GSERIALIZED* to SFCGAL::PreparedGeometry */ sfcgal_prepared_geometry_t* POSTGIS2SFCGALPreparedGeometry(GSERIALIZED *pglwgeom) { sfcgal_geometry_t* g; LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom); if (!lwgeom) { lwpgerror("POSTGIS2SFCGALPreparedGeometry: Unable to deserialize input"); } g = LWGEOM2SFCGAL(lwgeom); lwgeom_free(lwgeom); return sfcgal_prepared_geometry_create_from_geometry(g, gserialized_get_srid(pglwgeom)); }
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; }
Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS) { GSERIALIZED *input, *output; sfcgal_geometry_t *geom; sfcgal_geometry_t *result; srid_t srid; sfcgal_postgis_init(); input = PG_GETARG_GSERIALIZED_P(0); srid = gserialized_get_srid(input); geom = POSTGIS2SFCGALGeometry(input); PG_FREE_IF_COPY(input, 0); result = sfcgal_geometry_straight_skeleton(geom); sfcgal_geometry_delete(geom); output = SFCGALGeometry2POSTGIS(result, 0, srid); sfcgal_geometry_delete(result); PG_RETURN_POINTER(output); }
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))); }
/** * 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 transform_geom(PG_FUNCTION_ARGS) { GSERIALIZED *geom; GSERIALIZED *result=NULL; LWGEOM *lwgeom; projPJ input_pj, output_pj; char *input_proj4, *output_proj4; text *input_proj4_text; text *output_proj4_text; int32 result_srid ; char *pj_errstr; result_srid = PG_GETARG_INT32(3); if (result_srid == SRID_UNKNOWN) { elog(ERROR,"tranform: destination SRID = %d",SRID_UNKNOWN); PG_RETURN_NULL(); } geom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)); if (gserialized_get_srid(geom) == SRID_UNKNOWN) { pfree(geom); elog(ERROR,"transform_geom: source SRID = %d",SRID_UNKNOWN); PG_RETURN_NULL(); } /* Set the search path if we haven't already */ SetPROJ4LibPath(); /* Read the arguments */ input_proj4_text = (PG_GETARG_TEXT_P(1)); output_proj4_text = (PG_GETARG_TEXT_P(2)); /* Convert from text to cstring for libproj */ input_proj4 = text2cstring(input_proj4_text); output_proj4 = text2cstring(output_proj4_text); /* make input and output projection objects */ input_pj = lwproj_from_string(input_proj4); if ( input_pj == NULL ) { pj_errstr = pj_strerrno(*pj_get_errno_ref()); if ( ! pj_errstr ) pj_errstr = ""; /* we need this for error reporting */ /* pfree(input_proj4); */ pfree(output_proj4); pfree(geom); elog(ERROR, "transform_geom: could not parse proj4 string '%s' %s", input_proj4, pj_errstr); PG_RETURN_NULL(); } pfree(input_proj4); output_pj = lwproj_from_string(output_proj4); if ( output_pj == NULL ) { pj_errstr = pj_strerrno(*pj_get_errno_ref()); if ( ! pj_errstr ) pj_errstr = ""; /* we need this for error reporting */ /* pfree(output_proj4); */ pj_free(input_pj); pfree(geom); elog(ERROR, "transform_geom: couldn't parse proj4 output string: '%s': %s", output_proj4, pj_errstr); PG_RETURN_NULL(); } pfree(output_proj4); /* now we have a geometry, and input/output PJ structs. */ lwgeom = lwgeom_from_gserialized(geom); lwgeom_transform(lwgeom, input_pj, output_pj); lwgeom->srid = result_srid; /* clean up */ pj_free(input_pj); pj_free(output_pj); /* 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 */ }