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 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 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 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 LWGEOM_m_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom; LWPOINT *point = NULL; LWGEOM *lwgeom; POINT3DM p; geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); if ( gserialized_get_type(geom) != POINTTYPE ) lwerror("Argument to M() must be a point"); lwgeom = lwgeom_from_gserialized(geom); point = lwgeom_as_lwpoint(lwgeom); if ( lwgeom_is_empty(lwgeom) ) PG_RETURN_NULL(); /* no M in input */ if ( ! FLAGS_GET_M(point->flags) ) PG_RETURN_NULL(); getPoint3dm_p(point->point, 0, &p); PG_FREE_IF_COPY(geom, 0); PG_RETURN_FLOAT8(p.m); }
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_z_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom; LWPOINT *point = NULL; LWGEOM *lwgeom; POINT3DZ p; geom = PG_GETARG_GSERIALIZED_P(0); if ( gserialized_get_type(geom) != POINTTYPE ) lwpgerror("Argument to ST_Z() must be a point"); lwgeom = lwgeom_from_gserialized(geom); point = lwgeom_as_lwpoint(lwgeom); if ( lwgeom_is_empty(lwgeom) ) PG_RETURN_NULL(); /* no Z in input */ if ( ! gserialized_has_z(geom) ) PG_RETURN_NULL(); getPoint3dz_p(point->point, 0, &p); PG_FREE_IF_COPY(geom, 0); PG_RETURN_FLOAT8(p.z); }
Datum ST_AddMeasure(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 type = gserialized_get_type(gin); /* Raise an error if input is not a linestring or multilinestring */ if ( type != LINETYPE && type != MULTILINETYPE ) { lwpgerror("Only LINESTRING and MULTILINESTRING are supported"); PG_RETURN_NULL(); } lwin = lwgeom_from_gserialized(gin); if ( type == LINETYPE ) lwout = (LWGEOM*)lwline_measured_from_lwline((LWLINE*)lwin, start_measure, end_measure); else lwout = (LWGEOM*)lwmline_measured_from_lwmline((LWMLINE*)lwin, start_measure, end_measure); lwgeom_free(lwin); if ( lwout == NULL ) PG_RETURN_NULL(); gout = geometry_serialize(lwout); lwgeom_free(lwout); PG_RETURN_POINTER(gout); }
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); }
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); }
static int CircTreePIP(const CIRC_NODE* tree1, const GSERIALIZED* g1, const POINT4D* in_point) { int tree1_type = gserialized_get_type(g1); GBOX gbox1; GEOGRAPHIC_POINT in_gpoint; POINT3D in_point3d; POSTGIS_DEBUGF(3, "tree1_type=%d", tree1_type); /* If the tree'ed argument is a polygon, do the P-i-P using the tree-based P-i-P */ if ( tree1_type == POLYGONTYPE || tree1_type == MULTIPOLYGONTYPE ) { POSTGIS_DEBUG(3, "tree is a polygon, using tree PiP"); /* Need a gbox to calculate an outside point */ if ( LW_FAILURE == gserialized_get_gbox_p(g1, &gbox1) ) { LWGEOM* lwgeom1 = lwgeom_from_gserialized(g1); POSTGIS_DEBUG(3, "unable to read gbox from gserialized, calculating from scratch"); lwgeom_calculate_gbox_geodetic(lwgeom1, &gbox1); lwgeom_free(lwgeom1); } /* Flip the candidate point into geographics */ geographic_point_init(in_point->x, in_point->y, &in_gpoint); geog2cart(&in_gpoint, &in_point3d); /* If the candidate isn't in the tree box, it's not in the tree area */ if ( ! gbox_contains_point3d(&gbox1, &in_point3d) ) { POSTGIS_DEBUG(3, "in_point3d is not inside the tree gbox, CircTreePIP returning FALSE"); return LW_FALSE; } /* The candidate point is in the box, so it *might* be inside the tree */ else { POINT2D pt2d_outside; /* latlon */ POINT2D pt2d_inside; pt2d_inside.x = in_point->x; pt2d_inside.y = in_point->y; /* Calculate a definitive outside point */ gbox_pt_outside(&gbox1, &pt2d_outside); POSTGIS_DEBUGF(3, "p2d_inside=POINT(%g %g) p2d_outside=POINT(%g %g)", pt2d_inside.x, pt2d_inside.y, pt2d_outside.x, pt2d_outside.y); /* Test the candidate point for strict containment */ POSTGIS_DEBUG(3, "calling circ_tree_contains_point for PiP test"); return circ_tree_contains_point(tree1, &pt2d_inside, &pt2d_outside, NULL); } } else { POSTGIS_DEBUG(3, "tree1 not polygonal, so CircTreePIP returning FALSE"); return LW_FALSE; } }
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); }
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); }
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); }
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 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 ST_LocateBetweenElevations(PG_FUNCTION_ARGS) { GSERIALIZED *geom_in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); double from = PG_GETARG_FLOAT8(1); double to = PG_GETARG_FLOAT8(2); LWCOLLECTION *geom_out = NULL; LWGEOM *line_in = NULL; char geomtype = gserialized_get_type(geom_in); static int ordinate = 2; /* Z */ if ( ! ( geomtype == LINETYPE || geomtype == MULTILINETYPE ) ) { elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING as arguments."); PG_RETURN_NULL(); } line_in = lwgeom_from_gserialized(geom_in); if ( ! FLAGS_GET_Z(line_in->flags) ) { elog(ERROR,"This function only accepts LINESTRING or MULTILINESTRING with Z values as arguments."); PG_RETURN_NULL(); } if ( geomtype == LINETYPE ) { geom_out = lwline_clip_to_ordinate_range((LWLINE*)line_in, ordinate, from, to); } else if ( geomtype == MULTILINETYPE ) { geom_out = lwmline_clip_to_ordinate_range((LWMLINE*)line_in, ordinate, from, to); } lwgeom_free(line_in); if ( ! geom_out ) { elog(ERROR,"The lwline_clip_to_ordinate_range returned null."); PG_RETURN_NULL(); } PG_FREE_IF_COPY(geom_in, 0); PG_RETURN_POINTER(geometry_serialize((LWGEOM*)geom_out)); }
Datum geometry_geometrytype(PG_FUNCTION_ARGS) { GSERIALIZED *lwgeom; text *type_text; char *type_str = palloc(32); lwgeom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); /* Make it empty string to start */ *type_str = 0; /* Build up the output string */ strncat(type_str, "ST_", 32); strncat(type_str, lwtype_name(gserialized_get_type(lwgeom)), 32); /* Build a text type to store things in */ type_text = cstring2text(type_str); pfree(type_str); PG_FREE_IF_COPY(lwgeom, 0); PG_RETURN_TEXT_P(type_text); }
Datum geometry_geometrytype(PG_FUNCTION_ARGS) { GSERIALIZED *gser; text *type_text; static int type_str_len = 32; char type_str[type_str_len]; /* Read just the header from the toasted tuple */ gser = PG_GETARG_GSERIALIZED_P_SLICE(0, 0, gserialized_max_header_size()); /* Make it empty string to start */ type_str[0] = 0; /* Build up the output string */ strncat(type_str, "ST_", type_str_len); strncat(type_str, lwtype_name(gserialized_get_type(gser)), type_str_len - 3); /* Build a text type to store things in */ type_text = cstring2text(type_str); PG_FREE_IF_COPY(gser, 0); PG_RETURN_TEXT_P(type_text); }
Datum LWGEOM_x_point(PG_FUNCTION_ARGS) { GSERIALIZED *geom; LWGEOM *lwgeom; LWPOINT *point = NULL; POINT2D p; geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); if ( gserialized_get_type(geom) != POINTTYPE ) lwerror("Argument to X() must be a point"); lwgeom = lwgeom_from_gserialized(geom); point = lwgeom_as_lwpoint(lwgeom); if ( lwgeom_is_empty(lwgeom) ) PG_RETURN_NULL(); getPoint2d_p(point->point, 0, &p); PG_FREE_IF_COPY(geom, 0); PG_RETURN_FLOAT8(p.x); }
/** * 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 *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); double distance = PG_GETARG_FLOAT8(1); LWLINE *line; 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 isnt within [0,1]"); PG_RETURN_NULL(); } if ( gserialized_get_type(geom) != LINETYPE ) { elog(ERROR,"line_interpolate_point: 1st arg isnt a line"); PG_RETURN_NULL(); } line = lwgeom_as_lwline(lwgeom_from_gserialized(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_reference_data(FLAGS_GET_Z(line->flags), FLAGS_GET_M(line->flags), 1, (uint8_t*)&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_reference_data(FLAGS_GET_Z(line->flags), FLAGS_GET_M(line->flags), 1, (uint8_t*)&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_reference_data(FLAGS_GET_Z(line->flags), FLAGS_GET_M(line->flags), 1, (uint8_t*)&pt); point = lwpoint_construct(line->srid, NULL, opa); PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(point))); }
Datum LWGEOM_line_substring(PG_FUNCTION_ARGS) { GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); double from = PG_GETARG_FLOAT8(1); double to = PG_GETARG_FLOAT8(2); LWGEOM *olwgeom; POINTARRAY *ipa, *opa; GSERIALIZED *ret; int type = gserialized_get_type(geom); if ( from < 0 || from > 1 ) { elog(ERROR,"line_interpolate_point: 2nd arg isnt within [0,1]"); PG_RETURN_NULL(); } if ( to < 0 || to > 1 ) { elog(ERROR,"line_interpolate_point: 3rd arg isnt within [0,1]"); PG_RETURN_NULL(); } if ( from > to ) { elog(ERROR, "2nd arg must be smaller then 3rd arg"); PG_RETURN_NULL(); } if ( type == LINETYPE ) { LWLINE *iline = lwgeom_as_lwline(lwgeom_from_gserialized(geom)); if ( lwgeom_is_empty((LWGEOM*)iline) ) { /* TODO return empty line */ lwline_release(iline); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } ipa = iline->points; opa = ptarray_substring(ipa, from, to, 0); if ( opa->npoints == 1 ) /* Point returned */ olwgeom = (LWGEOM *)lwpoint_construct(iline->srid, NULL, opa); else olwgeom = (LWGEOM *)lwline_construct(iline->srid, NULL, opa); } else if ( type == MULTILINETYPE ) { LWMLINE *iline; int i = 0, g = 0; int homogeneous = LW_TRUE; LWGEOM **geoms = NULL; double length = 0.0, sublength = 0.0, minprop = 0.0, maxprop = 0.0; iline = lwgeom_as_lwmline(lwgeom_from_gserialized(geom)); if ( lwgeom_is_empty((LWGEOM*)iline) ) { /* TODO return empty collection */ lwmline_release(iline); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } /* Calculate the total length of the mline */ for ( i = 0; i < iline->ngeoms; i++ ) { LWLINE *subline = (LWLINE*)iline->geoms[i]; if ( subline->points && subline->points->npoints > 1 ) length += ptarray_length_2d(subline->points); } geoms = lwalloc(sizeof(LWGEOM*) * iline->ngeoms); /* Slice each sub-geometry of the multiline */ for ( i = 0; i < iline->ngeoms; i++ ) { LWLINE *subline = (LWLINE*)iline->geoms[i]; double subfrom = 0.0, subto = 0.0; if ( subline->points && subline->points->npoints > 1 ) sublength += ptarray_length_2d(subline->points); /* Calculate proportions for this subline */ minprop = maxprop; maxprop = sublength / length; /* This subline doesn't reach the lowest proportion requested or is beyond the highest proporton */ if ( from > maxprop || to < minprop ) continue; if ( from <= minprop ) subfrom = 0.0; if ( to >= maxprop ) subto = 1.0; if ( from > minprop && from <= maxprop ) subfrom = (from - minprop) / (maxprop - minprop); if ( to < maxprop && to >= minprop ) subto = (to - minprop) / (maxprop - minprop); opa = ptarray_substring(subline->points, subfrom, subto, 0); if ( opa && opa->npoints > 0 ) { if ( opa->npoints == 1 ) /* Point returned */ { geoms[g] = (LWGEOM *)lwpoint_construct(iline->srid, NULL, opa); homogeneous = LW_FALSE; } else { geoms[g] = (LWGEOM *)lwline_construct(iline->srid, NULL, opa); } g++; } } /* If we got any points, we need to return a GEOMETRYCOLLECTION */ if ( ! homogeneous ) type = COLLECTIONTYPE; olwgeom = (LWGEOM*)lwcollection_construct(type, iline->srid, NULL, g, geoms); } else { elog(ERROR,"line_interpolate_point: 1st arg isnt a line"); PG_RETURN_NULL(); } ret = geometry_serialize(olwgeom); lwgeom_free(olwgeom); PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(ret); }
Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS) { GSERIALIZED *geom; int32 wanted_index; LWCURVEPOLY *curvepoly = NULL; LWPOLY *poly = NULL; POINTARRAY *ring; LWLINE *line; LWGEOM *lwgeom; GSERIALIZED *result; GBOX *bbox = NULL; int type; POSTGIS_DEBUG(2, "LWGEOM_interierringn_polygon called."); wanted_index = PG_GETARG_INT32(1); if ( wanted_index < 1 ) { /* elog(ERROR, "InteriorRingN: ring number is 1-based"); */ PG_RETURN_NULL(); /* index out of range */ } geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); type = gserialized_get_type(geom); if ( (type != POLYGONTYPE) && (type != CURVEPOLYTYPE) ) { elog(ERROR, "InteriorRingN: geom is not a polygon"); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } lwgeom = lwgeom_from_gserialized(geom); if( lwgeom_is_empty(lwgeom) ) { lwpoly_free(poly); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } if ( type == POLYGONTYPE) { poly = lwgeom_as_lwpoly(lwgeom_from_gserialized(geom)); /* Ok, now we have a polygon. Let's see if it has enough holes */ if ( wanted_index >= poly->nrings ) { lwpoly_free(poly); PG_FREE_IF_COPY(geom, 0); PG_RETURN_NULL(); } ring = poly->rings[wanted_index]; /* COMPUTE_BBOX==TAINTING */ if ( poly->bbox ) { bbox = lwalloc(sizeof(GBOX)); ptarray_calculate_gbox_cartesian(ring, bbox); } /* This is a LWLINE constructed by interior ring POINTARRAY */ line = lwline_construct(poly->srid, bbox, ring); result = geometry_serialize((LWGEOM *)line); lwline_release(line); lwpoly_free(poly); } else { curvepoly = lwgeom_as_lwcurvepoly(lwgeom_from_gserialized(geom)); if (wanted_index >= curvepoly->nrings) { PG_FREE_IF_COPY(geom, 0); lwgeom_release((LWGEOM *)curvepoly); PG_RETURN_NULL(); } result = geometry_serialize(curvepoly->rings[wanted_index]); lwgeom_free((LWGEOM*)curvepoly); } PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
Datum LWGEOM_to_latlon(PG_FUNCTION_ARGS) { /* Get the parameters */ GSERIALIZED *pg_lwgeom = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); text *format_text = PG_GETARG_TEXT_P(1); LWGEOM *lwgeom; char *format_str = NULL; char * formatted_str; text * formatted_text; char * tmp; /* Only supports points. */ uint8_t geom_type = gserialized_get_type(pg_lwgeom); if (POINTTYPE != geom_type) { lwerror("Only points are supported, you tried type %s.", lwtype_name(geom_type)); } /* Convert to LWGEOM type */ lwgeom = lwgeom_from_gserialized(pg_lwgeom); if (format_text == NULL) { lwerror("ST_AsLatLonText: invalid format string (null"); PG_RETURN_NULL(); } format_str = text2cstring(format_text); assert(format_str != NULL); /* The input string supposedly will be in the database encoding, so convert to UTF-8. */ tmp = (char *)pg_do_encoding_conversion( (uint8_t *)format_str, strlen(format_str), GetDatabaseEncoding(), PG_UTF8); assert(tmp != NULL); if ( tmp != format_str ) { pfree(format_str); format_str = tmp; } /* Produce the formatted string. */ formatted_str = lwpoint_to_latlon((LWPOINT *)lwgeom, format_str); assert(formatted_str != NULL); pfree(format_str); /* Convert the formatted string from UTF-8 back to database encoding. */ tmp = (char *)pg_do_encoding_conversion( (uint8_t *)formatted_str, strlen(formatted_str), PG_UTF8, GetDatabaseEncoding()); assert(tmp != NULL); if ( tmp != formatted_str) { pfree(formatted_str); formatted_str = tmp; } /* Convert to the postgres output string type. */ formatted_text = cstring2text(formatted_str); pfree(formatted_str); PG_RETURN_POINTER(formatted_text); }
static int geography_distance_cache_tolerance(FunctionCallInfoData* fcinfo, const GSERIALIZED* g1, const GSERIALIZED* g2, const SPHEROID* s, double tolerance, double* distance) { CircTreeGeomCache* tree_cache = NULL; int type1 = gserialized_get_type(g1); int type2 = gserialized_get_type(g2); Assert(distance); /* Two points? Get outa here... */ if ( type1 == POINTTYPE && type2 == POINTTYPE ) return LW_FAILURE; /* Fetch/build our cache, if appropriate, etc... */ tree_cache = GetCircTreeGeomCache(fcinfo, g1, g2); /* OK, we have an index at the ready! Use it for the one tree argument and */ /* fill in the other tree argument */ if ( tree_cache && tree_cache->argnum && tree_cache->index ) { CIRC_NODE* circtree_cached = tree_cache->index; CIRC_NODE* circtree = NULL; const GSERIALIZED* g_cached; const GSERIALIZED* g; LWGEOM* lwgeom = NULL; int geomtype_cached; int geomtype; POINT4D p4d; /* We need to dynamically build a tree for the uncached side of the function call */ if ( tree_cache->argnum == 1 ) { g_cached = g1; g = g2; geomtype_cached = type1; geomtype = type2; } else if ( tree_cache->argnum == 2 ) { g_cached = g2; g = g1; geomtype_cached = type2; geomtype = type1; } else { lwpgerror("geography_distance_cache this cannot happen!"); return LW_FAILURE; } lwgeom = lwgeom_from_gserialized(g); if ( geomtype_cached == POLYGONTYPE || geomtype_cached == MULTIPOLYGONTYPE ) { lwgeom_startpoint(lwgeom, &p4d); if ( CircTreePIP(circtree_cached, g_cached, &p4d) ) { *distance = 0.0; lwgeom_free(lwgeom); return LW_SUCCESS; } } circtree = lwgeom_calculate_circ_tree(lwgeom); if ( geomtype == POLYGONTYPE || geomtype == MULTIPOLYGONTYPE ) { POINT2D p2d; circ_tree_get_point(circtree_cached, &p2d); p4d.x = p2d.x; p4d.y = p2d.y; if ( CircTreePIP(circtree, g, &p4d) ) { *distance = 0.0; circ_tree_free(circtree); lwgeom_free(lwgeom); return LW_SUCCESS; } } *distance = circ_tree_distance_tree(circtree_cached, circtree, s, tolerance); circ_tree_free(circtree); lwgeom_free(lwgeom); return LW_SUCCESS; } else { return LW_FAILURE; } }
/* * Populate a bounding box *without* allocating an LWGEOM. Useful * for some performance purposes. */ static int gserialized_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox) { uint32_t type = gserialized_get_type(g); /* Peeking doesn't help if you already have a box or are geodetic */ if ( FLAGS_GET_GEODETIC(g->flags) || FLAGS_GET_BBOX(g->flags) ) { return LW_FAILURE; } /* Boxes of points are easy peasy */ if ( type == POINTTYPE ) { int i = 1; /* Start past <pointtype><padding> */ double *dptr = (double*)(g->data); /* Read the empty flag */ int *iptr = (int*)(g->data); int isempty = (iptr[1] == 0); /* EMPTY point has no box */ if ( isempty ) return LW_FAILURE; gbox->xmin = gbox->xmax = dptr[i++]; gbox->ymin = gbox->ymax = dptr[i++]; if ( FLAGS_GET_Z(g->flags) ) { gbox->zmin = gbox->zmax = dptr[i++]; } if ( FLAGS_GET_M(g->flags) ) { gbox->mmin = gbox->mmax = dptr[i++]; } gbox_float_round(gbox); return LW_SUCCESS; } /* We can calculate the box of a two-point cartesian line trivially */ else if ( type == LINETYPE ) { int ndims = FLAGS_NDIMS(g->flags); int i = 0; /* Start at <linetype><npoints> */ double *dptr = (double*)(g->data); int *iptr = (int*)(g->data); int npoints = iptr[1]; /* Read the npoints */ /* This only works with 2-point lines */ if ( npoints != 2 ) return LW_FAILURE; /* Advance to X */ /* Past <linetype><npoints> */ i++; gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]); /* Advance to Y */ i++; gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]); if ( FLAGS_GET_Z(g->flags) ) { /* Advance to Z */ i++; gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]); } if ( FLAGS_GET_M(g->flags) ) { /* Advance to M */ i++; gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]); } gbox_float_round(gbox); return LW_SUCCESS; } /* We can also do single-entry multi-points */ else if ( type == MULTIPOINTTYPE ) { int i = 0; /* Start at <multipointtype><ngeoms> */ double *dptr = (double*)(g->data); int *iptr = (int*)(g->data); int ngeoms = iptr[1]; /* Read the ngeoms */ /* This only works with single-entry multipoints */ if ( ngeoms != 1 ) return LW_FAILURE; /* Move forward two doubles (four ints) */ /* Past <multipointtype><ngeoms> */ /* Past <pointtype><emtpyflat> */ i += 2; /* Read the doubles from the one point */ gbox->xmin = gbox->xmax = dptr[i++]; gbox->ymin = gbox->ymax = dptr[i++]; if ( FLAGS_GET_Z(g->flags) ) { gbox->zmin = gbox->zmax = dptr[i++]; } if ( FLAGS_GET_M(g->flags) ) { gbox->mmin = gbox->mmax = dptr[i++]; } gbox_float_round(gbox); return LW_SUCCESS; } /* And we can do single-entry multi-lines with two vertices (!!!) */ else if ( type == MULTILINETYPE ) { int ndims = FLAGS_NDIMS(g->flags); int i = 0; /* Start at <multilinetype><ngeoms> */ double *dptr = (double*)(g->data); int *iptr = (int*)(g->data); int ngeoms = iptr[1]; /* Read the ngeoms */ int npoints; /* This only works with 1-line multilines */ if ( ngeoms != 1 ) return LW_FAILURE; /* Npoints is at <multilinetype><ngeoms><linetype><npoints> */ npoints = iptr[3]; if ( npoints != 2 ) return LW_FAILURE; /* Advance to X */ /* Move forward two doubles (four ints) */ /* Past <multilinetype><ngeoms> */ /* Past <linetype><npoints> */ i += 2; gbox->xmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->xmax = FP_MAX(dptr[i], dptr[i+ndims]); /* Advance to Y */ i++; gbox->ymin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->ymax = FP_MAX(dptr[i], dptr[i+ndims]); if ( FLAGS_GET_Z(g->flags) ) { /* Advance to Z */ i++; gbox->zmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->zmax = FP_MAX(dptr[i], dptr[i+ndims]); } if ( FLAGS_GET_M(g->flags) ) { /* Advance to M */ i++; gbox->mmin = FP_MIN(dptr[i], dptr[i+ndims]); gbox->mmax = FP_MAX(dptr[i], dptr[i+ndims]); } gbox_float_round(gbox); return LW_SUCCESS; } return LW_FAILURE; }