From e45a5556a3a03b1c2c66d952110b4461742d3967 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Mon, 6 Sep 2004 16:04:13 +0000 Subject: [PATCH] Changed getbox2d_p signature to return 0 for EMPTY geometries. Ported DP simplifier. git-svn-id: http://svn.osgeo.org/postgis/trunk@771 b70326c6-7e19-0410-871a-916f4a2858ee --- lwgeom/MISSING_OBJECTS | 1 - lwgeom/TODO | 2 + lwgeom/lwgeom.h | 31 ++- lwgeom/lwgeom_api.c | 21 +- lwgeom/lwgeom_box2dfloat4.c | 16 +- lwgeom/lwgeom_box3d.c | 6 + lwgeom/lwgeom_functions_analytic.c | 332 +++++++++++++++++++++++++++++ lwgeom/lwgeom_functions_basic.c | 96 ++++----- lwgeom/lwgeom_inout.c | 108 +++++----- lwgeom/lwpostgis.sql.in | 21 +- 10 files changed, 507 insertions(+), 127 deletions(-) diff --git a/lwgeom/MISSING_OBJECTS b/lwgeom/MISSING_OBJECTS index 586eb232c..5e800ea30 100644 --- a/lwgeom/MISSING_OBJECTS +++ b/lwgeom/MISSING_OBJECTS @@ -1,6 +1,5 @@ # This is a list of objects still missing lwgeom support -FNCAST: KEEPING FNCAST geometry(text) (see CAST) FUNC: KEEPING FUNCTION: [line_interpolate_point(geometry, double precision)] FUNC: KEEPING FUNCTION: [simplify(geometry, double precision)] FUNC: KEEPING FUNCTION: [segmentize(geometry, double precision)] diff --git a/lwgeom/TODO b/lwgeom/TODO index feaf007cf..ed170f8a0 100644 --- a/lwgeom/TODO +++ b/lwgeom/TODO @@ -1,4 +1,6 @@ +- WKB: what to do with that ? do we want to keep it as a type ? + - Check spheroid misure functions o can't understand if 3d computation works since I get same result w/ 2d and 3d. diff --git a/lwgeom/lwgeom.h b/lwgeom/lwgeom.h index d73a69434..af2ae67a4 100644 --- a/lwgeom/lwgeom.h +++ b/lwgeom/lwgeom.h @@ -229,7 +229,7 @@ typedef struct POINTARRAY *points; // array of POINT3D } LWLINE; //"light-weight line" -// construct a new LWLINE. points will be copied +// construct a new LWLINE. points will *NOT* be copied // use SRID=-1 for unknown SRID (will have 8bit type's S = 0) extern LWLINE *lwline_construct(int ndims, int SRID, POINTARRAY *points); @@ -504,7 +504,7 @@ extern BOX3D *combine_boxes(BOX3D *b1, BOX3D *b2); // if this has a pre-built BOX2d, then we use it, // otherwise we need to compute it. extern BOX2DFLOAT4 getbox2d(char *serialized_form); -extern void getbox2d_p(char *serialized_form, BOX2DFLOAT4 *box); +extern int getbox2d_p(char *serialized_form, BOX2DFLOAT4 *box); // Expand given box of 'd' units in all directions void expand_box2d(BOX2DFLOAT4 *box, double d); @@ -702,3 +702,30 @@ extern double nextUp_d(float d); #endif #define abs(a) ((a) < (0) ? (-a) : (a)) + +// general utilities +double lwgeom_polygon_area(LWPOLY *poly); +double lwgeom_polygon_perimeter(LWPOLY *poly); +double lwgeom_polygon_perimeter2d(LWPOLY *poly); +double lwgeom_pointarray_length2d(POINTARRAY *pts); +double lwgeom_pointarray_length(POINTARRAY *pts); +void lwgeom_force2d_recursive(char *serialized, char *optr, int *retsize); +void lwgeom_force3d_recursive(char *serialized, char *optr, int *retsize); +double distance2d_pt_pt(POINT2D *p1, POINT2D *p2); +double distance2d_pt_seg(POINT2D *p, POINT2D *A, POINT2D *B); +double distance2d_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D); +double distance2d_pt_ptarray(POINT2D *p, POINTARRAY *pa); +double distance2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2); +int pt_in_ring_2d(POINT2D *p, POINTARRAY *ring); +int pt_in_poly_2d(POINT2D *p, LWPOLY *poly); +double distance2d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly); +double distance2d_point_point(LWPOINT *point1, LWPOINT *point2); +double distance2d_point_line(LWPOINT *point, LWLINE *line); +double distance2d_line_line(LWLINE *line1, LWLINE *line2); +double distance2d_point_poly(LWPOINT *point, LWPOLY *poly); +double distance2d_poly_poly(LWPOLY *poly1, LWPOLY *poly2); +double distance2d_line_poly(LWLINE *line, LWPOLY *poly); +double lwgeom_mindistance2d_recursive(char *lw1, char *lw2); +void lwgeom_translate_recursive(char *serialized, double xoff, double yoff, double zoff); +void lwgeom_translate_ptarray(POINTARRAY *pa, double xoff, double yoff, double zoff); +int lwgeom_pt_inside_circle(POINT2D *p, double cx, double cy, double rad); diff --git a/lwgeom/lwgeom_api.c b/lwgeom/lwgeom_api.c index f2fd1ecf6..1510f4b3a 100644 --- a/lwgeom/lwgeom_api.c +++ b/lwgeom/lwgeom_api.c @@ -376,7 +376,7 @@ BOX2DFLOAT4 getbox2d(char *serialized_form) // same as getbox2d, but modifies box instead of returning result on the stack -void +int getbox2d_p(char *serialized_form, BOX2DFLOAT4 *box) { unsigned char type = (unsigned char) serialized_form[0]; @@ -391,17 +391,22 @@ getbox2d_p(char *serialized_form, BOX2DFLOAT4 *box) //woot - this is easy //elog(NOTICE,"getbox2d has box"); memcpy(box,loc, sizeof(BOX2DFLOAT4)); - return ; + return 1; } //we have to actually compute it! //elog(NOTICE,"getbox2d_p:: computing box"); box3d = lw_geom_getBB_simple(serialized_form); + if ( ! box3d ) + { + return 0; + } box2 = box3d_to_box2df(box3d); memcpy(box,box2, sizeof(BOX2DFLOAT4)); pfree(box3d); pfree(box2); + return 1; } //************************************************************************ @@ -759,7 +764,7 @@ int32 get_int32(char *loc) // basic LWLINE functions -// construct a new LWLINE. points will be copied +// construct a new LWLINE. points will *NOT* be copied // use SRID=-1 for unknown SRID (will have 8bit type's S = 0) LWLINE *lwline_construct(int ndims, int SRID, POINTARRAY *points) { @@ -2894,6 +2899,11 @@ lwexploded_serialize(LWGEOM_EXPLODED *exploded, int wantbbox) BOX3D *box3d; char *ser; + if ( exploded->npoints + exploded->nlines + exploded->npolys == 0 ) + { + return lwgeom_constructempty(exploded->SRID, exploded->ndims); + } + // find size of all geoms. // If BBOX and SRID are included this size could be // larger then needed, but that should not be a problem @@ -2928,6 +2938,11 @@ lwexploded_serialize(LWGEOM_EXPLODED *exploded, int wantbbox) elog(NOTICE, " computed outtype: %d, ngeoms: %d", outtype, ngeoms); #endif + if ( ! ngeoms ) + { + return lwgeom_constructempty(exploded->SRID, exploded->ndims); + } + // For a single geometry just set SRID and BBOX (if requested) if ( ngeoms < 2 ) diff --git a/lwgeom/lwgeom_box2dfloat4.c b/lwgeom/lwgeom_box2dfloat4.c index 829682ff0..05f615a93 100644 --- a/lwgeom/lwgeom_box2dfloat4.c +++ b/lwgeom/lwgeom_box2dfloat4.c @@ -104,7 +104,10 @@ Datum LWGEOM_to_BOX2DFLOAT4(PG_FUNCTION_ARGS) BOX2DFLOAT4 *result; result = palloc(sizeof(BOX2DFLOAT4)); - getbox2d_p(SERIALIZED_FORM(lwgeom), result); + if ( ! getbox2d_p(SERIALIZED_FORM(lwgeom), result) ) + { + PG_RETURN_NULL(); // must be the empty geometry + } PG_RETURN_POINTER(result); } @@ -378,8 +381,8 @@ Datum BOX2DFLOAT4_combine(PG_FUNCTION_ARGS) if (box2d_ptr == NULL) { lwgeom = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - - box = getbox2d(lwgeom+4); + // empty geom would make getbox2d_p return NULL + if ( ! getbox2d_p(lwgeom+4, &box) ) PG_RETURN_NULL(); memcpy(result, &box, sizeof(BOX2DFLOAT4)); PG_RETURN_POINTER(result); } @@ -394,7 +397,12 @@ Datum BOX2DFLOAT4_combine(PG_FUNCTION_ARGS) //combine_bbox(BOX3D, geometry) => union(BOX3D, geometry->bvol) lwgeom = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - box = getbox2d(lwgeom+4); + if ( ! getbox2d_p(lwgeom+4, &box) ) + { + // must be the empty geom + memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX2DFLOAT4)); + PG_RETURN_POINTER(result); + } a = (BOX2DFLOAT4 *)PG_GETARG_DATUM(0); b = &box; diff --git a/lwgeom/lwgeom_box3d.c b/lwgeom/lwgeom_box3d.c index 29291e367..61e656f27 100644 --- a/lwgeom/lwgeom_box3d.c +++ b/lwgeom/lwgeom_box3d.c @@ -291,6 +291,7 @@ Datum BOX3D_combine(PG_FUNCTION_ARGS) { lwgeom = (LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); box = lw_geom_getBB(SERIALIZED_FORM(lwgeom)); + if ( ! box ) PG_RETURN_NULL(); // must be the empty geom memcpy(result, box, sizeof(BOX3D)); PG_RETURN_POINTER(result); } @@ -304,6 +305,11 @@ Datum BOX3D_combine(PG_FUNCTION_ARGS) lwgeom = (LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); box = lw_geom_getBB(SERIALIZED_FORM(lwgeom)); + if ( ! box ) // must be the empty geom + { + memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX3D)); + PG_RETURN_POINTER(result); + } a = (BOX3D *)PG_GETARG_DATUM(0); b = box; diff --git a/lwgeom/lwgeom_functions_analytic.c b/lwgeom/lwgeom_functions_analytic.c index e69de29bb..430ddc849 100644 --- a/lwgeom/lwgeom_functions_analytic.c +++ b/lwgeom/lwgeom_functions_analytic.c @@ -0,0 +1,332 @@ +#include "postgres.h" +#include "lwgeom.h" + +/*********************************************************************** + * Simple Douglas-Peucker line simplification. + * No checks are done to avoid introduction of self-intersections. + * No topology relations are considered. + * + * --strk@keybit.net; + ***********************************************************************/ + +#define SAMEPOINT(a,b) ((a)->x==(b)->x&&(a)->y==(b)->y&&(a)->z==(b)->z) +#define VERBOSE 0 + +#if VERBOSE > 0 +#define REPORT_POINTS_REDUCTION +#define REPORT_RINGS_REDUCTION +#define REPORT_RINGS_ADJUSTMENTS +#endif + +/* Prototypes */ +void DP_findsplit2d(POINTARRAY *pts, int p1, int p2, int *split, double *dist); +POINTARRAY *DP_simplify2d(POINTARRAY *inpts, double epsilon); +LWLINE *simplify2d_lwline(LWLINE *iline, double dist); +LWPOLY *simplify2d_lwpoly(LWPOLY *ipoly, double dist); +Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS); + + +/* + * Search farthest point from segment p1-p2 + * returns distance in an int pointer + */ +void +DP_findsplit2d(POINTARRAY *pts, int p1, int p2, int *split, double *dist) +{ + int k; + POINT2D *pa, *pb, *pk; + double tmp; + +#if VERBOSE > 4 +elog(NOTICE, "DP_findsplit called"); +#endif + + *dist = -1; + *split = p1; + + if (p1 + 1 < p2) + { + + pa = (POINT2D *)getPoint(pts, p1); + pb = (POINT2D *)getPoint(pts, p2); + +#if VERBOSE > 4 +elog(NOTICE, "DP_findsplit: P%d(%f,%f) to P%d(%f,%f)", + p1, pa->x, pa->y, p2, pb->x, pb->y); +#endif + + for (k=p1+1; k 4 +elog(NOTICE, "DP_findsplit: P%d(%f,%f)", k, pk->x, pk->y); +#endif + + /* distance computation */ + tmp = distance2d_pt_seg(pk, pa, pb); + + if (tmp > *dist) + { + *dist = tmp; /* record the maximum */ + *split = k; +#if VERBOSE > 4 +elog(NOTICE, "DP_findsplit: P%d is farthest (%g)", k, *dist); +#endif + } + } + + } /* length---should be redone if can == 0 */ + + else + { +#if VERBOSE > 3 +elog(NOTICE, "DP_findsplit: segment too short, no split/no dist"); +#endif + } + +} + + +POINTARRAY * +DP_simplify2d(POINTARRAY *inpts, double epsilon) +{ + int stack[inpts->npoints]; /* recursion stack */ + int sp=-1; /* recursion stack pointer */ + int p1, split; + double dist; + POINTARRAY *outpts; + int ptsize = sizeof(double)*inpts->ndims; + + p1 = 0; + stack[++sp] = inpts->npoints-1; + +#if VERBOSE > 4 + elog(NOTICE, "DP_simplify called input has %d pts and %d dims (ptsize: %d)", inpts->npoints, inpts->ndims, ptsize); +#endif + + // allocate space for output POINTARRAY + outpts = palloc(sizeof(POINTARRAY)); + outpts->ndims = inpts->ndims; + outpts->npoints=1; + outpts->serialized_pointlist = (char *)palloc(ptsize*inpts->npoints); + memcpy(getPoint(outpts, 0), getPoint(inpts, 0), ptsize); + +#if VERBOSE > 3 + elog(NOTICE, "DP_simplify: added P0 to simplified point array (size 1)"); +#endif + + + do + { + + DP_findsplit2d(inpts, p1, stack[sp], &split, &dist); +#if VERBOSE > 3 + elog(NOTICE, "DP_simplify: farthest point from P%d-P%d is P%d (dist. %g)", p1, stack[sp], split, dist); +#endif + + if (dist > epsilon) { + stack[++sp] = split; + } else { + outpts->npoints++; + memcpy(getPoint(outpts, outpts->npoints-1), + getPoint(inpts, stack[sp]), + ptsize); +#if VERBOSE > 3 + elog(NOTICE, "DP_simplify: added P%d to simplified point array (size: %d)", stack[sp], outpts->npoints); +#endif + p1 = stack[sp--]; + } +#if VERBOSE > 5 + elog(NOTICE, "stack pointer = %d", sp); +#endif + } + while (! (sp<0) ); + + /* + * If we have reduced the number of points realloc + * outpoints array to free up some memory. + * Might be turned on and off with a SAVE_MEMORY define ... + */ + if ( outpts->npoints < inpts->npoints ) + { + outpts->serialized_pointlist = (char *)repalloc( + outpts->serialized_pointlist, + ptsize*outpts->npoints); + if ( outpts->serialized_pointlist == NULL ) { + elog(ERROR, "Out of virtual memory"); + } + } + + return outpts; +} + +LWLINE * +simplify2d_lwline(LWLINE *iline, double dist) +{ + POINTARRAY *ipts; + POINTARRAY *opts; + LWLINE *oline; + +#if VERBOSE + elog(NOTICE, "simplify2d_lwline called"); +#endif + + ipts = iline->points; + opts = DP_simplify2d(ipts, dist); + oline = lwline_construct(ipts->ndims, iline->SRID, opts); + + return oline; +} + +// TODO +LWPOLY * +simplify2d_lwpoly(LWPOLY *ipoly, double dist) +{ + POINTARRAY *ipts; + POINTARRAY **orings = NULL; + LWPOLY *opoly; + int norings=0, ri; + +#ifdef REPORT_RINGS_REDUCTION + elog(NOTICE, "simplify_polygon3d: simplifying polygon with %d rings", ipoly->nrings); +#endif + + orings = (POINTARRAY **)palloc(sizeof(POINTARRAY *)*ipoly->nrings); + + for (ri=0; rinrings; ri++) + { + POINTARRAY *opts; + + ipts = ipoly->rings[ri]; + + opts = DP_simplify2d(ipts, dist); + + + if ( opts->npoints < 2 ) + { + /* There as to be an error in DP_simplify */ + elog(NOTICE, "DP_simplify returned a <2 pts array"); + pfree(opts); + continue; + } + + if ( opts->npoints < 4 ) + { + pfree(opts); +#ifdef REPORT_RINGS_ADJUSTMENTS + elog(NOTICE, "simplify_polygon3d: ring%d skipped ( <4 pts )", ri); +#endif + + if ( ri ) continue; + else break; + } + + +#ifdef REPORT_POINTS_REDUCTION + elog(NOTICE, "simplify_polygon3d: ring%d simplified from %d to %d points", ri, ipts->npoints, opts->npoints); +#endif + + + /* + * Add ring to simplified ring array + * (TODO: dinamic allocation of pts_per_ring) + */ + orings[norings] = opts; + norings++; + + } + +#ifdef REPORT_RINGS_REDUCTION +elog(NOTICE, "simplify_polygon3d: simplified polygon with %d rings", norings); +#endif + + if ( ! norings ) return NULL; + + opoly = palloc(sizeof(LWPOLY)); + opoly->SRID = ipoly->SRID; + opoly->ndims = ipoly->ndims; + opoly->nrings = norings; + opoly->rings = orings; + + return opoly; +} + +PG_FUNCTION_INFO_V1(LWGEOM_simplify2d); +Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS) +{ + LWGEOM *geom = (LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + LWGEOM_EXPLODED *exp = lwgeom_explode(SERIALIZED_FORM(geom)); + double dist = PG_GETARG_FLOAT8(1); + int i; + char **newlines; + int newlinesnum=0; + char **newpolys; + int newpolysnum=0; + LWGEOM *result; + char *serialized; + + // no lines, no points... return input + if ( exp->nlines + exp->npolys == 0 ) + { + pfree_exploded(exp); + PG_RETURN_POINTER(geom); + } + + if ( exp->nlines ) + { +#if VERBOSE + elog(NOTICE, "%d lines in exploded geom", exp->nlines); +#endif + newlines = palloc(sizeof(char *)*exp->nlines); + for ( i=0; inlines; i++ ) + { + LWLINE *iline = lwline_deserialize(exp->lines[i]); +#if VERBOSE + elog(NOTICE, " line %d deserialized", i); +#endif + LWLINE *oline = simplify2d_lwline(iline, dist); +#if VERBOSE + elog(NOTICE, " line %d simplified", i); +#endif + if ( oline == NULL ) continue; + newlines[newlinesnum] = lwline_serialize(oline); + newlinesnum++; + } + pfree(exp->lines); + exp->lines = newlines; + exp->nlines = newlinesnum; + } + + if ( exp->npolys ) + { + newpolys = palloc(sizeof(char *)*exp->npolys); + for ( i=0; inpolys; i++ ) + { + LWPOLY *ipoly = lwpoly_deserialize(exp->polys[i]); + LWPOLY *opoly = simplify2d_lwpoly(ipoly, dist); + if ( opoly == NULL ) continue; + newpolys[newpolysnum] = lwpoly_serialize(opoly); + newpolysnum++; + } + pfree(exp->polys); + exp->polys = newpolys; + exp->npolys = newpolysnum; + } + + // copy 1 (when lwexploded_serialize_buf will be implemented this + // can be avoided) + serialized = lwexploded_serialize(exp, lwgeom_hasBBOX(geom->type)); + pfree_exploded(exp); + + + // copy 2 (see above) + result = LWGEOM_construct(serialized, + lwgeom_getSRID(geom), lwgeom_hasBBOX(geom->type)); + + PG_RETURN_POINTER(result); +} + +/*********************************************************************** + * --strk@keybit.net; + ***********************************************************************/ diff --git a/lwgeom/lwgeom_functions_basic.c b/lwgeom/lwgeom_functions_basic.c index edfa8531e..4db73c3bb 100644 --- a/lwgeom/lwgeom_functions_basic.c +++ b/lwgeom/lwgeom_functions_basic.c @@ -48,32 +48,6 @@ int32 lwgeom_npoints_recursive(char *serialized); int32 lwgeom_nrings_recursive(char *serialized); void dump_lwexploded(LWGEOM_EXPLODED *exploded); -// general utilities (might be moved in lwgeom_api.c) -double lwgeom_polygon_area(LWPOLY *poly); -double lwgeom_polygon_perimeter(LWPOLY *poly); -double lwgeom_polygon_perimeter2d(LWPOLY *poly); -double lwgeom_pointarray_length2d(POINTARRAY *pts); -double lwgeom_pointarray_length(POINTARRAY *pts); -void lwgeom_force2d_recursive(char *serialized, char *optr, int *retsize); -void lwgeom_force3d_recursive(char *serialized, char *optr, int *retsize); -double distance2d_pt_pt(POINT2D *p1, POINT2D *p2); -double distance2d_pt_seg(POINT2D *p, POINT2D *A, POINT2D *B); -double distance2d_seg_seg(POINT2D *A, POINT2D *B, POINT2D *C, POINT2D *D); -double distance2d_pt_ptarray(POINT2D *p, POINTARRAY *pa); -double distance2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2); -int pt_in_ring_2d(POINT2D *p, POINTARRAY *ring); -int pt_in_poly_2d(POINT2D *p, LWPOLY *poly); -double distance2d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly); -double distance2d_point_point(LWPOINT *point1, LWPOINT *point2); -double distance2d_point_line(LWPOINT *point, LWLINE *line); -double distance2d_line_line(LWLINE *line1, LWLINE *line2); -double distance2d_point_poly(LWPOINT *point, LWPOLY *poly); -double distance2d_poly_poly(LWPOLY *poly1, LWPOLY *poly2); -double distance2d_line_poly(LWLINE *line, LWPOLY *poly); -double lwgeom_mindistance2d_recursive(char *lw1, char *lw2); -void lwgeom_translate_recursive(char *serialized, double xoff, double yoff, double zoff); -void lwgeom_translate_ptarray(POINTARRAY *pa, double xoff, double yoff, double zoff); -int lwgeom_pt_inside_circle(POINT2D *p, double cx, double cy, double rad); /*------------------------------------------------------------------*/ @@ -826,15 +800,24 @@ lwgeom_summary_recursive(char *serialized, int offset) LWLINE *line=NULL; LWPOINT *point=NULL; LWPOLY *poly=NULL; - char *subgeom=NULL; + char *subgeom=lwgeom_getsubgeometry_inspected(inspected, j); + + if ( lwgeom_getType(subgeom[0]) == 0 ) + { + size += 32; + result = repalloc(result,size); + sprintf(tmp,"Object %i is EMPTY()\n", idx++); + strcat(result,tmp); + continue; + } + point = lwgeom_getpoint_inspected(inspected,j); if (point !=NULL) { - size += 30; + size += 32; result = repalloc(result,size); - sprintf(tmp,"Object %i is a POINT()\n", - idx++); + sprintf(tmp,"Object %i is a POINT()\n", idx++); strcat(result,tmp); continue; } @@ -842,10 +825,10 @@ lwgeom_summary_recursive(char *serialized, int offset) poly = lwgeom_getpoly_inspected(inspected, j); if (poly !=NULL) { - size += 57*(poly->nrings+1); + size += 60*(poly->nrings+1); result = repalloc(result,size); sprintf(tmp,"Object %i is a POLYGON() with %i rings\n", - idx++, poly->nrings); + idx++, poly->nrings); strcat(result,tmp); for (i=0; inrings;i++) { @@ -861,26 +844,16 @@ lwgeom_summary_recursive(char *serialized, int offset) { size += 57; result = repalloc(result,size); - sprintf(tmp, - "Object %i is a LINESTRING() with %i points\n", - idx++, line->points->npoints); + sprintf(tmp, "Object %i is a LINESTRING() with %i points\n", idx++, line->points->npoints); strcat(result,tmp); continue; } - subgeom = lwgeom_getsubgeometry_inspected(inspected, j); - if ( subgeom != NULL ) - { - ptr = lwgeom_summary_recursive(subgeom, 1); - size += strlen(ptr); - result = repalloc(result,size); - strcat(result, ptr); - pfree(ptr); - } - else - { - elog(ERROR, "What ? lwgeom_getsubgeometry_inspected returned NULL??"); - } + ptr = lwgeom_summary_recursive(subgeom, j); + size += strlen(ptr); + result = repalloc(result,size); + strcat(result, ptr); + pfree(ptr); } pfree_inspected(inspected); @@ -1894,7 +1867,7 @@ dump_lwexploded(LWGEOM_EXPLODED *exploded) // collect( geom, geom ) returns a geometry which contains // all the sub_objects from both of the argument geometries // returned geometry is the simplest possible, based on the types -// of the colelct objects +// of the collected objects // ie. if all are of either X or multiX, then a multiX is returned. PG_FUNCTION_INFO_V1(LWGEOM_collect); Datum LWGEOM_collect(PG_FUNCTION_ARGS) @@ -2248,8 +2221,14 @@ Datum LWGEOM_expand(PG_FUNCTION_ARGS) LWGEOM *result; char *ser; - // get geometry box and SRID - getbox2d_p(SERIALIZED_FORM(geom), &box); + // get geometry box + if ( ! getbox2d_p(SERIALIZED_FORM(geom), &box) ) + { + // must be an EMPTY geometry + PG_RETURN_POINTER(geom); + } + + // get geometry SRID SRID = lwgeom_getsrid(SERIALIZED_FORM(geom)); // expand it @@ -2288,7 +2267,10 @@ Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS) BOX2DFLOAT4 box2d; BOX *result = (BOX *)palloc(sizeof(BOX)); - getbox2d_p(SERIALIZED_FORM(lwgeom), &box2d); + if ( ! getbox2d_p(SERIALIZED_FORM(lwgeom), &box2d) ) + { + PG_RETURN_NULL(); // must be the empty geometry + } box2df_to_box_p(&box2d, result); PG_RETURN_POINTER(result); @@ -2309,8 +2291,14 @@ Datum LWGEOM_envelope(PG_FUNCTION_ARGS) LWGEOM *result; char *ser; - // get geometry box and SRID - getbox2d_p(SERIALIZED_FORM(geom), &box); + // get bounding box + if ( ! getbox2d_p(SERIALIZED_FORM(geom), &box) ) + { + // must be the EMPTY geometry + PG_RETURN_POINTER(geom); + } + + // get geometry SRID SRID = lwgeom_getsrid(SERIALIZED_FORM(geom)); // Assign coordinates to POINT2D array diff --git a/lwgeom/lwgeom_inout.c b/lwgeom/lwgeom_inout.c index 053fe2fab..a86a35a43 100644 --- a/lwgeom/lwgeom_inout.c +++ b/lwgeom/lwgeom_inout.c @@ -131,54 +131,53 @@ Datum LWGEOM_out(PG_FUNCTION_ARGS) PG_FUNCTION_INFO_V1(LWGEOMFromWKB); Datum LWGEOMFromWKB(PG_FUNCTION_ARGS) { - WellKnownBinary *wkb_input = (WellKnownBinary *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char *wkb_srid_hexized; - int size_result,size_header; - int SRID = -1; - char sridText[100]; - char *loc; - char *lwgeom; - int t; - - - if ( ( PG_NARGS()>1) && ( ! PG_ARGISNULL(1) )) - SRID = PG_GETARG_INT32(1); - else - SRID = -1; + WellKnownBinary *wkb_input; + char *wkb_srid_hexized; + int size_result,size_header; + int SRID = -1; + char sridText[100]; + char *loc; + char *lwgeom; + int t; + + wkb_input = (WellKnownBinary *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + + if ( ( PG_NARGS()>1) && ( ! PG_ARGISNULL(1) )) + SRID = PG_GETARG_INT32(1); + else + SRID = -1; // elog(NOTICE,"LWGEOMFromWKB: entry with SRID=%i",SRID); elog(NOTICE,"wkb => lwgeom CONVERSION"); - // convert WKB to hexized WKB string - - - + // convert WKB to hexized WKB string - size_header = sprintf(sridText,"SRID=%i;",SRID); - size_result = size_header + 2*(wkb_input->size -4) + 1; //SRID text size + wkb size (+1 = NULL term) + size_header = sprintf(sridText,"SRID=%i;",SRID); + //SRID text size + wkb size (+1 = NULL term) + size_result = size_header + 2*(wkb_input->size -4) + 1; - wkb_srid_hexized = palloc(size_result); - wkb_srid_hexized[0] = 0; // empty - strcpy(wkb_srid_hexized, sridText); - loc = wkb_srid_hexized + size_header; // points to null in "SRID=#;" + wkb_srid_hexized = palloc(size_result); + wkb_srid_hexized[0] = 0; // empty + strcpy(wkb_srid_hexized, sridText); + loc = wkb_srid_hexized + size_header; // points to null in "SRID=#;" - for (t=0; t< (wkb_input->size -4); t++) - { - deparse_hex( ((unsigned char *) wkb_input)[4 + t], &loc[t*2]); - } + for (t=0; t< (wkb_input->size -4); t++) + { + deparse_hex( ((unsigned char *) wkb_input)[4 + t], &loc[t*2]); + } - wkb_srid_hexized[size_result-1] = 0; // null term + wkb_srid_hexized[size_result-1] = 0; // null term //elog(NOTICE,"size_header = %i",size_header); //elog(NOTICE,"size_result = %i", size_result); //elog(NOTICE,"LWGEOMFromWKB :: '%s'", wkb_srid_hexized); - lwgeom = parse_lwgeom_wkt(wkb_srid_hexized); + lwgeom = parse_lwgeom_wkt(wkb_srid_hexized); - pfree(wkb_srid_hexized); + pfree(wkb_srid_hexized); - PG_RETURN_POINTER(lwgeom); + PG_RETURN_POINTER(lwgeom); } // WKBFromLWGEOM(lwgeom) --> wkb @@ -189,7 +188,7 @@ Datum WKBFromLWGEOM(PG_FUNCTION_ARGS) char *lwgeom_input = (char *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); // SRID=#; - char *hexized_wkb_srid = unparse_WKB(lwgeom_input,palloc_fn,free_fn); + char *hexized_wkb_srid = unparse_WKB(lwgeom_input, palloc_fn, free_fn); char *hexized_wkb; // hexized_wkb_srid w/o srid char *result; //wkb @@ -197,41 +196,40 @@ Datum WKBFromLWGEOM(PG_FUNCTION_ARGS) int len_hexized_wkb; int size_result; char *semicolonLoc; - int t; + int t; //elog(NOTICE, "in WKBFromLWGEOM with WKB = '%s'", hexized_wkb_srid); elog(NOTICE,"lwgeom => wkb CONVERSION"); - hexized_wkb = hexized_wkb_srid; - semicolonLoc = strchr(hexized_wkb_srid,';'); + hexized_wkb = hexized_wkb_srid; + semicolonLoc = strchr(hexized_wkb_srid,';'); - if (semicolonLoc != NULL) - { - hexized_wkb = (semicolonLoc+1); - } + if (semicolonLoc != NULL) + { + hexized_wkb = (semicolonLoc+1); + } //elog(NOTICE, "in WKBFromLWGEOM with WKB (with no 'SRID=#;' = '%s'", hexized_wkb); + len_hexized_wkb = strlen(hexized_wkb); + size_result = len_hexized_wkb/2 + 4; + result = palloc(size_result); - len_hexized_wkb = strlen(hexized_wkb); - size_result = len_hexized_wkb/2 + 4; - result = palloc(size_result); - - memcpy(result, &size_result,4); // size header + memcpy(result, &size_result,4); // size header - // have a hexized string, want to make it binary + // have a hexized string, want to make it binary - for (t=0; t< (len_hexized_wkb/2); t++) - { - ((unsigned char *) result +4)[t] = parse_hex( hexized_wkb + (t*2) ); - } + for (t=0; t< (len_hexized_wkb/2); t++) + { + ((unsigned char *) result +4)[t] = parse_hex( hexized_wkb + (t*2) ); + } - pfree(hexized_wkb_srid); + pfree(hexized_wkb_srid); - PG_RETURN_POINTER(result); + PG_RETURN_POINTER(result); } @@ -588,9 +586,3 @@ char *parse_lwgeom_wkt(char *wkt_input) //return result; } - - - - - - diff --git a/lwgeom/lwpostgis.sql.in b/lwgeom/lwpostgis.sql.in index 7d80bae14..7047dbb03 100644 --- a/lwgeom/lwpostgis.sql.in +++ b/lwgeom/lwpostgis.sql.in @@ -108,11 +108,6 @@ CREATE TYPE geometry ( ); -CREATEFUNCTION geometry(text) - RETURNS geometry - AS '@MODULE_FILENAME@','parse_WKT_lwgeom' - LANGUAGE 'C' WITH (isstrict,iscachable); - ------------------------------------------------------------------- -- BOX3D TYPE ------------------------------------------------------------------- @@ -2420,6 +2415,22 @@ CREATEFUNCTION geometry(box3d) CREATE CAST (box3d as geometry) WITH FUNCTION geometry(box3d) AS IMPLICIT ; +CREATEFUNCTION geometry(text) + RETURNS geometry + AS '@MODULE_FILENAME@','parse_WKT_lwgeom' + LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE CAST ( text AS geometry) WITH FUNCTION geometry(text) AS IMPLICIT; + +--------------------------------------------------------------- +-- Algorithms +--------------------------------------------------------------- + +CREATEFUNCTION simplify(geometry, float8) + RETURNS geometry + AS '@MODULE_FILENAME@', 'LWGEOM_simplify2d' + LANGUAGE 'C' WITH (isstrict); + --------------------------------------------------------------- -- END --------------------------------------------------------------- -- 2.40.0