27 #include "../postgis_config.h"
41 # define LWTFMT_ELEMID "lld"
43 # define LWTFMT_ELEMID PRId64
77 #define CHECKCB(be, method) do { \
78 if ( ! (be)->cb || ! (be)->cb->method ) \
79 lwerror("Callback " # method " not registered by backend"); \
82 #define CB0(be, method) \
84 return (be)->cb->method((be)->data)
86 #define CB1(be, method, a1) \
88 return (be)->cb->method((be)->data, a1)
90 #define CBT0(to, method) \
91 CHECKCB((to)->be_iface, method);\
92 return (to)->be_iface->cb->method((to)->be_topo)
94 #define CBT1(to, method, a1) \
95 CHECKCB((to)->be_iface, method);\
96 return (to)->be_iface->cb->method((to)->be_topo, a1)
98 #define CBT2(to, method, a1, a2) \
99 CHECKCB((to)->be_iface, method);\
100 return (to)->be_iface->cb->method((to)->be_topo, a1, a2)
102 #define CBT3(to, method, a1, a2, a3) \
103 CHECKCB((to)->be_iface, method);\
104 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3)
106 #define CBT4(to, method, a1, a2, a3, a4) \
107 CHECKCB((to)->be_iface, method);\
108 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3, a4)
110 #define CBT5(to, method, a1, a2, a3, a4, a5) \
111 CHECKCB((to)->be_iface, method);\
112 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3, a4, a5)
114 #define CBT6(to, method, a1, a2, a3, a4, a5, a6) \
115 CHECKCB((to)->be_iface, method);\
116 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3, a4, a5, a6)
121 CB0(be, lastErrorMessage);
127 CB1(be, loadTopologyByName, name);
133 CBT0(topo, topoGetSRID);
139 CBT0(topo, topoGetPrecision);
145 CBT0(topo, topoHasZ);
151 CBT0(topo, freeTopology);
157 CBT3(topo, getNodeById, ids, numelems, fields);
168 CBT5(topo, getNodeWithinDistance2D, pt, dist, numelems, fields, limit);
174 CBT4(topo, getNodeWithinBox2D, box, numelems, fields, limit);
180 CBT4(topo, getEdgeWithinBox2D, box, numelems, fields, limit);
186 CBT4(topo, getFaceWithinBox2D, box, numelems, fields, limit);
192 CBT2(topo, insertNodes, node, numelems);
198 CBT2(topo, insertFaces, face, numelems);
204 CBT2(topo, deleteFacesById, ids, numelems);
210 CBT2(topo, deleteNodesById, ids, numelems);
216 CBT0(topo, getNextEdgeId);
222 CBT3(topo, getEdgeById, ids, numelems, fields);
228 CBT3(topo, getFaceById, ids, numelems, fields);
234 CBT3(topo, getEdgeByNode, ids, numelems, fields);
240 CBT4(topo, getEdgeByFace, ids, numelems, fields, box);
246 CBT4(topo, getNodeByFace, ids, numelems, fields, box);
257 CBT5(topo, getEdgeWithinDistance2D, pt, dist, numelems, fields, limit);
263 CBT2(topo, insertEdges, edge, numelems);
273 CBT6(topo, updateEdges, sel_edge, sel_fields,
274 upd_edge, upd_fields,
275 exc_edge, exc_fields);
285 CBT6(topo, updateNodes, sel_node, sel_fields,
286 upd_node, upd_fields,
287 exc_node, exc_fields);
295 CBT2(topo, updateFacesById, faces, numfaces);
303 CBT3(topo, updateEdgesById, edges, numedges, upd_fields);
311 CBT3(topo, updateNodesById, nodes, numnodes, upd_fields);
319 CBT2(topo, deleteEdges, sel_edge, sel_fields);
325 CBT3(topo, updateTopoGeomEdgeSplit, split_edge, new_edge1, new_edge2);
332 CBT3(topo, updateTopoGeomFaceSplit, split_face, new_face1, new_face2);
339 CBT3(topo, checkTopoGeomRemEdge, edge_id, face_left, face_right);
345 CBT1(topo, checkTopoGeomRemIsoEdge, edge_id);
352 CBT3(topo, checkTopoGeomRemNode, node_id, eid1, eid2);
358 CBT1(topo, checkTopoGeomRemIsoNode, node_id);
366 CBT3(topo, updateTopoGeomFaceHeal, face1, face2, newface);
374 CBT3(topo, updateTopoGeomEdgeHeal, edge1, edge2, newedge);
380 CBT3(topo, getRingEdges, edge, numedges, limit);
388 if (exists == UINT64_MAX)
401 if (exists == UINT64_MAX)
412 CBT3(topo, getClosestEdge, pt, numelems, fields);
440 }
while ( changed && iterations <= maxiterations );
442 LWDEBUGF(1,
"It took %d/%d iterations to properly snap",
443 iterations, maxiterations);
452 for ( i=0; i<num_faces; ++i ) {
453 if ( faces[i].mbr )
lwfree(faces[i].mbr);
462 for ( i=0; i<num_edges; ++i ) {
472 for ( i=0; i<num_nodes; ++i ) {
510 lwnotice(
"Could not release backend topology memory: %s",
526 LWPOINT* pt,
int skipISOChecks,
int checkFace )
532 lwerror(
"Cannot add empty point as isolated node");
537 if ( ! skipISOChecks )
541 lwerror(
"SQL/MM Spatial exception - coincident node");
546 lwerror(
"SQL/MM Spatial exception - edge crosses node.");
551 if ( checkFace && ( face == -1 || ! skipISOChecks ) )
554 if ( foundInFace == -1 ) {
558 if ( foundInFace == -1 ) foundInFace = 0;
564 else if ( ! skipISOChecks && foundInFace != face ) {
566 lwerror(
"SQL/MM Spatial exception - within face %d (not %d)",
569 lwerror(
"SQL/MM Spatial exception - not within face");
589 LWPOINT* pt,
int skipISOChecks )
609 uint64_t i, num_nodes, num_edges;
613 GEOSGeometry *edgegg;
628 LWDEBUGF(1,
"lwt_be_getNodeWithinBox2D returned %d nodes", num_nodes);
629 if (num_nodes == UINT64_MAX)
634 for ( i=0; i<num_nodes; ++i )
638 if ( node->
node_id == start_node )
continue;
639 if ( node->
node_id == end_node )
continue;
646 GEOSGeom_destroy(edgegg);
648 lwerror(
"SQL/MM Spatial exception - geometry crosses a node");
657 LWDEBUGF(1,
"lwt_be_getEdgeWithinBox2D returned %d edges", num_edges);
658 if (num_edges == UINT64_MAX)
660 GEOSGeom_destroy(edgegg);
664 for ( i=0; i<num_edges; ++i )
672 if ( edge_id == myself )
continue;
674 if ( ! edge->
geom ) {
676 lwerror(
"Edge %d has NULL geometry!", edge_id);
682 GEOSGeom_destroy(edgegg);
688 LWDEBUGF(2,
"Edge %d converted to GEOS", edge_id);
692 relate = GEOSRelateBoundaryNodeRule(eegg, edgegg, 2);
694 GEOSGeom_destroy(eegg);
695 GEOSGeom_destroy(edgegg);
701 LWDEBUGF(2,
"Edge %d relate pattern is %s", edge_id, relate);
703 match = GEOSRelatePatternMatch(relate,
"FF*F*****");
706 GEOSGeom_destroy(eegg);
710 GEOSGeom_destroy(edgegg);
717 match = GEOSRelatePatternMatch(relate,
"1FFF*FFF2");
720 GEOSGeom_destroy(edgegg);
721 GEOSGeom_destroy(eegg);
732 match = GEOSRelatePatternMatch(relate,
"1********");
735 GEOSGeom_destroy(edgegg);
736 GEOSGeom_destroy(eegg);
741 lwerror(
"Spatial exception - geometry intersects edge %"
747 match = GEOSRelatePatternMatch(relate,
"T********");
750 GEOSGeom_destroy(edgegg);
751 GEOSGeom_destroy(eegg);
756 lwerror(
"SQL/MM Spatial exception - geometry crosses edge %"
762 match = GEOSRelatePatternMatch(relate,
"*T*******");
765 GEOSGeom_destroy(edgegg);
766 GEOSGeom_destroy(eegg);
771 lwerror(
"Spatial exception - geometry boundary touches interior of edge %"
777 match = GEOSRelatePatternMatch(relate,
"***T*****");
780 GEOSGeom_destroy(edgegg);
781 GEOSGeom_destroy(eegg);
786 lwerror(
"Spatial exception - boundary of edge % touches interior of geometry"
792 LWDEBUGF(2,
"Edge %d analisys completed, it does no harm", edge_id);
795 GEOSGeom_destroy(eegg);
797 LWDEBUGF(1,
"No edge crossing detected among the %d candidate edges", num_edges);
801 GEOSGeom_destroy(edgegg);
818 int skipISOChecks = 0;
824 if (startNode == endNode)
826 lwerror(
"Closed edges would not be isolated, try lwt_AddEdgeNewFaces");
830 if ( ! skipISOChecks )
835 lwerror(
"SQL/MM Spatial exception - curve not simple");
849 node_ids[0] = startNode;
850 node_ids[1] = endNode;
853 if (num_nodes == UINT64_MAX)
858 else if ( num_nodes < 2 )
861 lwerror(
"SQL/MM Spatial exception - non-existent node");
864 for ( i=0; i<num_nodes; ++i )
870 lwerror(
"SQL/MM Spatial exception - not isolated node");
877 lwerror(
"SQL/MM Spatial exception - nodes in different faces");
881 if ( ! skipISOChecks )
891 lwerror(
"SQL/MM Spatial exception - "
892 "start node not geometry start point.");
904 lwerror(
"SQL/MM Spatial exception - "
905 "end node not geometry end point.");
914 if ( ! skipISOChecks )
934 if ( containing_face == -1 ) containing_face = 0;
947 }
else if ( ret == 0 ) {
948 lwerror(
"Insertion of split edge failed (no reason)");
958 updated_nodes[0].
node_id = startNode;
960 updated_nodes[1].
node_id = endNode;
981 LWDEBUG(1,
"calling lwt_be_getEdgeById");
983 LWDEBUGF(1,
"lwt_be_getEdgeById returned %p", *oldedge);
986 LWDEBUGF(1,
"lwt_be_getEdgeById returned NULL and set i=%d", i);
994 lwerror(
"SQL/MM Spatial exception - non-existent edge");
999 lwerror(
"Backend coding error: getEdgeById callback returned NULL "
1000 "but numelements output parameter has value %d "
1001 "(expected 0 or 1)", i);
1010 if ( ! skipISOChecks )
1012 LWDEBUG(1,
"calling lwt_be_ExistsCoincidentNode");
1015 LWDEBUG(1,
"lwt_be_ExistsCoincidentNode returned");
1017 lwerror(
"SQL/MM Spatial exception - coincident node");
1020 LWDEBUG(1,
"lwt_be_ExistsCoincidentNode returned");
1028 lwerror(
"could not split edge by point ?");
1032 if ( ! split_col ) {
1035 lwerror(
"lwgeom_as_lwcollection returned NULL");
1038 if (split_col->
ngeoms < 2) {
1041 lwerror(
"SQL/MM Spatial exception - point not on edge");
1049 LWDEBUGF(1,
"returning split col: %s", wkt);
1058 LWPOINT* pt,
int skipISOChecks )
1063 const LWGEOM *oldedge_geom;
1064 const LWGEOM *newedge_geom;
1069 split_col =
_lwt_EdgeSplit( topo, edge, pt, skipISOChecks, &oldedge );
1070 if ( ! split_col )
return -1;
1071 oldedge_geom = split_col->
geoms[0];
1072 newedge_geom = split_col->
geoms[1];
1075 ((
LWGEOM*)newedge_geom)->srid = split_col->
srid;
1092 lwerror(
"Backend coding error: "
1093 "insertNodes callback did not return node_id");
1099 if ( newedge1.
edge_id == -1 ) {
1114 if ( ! newedge1.
geom ) {
1117 lwerror(
"first geometry in lwgeom_split output is not a line");
1126 }
else if ( ret == 0 ) {
1129 lwerror(
"Insertion of split edge failed (no reason)");
1136 if ( ! updedge.
geom ) {
1139 lwerror(
"second geometry in lwgeom_split output is not a line");
1153 }
else if ( ret == 0 ) {
1156 lwerror(
"Edge being split (%d) disappeared during operations?", oldedge->
edge_id);
1158 }
else if ( ret > 1 ) {
1161 lwerror(
"More than a single edge found with id %d !", oldedge->
edge_id);
1215 LWPOINT* pt,
int skipISOChecks )
1220 const LWGEOM *oldedge_geom;
1221 const LWGEOM *newedge_geom;
1226 split_col =
_lwt_EdgeSplit( topo, edge, pt, skipISOChecks, &oldedge );
1227 if ( ! split_col )
return -1;
1228 oldedge_geom = split_col->
geoms[0];
1229 newedge_geom = split_col->
geoms[1];
1232 ((
LWGEOM*)newedge_geom)->srid = split_col->
srid;
1249 lwerror(
"Backend coding error: "
1250 "insertNodes callback did not return node_id");
1266 if ( newedges[0].edge_id == -1 ) {
1273 if ( newedges[1].edge_id == -1 ) {
1294 if ( ! newedges[0].geom ) {
1297 lwerror(
"first geometry in lwgeom_split output is not a line");
1315 if ( ! newedges[1].geom ) {
1318 lwerror(
"second geometry in lwgeom_split output is not a line");
1328 }
else if ( ret == 0 ) {
1331 lwerror(
"Insertion of split edge failed (no reason)");
1449 LWDEBUGF(1,
"first point is index %d", from);
1451 for ( i = from+inc; i != toofar; i += inc )
1453 LWDEBUGF(1,
"testing point %d", i);
1484 LWDEBUG(1,
"computing azimuth of first edge end");
1487 lwerror(
"Invalid edge (no two distinct vertices exist)");
1491 lwerror(
"error computing azimuth of first edgeend [%.15g %.15g,%.15g %.15g]",
1492 fp->
x, fp->
y, pt.
x, pt.
y);
1495 LWDEBUGF(1,
"azimuth of first edge end [%.15g %.15g,%.15g %.15g] is %g",
1496 fp->
x, fp->
y, pt.
x, pt.
y, fee->
myaz);
1499 LWDEBUG(1,
"computing azimuth of second edge end");
1502 lwerror(
"Invalid edge (no two distinct vertices exist)");
1506 lwerror(
"error computing azimuth of last edgeend [%.15g %.15g,%.15g %.15g]",
1507 lp->
x, lp->
y, pt.
x, pt.
y);
1510 LWDEBUGF(1,
"azimuth of last edge end [%.15g %.15g,%.15g %.15g] is %g",
1511 lp->
x, lp->
y, pt.
x, pt.
y, lee->
myaz);
1531 edgeend *other,
int myedge_id )
1534 uint64_t numedges = 1;
1536 double minaz, maxaz;
1544 if ( azdif < 0 ) azdif += 2 * M_PI;
1545 minaz = maxaz = azdif;
1547 LWDEBUGF(1,
"Other edge end has cwFace=%d and ccwFace=%d",
1554 " and adjacent to azimuth %g", node,
data->myaz);
1558 if (numedges == UINT64_MAX)
1564 LWDEBUGF(1,
"getEdgeByNode returned %d edges, minaz=%g, maxaz=%g",
1565 numedges, minaz, maxaz);
1568 for ( i = 0; i < numedges; ++i )
1578 if ( edge->
edge_id == myedge_id )
continue;
1591 " does not have two distinct points",
id);
1599 lwerror(
"Edge %d has no distinct vertices: [%.15g %.15g,%.15g %.15g]: ",
1605 ", edgeend is %g,%g-%g,%g",
1611 lwerror(
"error computing azimuth of edge %d first edgeend [%.15g %.15g,%.15g %.15g]",
1612 id, p1.
x, p1.
y, p2.
x, p2.
y);
1615 azdif = az -
data->myaz;
1617 ": %g (diff: %g)", edge->
edge_id, az, azdif);
1619 if ( azdif < 0 ) azdif += 2 * M_PI;
1620 if ( minaz == -1 ) {
1621 minaz = maxaz = azdif;
1628 " (face_right is new ccwFace, face_left is new cwFace)",
1632 if ( azdif < minaz ) {
1638 " (previous had minaz=%g, face_left is new cwFace)",
1643 else if ( azdif > maxaz ) {
1649 " (previous had maxaz=%g, face_right is new ccwFace)",
1661 lwerror(
"Edge %d has no distinct vertices: [%.15g %.15g,%.15g %.15g]: ",
1666 ", edgeend is %g,%g-%g,%g",
1672 lwerror(
"error computing azimuth of edge %d last edgeend [%.15g %.15g,%.15g %.15g]",
1673 id, p1.
x, p1.
y, p2.
x, p2.
y);
1676 azdif = az -
data->myaz;
1678 ": %g (diff: %g)", edge->
edge_id, az, azdif);
1679 if ( azdif < 0 ) azdif += 2 * M_PI;
1680 if ( minaz == -1 ) {
1681 minaz = maxaz = azdif;
1688 " (face_right is new cwFace, face_left is new ccwFace)",
1692 if ( azdif < minaz ) {
1698 " (previous had minaz=%g, face_right is new cwFace)",
1703 else if ( azdif > maxaz ) {
1707 ", outgoing, from start point, "
1709 " (previous had maxaz=%g, face_left is new ccwFace)",
1721 LWDEBUGF(1,
"edges adjacent to azimuth %g"
1724 data->myaz, node,
data->nextCW, minaz,
1725 data->nextCCW, maxaz);
1727 if ( myedge_id < 1 && numedges && data->cwFace !=
data->ccwFace )
1729 if (
data->cwFace != -1 &&
data->ccwFace != -1 ) {
1755 if ( pa->
npoints < 2 )
return 0;
1759 for (i=1; i<pa->
npoints-1; ++i)
1762 if (
p2d_same(&tp, &fp) )
continue;
1763 if (
p2d_same(&tp, &lp) )
continue;
1773 if (
p2d_same(&fp, &lp) )
return 0;
1775 ip->
x = fp.
x + ( (lp.
x - fp.
x) * 0.5 );
1776 ip->
y = fp.
y + ( (lp.
y - fp.
y) * 0.5 );
1785 uint64_t numedges, i, j;
1791 for (i=0; i<num_signed_edge_ids; ++i) {
1792 int absid = llabs(signed_edge_ids[i]);
1795 for (j=0; j<numedges; ++j) {
1796 if ( edge_ids[j] == absid ) {
1801 if ( ! found ) edge_ids[numedges++] = absid;
1807 if (i == UINT64_MAX)
1812 else if ( i != numedges )
1814 lwfree( signed_edge_ids );
1816 lwerror(
"Unexpected error: %d edges found when expecting %d", i, numedges);
1824 for ( i=0; i<num_signed_edge_ids; ++i )
1830 for ( j=0; j<numedges; ++j )
1832 if ( ring_edges[j].edge_id == llabs(eid) )
1834 edge = &(ring_edges[j]);
1841 lwerror(
"missing edge that was found in ring edges loop");
1899 uint64_t numfaceedges, i, j;
1900 int newface_outside;
1901 uint64_t num_signed_edge_ids;
1905 int forward_edges_count = 0;
1907 int backward_edges_count = 0;
1910 if (!signed_edge_ids)
1917 LWDEBUGF(1,
"getRingEdges returned %d edges", num_signed_edge_ids);
1920 for (i=0; i<num_signed_edge_ids; ++i) {
1921 if ( signed_edge_ids[i] == -sedge ) {
1924 lwfree( signed_edge_ids );
1930 sedge, face, mbr_only);
1939 num_signed_edge_ids);
1941 lwfree( signed_edge_ids );
1950 lwfree( signed_edge_ids );
1952 " is geometrically not-closed", sedge);
1958 sedge, isccw ?
"counter" :
"");
1967 lwfree( signed_edge_ids );
1971 LWDEBUG(1,
"The left face of this clockwise ring is the universe, "
1972 "won't create a new face there");
1977 if ( mbr_only && face != 0 )
1983 updface.
mbr = (
GBOX *)shellbox;
1987 lwfree( signed_edge_ids );
1994 lwfree( signed_edge_ids );
1996 lwerror(
"Unexpected error: %d faces found when expecting 1", ret);
2000 lwfree( signed_edge_ids );
2008 if ( face != 0 && ! isccw)
2011 uint64_t nfaces = 1;
2013 if (nfaces == UINT64_MAX)
2015 lwfree( signed_edge_ids );
2022 lwfree( signed_edge_ids );
2024 lwerror(
"Unexpected error: %d faces found when expecting 1", nfaces);
2027 newface.
mbr = oldface->
mbr;
2031 newface.
mbr = (
GBOX *)shellbox;
2038 lwfree( signed_edge_ids );
2045 lwfree( signed_edge_ids );
2047 lwerror(
"Unexpected error: %d faces inserted when expecting 1", ret);
2058 if ( face != 0 && ! isccw ) {
2060 LWDEBUG(1,
"New face is on the outside of the ring, updating rings in former shell");
2061 newface_outside = 1;
2064 LWDEBUG(1,
"New face is on the inside of the ring, updating forward edges in new ring");
2065 newface_outside = 0;
2078 if (numfaceedges == UINT64_MAX)
2084 LWDEBUGF(1,
"_lwt_AddFaceSplit: lwt_be_getEdgeByFace(%d) returned %d edges", face, numfaceedges);
2089 forward_edges_count = 0;
2091 backward_edges_count = 0;
2094 for ( i=0; i<numfaceedges; ++i )
2102 for ( j=0; j<num_signed_edge_ids; ++j )
2104 int seid = signed_edge_ids[j];
2108 LWDEBUGF(1,
"Edge %d is a known forward edge of the new ring", e->
edge_id);
2112 if ( found == 2 )
break;
2114 else if ( -seid == e->
edge_id )
2117 LWDEBUGF(1,
"Edge %d is a known backward edge of the new ring", e->
edge_id);
2121 if ( found == 2 )
break;
2124 if ( found )
continue;
2125 LWDEBUGF(1,
"Edge %d is not a known edge of the new ring", e->
edge_id);
2144 LWDEBUGF(1,
"Edge %d first point %s new ring",
2149 if ( newface_outside )
2153 LWDEBUGF(1,
"Edge %d not outside of the new ring, not updating it",
2162 LWDEBUGF(1,
"Edge %d not inside the new ring, not updating it",
2186 if ( forward_edges_count )
2189 forward_edges_count,
2193 lwfree( signed_edge_ids );
2197 if ( ret != forward_edges_count )
2199 lwfree( signed_edge_ids );
2200 lwerror(
"Unexpected error: %d edges updated when expecting %d",
2201 ret, forward_edges_count);
2207 if ( backward_edges_count )
2210 backward_edges_count,
2214 lwfree( signed_edge_ids );
2218 if ( ret != backward_edges_count )
2220 lwfree( signed_edge_ids );
2221 lwerror(
"Unexpected error: %d edges updated when expecting %d",
2222 ret, backward_edges_count);
2235 uint64_t numisonodes = 1;
2238 &numisonodes, fields, newface.
mbr);
2239 if (numisonodes == UINT64_MAX)
2245 if ( numisonodes ) {
2247 int nodes_to_update = 0;
2248 for (i=0; i<numisonodes; ++i)
2253 LWDEBUGF(1,
"Node %d is %scontained in new ring, newface is %s",
2255 newface_outside ?
"outside" :
"inside" );
2256 if ( newface_outside )
2260 LWDEBUGF(1,
"Node %d contained in an hole of the new face",
2269 LWDEBUGF(1,
"Node %d not contained in the face shell",
2280 if ( nodes_to_update )
2286 lwfree( signed_edge_ids );
2310 LWLINE *geom,
int skipChecks,
int modFace )
2319 const LWPOINT *start_node_geom = NULL;
2320 const LWPOINT *end_node_geom = NULL;
2334 lwerror(
"SQL/MM Spatial exception - curve not simple");
2341 newedge.
geom = geom;
2350 lwerror(
"Invalid edge (no two distinct vertices exist)");
2363 lwerror(
"Invalid edge (no two distinct vertices exist)");
2368 lwerror(
"error computing azimuth of first edgeend [%.15g %.15g,%.15g %.15g]",
2369 p1.
x, p1.
y, pn.
x, pn.
y);
2372 LWDEBUGF(1,
"edge's start node is %g,%g", p1.
x, p1.
y);
2380 lwerror(
"Invalid clean edge (no two distinct vertices exist) - should not happen");
2385 lwerror(
"error computing azimuth of last edgeend [%.15g %.15g,%.15g %.15g]",
2386 p2.
x, p2.
y, pn.
x, pn.
y);
2389 LWDEBUGF(1,
"edge's end node is %g,%g", p2.
x, p2.
y);
2396 if ( start_node != end_node ) {
2398 node_ids[0] = start_node;
2399 node_ids[1] = end_node;
2402 node_ids[0] = start_node;
2406 if (num_nodes == UINT64_MAX)
2411 for ( i=0; i<num_nodes; ++i )
2423 lwerror(
"SQL/MM Spatial exception - geometry crosses an edge"
2429 LWDEBUGF(1,
"Node %d, with geom %p (looking for %d and %d)",
2431 if ( node->
node_id == start_node ) {
2432 start_node_geom = node->
geom;
2434 if ( node->
node_id == end_node ) {
2435 end_node_geom = node->
geom;
2441 if ( ! start_node_geom )
2444 lwerror(
"SQL/MM Spatial exception - non-existent node");
2449 pa = start_node_geom->
point;
2454 lwerror(
"SQL/MM Spatial exception"
2455 " - start node not geometry start point."
2462 if ( ! end_node_geom )
2465 lwerror(
"SQL/MM Spatial exception - non-existent node");
2470 pa = end_node_geom->
point;
2475 lwerror(
"SQL/MM Spatial exception"
2476 " - end node not geometry end point."
2495 if ( newedge.
edge_id == -1 ) {
2501 int isclosed = start_node == end_node;
2504 isclosed ? &epan : NULL, -1 );
2509 LWDEBUGF(1,
"New edge %d is connected on start node, "
2510 "next_right is %d, prev_left is %d",
2512 if ( modFace != -1 )
2525 LWDEBUGF(1,
"New edge %d is isolated on start node, "
2526 "next_right is %d, prev_left is %d",
2531 isclosed ? &span : NULL, -1 );
2536 LWDEBUGF(1,
"New edge %d is connected on end node, "
2537 "next_left is %d, prev_right is %d",
2539 if ( modFace != -1 )
2545 lwerror(
"Side-location conflict: "
2546 "new edge starts in face"
2557 lwerror(
"Side-location conflict: "
2558 "new edge starts in face"
2570 LWDEBUGF(1,
"New edge %d is isolated on end node, "
2571 "next_left is %d, prev_right is %d",
2585 " faces mismatch: invalid topology ?",
2591 lwerror(
"Could not derive edge face from linked primitives:"
2592 " invalid topology ?");
2605 }
else if ( ret == 0 ) {
2606 lwerror(
"Insertion of split edge failed (no reason)");
2614 if ( llabs(prev_left) != newedge.
edge_id )
2616 if ( prev_left > 0 )
2633 &updedge, updfields,
2643 if ( llabs(prev_right) != newedge.
edge_id )
2645 if ( prev_right > 0 )
2657 seledge.
edge_id = -prev_right;
2662 &updedge, updfields,
2704 if ( modFace > -1 ) {
2708 LWDEBUG(1,
"New edge is dangling, so it cannot split any face");
2720 if ( newface1 == 0 ) {
2721 LWDEBUG(1,
"New edge does not split any face");
2730 if ( newface == 0 ) {
2731 LWDEBUG(1,
"New edge does not split any face");
2741 if ( newface < 0 )
return newedge.
edge_id;
2780 LWLINE *geom,
int skipChecks )
2782 return _lwt_AddEdge( topo, start_node, end_node, geom, skipChecks, 1 );
2788 LWLINE *geom,
int skipChecks )
2790 return _lwt_AddEdge( topo, start_node, end_node, geom, skipChecks, 0 );
2799 int i, validedges = 0;
2801 for ( i=0; i<numfaceedges; ++i )
2815 if ( numfaceedges )
lwfree(geoms);
2816 LWDEBUG(1,
"_lwt_FaceByEdges returning empty polygon");
2833 LWDEBUGF(1,
"_lwt_FaceByEdges returning area: %s", wkt);
2843 uint64_t numfaceedges;
2853 lwerror(
"SQL/MM Spatial exception - universal face has no geometry");
2865 if (numfaceedges == UINT64_MAX)
2871 if ( numfaceedges == 0 )
2875 if (i == UINT64_MAX)
2881 lwerror(
"SQL/MM Spatial exception - non-existent face.");
2886 lwerror(
"Corrupted topology: multiple face records have face_id=%"
2892 lwnotice(
"Corrupted topology: face %"
2909 lwnotice(
"Corrupted topology: face %"
2944 LWDEBUGF(1,
"Ring's 'from' point (%d) is %g,%g", from, p1.
x, p1.
y);
2948 for ( i=0; i<numedges; ++i )
2962 ") on both sides, skipping",
2970 " has only %"PRIu32
" points",
2987 LWDEBUGF(1,
"Rings's 'from' point is still %g,%g", p1.
x, p1.
y);
2990 LWDEBUG(1,
"p2d_same(p1,p2) returned true");
2992 " matches ring vertex %d", isoe->
edge_id, from);
2994 for ( j=1; j<epa->
npoints; ++j )
3000 if (
p2d_same(&p1, &p2) )
continue;
3003 LWDEBUGF(1,
"Ring's point %d is %g,%g",
3004 from+1, pt.
x, pt.
y);
3008 #if POSTGIS_DEBUG_LEVEL > 0
3011 " matches ring vertex %d", isoe->
edge_id, from+1);
3014 " does not match ring vertex %d", isoe->
edge_id, from+1);
3029 " matches ring vertex %d", isoe->
edge_id, from);
3031 for ( j=2; j<=epa->
npoints; j++ )
3037 if (
p2d_same(&p1, &p2) )
continue;
3040 LWDEBUGF(1,
"Ring's point %d is %g,%g",
3041 from+1, pt.
x, pt.
y);
3046 #if POSTGIS_DEBUG_LEVEL > 0
3049 " matches ring vertex %d", isoe->
edge_id, from+1);
3052 " does not match ring vertex %d", isoe->
edge_id, from+1);
3057 if ( match )
return i;
3073 ary[from++] = ary[to];
3096 uint64_t numfaceedges;
3111 if (numfaceedges == UINT64_MAX)
3116 if ( ! numfaceedges )
return 0;
3125 lwerror(
"Corrupted topology: unable to build geometry of face %"
3126 LWTFMT_ELEMID " from its %"PRIu64
" edges", face_id, numfaceedges);
3162 nseid = prevseid = 0;
3166 for ( i=0; i<facepoly->
nrings; ++i )
3175 while ( j < (int32_t) ring->
npoints-1 )
3177 LWDEBUGF(1,
"Looking for edge covering ring %d from vertex %d",
3187 lwerror(
"No edge (among %d) found to be defining geometry of face %"
3192 nextedge = &(edges[edgeno]);
3193 nextline = nextedge->
geom;
3196 " covers ring %d from vertex %d to %d",
3212 seid[nseid++] = nextedge->
face_left == face_id ?
3223 if ( (nseid - prevseid) > 1 )
3227 LWDEBUGF(1,
"Looking for smallest id among the %d edges "
3228 "composing ring %d", (nseid-prevseid), i);
3229 for ( j=prevseid; j<nseid; ++j )
3233 if ( ! minid ||
id < minid )
3240 " at position %d", minid, minidx);
3241 if ( minidx != prevseid )
3269 lwerror(
"SQL/MM Spatial exception - curve not simple");
3278 "lwt_be_getEdgeById returned NULL and set i=%d", i);
3279 if (i == UINT64_MAX)
3286 lwerror(
"SQL/MM Spatial exception - non-existent edge %"
3292 lwerror(
"Backend coding error: getEdgeById callback returned NULL "
3293 "but numelements output parameter has value %d "
3294 "(expected 0 or 1)", i);
3300 "old edge has %d points, new edge has %d points",
3311 lwerror(
"SQL/MM Spatial exception - "
3312 "start node not geometry start point.");
3323 " has less than 2 vertices", oldedge->
edge_id);
3330 lwerror(
"Invalid edge: less than 2 vertices");
3337 lwerror(
"SQL/MM Spatial exception - "
3338 "end node not geometry end point.");
3354 lwerror(
"Invalid edge (no two distinct vertices exist)");
3363 lwerror(
"Edge twist at node POINT(%g %g)", p1.
x, p1.
y);
3369 oldedge->
end_node, geom, edge_id ) )
3376 LWDEBUG(1,
"lwt_ChangeEdgeGeom: "
3377 "edge crossing check passed ");
3395 LWDEBUGF(1,
"lwt_be_getNodeWithinBox2D returned %d nodes", numnodes);
3396 if (numnodes == UINT64_MAX)
3403 if ( numnodes > ( 1 + isclosed ? 0 : 1 ) )
3406 for (i=0; i<numnodes; ++i)
3419 lwerror(
"Edge motion collision at %s", wkt);
3427 LWDEBUG(1,
"nodes containment check passed");
3440 isclosed ? &epan_pre : NULL, edge_id );
3442 isclosed ? &span_pre : NULL, edge_id );
3452 newedge.
geom = geom;
3463 lwerror(
"Unexpected error: %d edges updated when expecting 1", i);
3476 isclosed ? &epan_post : NULL, edge_id );
3478 isclosed ? &span_post : NULL, edge_id );
3493 lwerror(
"Edge changed disposition around start node %"
3504 lwerror(
"Edge changed disposition around end node %"
3521 uint64_t facestoupdate = 0;
3530 lwerror(
"lwt_ChangeEdgeGeom could not construct face %"
3539 LWDEBUGF(1,
"new geometry of face left (%d): %s", (
int)oldedge->
face_left, wkt);
3544 if ( ! nface1->
bbox )
3546 lwerror(
"Corrupted topology: face %d, left of edge %d, has no bbox",
3552 faces[facestoupdate++].
mbr = nface1->
bbox;
3561 lwerror(
"lwt_ChangeEdgeGeom could not construct face %"
3575 if ( ! nface2->
bbox )
3577 lwerror(
"Corrupted topology: face %d, right of edge %d, has no bbox",
3582 faces[facestoupdate++].
mbr = nface2->
bbox;
3584 LWDEBUGF(1,
"%d faces to update", facestoupdate);
3585 if ( facestoupdate )
3588 if (updatedFaces != facestoupdate)
3595 if (updatedFaces == UINT64_MAX)
3598 lwerror(
"Unexpected error: %d faces found when expecting 1", i);
3607 LWDEBUG(1,
"BBOX of changed edge did not change");
3610 LWDEBUG(1,
"all done, cleaning up edges");
3624 if (n == UINT64_MAX)
3630 lwerror(
"SQL/MM Spatial exception - non-existent node");
3636 lwerror(
"SQL/MM Spatial exception - not isolated node");
3651 if ( ! node )
return -1;
3656 lwerror(
"SQL/MM Spatial exception - coincident node");
3663 lwerror(
"SQL/MM Spatial exception - edge crosses node.");
3670 if ( newPointFace == -1 ) {
3677 lwerror(
"Cannot move isolated node across faces");
3702 if ( ! node )
return -1;
3714 lwerror(
"Unexpected error: %d nodes deleted when expecting 1", n);
3751 lwerror(
"SQL/MM Spatial exception - non-existent edge");
3757 lwerror(
"Corrupted topology: more than a single edge have id %"
3762 if ( edge[0].face_left != edge[0].face_right )
3765 lwerror(
"SQL/MM Spatial exception - not isolated edge");
3776 if ((n == UINT64_MAX) || (edge == NULL))
3781 for (i = 0; i < n; ++i)
3783 if (edge[i].edge_id !=
id)
3786 lwerror(
"SQL/MM Spatial exception - not isolated edge");
3794 if (n == UINT64_MAX)
3801 lwerror(
"Unexpected error: %d edges deleted when expecting 1", n);
3808 if ( nid[1] != nid[0] ) {
3815 if (n == UINT64_MAX)
3853 if ( ret == -1 )
return -1;
3861 if ( ret == -1 )
return -1;
3886 if ( ret == -1 )
return -1;
3900 uint64_t i, nedges, nfaces, fields;
3906 int nedge_right = 0;
3913 int fnode_edges = 0;
3915 int lnode_edges = 0;
3924 LWDEBUGF(1,
"lwt_be_getEdgeById returned NULL and set i=%d", i);
3925 if (i == UINT64_MAX)
3938 "Backend coding error: getEdgeById callback returned NULL "
3939 "but numelements output parameter has value %d "
3940 "(expected 0 or 1)",
3953 LWDEBUG(1,
"Updating next_{right,left}_face of ring edges...");
3961 node_ids[nedges++] = edge->
end_node;
3967 if (nedges == UINT64_MAX)
3972 nedge_left = nedge_right = 0;
3973 for ( i=0; i<nedges; ++i )
3976 if ( e->
edge_id == edge_id )
continue;
4014 LWDEBUGF(1,
"updating %d 'next_left' edges", nedge_left);
4027 LWDEBUGF(1,
"updating %d 'next_right' edges", nedge_right);
4038 LWDEBUGF(1,
"releasing %d updateable edges in %p", nedges, upd_edge);
4056 LWDEBUG(1,
"floodface is universe");
4070 if (nfaces == UINT64_MAX)
4077 for ( i=0; i<nfaces; ++i )
4079 if ( faces[i].face_id == edge->
face_left )
4081 if ( ! box1 ) box1 = faces[i].
mbr;
4087 lwerror(
"corrupted topology: more than 1 face have face_id=%"
4092 else if ( faces[i].face_id == edge->
face_right )
4094 if ( ! box2 ) box2 = faces[i].
mbr;
4100 lwerror(
"corrupted topology: more than 1 face have face_id=%"
4110 lwerror(
"Backend coding error: getFaceById returned face "
4119 lwerror(
"corrupted topology: no face have face_id=%"
4128 lwerror(
"corrupted topology: no face have face_id=%"
4149 lwerror(
"Unexpected error: %d faces updated when expecting 1", i);
4168 lwerror(
"Unexpected error: %d faces inserted when expecting 1",
result);
4233 if ( ! fnode_edges )
4275 return modFace ? floodface : newface.
face_id;
4298 uint64_t num_node_edges;
4305 int e2sign, e2freenode;
4309 size_t bufleft = 256;
4317 " with itself, try with another", eid1);
4324 if ((nedges == UINT64_MAX) || (edges == NULL))
4329 for ( i=0; i<nedges; ++i )
4331 if ( edges[i].edge_id == eid1 ) {
4334 lwerror(
"Corrupted topology: multiple edges have id %"
4340 else if ( edges[i].edge_id == eid2 ) {
4343 lwerror(
"Corrupted topology: multiple edges have id %"
4354 "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4362 "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4396 if ( commonnode != -1 )
4401 if (num_node_edges == UINT64_MAX)
4407 for (i=0; i<num_node_edges; ++i)
4410 if ( node_edges[i].edge_id == eid1 )
continue;
4411 if ( node_edges[i].edge_id == eid2 )
continue;
4414 if ( bufleft > 0 ) {
4416 ( ptr==buf ?
"" :
"," ), node_edges[i].edge_id);
4417 if (
r >= (
int) bufleft )
4435 if ( commonnode == -1 )
4448 if ( commonnode != -1 )
4453 if (num_node_edges == UINT64_MAX)
4459 for (i=0; i<num_node_edges; ++i)
4462 if ( node_edges[i].edge_id == eid1 )
continue;
4463 if ( node_edges[i].edge_id == eid2 )
continue;
4466 if ( bufleft > 0 ) {
4468 ( ptr==buf ?
"" :
"," ), node_edges[i].edge_id);
4469 if (
r >= (
int) bufleft )
4484 if ( num_node_edges )
lwfree(node_edges);
4488 if ( commonnode == -1 )
4493 lwerror(
"SQL/MM Spatial exception - other edges connected (%s)",
4498 lwerror(
"SQL/MM Spatial exception - non-connected edges");
4575 lwerror(
"Coding error: caseno=%d should never happen", caseno);
4601 lwerror(
"Unexpected error: %d edges updated when expecting 1", i);
4623 lwerror(
"Insertion of split edge failed (no reason)");
4727 eid1, eid2, newedge.
edge_id) )
4733 return modEdge ? commonnode : newedge.
edge_id;
4763 if (num == UINT64_MAX)
4773 lwerror(
"Two or more nodes found");
4798 if (num == UINT64_MAX)
4803 for (i=0; i<num;++i)
4814 " has null geometry", e->
edge_id);
4822 if ( dist > tol )
continue;
4828 lwerror(
"Two or more edges found");
4867 LWDEBUG(1,
"No face properly contains query point,"
4868 " looking for edges");
4875 if (num == UINT64_MAX)
4880 for (i=0; i<num; ++i)
4891 " has null geometry", e->
edge_id);
4899 " is dangling, won't consider it", e->
edge_id);
4907 " is %g (tol=%g)", e->
edge_id, dist, tol);
4910 if ( dist > tol )
continue;
4919 lwerror(
"Two or more faces found");
4923 if (
id &&
id != eface )
4926 lwerror(
"Two or more faces found"
4943 static inline double
4946 double ret = 3.6 * pow(10, - ( 15 - log10(d?d:1.0) ) );
4972 if ( ! gbox )
return 0;
4983 #define _LWT_MINTOLERANCE( topo, geom ) ( \
4984 topo->precision ? topo->precision : _lwt_minTolerance(geom) )
5013 findFace,
int *moved)
5016 double mindist = FLT_MAX;
5037 if (num == UINT64_MAX)
5044 LWDEBUGF(1,
"New point is within %.15g units of %d nodes", tol, num);
5049 for (i=0; i<num; ++i)
5051 sorted[i].
ptr = nodes+i;
5054 ((
LWT_ISO_NODE*)(sorted[i].ptr))->node_id, sorted[i].score);
5058 for (i=0; i<num; ++i)
5067 for ( i=0; i<num; ++i )
5074 if ( dist && dist >= tol )
continue;
5075 if ( !
id || dist < mindist )
5085 if ( moved ) *moved = mindist == 0 ? 0 : 1;
5099 if (num == UINT64_MAX)
5106 LWDEBUGF(1,
"New point is within %.15g units of %d edges", tol, num);
5113 for (i=0; i<num; ++i)
5115 sorted[i].
ptr = edges+i;
5118 ((
LWT_ISO_EDGE*)(sorted[i].ptr))->edge_id, sorted[i].score);
5122 for (j=0, i=0; i<num; ++i)
5124 if ( sorted[i].score == sorted[0].score )
5139 for (i=0; i<num; ++i)
5152 if ( moved ) *moved =
lwgeom_same(prj,pt) ? 0 : 1;
5184 " does not contain projected point to it",
5191 LWDEBUG(1,
"But there's another to check");
5206 LWDEBUGF(1,
"Edge snapped with tolerance %g", snaptol);
5209 #if POSTGIS_DEBUG_LEVEL > 0
5214 LWDEBUGF(1,
"Edge %s snapped became %s", wkt1, wkt2);
5227 LWDEBUGF(1,
"Edge first point is %g %g, "
5228 "snapline first point is %g %g",
5229 p1.
x, p1.
y, p2.
x, p2.
y);
5230 if ( p1.
x != p2.
x || p1.
y != p2.
y )
5232 LWDEBUG(1,
"Snapping moved first point, re-adding it");
5241 #if POSTGIS_DEBUG_LEVEL > 0
5245 LWDEBUGF(1,
"Tweaked snapline became %s", wkt1);
5250 #if POSTGIS_DEBUG_LEVEL > 0
5252 LWDEBUG(1,
"Snapping did not move first point");
5262 lwerror(
"lwt_ChangeEdgeGeom failed");
5267 #if POSTGIS_DEBUG_LEVEL > 0
5273 LWDEBUGF(1,
"Edge %s contains projected point %s", wkt1, wkt2);
5286 lwerror(
"lwt_ModEdgeSplit failed");
5314 if ( moved ) *moved = 0;
5318 lwerror(
"lwt_AddIsoNode failed");
5346 GEOSGeometry *edgeg;
5350 if (num == UINT64_MAX)
5366 for (i=0; i<num; ++i)
5375 GEOSGeom_destroy(edgeg);
5380 equals = GEOSEquals(gg, edgeg);
5381 GEOSGeom_destroy(gg);
5384 GEOSGeom_destroy(edgeg);
5426 GEOSGeom_destroy(edgeg);
5431 GEOSGeom_destroy(edgeg);
5455 int handleFaceSplit,
int *forward )
5458 LWPOINT *start_point, *end_point;
5468 LWDEBUGF(1,
"_lwtAddLineEdge with tolerance %g", tol);
5471 if ( ! start_point )
5473 lwnotice(
"Empty component of noded line");
5478 handleFaceSplit, &mm );
5480 if ( nid[0] == -1 )
return -1;
5487 lwerror(
"could not get last point of line "
5488 "after successfully getting first point !?");
5493 handleFaceSplit, &mm );
5496 if ( nid[1] == -1 )
return -1;
5505 nn = nid[0] == nid[1] ? 1 : 2;
5508 if (nn == UINT64_MAX)
5513 start_point = NULL; end_point = NULL;
5514 for (i=0; i<nn; ++i)
5516 if ( node[i].node_id == nid[0] ) start_point = node[i].
geom;
5517 if ( node[i].node_id == nid[1] ) end_point = node[i].
geom;
5519 if ( ! start_point || ! end_point )
5547 if ( colex->
ngeoms == 0 )
5551 LWDEBUG(1,
"Made-valid snapped edge collapsed");
5563 lwerror(
"lwcollection_extract(LINETYPE) returned a non-line?");
5572 LWDEBUGF(1,
"Made-valid snapped edge collapsed to %s",
5601 LWDEBUGG(1, tmp2,
"Repeated-point removed");
5610 LWDEBUG(1,
"Repeated-point removed edge collapsed");
5631 id =
_lwt_AddEdge( topo, nid[0], nid[1], edge, 0, handleFaceSplit ? 1 : -1 );
5654 if ( ! col->
ngeoms )
return bg;
5656 for (i=0; i<col->
ngeoms; ++i)
5670 int handleFaceSplit)
5680 uint64_t num, numedges = 0, numnodes = 0;
5684 int input_was_closed = 0;
5695 input_was_closed = 1;
5697 LWDEBUGF(1,
"Input line is closed, original point is %g,%g", originalStartPoint.
x, originalStartPoint.
y);
5704 LWDEBUGF(1,
"Working tolerance:%.15g", tol);
5712 LWDEBUGG(1, tmp,
"Repeated-point removed");
5713 }}
else tmp=(
LWGEOM*)line;
5718 if ( ! noded )
return NULL;
5725 LWDEBUGF(1,
"BOX expanded by %g is %.15g %.15g, %.15g %.15g",
5729 int nearbyindex = 0;
5730 int nearbycount = 0;
5734 if (numedges == UINT64_MAX)
5740 LWDEBUGF(1,
"Line has %d points, its bbox intersects %d edges bboxes",
5745 nearbycount += numedges;
5747 for (i=0; i<numedges; ++i)
5755 if ( dist && dist >= tol )
continue;
5756 nearby[nearbyindex++] = g;
5758 LWDEBUGF(1,
"Found %d edges closer than tolerance (%g)", nearbyindex, tol);
5760 int nearbyedgecount = nearbyindex;
5767 if (numnodes == UINT64_MAX)
5773 LWDEBUGF(1,
"Line bbox intersects %d nodes bboxes", numnodes);
5777 nearbycount = nearbyedgecount + numnodes;
5784 for (i=0; i<numnodes; ++i)
5791 if ( dist && dist >= tol )
5793 LWDEBUGF(1,
"Node %d is %g units away, we tolerate only %g", n->
node_id, dist, tol);
5796 nearby[nearbyindex++] = g;
5799 LWDEBUGF(1,
"Found %d isolated nodes closer than tolerance (%g)", nn, tol);
5801 int nearbynodecount = nearbyindex - nearbyedgecount;
5802 nearbycount = nearbyindex;
5804 LWDEBUGF(1,
"Number of nearby elements is %d", nearbycount);
5813 NULL, nearbycount, nearby);
5816 LWDEBUGG(1, elems,
"Collected nearby elements");
5821 LWDEBUGG(1, noded,
"Elements-snapped");
5822 if ( input_was_closed )
5829 LWDEBUGF(1,
"Closed input line start point after snap %g,%g", originalStartPoint.
x, originalStartPoint.
y);
5844 LWDEBUGG(1, noded,
"Unary-unioned");
5848 if ( nearbyedgecount )
5854 LWDEBUGF(1,
"Line intersects %d edges", nearbyedgecount);
5857 NULL, nearbyedgecount, nearby);
5859 LWDEBUGG(1, iedges,
"Collected edges");
5861 LWDEBUGF(1,
"Diffing noded, with srid=%d "
5862 "and interesecting edges, with srid=%d",
5867 LWDEBUGF(1,
"Intersecting noded, with srid=%d "
5868 "and interesecting edges, with srid=%d",
5888 LWDEBUG(1,
"Linemerging intersection");
5898 LWDEBUG(1,
"Unioning difference and (linemerged) intersection");
5900 LWDEBUGG(1, noded,
"Diff-Xset Unioned");
5907 if ( input_was_closed )
5919 LWDEBUGG(1, xset,
"Linemerged intersected input is not a line anymore");
5932 if ( nearbyedgecount )
5934 nearbycount += nearbyedgecount * 2;
5936 for (
int i=0; i<nearbyedgecount; i++)
5948 if ( nearbynodecount )
5951 NULL, nearbynodecount,
5952 nearby + nearbyedgecount);
5964 LWDEBUG(1,
"Freeing up nearby elements");
5967 if ( nearby )
lwfree(nearby);
5971 LWDEBUGG(1, noded,
"Finally-noded");
5977 LWDEBUG(1,
"Noded line was a collection");
5983 LWDEBUG(1,
"Noded line was a single geom");
5984 geomsbuf[0] = noded;
5989 LWDEBUGF(1,
"Line was split into %d edges", ngeoms);
5997 for ( i=0; i<ngeoms; ++i )
6003 #if POSTGIS_DEBUG_LEVEL > 0
6007 LWDEBUGF(1,
"Component %d of split line is: %s", i, wkt1);
6022 LWDEBUGF(1,
"Component %d of split line collapsed", i);
6027 i, forward ?
"forward" :
"backward",
id);
6028 ids[num++] = forward ? id : -id;
6031 LWDEBUGG(1, noded,
"Noded before free");
6059 uint64_t nfacesinbox;
6063 const GEOSPreparedGeometry *ppoly;
6064 GEOSGeometry *polyg;
6075 LWDEBUGF(1,
"Working tolerance:%.15g", tol);
6078 for ( i=0; i<poly->
nrings; ++i )
6091 lwerror(
"Error adding ring %d of polygon", i);
6106 if (nfacesinbox == UINT64_MAX)
6123 ppoly = GEOSPrepare(polyg);
6125 for ( j=0; j<nfacesinbox; ++j )
6129 GEOSGeometry *fgg, *sp;
6137 GEOSPreparedGeom_destroy(ppoly);
6138 GEOSGeom_destroy(polyg);
6149 GEOSPreparedGeom_destroy(ppoly);
6150 GEOSGeom_destroy(polyg);
6155 sp = GEOSPointOnSurface(fgg);
6156 GEOSGeom_destroy(fgg);
6159 GEOSPreparedGeom_destroy(ppoly);
6160 GEOSGeom_destroy(polyg);
6165 covers = GEOSPreparedCovers( ppoly, sp );
6166 GEOSGeom_destroy(sp);
6169 GEOSPreparedGeom_destroy(ppoly);
6170 GEOSGeom_destroy(polyg);
6183 GEOSPreparedGeom_destroy(ppoly);
6184 GEOSGeom_destroy(polyg);
6224 void *match = bsearch( &key, tab->
edges, tab->
size,
6252 #define LWT_EDGERING_INIT(a) { \
6254 (a)->capacity = 1; \
6255 (a)->elems = lwalloc(sizeof(LWT_EDGERING_ELEM *) * (a)->capacity); \
6260 #define LWT_EDGERING_PUSH(a, r) { \
6261 if ( (a)->size + 1 > (a)->capacity ) { \
6262 (a)->capacity *= 2; \
6263 (a)->elems = lwrealloc((a)->elems, sizeof(LWT_EDGERING_ELEM *) * (a)->capacity); \
6266 (a)->elems[(a)->size++] = (r); \
6269 #define LWT_EDGERING_CLEAN(a) { \
6270 int i; for (i=0; i<(a)->size; ++i) { \
6271 if ( (a)->elems[i] ) { \
6273 lwfree((a)->elems[i]); \
6276 if ( (a)->elems ) { lwfree((a)->elems); (a)->elems = NULL; } \
6278 (a)->capacity = 0; \
6279 if ( (a)->env ) { lwfree((a)->env); (a)->env = NULL; } \
6280 if ( (a)->genv ) { GEOSGeom_destroy((a)->genv); (a)->genv = NULL; } \
6291 #define LWT_EDGERING_ARRAY_INIT(a) { \
6293 (a)->capacity = 1; \
6294 (a)->rings = lwalloc(sizeof(LWT_EDGERING *) * (a)->capacity); \
6300 #define LWT_EDGERING_ARRAY_CLEAN(a) { \
6301 int j; for (j=0; j<(a)->size; ++j) { \
6302 LWT_EDGERING_CLEAN((a)->rings[j]); \
6304 if ( (a)->capacity ) lwfree((a)->rings); \
6305 if ( (a)->tree ) { \
6306 GEOSSTRtree_destroy( (a)->tree ); \
6311 #define LWT_EDGERING_ARRAY_PUSH(a, r) { \
6312 if ( (a)->size + 1 > (a)->capacity ) { \
6313 (a)->capacity *= 2; \
6314 (a)->rings = lwrealloc((a)->rings, sizeof(LWT_EDGERING *) * (a)->capacity); \
6316 (a)->rings[(a)->size++] = (r); \
6332 if ( ! el )
return 0;
6344 if ( it->
curidx < 0 ) tonext = 1;
6349 LWDEBUG(3,
"iterator moving to next element");
6380 #define LWT_HOLES_FACE_PLACEHOLDER INT32_MIN
6386 from < etab->size &&
6390 return from < etab->
size ? from : -1;
6398 uint64_t nelems = 1;
6402 if (nelems == UINT64_MAX)
6424 int forward_edges_count = 0;
6426 int backward_edges_count = 0;
6432 forward_edges_count = 0;
6434 backward_edges_count = 0;
6436 for ( i=0; i<ring->
size; ++i )
6443 LWDEBUGF(3,
"Forward edge %d is %d", forward_edges_count,
id);
6444 forward_edges[forward_edges_count].
edge_id = id;
6445 forward_edges[forward_edges_count++].
face_left = face;
6450 LWDEBUGF(3,
"Backward edge %d is %d", forward_edges_count,
id);
6451 backward_edges[backward_edges_count].
edge_id = id;
6452 backward_edges[backward_edges_count++].
face_right = face;
6458 if ( forward_edges_count )
6461 forward_edges_count,
6466 lwfree( backward_edges );
6470 if ( ret != forward_edges_count )
6473 lwfree( backward_edges );
6474 lwerror(
"Unexpected error: %d edges updated when expecting %d (forward)",
6475 ret, forward_edges_count);
6481 if ( backward_edges_count )
6484 backward_edges_count,
6489 lwfree( backward_edges );
6493 if ( ret != backward_edges_count )
6496 lwfree( backward_edges );
6497 lwerror(
"Unexpected error: %d edges updated when expecting %d (backward)",
6498 ret, backward_edges_count);
6504 lwfree( backward_edges );
6527 LWDEBUGF(2,
"Building rings for edge %d (side %d)",
cur->edge_id, side);
6534 elem->
left = ( curside == 1 );
6541 next = elem->
left ?
cur->next_left :
cur->next_right;
6543 LWDEBUGF(3,
" next edge is %d", next);
6545 if ( next > 0 ) curside = 1;
6546 else { curside = -1; next = -next; }
6550 lwerror(
"Could not find edge with id %d", next);
6553 }
while (
cur != edge || curside != side);
6567 double x0,
x, y1, y2;
6572 LWDEBUG(2,
"_lwt_EdgeRingSignedArea");
6597 LWDEBUGF(2,
"_lwt_EdgeRingIsCCW, ring has %d elems", ring->
size);
6600 LWDEBUGF(2,
"_lwt_EdgeRingIsCCW, signed area is %g", sa);
6602 if ( sa >= 0 )
return 0;
6625 ((v1.
y <= p->
y) && (v2.
y > p->
y))
6627 || ((v1.
y > p->
y) && (v2.
y <= p->
y))
6631 vt = (double)(p->
y - v1.
y) / (v2.
y - v1.
y);
6634 if (p->
x < v1.
x + vt * (v2.
x - v1.
x))
6643 LWDEBUGF(3,
"_lwt_EdgeRingCrossingCount returning %d", cn);
6646 if ( memcmp(&v1, &v0,
sizeof(
POINT2D)) )
6648 lwerror(
"_lwt_EdgeRingCrossingCount: V[n] != V[0] (%g %g != %g %g)",
6649 v1.
x, v1.
y, v0.
x, v0.
y);
6676 LWDEBUGF(2,
"Computing GBOX for ring %p", ring);
6677 for (i=0; i<ring->
size; ++i)
6738 LWDEBUG(2,
"Ring built, calling EdgeRingIsCCW");
6763 lwerror(
"Unexpected error: %d faces inserted when expecting 1", ret);
6767 *registered = newface.
face_id;
6774 lwerror(
"Errors updating edgering side face: %s",
6783 *registered = placeholder_faceid;
6804 const GBOX *minenv = NULL;
6806 const GBOX *testbox;
6807 GEOSGeometry *ghole;
6825 if ( ! shells->
tree )
6828 LWDEBUG(1,
"Building STRtree");
6830 if (shells->
tree == NULL)
6835 for (i=0; i<shells->
size; ++i)
6839 LWDEBUGF(2,
"GBOX of shell %p for edge %d is %g %g,%g %g",
6845 pt.
x = shellbox->
xmin;
6846 pt.
y = shellbox->
ymin;
6848 pt.
x = shellbox->
xmax;
6849 pt.
y = shellbox->
ymax;
6856 GEOSSTRtree_insert(shells->
tree, sring->
genv, sring);
6858 LWDEBUG(1,
"STRtree build completed");
6864 LWDEBUGF(1,
"Found %d candidate shells containing first point of ring's originating edge %d",
6869 for (i=0; i<candidates.
size; ++i)
6877 LWDEBUGF(1,
"Shell %d is on other side of ring",
6885 LWDEBUGF(1,
"Bbox of shell %d equals that of hole ring",
6893 LWDEBUGF(1,
"Bbox of shell %d does not contain bbox of ring point",
6902 LWDEBUGF(2,
"Bbox of shell %d (face %d) not contained by bbox "
6903 "of last shell found to contain the point",
6914 LWDEBUGF(1,
"Shell %d contains hole of edge %d",
6921 if ( foundInFace == -1 ) foundInFace = 0;
6923 candidates.
size = 0;
6926 GEOSGeom_destroy(ghole);
6941 uint64_t nelems = 1;
6947 if (nelems == UINT64_MAX)
6994 if ( numfaces != 0 ) {
6995 if ( numfaces > 0 ) {
6997 lwerror(
"Polygonize: face table is not empty.");
7005 if ( ! edgetable.
edges ) {
7006 if (edgetable.
size == 0) {
7018 for (i=0; i<edgetable.
size; ++i)
7026 edge = &(edgetable.
edges[i]);
7030 LWDEBUGF(1,
"Next face-missing edge has id:%d, face_left:%d, face_right:%d",
7035 &holes, &shells, &newface);
7037 LWDEBUGF(1,
"New face on the left of edge %d is %d",
7044 &holes, &shells, &newface);
7046 LWDEBUGF(1,
"New face on the right of edge %d is %d",
7057 lwerror(
"Errors fetching or registering face-missing edges: %s",
7067 for (i=0; i<holes.
size; ++i)
7074 if ( containing_face == -1 )
7079 lwerror(
"Errors finding face containing ring: %s",
7089 lwerror(
"Errors updating edgering side face: %s",
7095 LWDEBUG(1,
"All holes assigned, cleaning up");
7111 uint64_t numedges, i;
7113 const POINT2D *closestPointOnEdge = NULL;
7114 uint32_t closestSegmentIndex;
7115 int closestSegmentSide;
7116 uint32_t closestPointVertex;
7117 const POINT2D *closestSegmentP0, *closestSegmentP1;
7120 int containingFace = -1;
7130 if (numedges == UINT64_MAX)
7176 closestSegmentP0->
x,
7177 closestSegmentP0->
y,
7178 closestSegmentP1->
x,
7196 const POINT2D *p = queryPoint;
7197 const POINT2D *A = closestSegmentP0;
7198 const POINT2D *B = closestSegmentP1;
7199 double r = ( (p->
x-A->
x) * (B->
x-A->
x) + (p->
y-A->
y) * (B->
y-A->
y) )/( (B->
x-A->
x)*(B->
x-A->
x) +(B->
y-A->
y)*(B->
y-A->
y) );
7202 closestPointOnEdge = A;
7203 closestPointVertex = closestSegmentIndex;
7204 if ( closestSegmentIndex == 0 )
7211 closestPointOnEdge = B;
7212 closestPointVertex = closestSegmentIndex + 1;
7215 closestNode = closestEdge->
end_node;
7223 if ( closestNode != 0 )
7225 LWDEBUGF(1,
"Closest point is node %d", closestNode);
7228 LWDEBUGF(1,
"Query point is node %d", closestNode);
7239 lwerror(
"Two or more faces found");
7242 containingFace = closestEdge->
face_left;
7247 if (numedges == UINT64_MAX)
7254 for (i=0; i<numedges; ++i)
7256 if ( edges[i].face_left != containingFace ||
7257 edges[i].face_right != containingFace )
7261 lwerror(
"Two or more faces found");
7267 lwerror(
"Unexpected backend return: getEdgeByNode(%d) returns no edges when we previously found edge %d ending on that node",
7268 closestNode, closestEdge->
edge_id);
7273 LWDEBUGF(1,
"lwt_be_getEdgeByNode returned %d edges", numedges);
7276 return containingFace;
7284 lwerror(
"error computing azimuth of query point [%.15g %.15g,%.15g %.15g]",
7285 closestPointOnEdge->
x, closestPointOnEdge->
y,
7286 queryPoint->
x, queryPoint->
y);
7295 lwerror(
"Unexpected backend return: _lwt_FindAdjacentEdges(%d) found no edges when we previously found edge %d ending on that node",
7296 closestNode, closestEdge->
edge_id);
7306 LWDEBUG(1,
"Closest point is NOT a node");
7312 containingFace = closestEdge->
face_left;
7314 return containingFace;
7321 lwerror(
"Two or more faces found");
7329 LWDEBUGF(1,
"Closest point is vertex %d of closest segment", closestPointVertex);
7340 uint32_t prevVertexIndex = closestPointVertex > 0 ?
7341 closestPointVertex - 1u :
7349 LWDEBUGF(1,
"Previous vertex %u is POINT(%.15g %.15g)",
7355 uint32_t nextVertexIndex = closestPointVertex == closestEdge->
geom->
points->
npoints - 1u ?
7357 closestPointVertex + 1u;
7364 LWDEBUGF(1,
"Next vertex %u is POINT(%.15g %.15g)",
7375 if ( !
azimuth_pt_pt(closestPointOnEdge, prevVertex, &azS0)) {
7376 lwerror(
"error computing azimuth of segment to closest point [%.15g %.15g,%.15g %.15g]",
7377 closestPointOnEdge->
x, closestPointOnEdge->
y,
7378 prevVertex->
x, prevVertex->
y);
7382 if ( !
azimuth_pt_pt(closestPointOnEdge, nextVertex, &azS1)) {
7383 lwerror(
"error computing azimuth of segment from closest point [%.15g %.15g,%.15g %.15g]",
7384 closestPointOnEdge->
x, closestPointOnEdge->
y,
7385 nextVertex->
x, nextVertex->
y);
7389 if ( !
azimuth_pt_pt(closestPointOnEdge, queryPoint, &azSL) ) {
7390 lwerror(
"error computing azimuth of queryPoint [%.15g %.15g,%.15g %.15g]",
7391 closestPointOnEdge->
x, closestPointOnEdge->
y,
7392 queryPoint->
x, queryPoint->
y);
7397 double angle_S0_S1 = azS1 - azS0;
7398 if ( angle_S0_S1 < 0 ) angle_S0_S1 += 2 * M_PI;
7400 double angle_S0_SL = azSL - azS0;
7401 if ( angle_S0_SL < 0 ) angle_S0_SL += 2 * M_PI;
7403 LWDEBUGF(1,
"Azimuths from closest (vertex) point: P:%g, N:%g (+%g), Q:%g (+%g)",
7408 if ( angle_S0_SL < angle_S0_S1 )
7411 containingFace = closestEdge->
face_left;
7424 LWDEBUGF(1,
"Closest point is internal to closest segment, calling lw_segment_side((%g,%g),(%g,%g),(%g,%g)",
7425 closestSegmentP0->
x,
7426 closestSegmentP0->
y,
7427 closestSegmentP1->
x,
7428 closestSegmentP1->
y,
7433 closestSegmentSide =
lw_segment_side(closestSegmentP0, closestSegmentP1, queryPoint);
7434 LWDEBUGF(1,
"Side of closest segment query point falls on: %d", closestSegmentSide);
7436 if ( closestSegmentSide == -1 )
7438 containingFace = closestEdge->
face_left;
7440 else if ( closestSegmentSide == 1 )
7446 lwerror(
"Unexpected collinearity reported from lw_segment_side");
7454 return containingFace;
char result[OUT_DOUBLE_BUFFER_SIZE]
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.
int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout)
Update the output GBOX to be large enough to include both inputs.
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
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,...)
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
char lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
geom1 same as geom2 iff
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
int ptarray_closest_segment_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
LWGEOM * lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
int azimuth_pt_pt(const POINT2D *p1, const POINT2D *p2, double *ret)
Compute the azimuth of segment AB in radians.
LWGEOM * lwgeom_node(const LWGEOM *lwgeom_in)
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance)
Append a POINTARRAY, pa2 to the end of an existing POINTARRAY, pa1.
void lwpoint_free(LWPOINT *pt)
void lwgeom_free(LWGEOM *geom)
LWGEOM * lwgeom_split(const LWGEOM *lwgeom_in, const LWGEOM *blade_in)
LWGEOM * lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2)
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
int lwgeom_is_simple(const LWGEOM *lwgeom)
LWGEOM * lwgeom_snap(const LWGEOM *geom1, const LWGEOM *geom2, double tolerance)
Snap vertices and segments of a geometry to another using a given tolerance.
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
LWGEOM * lwgeom_difference(const LWGEOM *geom1, const LWGEOM *geom2)
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
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...
LWGEOM * lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom, double zval)
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
int ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, uint32_t where)
Insert a point into an existing POINTARRAY.
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count the total number of vertices in any LWGEOM.
void * lwrealloc(void *mem, size_t size)
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
double lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
LWGEOM * lwgeom_unaryunion(const LWGEOM *geom1)
LWCOLLECTION * lwcollection_extract(const LWCOLLECTION *col, uint32_t type)
LWGEOM * lwgeom_buildarea(const LWGEOM *geom)
Take a geometry and return an areal geometry (Polygon or MultiPolygon).
void lwcollection_release(LWCOLLECTION *lwcollection)
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing min distance calculation.
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
void lwcollection_free(LWCOLLECTION *col)
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
void ptarray_free(POINTARRAY *pa)
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
void lwline_setPoint4d(LWLINE *line, uint32_t which, POINT4D *newpoint)
LWGEOM * lwgeom_linemerge(const LWGEOM *geom1)
void * lwalloc(size_t size)
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
int ptarray_is_closed_2d(const POINTARRAY *pa)
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
void lwpoly_free(LWPOLY *poly)
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
LWPOLY * lwpoly_construct(int32_t srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
void lwline_free(LWLINE *line)
LWGEOM * lwgeom_union(const LWGEOM *geom1, const LWGEOM *geom2)
LWGEOM * lwgeom_make_valid(LWGEOM *geom)
Attempts to make an invalid geometries valid w/out losing points.
void lwgeom_reverse_in_place(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
LWPOINT * lwline_get_lwpoint(const LWLINE *line, uint32_t where)
Returns freshly allocated LWPOINT that corresponds to the index where.
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
#define LW_INSIDE
Constants for point-in-polygon return values.
LWGEOM * lwline_remove_repeated_points(const LWLINE *in, double tolerance)
void ptarray_reverse_in_place(POINTARRAY *pa)
int lwline_is_empty(const LWLINE *line)
#define LW_ON_INTERRUPT(x)
int lwline_is_closed(const LWLINE *line)
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
int ptarray_scroll_in_place(POINTARRAY *pa, const POINT4D *newbase)
int lwpoint_is_empty(const LWPOINT *point)
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
Return 1 if the point is inside the POINTARRAY, -1 if it is outside, and 0 if it is on the boundary.
int lwpoly_is_empty(const LWPOLY *poly)
int ptarray_isccw(const POINTARRAY *pa)
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
int p2d_same(const POINT2D *p1, const POINT2D *p2)
#define LWT_COL_EDGE_FACE_RIGHT
#define LWT_COL_FACE_FACE_ID
Face fields.
LWT_INT64 LWT_ELEMID
Identifier of topology element.
struct LWT_BE_TOPOLOGY_T LWT_BE_TOPOLOGY
Topology handler.
#define LWT_COL_EDGE_START_NODE
#define LWT_COL_EDGE_FACE_LEFT
#define LWT_COL_EDGE_NEXT_RIGHT
#define LWT_COL_NODE_CONTAINING_FACE
#define LWT_COL_EDGE_EDGE_ID
Edge fields.
#define LWT_COL_NODE_GEOM
#define LWT_COL_EDGE_END_NODE
#define LWT_COL_EDGE_NEXT_LEFT
#define LWT_COL_NODE_NODE_ID
Node fields.
struct LWT_BE_DATA_T LWT_BE_DATA
Backend private data pointer.
#define LWT_COL_EDGE_GEOM
static const int STRTREE_NODE_CAPACITY
#define LWDEBUG(level, msg)
#define LWDEBUGF(level, msg,...)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
#define LWDEBUGGF(level, geom, fmt,...)
#define LWDEBUGG(level, geom, msg)
static LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
static LWT_ELEMID * lwt_be_getRingEdges(LWT_TOPOLOGY *topo, LWT_ELEMID edge, uint64_t *numedges, uint64_t limit)
LWT_ELEMID lwt_AddPoint(LWT_TOPOLOGY *topo, LWPOINT *point, double tol)
Adds a point to the topology.
#define CBT2(to, method, a1, a2)
int lwt_be_ExistsEdgeIntersectingPoint(LWT_TOPOLOGY *topo, LWPOINT *pt)
struct LWT_ISO_EDGE_TABLE_T LWT_ISO_EDGE_TABLE
static uint64_t lwt_be_updateFacesById(LWT_TOPOLOGY *topo, const LWT_ISO_FACE *faces, uint64_t numfaces)
static double _lwt_EdgeRingSignedArea(LWT_EDGERING_POINT_ITERATOR *it)
void lwt_BackendIfaceRegisterCallbacks(LWT_BE_IFACE *iface, const LWT_BE_CALLBACKS *cb)
Register backend callbacks into the opaque iface handler.
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
static int _lwt_FindNextRingEdge(const POINTARRAY *ring, int from, const LWT_ISO_EDGE *edges, int numedges)
LWT_BE_IFACE * lwt_CreateBackendIface(const LWT_BE_DATA *data)
Create a new backend interface.
static int lwt_be_deleteNodesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t numelems)
int lwt_RemoveIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID nid)
Remove an isolated node.
struct LWT_EDGERING_POINT_ITERATOR_T LWT_EDGERING_POINT_ITERATOR
#define CB1(be, method, a1)
static int _lwt_EdgeRingContainsPoint(LWT_EDGERING *ring, POINT2D *p)
static int lwt_be_deleteFacesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t numelems)
static int lwt_be_checkTopoGeomRemEdge(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, LWT_ELEMID face_left, LWT_ELEMID face_right)
static LWT_ELEMID _lwt_AddEdge(LWT_TOPOLOGY *topo, LWT_ELEMID start_node, LWT_ELEMID end_node, LWLINE *geom, int skipChecks, int modFace)
LWT_ELEMID lwt_GetFaceContainingPoint(LWT_TOPOLOGY *topo, const LWPOINT *pt)
Find the face-id of the face properly containing a given point.
static int _lwt_InitEdgeEndByLine(edgeend *fee, edgeend *lee, LWLINE *edge, POINT2D *fp, POINT2D *lp)
LWT_ISO_EDGE * lwt_be_getEdgeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
static double lwt_be_topoGetPrecision(LWT_TOPOLOGY *topo)
static int _lwt_UpdateEdgeFaceRef(LWT_TOPOLOGY *topo, LWT_ELEMID of, LWT_ELEMID nf)
void lwt_FreeBackendIface(LWT_BE_IFACE *iface)
Release memory associated with an LWT_BE_IFACE.
static int _lwt_GetInteriorEdgePoint(const LWLINE *edge, POINT2D *ip)
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
LWT_ELEMID lwt_GetEdgeByPoint(LWT_TOPOLOGY *topo, LWPOINT *pt, double tol)
Find the edge-id of an edge that intersects a given point.
LWT_ELEMID lwt_AddEdgeModFace(LWT_TOPOLOGY *topo, LWT_ELEMID start_node, LWT_ELEMID end_node, LWLINE *geom, int skipChecks)
Add a new edge possibly splitting a face (modifying it)
static int lwt_be_checkTopoGeomRemIsoEdge(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id)
struct LWT_EDGERING_ARRAY_T LWT_EDGERING_ARRAY
#define CBT3(to, method, a1, a2, a3)
LWT_ELEMID lwt_AddIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID face, LWPOINT *pt, int skipISOChecks)
Add an isolated node.
LWT_ELEMID lwt_ModEdgeSplit(LWT_TOPOLOGY *topo, LWT_ELEMID edge, LWPOINT *pt, int skipISOChecks)
Split an edge by a node, modifying the original edge and adding a new one.
static int lwt_be_updateTopoGeomEdgeHeal(LWT_TOPOLOGY *topo, LWT_ELEMID edge1, LWT_ELEMID edge2, LWT_ELEMID newedge)
#define CBT1(to, method, a1)
#define LWT_EDGERING_INIT(a)
static LWT_ISO_EDGE * lwt_be_getEdgeByNode(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
static int _lwt_FirstDistinctVertex2D(const POINTARRAY *pa, POINT2D *ref, int from, int dir, POINT2D *op)
static LWGEOM * _lwt_split_by_nodes(const LWGEOM *g, const LWGEOM *nodes)
LWT_ELEMID lwt_be_getNextEdgeId(LWT_TOPOLOGY *topo)
static LWT_ISO_NODE * _lwt_GetIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID nid)
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_AddIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID face, LWPOINT *pt, int skipISOChecks, int checkFace)
static LWT_ELEMID _lwt_EdgeRingGetFace(LWT_EDGERING *ring)
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
LWT_ELEMID lwt_AddIsoEdge(LWT_TOPOLOGY *topo, LWT_ELEMID startNode, LWT_ELEMID endNode, const LWLINE *geom)
Add an isolated edge connecting two existing isolated nodes.
static LWPOLY * _lwt_MakeRingShell(LWT_TOPOLOGY *topo, LWT_ELEMID *signed_edge_ids, uint64_t num_signed_edge_ids)
LWT_ELEMID lwt_GetFaceByPoint(LWT_TOPOLOGY *topo, const LWPOINT *pt, double tol)
Find the face-id of a face containing a given point.
static int lwt_be_updateTopoGeomFaceSplit(LWT_TOPOLOGY *topo, LWT_ELEMID split_face, LWT_ELEMID new_face1, LWT_ELEMID new_face2)
static int lwt_be_updateNodesById(LWT_TOPOLOGY *topo, const LWT_ISO_NODE *nodes, int numnodes, int upd_fields)
LWT_ELEMID lwt_NewEdgesSplit(LWT_TOPOLOGY *topo, LWT_ELEMID edge, LWPOINT *pt, int skipISOChecks)
Split an edge by a node, replacing it with two new edges.
static int _lwt_CheckEdgeCrossing(LWT_TOPOLOGY *topo, LWT_ELEMID start_node, LWT_ELEMID end_node, const LWLINE *geom, LWT_ELEMID myself)
static void _lwt_release_nodes(LWT_ISO_NODE *nodes, int num_nodes)
LWT_ELEMID lwt_RemEdgeNewFace(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id)
Remove an edge, possibly merging two faces (replacing both with a new one)
static double _lwt_minToleranceDouble(double d)
static int lwt_be_checkTopoGeomRemNode(LWT_TOPOLOGY *topo, LWT_ELEMID node_id, LWT_ELEMID eid1, LWT_ELEMID eid2)
static int lwt_be_updateTopoGeomFaceHeal(LWT_TOPOLOGY *topo, LWT_ELEMID face1, LWT_ELEMID face2, LWT_ELEMID newface)
static int lwt_be_insertFaces(LWT_TOPOLOGY *topo, LWT_ISO_FACE *face, uint64_t numelems)
int lwt_be_updateTopoGeomEdgeSplit(LWT_TOPOLOGY *topo, LWT_ELEMID split_edge, LWT_ELEMID new_edge1, LWT_ELEMID new_edge2)
static double _lwt_minTolerance(LWGEOM *g)
static int _lwt_UpdateEdgeRingSideFace(LWT_TOPOLOGY *topo, LWT_EDGERING *ring, LWT_ELEMID face)
static int _lwt_EdgeRingIsCCW(LWT_EDGERING *ring)
static LWT_ISO_EDGE * lwt_be_getEdgeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields, const GBOX *box)
static LWT_ISO_EDGE * lwt_be_getClosestEdge(const LWT_TOPOLOGY *topo, const LWPOINT *pt, uint64_t *numelems, int fields)
int lwt_be_insertNodes(LWT_TOPOLOGY *topo, LWT_ISO_NODE *node, uint64_t numelems)
LWT_ISO_NODE * lwt_be_getNodeWithinDistance2D(LWT_TOPOLOGY *topo, LWPOINT *pt, double dist, uint64_t *numelems, int fields, int64_t limit)
int lwt_Polygonize(LWT_TOPOLOGY *topo)
LWT_ELEMID lwt_AddEdgeNewFaces(LWT_TOPOLOGY *topo, LWT_ELEMID start_node, LWT_ELEMID end_node, LWLINE *geom, int skipChecks)
Add a new edge possibly splitting a face (replacing with two new faces)
static LWT_EDGERING_POINT_ITERATOR * _lwt_EdgeRingIterator_begin(LWT_EDGERING *er)
LWT_TOPOLOGY * lwt_LoadTopology(LWT_BE_IFACE *iface, const char *name)
Loads an existing topology by name from the database.
static int _lwt_EdgeRingIterator_next(LWT_EDGERING_POINT_ITERATOR *it, POINT2D *pt)
#define LWT_HOLES_FACE_PLACEHOLDER
static int _lwt_CheckFacesExist(LWT_TOPOLOGY *topo)
int lwt_be_updateEdges(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *sel_edge, int sel_fields, const LWT_ISO_EDGE *upd_edge, int upd_fields, const LWT_ISO_EDGE *exc_edge, int exc_fields)
static GBOX * _lwt_EdgeRingGetBbox(LWT_EDGERING *ring)
static LWT_ELEMID _lwt_GetEqualEdge(LWT_TOPOLOGY *topo, LWLINE *edge, int *forward)
static void _lwt_RotateElemidArray(LWT_ELEMID *ary, int from, int to, int rotidx)
#define LWT_EDGERING_ARRAY_INIT(a)
struct LWT_EDGERING_ELEM_T LWT_EDGERING_ELEM
static int compare_scored_pointer(const void *si1, const void *si2)
LWT_ELEMID lwt_RemEdgeModFace(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id)
Remove an edge, possibly merging two faces (replacing one with the other)
LWT_ELEMID * lwt_AddPolygon(LWT_TOPOLOGY *topo, LWPOLY *poly, double tol, int *nfaces)
Adds a polygon to the topology.
int lwt_be_deleteEdges(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *sel_edge, int sel_fields)
static LWT_ISO_EDGE * _lwt_getIsoEdgeById(LWT_ISO_EDGE_TABLE *tab, LWT_ELEMID id)
int lwt_GetFaceEdges(LWT_TOPOLOGY *topo, LWT_ELEMID face_id, LWT_ELEMID **out)
Return the list of directed edges bounding a face.
static int _lwt_UpdateNodeFaceRef(LWT_TOPOLOGY *topo, LWT_ELEMID of, LWT_ELEMID nf)
#define CBT4(to, method, a1, a2, a3, a4)
int lwt_MoveIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID nid, LWPOINT *pt)
Move an isolated node.
static int _lwt_FindAdjacentEdges(LWT_TOPOLOGY *topo, LWT_ELEMID node, edgeend *data, edgeend *other, int myedge_id)
LWT_ELEMID * lwt_AddLineNoFace(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology without determining generated faces.
LWT_ISO_NODE * lwt_be_getNodeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
static int lwt_be_topoHasZ(LWT_TOPOLOGY *topo)
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 LWT_ISO_NODE * lwt_be_getNodeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
LWT_ELEMID lwt_ModEdgeHeal(LWT_TOPOLOGY *topo, LWT_ELEMID e1, LWT_ELEMID e2)
Merge two edges, modifying the first and deleting the second.
static void _lwt_AccumulateCanditates(void *item, void *userdata)
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
#define LWT_EDGERING_PUSH(a, r)
static LWT_ELEMID _lwt_AddFaceSplit(LWT_TOPOLOGY *topo, LWT_ELEMID sedge, LWT_ELEMID face, int mbr_only)
static int lwt_be_checkTopoGeomRemIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID node_id)
static LWT_ELEMID _lwt_FindFaceContainingRing(LWT_TOPOLOGY *topo, LWT_EDGERING *ring, LWT_EDGERING_ARRAY *shells)
#define _LWT_MINTOLERANCE(topo, geom)
#define CBT6(to, method, a1, a2, a3, a4, a5, a6)
static LWT_ISO_EDGE * lwt_be_getEdgeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
int lwt_be_freeTopology(LWT_TOPOLOGY *topo)
void lwt_FreeTopology(LWT_TOPOLOGY *topo)
Release memory associated with an LWT_TOPOLOGY.
LWT_ELEMID lwt_NewEdgeHeal(LWT_TOPOLOGY *topo, LWT_ELEMID e1, LWT_ELEMID e2)
Merge two edges, replacing both with a new one.
static LWCOLLECTION * _lwt_EdgeSplit(LWT_TOPOLOGY *topo, LWT_ELEMID edge, LWPOINT *pt, int skipISOChecks, LWT_ISO_EDGE **oldedge)
static LWT_ELEMID _lwt_AddLineEdge(LWT_TOPOLOGY *topo, LWLINE *edge, double tol, int handleFaceSplit, int *forward)
#define CBT5(to, method, a1, a2, a3, a4, a5)
int lwt_be_insertEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, uint64_t numelems)
#define LWT_EDGERING_ARRAY_CLEAN(a)
int lwt_be_ExistsCoincidentNode(LWT_TOPOLOGY *topo, LWPOINT *pt)
static LWT_ISO_EDGE * _lwt_FetchAllEdges(LWT_TOPOLOGY *topo, int *numedges)
static LWT_ELEMID _lwt_HealEdges(LWT_TOPOLOGY *topo, LWT_ELEMID eid1, LWT_ELEMID eid2, int modEdge)
static LWT_ELEMID * _lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges, int handleFaceSplit)
static LWGEOM * _lwt_FaceByEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edges, int numfaceedges)
static int compare_iso_edges_by_id(const void *si1, const void *si2)
LWT_BE_TOPOLOGY * lwt_be_loadTopologyByName(LWT_BE_IFACE *be, const char *name)
static LWT_ISO_FACE * lwt_be_getFaceById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
static LWT_ISO_NODE * lwt_be_getNodeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields, const GBOX *box)
static LWGEOM * _lwt_toposnap(LWGEOM *src, LWGEOM *tgt, double tol)
static int _lwt_FetchNextUnvisitedEdge(__attribute__((__unused__)) LWT_TOPOLOGY *topo, LWT_ISO_EDGE_TABLE *etab, int from)
struct scored_pointer_t scored_pointer
#define LWT_EDGERING_ARRAY_PUSH(a, r)
LWT_ELEMID lwt_GetNodeByPoint(LWT_TOPOLOGY *topo, LWPOINT *pt, double tol)
Retrieve the id of a node at a point location.
static int lwt_be_topoGetSRID(LWT_TOPOLOGY *topo)
static void _lwt_ReverseElemidArray(LWT_ELEMID *ary, int from, int to)
static LWT_ELEMID _lwt_AddPoint(LWT_TOPOLOGY *topo, LWPOINT *point, double tol, int findFace, int *moved)
int lwt_RemIsoEdge(LWT_TOPOLOGY *topo, LWT_ELEMID id)
Remove an isolated edge.
static int lwt_be_updateNodes(LWT_TOPOLOGY *topo, const LWT_ISO_NODE *sel_node, int sel_fields, const LWT_ISO_NODE *upd_node, int upd_fields, const LWT_ISO_NODE *exc_node, int exc_fields)
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
static int _lwt_EdgeRingCrossingCount(const POINT2D *p, LWT_EDGERING_POINT_ITERATOR *it)
int lwt_ChangeEdgeGeom(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, LWLINE *geom)
Changes the shape of an edge without affecting the topology structure.
static int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
struct LWT_EDGERING_T LWT_EDGERING
static LWT_ELEMID _lwt_RemEdge(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, int modFace)
LWT_ISO_EDGE * lwt_be_getEdgeWithinDistance2D(LWT_TOPOLOGY *topo, const LWPOINT *pt, double dist, uint64_t *numelems, int fields, int64_t limit)
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Datum contains(PG_FUNCTION_ARGS)
Datum covers(PG_FUNCTION_ARGS)
Structure containing base backend callbacks.
const LWT_BE_CALLBACKS * cb
LWT_EDGERING_ELEM * curelem
LWT_EDGERING_ELEM ** elems
LWT_ELEMID containing_face
LWT_BE_TOPOLOGY * be_topo
const LWT_BE_IFACE * be_iface