From: Paul Ramsey Date: Wed, 17 Dec 2008 20:47:36 +0000 (+0000) Subject: Partial work into SVN where I can get at it elsewhere. X-Git-Tag: 1.4.0b1~393 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bdebdb69036b73e9c6355abbfc9efb3b80e43705;p=postgis Partial work into SVN where I can get at it elsewhere. git-svn-id: http://svn.osgeo.org/postgis/trunk@3439 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/TODO b/TODO index 59faeac7d..992e8f7f0 100644 --- a/TODO +++ b/TODO @@ -91,4 +91,5 @@ See, * Convert the LWGEOM struct(s) to have enough padding that the coordinates are double-aligned and can be accessed directly as doubles on all architectures - +* Support all typologies of EMPTY (POINT EMPTY, LINESTRING EMPTY) instead + of just using GEOMETRYCOLLECTION EMPTY all the time. diff --git a/liblwgeom/liblwgeom.h b/liblwgeom/liblwgeom.h index b6b4eaaf7..62533480d 100644 --- a/liblwgeom/liblwgeom.h +++ b/liblwgeom/liblwgeom.h @@ -5,6 +5,23 @@ #include #include +/** +* @file liblwgeom.h +* +* This library is the generic geometry handling section of PostGIS. The geometry +* objects, constructors, destructors, and a set of spatial processing functions, +* are implemented here. +* +* The library is designed for use in non-PostGIS applications if necessary. The +* units tests at cunit/cu_tester.c and the loader/dumper programs at +* ../loader/shp2pgsql.c are examples of non-PostGIS applications using liblwgeom. +* +* Programs using this library should set up the default memory managers and error +* handlers by implementing an lwgeom_init_allocators() function, which can be as +* a wrapper around the lwgeom_install_default_allocators() function if you want +* no special handling for memory management and error reporting. +*/ + #define INTEGRITY_CHECKS 1 /* @@ -25,20 +42,13 @@ #define LW_TRUE 1 #define LW_FALSE 0 - /* - * Memory management function types + * this will change to NaN when I figure out how to + * get NaN in a platform-independent way */ -extern void lwgeom_init_allocators(void); -extern void lwgeom_install_default_allocators(void); - -typedef void* (*lwallocator)(size_t size); -typedef void* (*lwreallocator)(void *mem, size_t size); -typedef void (*lwfreeor)(void* mem); -typedef void (*lwreporter)(const char* fmt, va_list ap); - -void lwnotice(const char *fmt, ...); -void lwerror(const char *fmt, ...); +#define NO_VALUE 0.0 +#define NO_Z_VALUE NO_VALUE +#define NO_M_VALUE NO_VALUE #ifndef C_H @@ -47,29 +57,54 @@ typedef int int32; #endif -/* - * this will change to NaN when I figure out how to - * get NaN in a platform-independent way - */ -#define NO_VALUE 0.0 -#define NO_Z_VALUE NO_VALUE -#define NO_M_VALUE NO_VALUE +/** +* Supply the memory management and error handling functions you want your +* application to use. +* @ingroup system +*/ +extern void lwgeom_init_allocators(void); +/** +* Apply the default memory management (malloc() and free()) and error handlers. +* Called inside lwgeom_init_allocators() generally. +* @ingroup system +*/ +extern void lwgeom_install_default_allocators(void); + + +/** +* Write a notice out to the notice handler. Uses standard printf() substitutions. +* Use for messages you always want output. For debugging, use LWDEBUG() or LWDEBUGF(). +* @ingroup logging +*/ +void lwnotice(const char *fmt, ...); +/** +* Write a notice out to the error handler. Uses standard printf() substitutions. +* Use for errors you always want output. For debugging, use LWDEBUG() or LWDEBUGF(). +* @ingroup logging +*/ +void lwerror(const char *fmt, ...); -/* prototypes */ -void *default_allocator(size_t size); -void *default_reallocator(void *mem, size_t size); -void default_freeor(void *ptr); -void default_errorreporter(const char *fmt, va_list ap); -void default_noticereporter(const char *fmt, va_list ap); -/* globals */ +/* Globals for memory/logging handlers. */ +typedef void* (*lwallocator)(size_t size); +typedef void* (*lwreallocator)(void *mem, size_t size); +typedef void (*lwfreeor)(void* mem); +typedef void (*lwreporter)(const char* fmt, va_list ap); extern lwreallocator lwrealloc_var; extern lwallocator lwalloc_var; extern lwfreeor lwfree_var; extern lwreporter lwerror_var; extern lwreporter lwnotice_var; +/* The default memory/logging handlers installed by lwgeom_install_default_allocators() */ +void *default_allocator(size_t size); +void *default_reallocator(void *mem, size_t size); +void default_freeor(void *ptr); +void default_errorreporter(const char *fmt, va_list ap); +void default_noticereporter(const char *fmt, va_list ap); + + extern int lw_vasprintf (char **result, const char *format, va_list args); /* Debug macros */ diff --git a/liblwgeom/lwalgorithm.c b/liblwgeom/lwalgorithm.c index f5a02c6b5..63e9b3c04 100644 --- a/liblwgeom/lwalgorithm.c +++ b/liblwgeom/lwalgorithm.c @@ -13,7 +13,7 @@ #include "lwalgorithm.h" /* -** segmentSide() +** lw_segment_side() ** ** Return < 0.0 if point Q is left of segment P ** Return > 0.0 if point Q is right of segment P @@ -24,7 +24,8 @@ double lw_segment_side(POINT2D *p1, POINT2D *p2, POINT2D *q) return ( (q->x - p1->x) * (p2->y - p1->y) - (p2->x - p1->x) * (q->y - p1->y) ); } -int lw_segment_envelope_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2) { +int lw_segment_envelope_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2) +{ double minq=LW_MIN(q1->x,q2->x); double maxq=LW_MAX(q1->x,q2->x); double minp=LW_MIN(p1->x,p2->x); @@ -45,7 +46,7 @@ int lw_segment_envelope_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2 } /* -** segmentIntersects() +** lw_segment_intersects() ** ** Returns one of ** SEG_ERROR = -1, @@ -56,31 +57,36 @@ int lw_segment_envelope_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2 ** SEG_TOUCH_LEFT = 4, ** SEG_TOUCH_RIGHT = 5 */ -int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2) { +int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2) +{ double pq1, pq2, qp1, qp2; /* No envelope interaction => we are done. */ - if (!lw_segment_envelope_intersects(p1, p2, q1, p2)) { + if (!lw_segment_envelope_intersects(p1, p2, q1, p2)) + { return SEG_NO_INTERSECTION; } /* Are the start and end points of q on the same side of p? */ pq1=lw_segment_side(p1,p2,q1); pq2=lw_segment_side(p1,p2,q2); - if ((pq1>0 && pq2>0) || (pq1<0 && pq2<0)) { + if ((pq1>0 && pq2>0) || (pq1<0 && pq2<0)) + { return SEG_NO_INTERSECTION; } /* Are the start and end points of p on the same side of q? */ qp1=lw_segment_side(q1,q2,p1); qp2=lw_segment_side(q1,q2,p2); - if ((qp1>0 && qp2>0) || (qp1<0 && qp2<0)) { + if ((qp1>0 && qp2>0) || (qp1<0 && qp2<0)) + { return SEG_NO_INTERSECTION; } /* Nobody is on one side or another? Must be colinear. */ - if (pq1 == 0.0 && pq2 == 0.0 && qp1 == 0.0 && qp2 == 0.0) { + if (pq1 == 0.0 && pq2 == 0.0 && qp1 == 0.0 && qp2 == 0.0) + { return SEG_COLINEAR; } @@ -88,13 +94,15 @@ int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2) { ** When one end-point touches, the sidedness is determined by the ** location of the other end-point. */ - if ( pq2 == 0.0 ) { + if ( pq2 == 0.0 ) + { if ( pq1 < 0.0 ) return SEG_TOUCH_LEFT; else return SEG_TOUCH_RIGHT; } - if ( pq1 == 0.0 ) { + if ( pq1 == 0.0 ) + { if ( pq2 < 0.0 ) return SEG_TOUCH_LEFT; else @@ -113,7 +121,7 @@ int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2) { } /* -** lineCrossingDirection() +** lwline_crossing_direction() ** ** Returns one of ** LINE_NO_CROSS = 0 @@ -127,7 +135,8 @@ int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2) { ** LINE_TOUCH_RIGHT = 4 ** */ -int lwline_crossing_direction(LWLINE *l1, LWLINE *l2) { +int lwline_crossing_direction(LWLINE *l1, LWLINE *l2) +{ int i = 0, j = 0, rv = 0; POINT2D *p1; @@ -159,12 +168,14 @@ int lwline_crossing_direction(LWLINE *l1, LWLINE *l2) { LWDEBUGF(4, "lineCrossingDirection: l1 = %s", lwgeom_to_ewkt((LWGEOM*)l1,0)); LWDEBUGF(4, "lineCrossingDirection: l2 = %s", lwgeom_to_ewkt((LWGEOM*)l2,0)); - for ( i = 1; i < pa2->npoints; i++ ) { + for ( i = 1; i < pa2->npoints; i++ ) + { rv = getPoint2d_p(pa2, i-1, q1); rv = getPoint2d_p(pa2, i, q2); - for ( j = 1; j < pa1->npoints; j++ ) { + for ( j = 1; j < pa1->npoints; j++ ) + { rv = getPoint2d_p(pa1, j-1, p1); rv = getPoint2d_p(pa1, j, p2); @@ -178,12 +189,14 @@ int lwline_crossing_direction(LWLINE *l1, LWLINE *l2) { if( this_cross ) final_cross = this_cross; - if( this_cross == SEG_CROSS_LEFT ) { + if( this_cross == SEG_CROSS_LEFT ) + { cross_left++; break; } - if( this_cross == SEG_CROSS_RIGHT ) { + if( this_cross == SEG_CROSS_RIGHT ) + { cross_right++; break; } @@ -193,7 +206,8 @@ int lwline_crossing_direction(LWLINE *l1, LWLINE *l2) { ** a vertex by pulling the original touch point forward along ** the co-linearity. */ - if( this_cross == SEG_COLINEAR && vertex_touch == (i-1) ) { + if( this_cross == SEG_COLINEAR && vertex_touch == (i-1) ) + { vertex_touch = i; break; } @@ -203,7 +217,8 @@ int lwline_crossing_direction(LWLINE *l1, LWLINE *l2) { ** j-1 and two at j. We avoid incrementing our cross count by ignoring the ** second pair. */ - if( this_cross == SEG_TOUCH_LEFT ) { + if( this_cross == SEG_TOUCH_LEFT ) + { if ( vertex_touch == (i-1) && vertex_touch_type == SEG_TOUCH_RIGHT ) { cross_left++; vertex_touch = -1; @@ -215,7 +230,8 @@ int lwline_crossing_direction(LWLINE *l1, LWLINE *l2) { } break; } - if( this_cross == SEG_TOUCH_RIGHT ) { + if( this_cross == SEG_TOUCH_RIGHT ) + { if ( vertex_touch == (i-1) && vertex_touch_type == SEG_TOUCH_LEFT ) { cross_right++; vertex_touch = -1; @@ -276,3 +292,97 @@ int lwline_crossing_direction(LWLINE *l1, LWLINE *l2) { } +#if 0 +/* +** lwpoint_get_ordinate(point, ordinate) => double +*/ +double lwpoint_get_ordinate(POINT4D *p, int ordinate) +{ + if( ! p ) + { + lwerror("Null input geometry."); + return 0.0; + } + + if( ordinate > 3 || ordinate < 0 ) + { + lwerror("Cannot extract ordinate %d.", ordinate); + return 0.0; + } + + if( ordinate == 3 ) + return p->m; + if( ordinate == 2 ) + return p->z; + if( ordinate == 1 ) + return p->y; + + return p->x; + +} + +/* +** lwline_clip_to_ordinate_range(line, ordinate, from, to) => lwmline +** +** Take in a LINESTRING and return a MULTILINESTRING of those portions of the +** LINESTRING between the from/to range for the specified ordinate (XYZM) +*/ +LWLINE *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double from, double to) +{ + + POINTARRAY *pa_in; + LWMLINE *mline_out; + POINTARRAY *pa_out; + DYNPTARRAY *dp; + int i, rv; + int last_point = 0; + int nparts = 0; + POINT4D *p, *q; + double ordinate_value; + + + /* Null input, nothing we can do. */ + if( ! line ) + { + lwerror("Null input geometry."); + return NULL; + } + + /* Ensure 'from' is less than 'to'. */ + if( to < from ) + { + double t = from; + from = to; + to = t; + } + + int ndims = TYPE_NDIMS(line->type); + + /* Asking for an ordinate we don't have. */ + if( ordinate >= ndims ) + { + lwerror("Cannot clip on ordinate %d in a %d-d geometry.", ordinate, ndims); + return NULL; + } + + p = lwalloc(sizeof(POINT4D)); + q = lwalloc(sizeof(POINT4D)); + + pa_in = (POINTARRAY*)line->points; + + dp = dynptarray_create(64, ndims); + + + for ( i = 1; i < pa_in->npoints; i++ ) + { + rv = getPoint4d_p(pa_in, i, p); + ordinate_value = lwpoint_get_ordinate(p, ordinate); + if ( ordinate_value >= from && ordinate_value <= to ) + { + rv =dynptarray_addPoint4d(dp, p, 1); + } + } + + +} +#endif diff --git a/liblwgeom/lwalgorithm.h b/liblwgeom/lwalgorithm.h index 638fd853e..b1ae14eb8 100644 --- a/liblwgeom/lwalgorithm.h +++ b/liblwgeom/lwalgorithm.h @@ -38,3 +38,5 @@ enum CG_LINE_CROSS_TYPE { }; int lwline_crossing_direction(LWLINE *l1, LWLINE *l2); + +double lwpoint_get_ordinate(POINT4D *p, int ordinate);