From aab816f87d78b921dcc89b79fa8fa2e76d3f5b12 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Fri, 20 Feb 2015 20:31:25 +0000 Subject: [PATCH] Move snap-to-grid functions into lwgeom where they belong. Modernize geometry construction to use accessors more git-svn-id: http://svn.osgeo.org/postgis/trunk@13255 b70326c6-7e19-0410-871a-916f4a2858ee --- liblwgeom/cunit/cu_misc.c | 22 ++ liblwgeom/g_serialized.c | 2 +- liblwgeom/liblwgeom.h.in | 30 ++- liblwgeom/liblwgeom_internal.h | 11 +- liblwgeom/lwcircstring.c | 20 ++ liblwgeom/lwcollection.c | 18 ++ liblwgeom/lwgeom.c | 26 +++ liblwgeom/lwgeom_api.c | 21 ++ liblwgeom/lwline.c | 19 ++ liblwgeom/lwpoint.c | 8 + liblwgeom/lwpoly.c | 55 +++++ liblwgeom/ptarray.c | 51 ++++ libpgcommon/lwgeom_pg.h | 2 + postgis/lwgeom_functions_analytic.c | 347 +++------------------------- postgis/lwgeom_ogc.c | 10 +- 15 files changed, 324 insertions(+), 318 deletions(-) diff --git a/liblwgeom/cunit/cu_misc.c b/liblwgeom/cunit/cu_misc.c index cd483dbbf..24a8a1900 100644 --- a/liblwgeom/cunit/cu_misc.c +++ b/liblwgeom/cunit/cu_misc.c @@ -119,6 +119,27 @@ static void test_misc_wkb(void) } + +static void test_grid(void) +{ + gridspec grid; + static char *wkt = "MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)))"; + LWGEOM *geom = lwgeom_from_wkt(wkt, LW_PARSER_CHECK_ALL); + LWGEOM *geomgrid; + char *str; + + grid.ipx = grid.ipy = 0; + grid.xsize = grid.ysize = 20; + + geomgrid = lwgeom_grid(geom, &grid); + str = lwgeom_to_ewkt(geomgrid); + CU_ASSERT_STRING_EQUAL(str, "MULTIPOLYGON EMPTY"); + lwfree(str); + lwgeom_free(geom); + lwgeom_free(geomgrid); +} + + /* ** Used by the test harness to register the tests in this file. */ @@ -131,4 +152,5 @@ void misc_suite_setup(void) PG_ADD_TEST(suite, test_misc_count_vertices); PG_ADD_TEST(suite, test_misc_area); PG_ADD_TEST(suite, test_misc_wkb); + PG_ADD_TEST(suite, test_grid); } diff --git a/liblwgeom/g_serialized.c b/liblwgeom/g_serialized.c index 5e3f06ec6..fa36da795 100644 --- a/liblwgeom/g_serialized.c +++ b/liblwgeom/g_serialized.c @@ -42,7 +42,7 @@ int gserialized_ndims(const GSERIALIZED *gser) return FLAGS_NDIMS(gser->flags); } -uint32_t gserialized_max_header_size() +uint32_t gserialized_max_header_size(void) { /* read GSERIALIZED size + max bbox according gbox_serialized_size (2 + Z + M) + 1 int for type */ return sizeof(GSERIALIZED) + 8 * sizeof(float) + sizeof(int); diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index 523247aa4..0c0b80706 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -578,7 +578,9 @@ typedef struct } LWTIN; - +/** +* TWKB Support Structures +*/ typedef struct { int64_t id; //Id, from function parameter @@ -599,6 +601,22 @@ typedef struct } twkb_geom_arrays; +/** +* Snap-to-grid Support +*/ +typedef struct gridspec_t +{ + double ipx; + double ipy; + double ipz; + double ipm; + double xsize; + double ysize; + double zsize; + double msize; +} +gridspec; + /* Casts LWGEOM->LW* (return NULL if cast is illegal) */ extern LWMPOLY *lwgeom_as_lwmpoly(const LWGEOM *lwgeom); extern LWMLINE *lwgeom_as_lwmline(const LWGEOM *lwgeom); @@ -660,7 +678,7 @@ extern uint32_t gserialized_get_type(const GSERIALIZED *g); * Returns the size in bytes to read from toast to get the basic * information from a geometry: GSERIALIZED struct, bbox and type */ -extern uint32_t gserialized_max_header_size(); +extern uint32_t gserialized_max_header_size(void); /** * Extract the SRID from the serialized form (it is packed into @@ -829,6 +847,14 @@ extern const POINT2D* getPoint2d_cp(const POINTARRAY *pa, int n); */ extern const POINT3DZ* getPoint3dz_cp(const POINTARRAY *pa, int n); +/** +* Returns a POINT4D pointer into the POINTARRAY serialized_ptlist, +* suitable for reading from. This is very high performance +* and declared const because you aren't allowed to muck with the +* values, only read them. +*/ +extern const POINT4D* getPoint4d_cp(const POINTARRAY *pa, int n); + /* * set point N to the given value * NOTE that the pointarray can be of any diff --git a/liblwgeom/liblwgeom_internal.h b/liblwgeom/liblwgeom_internal.h index 77eb6dcb4..a1eafdb7f 100644 --- a/liblwgeom/liblwgeom_internal.h +++ b/liblwgeom/liblwgeom_internal.h @@ -354,7 +354,16 @@ int lwcompound_is_closed(const LWCOMPOUND *curve); int lwpsurface_is_closed(const LWPSURFACE *psurface); int lwtin_is_closed(const LWTIN *tin); - +/** +* Snap to grid +*/ +LWGEOM* lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid); +LWCOLLECTION* lwcollection_grid(const LWCOLLECTION *coll, const gridspec *grid); +LWPOINT* lwpoint_grid(const LWPOINT *point, const gridspec *grid); +LWPOLY* lwpoly_grid(const LWPOLY *poly, const gridspec *grid); +LWLINE* lwline_grid(const LWLINE *line, const gridspec *grid); +LWCIRCSTRING* lwcircstring_grid(const LWCIRCSTRING *line, const gridspec *grid); +POINTARRAY* ptarray_grid(const POINTARRAY *pa, const gridspec *grid); /* * What side of the line formed by p1 and p2 does q fall? diff --git a/liblwgeom/lwcircstring.c b/liblwgeom/lwcircstring.c index a8f73f04b..3361cd603 100644 --- a/liblwgeom/lwcircstring.c +++ b/liblwgeom/lwcircstring.c @@ -298,3 +298,23 @@ LWPOINT* lwcircstring_get_lwpoint(LWCIRCSTRING *circ, int where) { lwpoint = lwpoint_construct(circ->srid, NULL, pa); return lwpoint; } + +/* +* Snap to grid +*/ +LWCIRCSTRING* lwcircstring_grid(const LWCIRCSTRING *line, const gridspec *grid) +{ + LWCIRCSTRING *oline; + POINTARRAY *opa; + + opa = ptarray_grid(line->points, grid); + + /* Skip line3d with less then 2 points */ + if ( opa->npoints < 2 ) return NULL; + + /* TODO: grid bounding box... */ + oline = lwcircstring_construct(line->srid, NULL, opa); + + return oline; +} + diff --git a/liblwgeom/lwcollection.c b/liblwgeom/lwcollection.c index 089ad61af..8d81ab589 100644 --- a/liblwgeom/lwcollection.c +++ b/liblwgeom/lwcollection.c @@ -564,3 +564,21 @@ lwcollection_startpoint(const LWCOLLECTION* col, POINT4D* pt) return lwgeom_startpoint(col->geoms[0], pt); } + + +LWCOLLECTION* lwcollection_grid(const LWCOLLECTION *coll, const gridspec *grid) +{ + uint32_t i; + LWCOLLECTION *newcoll; + + newcoll = lwcollection_construct_empty(coll->type, coll->srid, lwgeom_has_z((LWGEOM*)coll), lwgeom_has_m((LWGEOM*)coll)); + + for (i=0; ingeoms; i++) + { + LWGEOM *g = lwgeom_grid(coll->geoms[i], grid); + if ( g ) + lwcollection_add_lwgeom(newcoll, g); + } + + return newcoll; +} diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c index ad76eeee9..07faeaf23 100644 --- a/liblwgeom/lwgeom.c +++ b/liblwgeom/lwgeom.c @@ -1754,3 +1754,29 @@ lwgeom_startpoint(const LWGEOM* lwgeom, POINT4D* pt) } } + +LWGEOM * +lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid) +{ + switch ( lwgeom->type ) + { + case POINTTYPE: + return (LWGEOM *)lwpoint_grid((LWPOINT *)lwgeom, grid); + case LINETYPE: + return (LWGEOM *)lwline_grid((LWLINE *)lwgeom, grid); + case POLYGONTYPE: + return (LWGEOM *)lwpoly_grid((LWPOLY *)lwgeom, grid); + case MULTIPOINTTYPE: + case MULTILINETYPE: + case MULTIPOLYGONTYPE: + case COLLECTIONTYPE: + case COMPOUNDTYPE: + return (LWGEOM *)lwcollection_grid((LWCOLLECTION *)lwgeom, grid); + case CIRCSTRINGTYPE: + return (LWGEOM *)lwcircstring_grid((LWCIRCSTRING *)lwgeom, grid); + default: + lwerror("lwgeom_grid: Unsupported geometry type: %s", + lwtype_name(lwgeom->type)); + return NULL; + } +} diff --git a/liblwgeom/lwgeom_api.c b/liblwgeom/lwgeom_api.c index c35a1506e..1e9fcd8fd 100644 --- a/liblwgeom/lwgeom_api.c +++ b/liblwgeom/lwgeom_api.c @@ -488,6 +488,27 @@ getPoint3dz_cp(const POINTARRAY *pa, int n) } +const POINT4D* +getPoint4d_cp(const POINTARRAY *pa, int n) +{ + if ( ! pa ) return 0; + + if ( ! (FLAGS_GET_Z(pa->flags) && FLAGS_GET_Z(pa->flags)) ) + { + lwerror("getPoint3dz_cp: no Z and M coordinates in point array"); + return 0; /*error */ + } + + if ( (n<0) || (n>=pa->npoints)) + { + lwerror("getPoint3dz_cp: point offset out of range"); + return 0; /*error */ + } + + return (const POINT4D*)getPoint_internal(pa, n); +} + + /* * set point N to the given value diff --git a/liblwgeom/lwline.c b/liblwgeom/lwline.c index 0fe0138a6..446b20845 100644 --- a/liblwgeom/lwline.c +++ b/liblwgeom/lwline.c @@ -504,3 +504,22 @@ double lwline_length_2d(const LWLINE *line) return 0.0; return ptarray_length_2d(line->points); } + + + +LWLINE* lwline_grid(const LWLINE *line, const gridspec *grid) +{ + LWLINE *oline; + POINTARRAY *opa; + + opa = ptarray_grid(line->points, grid); + + /* Skip line3d with less then 2 points */ + if ( opa->npoints < 2 ) return NULL; + + /* TODO: grid bounding box... */ + oline = lwline_construct(line->srid, NULL, opa); + + return oline; +} + diff --git a/liblwgeom/lwpoint.c b/liblwgeom/lwpoint.c index 8da187bd6..c9e8612a8 100644 --- a/liblwgeom/lwpoint.c +++ b/liblwgeom/lwpoint.c @@ -262,3 +262,11 @@ int lwpoint_is_empty(const LWPOINT *point) return LW_FALSE; } + +LWPOINT * +lwpoint_grid(const LWPOINT *point, const gridspec *grid) +{ + POINTARRAY *opa = ptarray_grid(point->point, grid); + return lwpoint_construct(point->srid, NULL, opa); +} + diff --git a/liblwgeom/lwpoly.c b/liblwgeom/lwpoly.c index 4954a3551..d11aa3349 100644 --- a/liblwgeom/lwpoly.c +++ b/liblwgeom/lwpoly.c @@ -489,3 +489,58 @@ lwpoly_startpoint(const LWPOLY* poly, POINT4D* pt) return ptarray_startpoint(poly->rings[0], pt); } + +LWPOLY* lwpoly_grid(const LWPOLY *poly, const gridspec *grid) +{ + LWPOLY *opoly; + int ri; + +#if 0 + /* + * TODO: control this assertion + * it is assumed that, since the grid size will be a pixel, + * a visible ring should show at least a white pixel inside, + * thus, for a square, that would be grid_xsize*grid_ysize + */ + double minvisiblearea = grid->xsize * grid->ysize; +#endif + + LWDEBUGF(3, "lwpoly_grid: applying grid to polygon with %d rings", poly->nrings); + + opoly = lwpoly_construct_empty(poly->srid, lwgeom_has_z((LWGEOM*)poly), lwgeom_has_m((LWGEOM*)poly)); + + for (ri=0; rinrings; ri++) + { + POINTARRAY *ring = poly->rings[ri]; + POINTARRAY *newring; + + newring = ptarray_grid(ring, grid); + + /* Skip ring if not composed by at least 4 pts (3 segments) */ + if ( newring->npoints < 4 ) + { + ptarray_free(newring); + + LWDEBUGF(3, "grid_polygon3d: ring%d skipped ( <4 pts )", ri); + + if ( ri ) continue; + else break; /* this is the external ring, no need to work on holes */ + } + + if ( ! lwpoly_add_ring(opoly, newring) ) + { + lwerror("lwpoly_grid, memory error"); + return NULL; + } + } + + LWDEBUGF(3, "lwpoly_grid: simplified polygon with %d rings", opoly->nrings); + + if ( ! opoly->nrings ) + { + lwpoly_free(opoly); + return NULL; + } + + return opoly; +} diff --git a/liblwgeom/ptarray.c b/liblwgeom/ptarray.c index 8330ce59a..2a9d96ca6 100644 --- a/liblwgeom/ptarray.c +++ b/liblwgeom/ptarray.c @@ -1733,3 +1733,54 @@ ptarray_startpoint(const POINTARRAY* pa, POINT4D* pt) { return getPoint4d_p(pa, 0, pt); } + + + + +/* + * Stick an array of points to the given gridspec. + * Return "gridded" points in *outpts and their number in *outptsn. + * + * Two consecutive points falling on the same grid cell are collapsed + * into one single point. + * + */ +POINTARRAY * +ptarray_grid(const POINTARRAY *pa, const gridspec *grid) +{ + POINT4D pt; + int ipn; /* input point numbers */ + POINTARRAY *dpa; + + LWDEBUGF(2, "ptarray_grid called on %p", pa); + + dpa = ptarray_construct_empty(FLAGS_GET_Z(pa->flags),FLAGS_GET_M(pa->flags), pa->npoints); + + for (ipn=0; ipnnpoints; ++ipn) + { + + getPoint4d_p(pa, ipn, &pt); + + if ( grid->xsize ) + pt.x = rint((pt.x - grid->ipx)/grid->xsize) * + grid->xsize + grid->ipx; + + if ( grid->ysize ) + pt.y = rint((pt.y - grid->ipy)/grid->ysize) * + grid->ysize + grid->ipy; + + if ( FLAGS_GET_Z(pa->flags) && grid->zsize ) + pt.z = rint((pt.z - grid->ipz)/grid->zsize) * + grid->zsize + grid->ipz; + + if ( FLAGS_GET_M(pa->flags) && grid->msize ) + pt.m = rint((pt.m - grid->ipm)/grid->msize) * + grid->msize + grid->ipm; + + ptarray_append_point(dpa, &pt, LW_FALSE); + + } + + return dpa; +} + diff --git a/libpgcommon/lwgeom_pg.h b/libpgcommon/lwgeom_pg.h index 9de4eaff5..4c6b1ff90 100644 --- a/libpgcommon/lwgeom_pg.h +++ b/libpgcommon/lwgeom_pg.h @@ -25,6 +25,8 @@ /* Install PosgreSQL handlers for liblwgeom use */ void pg_install_lwgeom_handlers(void); +#define PG_GETARG_GSERIALIZED(varno) ((GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(varno))) + /* Debugging macros */ #if POSTGIS_DEBUG_LEVEL > 0 diff --git a/postgis/lwgeom_functions_analytic.c b/postgis/lwgeom_functions_analytic.c index 60b32c29e..1229b4f70 100644 --- a/postgis/lwgeom_functions_analytic.c +++ b/postgis/lwgeom_functions_analytic.c @@ -271,319 +271,40 @@ Datum LWGEOM_line_interpolate_point(PG_FUNCTION_ARGS) #define CHECK_RING_IS_CLOSE #define SAMEPOINT(a,b) ((a)->x==(b)->x&&(a)->y==(b)->y) -typedef struct gridspec_t -{ - double ipx; - double ipy; - double ipz; - double ipm; - double xsize; - double ysize; - double zsize; - double msize; -} -gridspec; /* Forward declarations */ -LWGEOM *lwgeom_grid(LWGEOM *lwgeom, gridspec *grid); -LWCOLLECTION *lwcollection_grid(LWCOLLECTION *coll, gridspec *grid); -LWPOINT * lwpoint_grid(LWPOINT *point, gridspec *grid); -LWPOLY * lwpoly_grid(LWPOLY *poly, gridspec *grid); -LWLINE *lwline_grid(LWLINE *line, gridspec *grid); -LWCIRCSTRING *lwcirc_grid(LWCIRCSTRING *line, gridspec *grid); -POINTARRAY *ptarray_grid(POINTARRAY *pa, gridspec *grid); Datum LWGEOM_snaptogrid(PG_FUNCTION_ARGS); Datum LWGEOM_snaptogrid_pointoff(PG_FUNCTION_ARGS); -static int grid_isNull(const gridspec *grid); -#if POSTGIS_DEBUG_LEVEL >=4 -static void grid_print(const gridspec *grid); -#endif - -/* A NULL grid is a grid in which size in all dimensions is 0 */ -static int -grid_isNull(const gridspec *grid) -{ - if ( grid->xsize==0 && - grid->ysize==0 && - grid->zsize==0 && - grid->msize==0 ) return 1; - else return 0; -} - -#if POSTGIS_DEBUG_LEVEL >= 4 -/* Print grid using given reporter */ -static void -grid_print(const gridspec *grid) -{ - lwnotice("GRID(%g %g %g %g, %g %g %g %g)", - grid->ipx, grid->ipy, grid->ipz, grid->ipm, - grid->xsize, grid->ysize, grid->zsize, grid->msize); -} -#endif - -/* - * Stick an array of points to the given gridspec. - * Return "gridded" points in *outpts and their number in *outptsn. - * - * Two consecutive points falling on the same grid cell are collapsed - * into one single point. - * - */ -POINTARRAY * -ptarray_grid(POINTARRAY *pa, gridspec *grid) -{ - POINT4D pbuf; - int ipn; /* input point numbers */ - POINTARRAY *dpa; - - POSTGIS_DEBUGF(2, "ptarray_grid called on %p", pa); - - dpa = ptarray_construct_empty(FLAGS_GET_Z(pa->flags),FLAGS_GET_M(pa->flags), pa->npoints); - - for (ipn=0; ipnnpoints; ++ipn) - { - - getPoint4d_p(pa, ipn, &pbuf); - - if ( grid->xsize ) - pbuf.x = rint((pbuf.x - grid->ipx)/grid->xsize) * - grid->xsize + grid->ipx; - - if ( grid->ysize ) - pbuf.y = rint((pbuf.y - grid->ipy)/grid->ysize) * - grid->ysize + grid->ipy; - - if ( FLAGS_GET_Z(pa->flags) && grid->zsize ) - pbuf.z = rint((pbuf.z - grid->ipz)/grid->zsize) * - grid->zsize + grid->ipz; - - if ( FLAGS_GET_M(pa->flags) && grid->msize ) - pbuf.m = rint((pbuf.m - grid->ipm)/grid->msize) * - grid->msize + grid->ipm; - - ptarray_append_point(dpa, &pbuf, LW_FALSE); - - } - return dpa; -} - -LWLINE * -lwline_grid(LWLINE *line, gridspec *grid) -{ - LWLINE *oline; - POINTARRAY *opa; - - opa = ptarray_grid(line->points, grid); - - /* Skip line3d with less then 2 points */ - if ( opa->npoints < 2 ) return NULL; - - /* TODO: grid bounding box... */ - oline = lwline_construct(line->srid, NULL, opa); - - return oline; -} - -LWCIRCSTRING * -lwcirc_grid(LWCIRCSTRING *line, gridspec *grid) -{ - LWCIRCSTRING *oline; - POINTARRAY *opa; - - opa = ptarray_grid(line->points, grid); - - /* Skip line3d with less then 2 points */ - if ( opa->npoints < 2 ) return NULL; - - /* TODO: grid bounding box... */ - oline = lwcircstring_construct(line->srid, NULL, opa); - - return oline; -} - -LWPOLY * -lwpoly_grid(LWPOLY *poly, gridspec *grid) -{ - LWPOLY *opoly; - int ri; - POINTARRAY **newrings = NULL; - int nrings = 0; -#if 0 - /* - * TODO: control this assertion - * it is assumed that, since the grid size will be a pixel, - * a visible ring should show at least a white pixel inside, - * thus, for a square, that would be grid_xsize*grid_ysize - */ - double minvisiblearea = grid->xsize * grid->ysize; -#endif - - nrings = 0; - - POSTGIS_DEBUGF(3, "grid_polygon3d: applying grid to polygon with %d rings", - poly->nrings); - - for (ri=0; rinrings; ri++) - { - POINTARRAY *ring = poly->rings[ri]; - POINTARRAY *newring; - -#if POSTGIS_DEBUG_LEVEL >= 4 - POINT2D p1, p2; - getPoint2d_p(ring, 0, &p1); - getPoint2d_p(ring, ring->npoints-1, &p2); - if ( ! SAMEPOINT(&p1, &p2) ) - POSTGIS_DEBUG(4, "Before gridding: first point != last point"); -#endif - - newring = ptarray_grid(ring, grid); - - /* Skip ring if not composed by at least 4 pts (3 segments) */ - if ( newring->npoints < 4 ) - { - pfree(newring); - - POSTGIS_DEBUGF(3, "grid_polygon3d: ring%d skipped ( <4 pts )", ri); - - if ( ri ) continue; - else break; /* this is the external ring, no need to work on holes */ - } - -#if POSTGIS_DEBUG_LEVEL >= 4 - getPoint2d_p(newring, 0, &p1); - getPoint2d_p(newring, newring->npoints-1, &p2); - if ( ! SAMEPOINT(&p1, &p2) ) - POSTGIS_DEBUG(4, "After gridding: first point != last point"); -#endif - POSTGIS_DEBUGF(3, "grid_polygon3d: ring%d simplified from %d to %d points", ri, - ring->npoints, newring->npoints); - - /* - * Add ring to simplified ring array - * (TODO: dinamic allocation of pts_per_ring) - */ - if ( ! nrings ) - { - newrings = palloc(sizeof(POINTARRAY *)); - } - else - { - newrings = repalloc(newrings, sizeof(POINTARRAY *)*(nrings+1)); - } - if ( ! newrings ) - { - elog(ERROR, "Out of virtual memory"); - return NULL; - } - newrings[nrings++] = newring; - } - - POSTGIS_DEBUGF(3, "grid_polygon3d: simplified polygon with %d rings", nrings); - - if ( ! nrings ) return NULL; - - opoly = lwpoly_construct(poly->srid, NULL, nrings, newrings); - return opoly; -} - -LWPOINT * -lwpoint_grid(LWPOINT *point, gridspec *grid) -{ - LWPOINT *opoint; - POINTARRAY *opa; - - opa = ptarray_grid(point->point, grid); - - /* TODO: grid bounding box ? */ - opoint = lwpoint_construct(point->srid, NULL, opa); - - POSTGIS_DEBUG(2, "lwpoint_grid called"); - - return opoint; -} - -LWCOLLECTION * -lwcollection_grid(LWCOLLECTION *coll, gridspec *grid) -{ - uint32 i; - LWGEOM **geoms; - uint32 ngeoms=0; - - geoms = palloc(coll->ngeoms * sizeof(LWGEOM *)); - - for (i=0; ingeoms; i++) - { - LWGEOM *g = lwgeom_grid(coll->geoms[i], grid); - if ( g ) geoms[ngeoms++] = g; - } - - if ( ! ngeoms ) return lwcollection_construct_empty(coll->type, coll->srid, 0, 0); - - return lwcollection_construct(coll->type, coll->srid, - NULL, ngeoms, geoms); -} - -LWGEOM * -lwgeom_grid(LWGEOM *lwgeom, gridspec *grid) -{ - switch (lwgeom->type) - { - case POINTTYPE: - return (LWGEOM *)lwpoint_grid((LWPOINT *)lwgeom, grid); - case LINETYPE: - return (LWGEOM *)lwline_grid((LWLINE *)lwgeom, grid); - case POLYGONTYPE: - return (LWGEOM *)lwpoly_grid((LWPOLY *)lwgeom, grid); - case MULTIPOINTTYPE: - case MULTILINETYPE: - case MULTIPOLYGONTYPE: - case COLLECTIONTYPE: - case COMPOUNDTYPE: - return (LWGEOM *)lwcollection_grid((LWCOLLECTION *)lwgeom, grid); - case CIRCSTRINGTYPE: - return (LWGEOM *)lwcirc_grid((LWCIRCSTRING *)lwgeom, grid); - default: - elog(ERROR, "lwgeom_grid: Unsupported geometry type: %s", - lwtype_name(lwgeom->type)); - return NULL; - } -} PG_FUNCTION_INFO_V1(LWGEOM_snaptogrid); Datum LWGEOM_snaptogrid(PG_FUNCTION_ARGS) { - Datum datum; - GSERIALIZED *in_geom; LWGEOM *in_lwgeom; GSERIALIZED *out_geom = NULL; LWGEOM *out_lwgeom; gridspec grid; - /* BOX3D box3d; */ - if ( PG_ARGISNULL(0) ) PG_RETURN_NULL(); - datum = PG_GETARG_DATUM(0); - in_geom = (GSERIALIZED *)PG_DETOAST_DATUM(datum); + GSERIALIZED *in_geom = PG_GETARG_GSERIALIZED(0); - if ( PG_ARGISNULL(1) ) PG_RETURN_NULL(); - grid.ipx = PG_GETARG_FLOAT8(1); + /* Set grid values to zero to start */ + memset(&grid, 0, sizeof(gridspec)); - if ( PG_ARGISNULL(2) ) PG_RETURN_NULL(); + grid.ipx = PG_GETARG_FLOAT8(1); grid.ipy = PG_GETARG_FLOAT8(2); - - if ( PG_ARGISNULL(3) ) PG_RETURN_NULL(); grid.xsize = PG_GETARG_FLOAT8(3); - - if ( PG_ARGISNULL(4) ) PG_RETURN_NULL(); grid.ysize = PG_GETARG_FLOAT8(4); - /* Do not support gridding Z and M values for now */ - grid.ipz=grid.ipm=grid.zsize=grid.msize=0; - - /* Return input geometry if grid is null or input geometry is empty */ - if ( grid_isNull(&grid) || gserialized_is_empty(in_geom) ) + /* Return input geometry if input geometry is empty */ + if ( gserialized_is_empty(in_geom) ) + { + PG_RETURN_POINTER(in_geom); + } + + /* Return input geometry if input grid is meaningless */ + if ( grid.xsize==0 && grid.ysize==0 && grid.zsize==0 && grid.msize==0 ) { PG_RETURN_POINTER(in_geom); } @@ -596,7 +317,8 @@ Datum LWGEOM_snaptogrid(PG_FUNCTION_ARGS) if ( out_lwgeom == NULL ) PG_RETURN_NULL(); /* COMPUTE_BBOX TAINTING */ - if ( in_lwgeom->bbox ) lwgeom_add_bbox(out_lwgeom); + if ( in_lwgeom->bbox ) + lwgeom_add_bbox(out_lwgeom); POSTGIS_DEBUGF(3, "SnapToGrid made a %s", lwtype_name(out_lwgeom->type)); @@ -606,10 +328,22 @@ Datum LWGEOM_snaptogrid(PG_FUNCTION_ARGS) PG_RETURN_POINTER(out_geom); } + +#if POSTGIS_DEBUG_LEVEL >= 4 +/* Print grid using given reporter */ +static void +grid_print(const gridspec *grid) +{ + lwnotice("GRID(%g %g %g %g, %g %g %g %g)", + grid->ipx, grid->ipy, grid->ipz, grid->ipm, + grid->xsize, grid->ysize, grid->zsize, grid->msize); +} +#endif + + PG_FUNCTION_INFO_V1(LWGEOM_snaptogrid_pointoff); Datum LWGEOM_snaptogrid_pointoff(PG_FUNCTION_ARGS) { - Datum datum; GSERIALIZED *in_geom, *in_point; LWGEOM *in_lwgeom; LWPOINT *in_lwpoint; @@ -619,29 +353,24 @@ Datum LWGEOM_snaptogrid_pointoff(PG_FUNCTION_ARGS) /* BOX3D box3d; */ POINT4D offsetpoint; - if ( PG_ARGISNULL(0) ) PG_RETURN_NULL(); - datum = PG_GETARG_DATUM(0); - in_geom = (GSERIALIZED *)PG_DETOAST_DATUM(datum); + in_geom = PG_GETARG_GSERIALIZED(0); - if ( PG_ARGISNULL(1) ) PG_RETURN_NULL(); - datum = PG_GETARG_DATUM(1); - in_point = (GSERIALIZED *)PG_DETOAST_DATUM(datum); + /* Return input geometry if input geometry is empty */ + if ( gserialized_is_empty(in_geom) ) + { + PG_RETURN_POINTER(in_geom); + } + + in_point = PG_GETARG_GSERIALIZED(1); in_lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(in_point)); if ( in_lwpoint == NULL ) { lwerror("Offset geometry must be a point"); } - if ( PG_ARGISNULL(2) ) PG_RETURN_NULL(); grid.xsize = PG_GETARG_FLOAT8(2); - - if ( PG_ARGISNULL(3) ) PG_RETURN_NULL(); grid.ysize = PG_GETARG_FLOAT8(3); - - if ( PG_ARGISNULL(4) ) PG_RETURN_NULL(); grid.zsize = PG_GETARG_FLOAT8(4); - - if ( PG_ARGISNULL(5) ) PG_RETURN_NULL(); grid.msize = PG_GETARG_FLOAT8(5); /* Take offsets from point geometry */ @@ -656,9 +385,9 @@ Datum LWGEOM_snaptogrid_pointoff(PG_FUNCTION_ARGS) #if POSTGIS_DEBUG_LEVEL >= 4 grid_print(&grid); #endif - - /* Return input geometry if grid is null */ - if ( grid_isNull(&grid) ) + + /* Return input geometry if input grid is meaningless */ + if ( grid.xsize==0 && grid.ysize==0 && grid.zsize==0 && grid.msize==0 ) { PG_RETURN_POINTER(in_geom); } diff --git a/postgis/lwgeom_ogc.c b/postgis/lwgeom_ogc.c index 11eb6a9cc..33fed1f41 100644 --- a/postgis/lwgeom_ogc.c +++ b/postgis/lwgeom_ogc.c @@ -169,21 +169,21 @@ Datum geometry_geometrytype(PG_FUNCTION_ARGS) { GSERIALIZED *gser; text *type_text; - char *type_str = palloc(32); + static int type_str_len = 32; + char type_str[type_str_len]; /* Read just the header from the toasted tuple */ gser = (GSERIALIZED*)PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(0), 0, gserialized_max_header_size()); /* Make it empty string to start */ - *type_str = 0; + type_str[0] = 0; /* Build up the output string */ - strncat(type_str, "ST_", 32); - strncat(type_str, lwtype_name(gserialized_get_type(gser)), 32); + strncat(type_str, "ST_", type_str_len); + strncat(type_str, lwtype_name(gserialized_get_type(gser)), type_str_len); /* Build a text type to store things in */ type_text = cstring2text(type_str); - pfree(type_str); PG_FREE_IF_COPY(gser, 0); PG_RETURN_TEXT_P(type_text); -- 2.50.1