/** * Create a new point. Null point array implies empty. Null dimensionality * implies no specified dimensionality in the WKT. */ LWGEOM* wkt_parser_point_new(POINTARRAY *pa, char *dimensionality) { uint8_t flags = wkt_dimensionality(dimensionality); LWDEBUG(4,"entered"); /* No pointarray means it is empty */ if( ! pa ) return lwpoint_as_lwgeom(lwpoint_construct_empty(SRID_UNKNOWN, FLAGS_GET_Z(flags), FLAGS_GET_M(flags))); /* If the number of dimensions is not consistent, we have a problem. */ if( wkt_pointarray_dimensionality(pa, flags) == LW_FALSE ) { ptarray_free(pa); SET_PARSER_ERROR(PARSER_ERROR_MIXDIMS); return NULL; } /* Only one point allowed in our point array! */ if( pa->npoints != 1 ) { ptarray_free(pa); SET_PARSER_ERROR(PARSER_ERROR_LESSPOINTS); return NULL; } return lwpoint_as_lwgeom(lwpoint_construct(SRID_UNKNOWN, NULL, pa)); }
LWGEOM * lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm) { switch(type) { case POINTTYPE: return lwpoint_as_lwgeom(lwpoint_construct_empty(srid, hasz, hasm)); case LINETYPE: return lwline_as_lwgeom(lwline_construct_empty(srid, hasz, hasm)); case POLYGONTYPE: return lwpoly_as_lwgeom(lwpoly_construct_empty(srid, hasz, hasm)); case CURVEPOLYTYPE: return lwcurvepoly_as_lwgeom(lwcurvepoly_construct_empty(srid, hasz, hasm)); case CIRCSTRINGTYPE: return lwcircstring_as_lwgeom(lwcircstring_construct_empty(srid, hasz, hasm)); case TRIANGLETYPE: return lwtriangle_as_lwgeom(lwtriangle_construct_empty(srid, hasz, hasm)); case COMPOUNDTYPE: case MULTIPOINTTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: case COLLECTIONTYPE: return lwcollection_as_lwgeom(lwcollection_construct_empty(type, srid, hasz, hasm)); default: lwerror("lwgeom_construct_empty: unsupported geometry type: %s", lwtype_name(type)); return NULL; } }
/** * POINT */ static LWPOINT* lwpoint_from_twkb_state(twkb_parse_state *s) { static uint32_t npoints = 1; POINTARRAY *pa; LWDEBUG(2,"Entering lwpoint_from_twkb_state"); if ( s->is_empty ) return lwpoint_construct_empty(SRID_UNKNOWN, s->has_z, s->has_m); pa = ptarray_from_twkb_state(s, npoints); return lwpoint_construct(SRID_UNKNOWN, NULL, pa); }
/** * POINT * Read a WKB point, starting just after the endian byte, * type number and optional srid number. * Advance the parse state forward appropriately. * WKB point has just a set of doubles, with the quantity depending on the * dimension of the point, so this looks like a special case of the above * with only one point. */ static LWPOINT* lwpoint_from_wkb_state(wkb_parse_state *s) { static uint32_t npoints = 1; POINTARRAY *pa = NULL; size_t pa_size; uint32_t ndims = 2; const POINT2D *pt; /* Count the dimensions. */ if( s->has_z ) ndims++; if( s->has_m ) ndims++; pa_size = ndims * WKB_DOUBLE_SIZE; /* Does the data we want to read exist? */ wkb_parse_state_check(s, pa_size); /* If we're in a native endianness, we can just copy the data directly! */ if( ! s->swap_bytes ) { pa = ptarray_construct_copy_data(s->has_z, s->has_m, npoints, (uint8_t*)s->pos); s->pos += pa_size; } /* Otherwise we have to read each double, separately */ else { int i = 0; double *dlist; pa = ptarray_construct(s->has_z, s->has_m, npoints); dlist = (double*)(pa->serialized_pointlist); for( i = 0; i < ndims; i++ ) { dlist[i] = double_from_wkb_state(s); } } /* Check for POINT(NaN NaN) ==> POINT EMPTY */ pt = getPoint2d_cp(pa, 0); if ( isnan(pt->x) && isnan(pt->y) ) { ptarray_free(pa); return lwpoint_construct_empty(s->srid, s->has_z, s->has_m); } else { return lwpoint_construct(s->srid, NULL, pa); } }
LWPOINT* lwpoint_force_dims(const LWPOINT *point, int hasz, int hasm) { POINTARRAY *pdims = NULL; LWPOINT *pointout; /* Return 2D empty */ if( lwpoint_is_empty(point) ) { pointout = lwpoint_construct_empty(point->srid, hasz, hasm); } else { /* Always we duplicate the ptarray and return */ pdims = ptarray_force_dims(point->point, hasz, hasm); pointout = lwpoint_construct(point->srid, NULL, pdims); } pointout->type = point->type; return pointout; }
/** * 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; }
/* Return an LWGEOM from a Geometry */ LWGEOM * GEOS2LWGEOM(const GEOSGeometry *geom, char want3d) { int type = GEOSGeomTypeId(geom) ; int hasZ; int SRID = GEOSGetSRID(geom); /* GEOS's 0 is equivalent to our unknown as for SRID values */ if ( SRID == 0 ) SRID = SRID_UNKNOWN; if ( want3d ) { hasZ = GEOSHasZ(geom); if ( ! hasZ ) { LWDEBUG(3, "Geometry has no Z, won't provide one"); want3d = 0; } } /* if ( GEOSisEmpty(geom) ) { return (LWGEOM*)lwcollection_construct_empty(COLLECTIONTYPE, SRID, want3d, 0); } */ switch (type) { const GEOSCoordSequence *cs; POINTARRAY *pa, **ppaa; const GEOSGeometry *g; LWGEOM **geoms; uint32_t i, ngeoms; case GEOS_POINT: LWDEBUG(4, "lwgeom_from_geometry: it's a Point"); cs = GEOSGeom_getCoordSeq(geom); if ( GEOSisEmpty(geom) ) return (LWGEOM*)lwpoint_construct_empty(SRID, want3d, 0); pa = ptarray_from_GEOSCoordSeq(cs, want3d); return (LWGEOM *)lwpoint_construct(SRID, NULL, pa); case GEOS_LINESTRING: case GEOS_LINEARRING: LWDEBUG(4, "lwgeom_from_geometry: it's a LineString or LinearRing"); if ( GEOSisEmpty(geom) ) return (LWGEOM*)lwline_construct_empty(SRID, want3d, 0); cs = GEOSGeom_getCoordSeq(geom); pa = ptarray_from_GEOSCoordSeq(cs, want3d); return (LWGEOM *)lwline_construct(SRID, NULL, pa); case GEOS_POLYGON: LWDEBUG(4, "lwgeom_from_geometry: it's a Polygon"); if ( GEOSisEmpty(geom) ) return (LWGEOM*)lwpoly_construct_empty(SRID, want3d, 0); ngeoms = GEOSGetNumInteriorRings(geom); ppaa = lwalloc(sizeof(POINTARRAY *)*(ngeoms+1)); g = GEOSGetExteriorRing(geom); cs = GEOSGeom_getCoordSeq(g); ppaa[0] = ptarray_from_GEOSCoordSeq(cs, want3d); for (i=0; i<ngeoms; i++) { g = GEOSGetInteriorRingN(geom, i); cs = GEOSGeom_getCoordSeq(g); ppaa[i+1] = ptarray_from_GEOSCoordSeq(cs, want3d); } return (LWGEOM *)lwpoly_construct(SRID, NULL, ngeoms+1, ppaa); case GEOS_MULTIPOINT: case GEOS_MULTILINESTRING: case GEOS_MULTIPOLYGON: case GEOS_GEOMETRYCOLLECTION: LWDEBUG(4, "lwgeom_from_geometry: it's a Collection or Multi"); ngeoms = GEOSGetNumGeometries(geom); geoms = NULL; if ( ngeoms ) { geoms = lwalloc(sizeof(LWGEOM *)*ngeoms); for (i=0; i<ngeoms; i++) { g = GEOSGetGeometryN(geom, i); geoms[i] = GEOS2LWGEOM(g, want3d); } } return (LWGEOM *)lwcollection_construct(type, SRID, NULL, ngeoms, geoms); default: lwerror("GEOS2LWGEOM: unknown geometry type: %d", type); return NULL; } }
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))); }