int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox) { if ( ! lwgeom ) return G_FAILURE; switch (TYPE_GETTYPE(lwgeom->type)) { case POINTTYPE: return lwpoint_calculate_gbox((LWPOINT *)lwgeom, gbox); case LINETYPE: return lwline_calculate_gbox((LWLINE *)lwgeom, gbox); case CIRCSTRINGTYPE: return lwcircstring_calculate_gbox((LWCIRCSTRING *)lwgeom, gbox); case POLYGONTYPE: return lwpoly_calculate_gbox((LWPOLY *)lwgeom, gbox); case COMPOUNDTYPE: case CURVEPOLYTYPE: case MULTIPOINTTYPE: case MULTILINETYPE: case MULTICURVETYPE: case MULTIPOLYGONTYPE: case MULTISURFACETYPE: case COLLECTIONTYPE: return lwcollection_calculate_gbox((LWCOLLECTION *)lwgeom, gbox); } /* Never get here, please. */ lwerror("unsupported type (%d)", TYPE_GETTYPE(lwgeom->type)); return G_FAILURE; }
Datum BOX2DFLOAT4_construct(PG_FUNCTION_ARGS) { PG_LWGEOM *min = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); PG_LWGEOM *max = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); BOX2DFLOAT4 *result = palloc(sizeof(BOX2DFLOAT4)); LWGEOM *minpoint, *maxpoint; POINT2D minp, maxp; minpoint = lwgeom_deserialize(SERIALIZED_FORM(min)); maxpoint = lwgeom_deserialize(SERIALIZED_FORM(max)); if ( TYPE_GETTYPE(minpoint->type) != POINTTYPE || TYPE_GETTYPE(maxpoint->type) != POINTTYPE ) { elog(ERROR, "BOX2DFLOAT4_construct: args must be points"); PG_RETURN_NULL(); } errorIfSRIDMismatch(minpoint->SRID, maxpoint->SRID); getPoint2d_p(((LWPOINT *)minpoint)->point, 0, &minp); getPoint2d_p(((LWPOINT *)maxpoint)->point, 0, &maxp); result->xmax = maxp.x; result->ymax = maxp.y; result->xmin = minp.x; result->ymin = minp.y; PG_RETURN_POINTER(result); }
Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS) { PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); LWPOLY *poly = NULL; LWCURVEPOLY *curvepoly = NULL; POINTARRAY *extring; LWGEOM *ring; LWLINE *line; PG_LWGEOM *result; BOX2DFLOAT4 *bbox=NULL; POSTGIS_DEBUG(2, "LWGEOM_exteriorring_polygon called."); if ( TYPE_GETTYPE(geom->type) != POLYGONTYPE && TYPE_GETTYPE(geom->type) != CURVEPOLYTYPE) { elog(ERROR, "ExteriorRing: geom is not a polygon"); PG_RETURN_NULL(); } if (lwgeom_getType((uchar)SERIALIZED_FORM(geom)[0]) == POLYGONTYPE) { poly = lwpoly_deserialize(SERIALIZED_FORM(geom)); /* Ok, now we have a polygon. Here is its exterior ring. */ extring = poly->rings[0]; /* * This is a LWLINE constructed by exterior ring POINTARRAY * If the input geom has a bbox, use it for * the output geom, as exterior ring makes it up ! */ if ( poly->bbox ) bbox=box2d_clone(poly->bbox); line = lwline_construct(poly->SRID, bbox, extring); result = pglwgeom_serialize((LWGEOM *)line); lwgeom_release((LWGEOM *)line); lwgeom_release((LWGEOM *)poly); } else { curvepoly = lwcurvepoly_deserialize(SERIALIZED_FORM(geom)); ring = curvepoly->rings[0]; result = pglwgeom_serialize(ring); lwgeom_release(ring); } PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }
/* * Construct a LWLINE from an array of LWPOINTs * LWLINE dimensions are large enough to host all input dimensions. */ LWLINE * lwline_from_lwpointarray(int SRID, unsigned int npoints, LWPOINT **points) { int zmflag=0; unsigned int i; POINTARRAY *pa; uchar *newpoints, *ptr; size_t ptsize, size; /* * Find output dimensions, check integrity */ for (i=0; i<npoints; i++) { if ( TYPE_GETTYPE(points[i]->type) != POINTTYPE ) { lwerror("lwline_from_lwpointarray: invalid input type: %s", lwgeom_typename(TYPE_GETTYPE(points[i]->type))); return NULL; } if ( TYPE_HASZ(points[i]->type) ) zmflag |= 2; if ( TYPE_HASM(points[i]->type) ) zmflag |= 1; if ( zmflag == 3 ) break; } if ( zmflag == 0 ) ptsize=2*sizeof(double); else if ( zmflag == 3 ) ptsize=4*sizeof(double); else ptsize=3*sizeof(double); /* * Allocate output points array */ size = ptsize*npoints; newpoints = lwalloc(size); memset(newpoints, 0, size); ptr=newpoints; for (i=0; i<npoints; i++) { size=pointArray_ptsize(points[i]->point); memcpy(ptr, getPoint_internal(points[i]->point, 0), size); ptr+=ptsize; } pa = pointArray_construct(newpoints, zmflag&2, zmflag&1, npoints); return lwline_construct(SRID, NULL, pa); }
char * lwgeom_summary(LWGEOM *lwgeom, int offset) { char *result; switch (TYPE_GETTYPE(lwgeom->type)) { case POINTTYPE: return lwpoint_summary((LWPOINT *)lwgeom, offset); case LINETYPE: return lwline_summary((LWLINE *)lwgeom, offset); case POLYGONTYPE: return lwpoly_summary((LWPOLY *)lwgeom, offset); case MULTIPOINTTYPE: case MULTILINETYPE: case MULTIPOLYGONTYPE: case COLLECTIONTYPE: return lwcollection_summary((LWCOLLECTION *)lwgeom, offset); default: result = palloc(256); sprintf(result, "Object is of unknown type: %d", lwgeom->type); return result; } return NULL; }
char * lwpoly_summary(LWPOLY *poly, int offset) { char tmp[256]; size_t size = 64*(poly->nrings+1)+128; char *result; int i; char *pad=""; LWDEBUG(2, "lwpoly_summary called"); result = lwalloc(size); sprintf(result, "%*.s%s[%s] with %i rings\n", offset, pad, lwgeom_typename(TYPE_GETTYPE(poly->type)), lwgeom_typeflags(poly->type), poly->nrings); for (i=0; i<poly->nrings; i++) { sprintf(tmp,"%s ring %i has %i points\n", pad, i, poly->rings[i]->npoints); strcat(result,tmp); } LWDEBUG(3, "lwpoly_summary returning"); return result; }
char * lwcollection_summary(LWCOLLECTION *col, int offset) { size_t size = 128; char *result; char *tmp; int i; char *pad=""; LWDEBUG(2, "lwcollection_summary called"); result = (char *)lwalloc(size); sprintf(result, "%*.s%s[%s] with %d elements\n", offset, pad, lwgeom_typename(TYPE_GETTYPE(col->type)), lwgeom_typeflags(col->type), col->ngeoms); for (i=0; i<col->ngeoms; i++) { tmp = lwgeom_summary(col->geoms[i], offset+2); size += strlen(tmp)+1; result = lwrealloc(result, size); LWDEBUGF(4, "Reallocated %d bytes for result", size); strcat(result, tmp); lwfree(tmp); } LWDEBUG(3, "lwcollection_summary returning"); return result; }
/* * Add 'what' to this string at position 'where' * where=0 == prepend * where=-1 == append * Returns a COMPOUND or a GEOMETRYCOLLECTION */ LWGEOM * lwcompound_add(const LWCOMPOUND *to, uint32 where, const LWGEOM *what) { LWCOLLECTION *col; LWGEOM **geoms; int newtype; LWDEBUG(2, "lwcompound_add called."); if(where != -1 && where != 0) { lwerror("lwcompound_add only supports 0 or -1 as a second argument, not %d", where); return NULL; } /* dimensions compatibility are checked by caller */ /* Construct geoms array */ geoms = lwalloc(sizeof(LWGEOM *)*2); if(where == -1) /* append */ { geoms[0] = lwgeom_clone((LWGEOM *)to); geoms[1] = lwgeom_clone(what); } else /* prepend */ { geoms[0] = lwgeom_clone(what); geoms[1] = lwgeom_clone((LWGEOM *)to); } /* reset SRID and wantbbox flag from component types */ geoms[0]->SRID = geoms[1]->SRID = -1; TYPE_SETHASSRID(geoms[0]->type, 0); TYPE_SETHASSRID(geoms[1]->type, 0); TYPE_SETHASBBOX(geoms[0]->type, 0); TYPE_SETHASBBOX(geoms[1]->type, 0); /* Find appropriate geom type */ if(TYPE_GETTYPE(what->type) == LINETYPE || TYPE_GETTYPE(what->type) == CIRCSTRINGTYPE) newtype = COMPOUNDTYPE; else newtype = COLLECTIONTYPE; col = lwcollection_construct(newtype, to->SRID, NULL, 2, geoms); return (LWGEOM *)col; }
/** * Re-write the measure ordinate (or add one, if it isn't already there) interpolating * the measure between the supplied start and end values. */ LWLINE* lwline_measured_from_lwline(const LWLINE *lwline, double m_start, double m_end) { int i = 0; int hasm = 0, hasz = 0; int npoints = 0; double length = 0.0; double length_so_far = 0.0; double m_range = m_end - m_start; double m; POINTARRAY *pa = NULL; POINT3DZ p1, p2; if ( TYPE_GETTYPE(lwline->type) != LINETYPE ) { lwerror("lwline_construct_from_lwline: only line types supported"); return NULL; } hasz = TYPE_HASZ(lwline->type); hasm = 1; /* Null points or npoints == 0 will result in empty return geometry */ if ( lwline->points ) { npoints = lwline->points->npoints; length = lwgeom_pointarray_length2d(lwline->points); getPoint3dz_p(lwline->points, 0, &p1); } pa = ptarray_construct(hasz, hasm, npoints); for ( i = 0; i < npoints; i++ ) { POINT4D q; POINT2D a, b; getPoint3dz_p(lwline->points, i, &p2); a.x = p1.x; a.y = p1.y; b.x = p2.x; b.y = p2.y; length_so_far += distance2d_pt_pt(&a, &b); if ( length > 0.0 ) m = m_start + m_range * length_so_far / length; else m = 0.0; q.x = p2.x; q.y = p2.y; q.z = p2.z; q.m = m; setPoint4d(pa, i, &q); p1 = p2; } return lwline_construct(lwline->SRID, NULL, pa); }
/** * Calculate the area of an LWGEOM. Anything except POLYGON, MULTIPOLYGON * and GEOMETRYCOLLECTION return zero immediately. Multi's recurse, polygons * calculate external ring area and subtract internal ring area. A GBOX is * required to check relationship to equator an outside point. * WARNING: Does NOT WORK for polygons over equator or pole. */ double lwgeom_area_spheroid(const LWGEOM *lwgeom, const GBOX *gbox, const SPHEROID *spheroid) { int type; assert(lwgeom); /* No area in nothing */ if ( lwgeom_is_empty(lwgeom) ) return 0.0; /* Read the geometry type number */ type = TYPE_GETTYPE(lwgeom->type); /* Anything but polygons and collections returns zero */ if ( ! ( type == POLYGONTYPE || type == MULTIPOLYGONTYPE || type == COLLECTIONTYPE ) ) return 0.0; /* Actually calculate area */ if ( type == POLYGONTYPE ) { LWPOLY *poly = (LWPOLY*)lwgeom; int i; double area = 0.0; /* Just in case there's no rings */ if ( poly->nrings < 1 ) return 0.0; /* First, the area of the outer ring */ area += ptarray_area_spheroid(poly->rings[0], spheroid); /* Subtract areas of inner rings */ for ( i = 1; i < poly->nrings; i++ ) { area -= ptarray_area_spheroid(poly->rings[i], spheroid); } return area; } /* Recurse into sub-geometries to get area */ if ( type == MULTIPOLYGONTYPE || type == COLLECTIONTYPE ) { LWCOLLECTION *col = (LWCOLLECTION*)lwgeom; int i; double area = 0.0; for ( i = 0; i < col->ngeoms; i++ ) { area += lwgeom_area_spheroid(col->geoms[i], gbox, spheroid); } return area; } /* Shouldn't get here. */ return 0.0; }
/* * Add 'what' to this multisurface at position 'where' * where=0 == prepend * where=-1 == append * Returns a MULTISURFACE or a COLLECTION */ LWGEOM * lwmsurface_add(const LWMSURFACE *to, uint32 where, const LWGEOM *what) { LWCOLLECTION *col; LWGEOM **geoms; int newtype; uint32 i; if (where == -1) where = to->ngeoms; else if (where < -1 || where > to->ngeoms) { lwerror("lwmsurface_add: add position out of range %d..%d", -1, to->ngeoms); return NULL; } /* dimensions compatibility are checked by caller */ /* Construct geoms array */ geoms = lwalloc(sizeof(LWGEOM *)*(to->ngeoms+1)); for (i = 0; i < where; i++) { geoms[i] = lwgeom_clone((LWGEOM *)to->geoms[i]); } geoms[where] = lwgeom_clone(what); for (i = where; i < to->ngeoms; i++) { geoms[i+1] = lwgeom_clone((LWGEOM *)to->geoms[i]); } if (TYPE_GETTYPE(what->type) == POLYGONTYPE || TYPE_GETTYPE(what->type) == CURVEPOLYTYPE) newtype = MULTISURFACETYPE; else newtype = COLLECTIONTYPE; col = lwcollection_construct(newtype, to->SRID, NULL, to->ngeoms + 1, geoms); return (LWGEOM *)col; }
/* * Returns an alloced string containing summary for the LWGEOM object */ char * lwpoint_summary(LWPOINT *point, int offset) { char *result; char *pad=""; result = lwalloc(128+offset); sprintf(result, "%*.s%s[%s]\n", offset, pad, lwgeom_typename(TYPE_GETTYPE(point->type)), lwgeom_typeflags(point->type)); return result; }
char * lwline_summary(LWLINE *line, int offset) { char *result; char *pad=""; result = lwalloc(128+offset); sprintf(result, "%*.s%s[%s] with %d points\n", offset, pad, lwgeom_typename(TYPE_GETTYPE(line->type)), lwgeom_typeflags(line->type), line->points->npoints); return result; }
/* * Add 'what' to this point at position 'where'. * where=0 == prepend * where=-1 == append * Returns a MULTIPOINT or a GEOMETRYCOLLECTION */ LWGEOM * lwpoint_add(const LWPOINT *to, uint32 where, const LWGEOM *what) { LWCOLLECTION *col; LWGEOM **geoms; int newtype; if ( where != -1 && where != 0 ) { lwerror("lwpoint_add only supports 0 or -1 as second argument, got %d", where); return NULL; } /* dimensions compatibility are checked by caller */ /* Construct geoms array */ geoms = lwalloc(sizeof(LWGEOM *)*2); if ( where == -1 ) /* append */ { geoms[0] = lwgeom_clone((LWGEOM *)to); geoms[1] = lwgeom_clone(what); } else /* prepend */ { geoms[0] = lwgeom_clone(what); geoms[1] = lwgeom_clone((LWGEOM *)to); } /* reset SRID and wantbbox flag from component types */ lwgeom_dropSRID(geoms[0]); lwgeom_drop_bbox(geoms[0]); lwgeom_dropSRID(geoms[1]); lwgeom_drop_bbox(geoms[1]); /* Find appropriate geom type */ if ( TYPE_GETTYPE(what->type) == POINTTYPE ) newtype = MULTIPOINTTYPE; else newtype = COLLECTIONTYPE; col = lwcollection_construct(newtype, to->SRID, NULL, 2, geoms); return (LWGEOM *)col; }
Datum LWGEOM_y_point(PG_FUNCTION_ARGS) { PG_LWGEOM *geom; LWPOINT *point = NULL; POINT2D p; geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); if ( TYPE_GETTYPE(geom->type) != POINTTYPE ) lwerror("Argument to Y() must be a point"); point = lwgeom_getpoint(SERIALIZED_FORM(geom), 0); getPoint2d_p(point->point, 0, &p); PG_FREE_IF_COPY(geom, 0); PG_RETURN_FLOAT8(p.y); }
Datum LWGEOM_m_point(PG_FUNCTION_ARGS) { PG_LWGEOM *geom; LWPOINT *point = NULL; POINT3DM p; geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); if ( TYPE_GETTYPE(geom->type) != POINTTYPE ) lwerror("Argument to M() must be a point"); point = lwgeom_getpoint(SERIALIZED_FORM(geom), 0); /* no M in input */ if ( ! TYPE_HASM(point->type) ) PG_RETURN_NULL(); getPoint3dm_p(point->point, 0, &p); PG_FREE_IF_COPY(geom, 0); PG_RETURN_FLOAT8(p.m); }
Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS) { PG_LWGEOM *geom; int32 wanted_index; LWCURVEPOLY *curvepoly = NULL; LWPOLY *poly = NULL; POINTARRAY *ring; LWLINE *line; PG_LWGEOM *result; BOX2DFLOAT4 *bbox = NULL; 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 = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); if ( TYPE_GETTYPE(geom->type) != POLYGONTYPE && TYPE_GETTYPE(geom->type) != CURVEPOLYTYPE ) { PG_FREE_IF_COPY(geom, 0); elog(ERROR, "InteriorRingN: geom is not a polygon"); PG_RETURN_NULL(); } if ( TYPE_GETTYPE(geom->type) == POLYGONTYPE) { poly = lwpoly_deserialize(SERIALIZED_FORM(geom)); /* Ok, now we have a polygon. Let's see if it has enough holes */ if ( wanted_index >= poly->nrings ) { PG_FREE_IF_COPY(geom, 0); lwgeom_release((LWGEOM *)poly); PG_RETURN_NULL(); } ring = poly->rings[wanted_index]; /* COMPUTE_BBOX==TAINTING */ if ( poly->bbox ) bbox = ptarray_compute_box2d(ring); /* This is a LWLINE constructed by interior ring POINTARRAY */ line = lwline_construct(poly->SRID, bbox, ring); /* Copy SRID from polygon */ line->SRID = poly->SRID; result = pglwgeom_serialize((LWGEOM *)line); lwgeom_release((LWGEOM *)line); lwgeom_release((LWGEOM *)poly); } else { curvepoly = lwcurvepoly_deserialize(SERIALIZED_FORM(geom)); if (wanted_index >= curvepoly->nrings) { PG_FREE_IF_COPY(geom, 0); lwgeom_release((LWGEOM *)curvepoly); PG_RETURN_NULL(); } result = pglwgeom_serialize(curvepoly->rings[wanted_index]); lwgeom_release((LWGEOM *)curvepoly); } PG_FREE_IF_COPY(geom, 0); PG_RETURN_POINTER(result); }