29 #include "../postgis_config.h"
37 #include "lwgeom_geos.h"
64 void *match = bsearch( &key, tab->
edges, tab->
size,
92 #define LWT_EDGERING_INIT(a) { \
95 (a)->elems = lwalloc(sizeof(LWT_EDGERING_ELEM *) * (a)->capacity); \
100 #define LWT_EDGERING_PUSH(a, r) { \
101 if ( (a)->size + 1 > (a)->capacity ) { \
102 (a)->capacity *= 2; \
103 (a)->elems = lwrealloc((a)->elems, sizeof(LWT_EDGERING_ELEM *) * (a)->capacity); \
106 (a)->elems[(a)->size++] = (r); \
109 #define LWT_EDGERING_CLEAN(a) { \
110 int i; for (i=0; i<(a)->size; ++i) { \
111 if ( (a)->elems[i] ) { \
113 lwfree((a)->elems[i]); \
116 if ( (a)->elems ) { lwfree((a)->elems); (a)->elems = NULL; } \
119 if ( (a)->env ) { lwfree((a)->env); (a)->env = NULL; } \
120 if ( (a)->genv ) { GEOSGeom_destroy((a)->genv); (a)->genv = NULL; } \
131 #define LWT_EDGERING_ARRAY_INIT(a) { \
134 (a)->rings = lwalloc(sizeof(LWT_EDGERING *) * (a)->capacity); \
140 #define LWT_EDGERING_ARRAY_CLEAN(a) { \
141 int j; for (j=0; j<(a)->size; ++j) { \
142 LWT_EDGERING_CLEAN((a)->rings[j]); \
144 if ( (a)->capacity ) lwfree((a)->rings); \
146 GEOSSTRtree_destroy( (a)->tree ); \
151 #define LWT_EDGERING_ARRAY_PUSH(a, r) { \
152 if ( (a)->size + 1 > (a)->capacity ) { \
153 (a)->capacity *= 2; \
154 (a)->rings = lwrealloc((a)->rings, sizeof(LWT_EDGERING *) * (a)->capacity); \
156 (a)->rings[(a)->size++] = (r); \
172 if ( ! el )
return 0;
184 if ( it->
curidx < 0 ) tonext = 1;
189 LWDEBUG(3,
"iterator moving to next element");
220 #define LWT_HOLES_FACE_PLACEHOLDER INT32_MIN
230 return from < etab->
size ? from : -1;
242 if (nelems == UINT64_MAX)
264 int forward_edges_count = 0;
266 int backward_edges_count = 0;
272 forward_edges_count = 0;
274 backward_edges_count = 0;
276 for ( i=0; i<ring->
size; ++i )
283 LWDEBUGF(3,
"Forward edge %d is %lld", forward_edges_count,
id);
284 forward_edges[forward_edges_count].
edge_id = id;
285 forward_edges[forward_edges_count++].
face_left = face;
290 LWDEBUGF(3,
"Backward edge %d is %lld", forward_edges_count,
id);
291 backward_edges[backward_edges_count].
edge_id = id;
292 backward_edges[backward_edges_count++].
face_right = face;
298 if ( forward_edges_count )
310 if ( ret != forward_edges_count )
314 lwerror(
"Unexpected error: %d edges updated when expecting %d (forward)",
315 ret, forward_edges_count);
321 if ( backward_edges_count )
324 backward_edges_count,
333 if ( ret != backward_edges_count )
337 lwerror(
"Unexpected error: %d edges updated when expecting %d (backward)",
338 ret, backward_edges_count);
367 LWDEBUGF(2,
"Building rings for edge %lld (side %d)",
cur->edge_id, side);
374 elem->
left = ( curside == 1 );
381 next = elem->
left ?
cur->next_left :
cur->next_right;
383 LWDEBUGF(3,
" next edge is %lld", next);
385 if ( next > 0 ) curside = 1;
386 else { curside = -1; next = -next; }
393 }
while (
cur != edge || curside != side);
407 double x0,
x, y1, y2;
412 LWDEBUG(2,
"_lwt_EdgeRingSignedArea");
437 LWDEBUGF(2,
"_lwt_EdgeRingIsCCW, ring has %d elems", ring->
size);
440 LWDEBUGF(2,
"_lwt_EdgeRingIsCCW, signed area is %g", sa);
442 if ( sa >= 0 )
return 0;
465 ((v1.
y <= p->
y) && (v2.
y > p->
y))
467 || ((v1.
y > p->
y) && (v2.
y <= p->
y))
471 vt = (double)(p->
y - v1.
y) / (v2.
y - v1.
y);
474 if (p->
x < v1.
x + vt * (v2.
x - v1.
x))
483 LWDEBUGF(3,
"_lwt_EdgeRingCrossingCount returning %d", cn);
486 if ( memcmp(&v1, &v0,
sizeof(
POINT2D)) )
488 lwerror(
"_lwt_EdgeRingCrossingCount: V[n] != V[0] (%g %g != %g %g)",
489 v1.
x, v1.
y, v0.
x, v0.
y);
516 LWDEBUGF(2,
"Computing GBOX for ring %p", ring);
517 for (i=0; i<ring->
size; ++i)
578 LWDEBUG(2,
"Ring built, calling EdgeRingIsCCW");
588 LWDEBUGF(1,
"Ring of edge %lld is a shell (shell %d)", edge->
edge_id * side, shells->
size);
603 lwerror(
"Unexpected error: %d faces inserted when expecting 1", ret);
614 lwerror(
"Errors updating edgering side face: %s",
623 *registered = placeholder_faceid;
644 const GBOX *minenv = NULL;
665 if ( ! shells->
tree )
668 LWDEBUG(1,
"Building STRtree");
670 if (shells->
tree == NULL)
675 for (i=0; i<shells->
size; ++i)
679 LWDEBUGF(2,
"GBOX of shell %p for edge %lld is %g %g,%g %g",
685 pt.
x = shellbox->
xmin;
686 pt.
y = shellbox->
ymin;
688 pt.
x = shellbox->
xmax;
689 pt.
y = shellbox->
ymax;
696 GEOSSTRtree_insert(shells->
tree, sring->
genv, sring);
698 LWDEBUG(1,
"STRtree build completed");
704 LWDEBUGF(1,
"Found %d candidate shells containing first point of ring's originating edge %lld",
709 for (i=0; i<candidates.
size; ++i)
717 LWDEBUGF(1,
"Shell %lld is on other side of ring",
725 LWDEBUGF(1,
"Bbox of shell %lld equals that of hole ring",
733 LWDEBUGF(1,
"Bbox of shell %lld does not contain bbox of ring point",
742 LWDEBUGF(2,
"Bbox of shell %d (face %lld) not contained by bbox "
743 "of last shell found to contain the point",
754 LWDEBUGF(1,
"Shell %lld contains hole of edge %lld",
761 if ( foundInFace == -1 ) foundInFace = 0;
766 GEOSGeom_destroy(ghole);
787 if (nelems == UINT64_MAX)
839 if ( numfaces != 0 ) {
840 if ( numfaces > 0 ) {
842 lwerror(
"Polygonize: face table is not empty.");
850 if ( ! edgetable.
edges ) {
851 if (edgetable.
size == 0) {
863 for (i=0; i<edgetable.
size; ++i)
871 edge = &(edgetable.
edges[i]);
875 LWDEBUGF(1,
"Next face-missing edge has id:%lld, face_left:%lld, face_right:%lld",
880 &holes, &shells, &newface);
882 LWDEBUGF(1,
"New face on the left of edge %lld is %lld",
889 &holes, &shells, &newface);
891 LWDEBUGF(1,
"New face on the right of edge %lld is %lld",
902 lwerror(
"Errors fetching or registering face-missing edges: %s",
912 for (i=0; i<holes.
size; ++i)
919 if ( containing_face == -1 )
924 lwerror(
"Errors finding face containing ring: %s",
934 lwerror(
"Errors updating edgering side face: %s",
940 LWDEBUG(1,
"All holes assigned, cleaning up");
int gbox_merge(const GBOX *new_box, GBOX *merge_box)
Update the merged GBOX to be large enough to include itself and the new box.
int gbox_same(const GBOX *g1, const GBOX *g2)
Check if 2 given Gbox are the same.
GBOX * gbox_clone(const GBOX *gbox)
int gbox_contains_2d(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the first GBOX contains the second on the 2d plane, LW_FALSE otherwise.
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
void lwgeom_geos_error(const char *fmt,...)
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
void lwpoint_free(LWPOINT *pt)
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
void * lwalloc(size_t size)
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
void lwline_free(LWLINE *line)
#define LWT_COL_EDGE_FACE_RIGHT
#define LWT_COL_FACE_FACE_ID
Face fields.
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_EDGE_FACE_LEFT
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
LWT_ISO_EDGE * lwt_be_getEdgeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
#define PGTOPO_BE_ERROR()
int lwt_be_insertFaces(LWT_TOPOLOGY *topo, LWT_ISO_FACE *face, uint64_t numelems)
static const int STRTREE_NODE_CAPACITY
Datum contains(PG_FUNCTION_ARGS)
#define LWDEBUG(level, msg)
#define LWDEBUGF(level, msg,...)
void lwnotice(const char *fmt,...) __attribute__((format(printf
Write a notice out to the notice handler.
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
struct LWT_ISO_EDGE_TABLE_T LWT_ISO_EDGE_TABLE
static double _lwt_EdgeRingSignedArea(LWT_EDGERING_POINT_ITERATOR *it)
struct LWT_EDGERING_POINT_ITERATOR_T LWT_EDGERING_POINT_ITERATOR
static int _lwt_EdgeRingContainsPoint(LWT_EDGERING *ring, POINT2D *p)
struct LWT_EDGERING_ARRAY_T LWT_EDGERING_ARRAY
#define LWT_EDGERING_INIT(a)
static LWT_EDGERING * _lwt_BuildEdgeRing(__attribute__((__unused__)) LWT_TOPOLOGY *topo, LWT_ISO_EDGE_TABLE *edges, LWT_ISO_EDGE *edge, int side)
static LWT_ELEMID _lwt_EdgeRingGetFace(LWT_EDGERING *ring)
static int _lwt_UpdateEdgeRingSideFace(LWT_TOPOLOGY *topo, LWT_EDGERING *ring, LWT_ELEMID face)
static int _lwt_EdgeRingIsCCW(LWT_EDGERING *ring)
int lwt_Polygonize(LWT_TOPOLOGY *topo)
static LWT_EDGERING_POINT_ITERATOR * _lwt_EdgeRingIterator_begin(LWT_EDGERING *er)
static int _lwt_EdgeRingIterator_next(LWT_EDGERING_POINT_ITERATOR *it, POINT2D *pt)
#define LWT_HOLES_FACE_PLACEHOLDER
static int _lwt_CheckFacesExist(LWT_TOPOLOGY *topo)
static GBOX * _lwt_EdgeRingGetBbox(LWT_EDGERING *ring)
#define LWT_EDGERING_ARRAY_INIT(a)
struct LWT_EDGERING_ELEM_T LWT_EDGERING_ELEM
static LWT_ISO_EDGE * _lwt_getIsoEdgeById(LWT_ISO_EDGE_TABLE *tab, LWT_ELEMID id)
static int _lwt_RegisterFaceOnEdgeSide(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, int side, LWT_ISO_EDGE_TABLE *edges, LWT_EDGERING_ARRAY *holes, LWT_EDGERING_ARRAY *shells, LWT_ELEMID *registered)
static void _lwt_AccumulateCanditates(void *item, void *userdata)
#define LWT_EDGERING_PUSH(a, r)
static LWT_ELEMID _lwt_FindFaceContainingRing(LWT_TOPOLOGY *topo, LWT_EDGERING *ring, LWT_EDGERING_ARRAY *shells)
#define LWT_EDGERING_ARRAY_CLEAN(a)
static LWT_ISO_EDGE * _lwt_FetchAllEdges(LWT_TOPOLOGY *topo, int *numedges)
static int compare_iso_edges_by_id(const void *si1, const void *si2)
static int _lwt_FetchNextUnvisitedEdge(__attribute__((__unused__)) LWT_TOPOLOGY *topo, LWT_ISO_EDGE_TABLE *etab, int from)
#define LWT_EDGERING_ARRAY_PUSH(a, r)
static int _lwt_EdgeRingCrossingCount(const POINT2D *p, LWT_EDGERING_POINT_ITERATOR *it)
struct LWT_EDGERING_T LWT_EDGERING
LWT_EDGERING_ELEM * curelem
LWT_EDGERING_ELEM ** elems
const LWT_BE_IFACE * be_iface