27 #include "../postgis_config.h"
42 # define LWTFMT_ELEMID "lld"
44 # define LWTFMT_ELEMID PRId64
78 #define CHECKCB(be, method) do { \
79 if ( ! (be)->cb || ! (be)->cb->method ) \
80 lwerror("Callback " # method " not registered by backend"); \
83 #define CB0(be, method) \
85 return (be)->cb->method((be)->data)
87 #define CB1(be, method, a1) \
89 return (be)->cb->method((be)->data, a1)
91 #define CBT0(to, method) \
92 CHECKCB((to)->be_iface, method);\
93 return (to)->be_iface->cb->method((to)->be_topo)
95 #define CBT1(to, method, a1) \
96 CHECKCB((to)->be_iface, method);\
97 return (to)->be_iface->cb->method((to)->be_topo, a1)
99 #define CBT2(to, method, a1, a2) \
100 CHECKCB((to)->be_iface, method);\
101 return (to)->be_iface->cb->method((to)->be_topo, a1, a2)
103 #define CBT3(to, method, a1, a2, a3) \
104 CHECKCB((to)->be_iface, method);\
105 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3)
107 #define CBT4(to, method, a1, a2, a3, a4) \
108 CHECKCB((to)->be_iface, method);\
109 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3, a4)
111 #define CBT5(to, method, a1, a2, a3, a4, a5) \
112 CHECKCB((to)->be_iface, method);\
113 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3, a4, a5)
115 #define CBT6(to, method, a1, a2, a3, a4, a5, a6) \
116 CHECKCB((to)->be_iface, method);\
117 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3, a4, a5, a6)
122 CB0(be, lastErrorMessage);
128 CB1(be, loadTopologyByName, name);
134 CBT0(topo, topoGetSRID);
140 CBT0(topo, topoGetPrecision);
146 CBT0(topo, topoHasZ);
152 CBT0(topo, freeTopology);
157 int* numelems,
int fields)
159 CBT3(topo, getNodeById, ids, numelems, fields);
164 double dist,
int* numelems,
int fields,
167 CBT5(topo, getNodeWithinDistance2D, pt, dist, numelems, fields, limit);
172 const GBOX* box,
int* numelems,
int fields,
175 CBT4(topo, getNodeWithinBox2D, box, numelems, fields, limit);
180 const GBOX* box,
int* numelems,
int fields,
183 CBT4(topo, getEdgeWithinBox2D, box, numelems, fields, limit);
188 const GBOX* box,
int* numelems,
int fields,
191 CBT4(topo, getFaceWithinBox2D, box, numelems, fields, limit);
197 CBT2(topo, insertNodes, node, numelems);
203 CBT2(topo, insertFaces, face, numelems);
209 CBT2(topo, deleteFacesById, ids, numelems);
215 CBT2(topo, deleteNodesById, ids, numelems);
221 CBT0(topo, getNextEdgeId);
226 int* numelems,
int fields)
228 CBT3(topo, getEdgeById, ids, numelems, fields);
233 int* numelems,
int fields)
235 CBT3(topo, getFaceById, ids, numelems, fields);
240 int* numelems,
int fields)
242 CBT3(topo, getEdgeByNode, ids, numelems, fields);
247 int* numelems,
int fields,
const GBOX *box)
249 CBT4(topo, getEdgeByFace, ids, numelems, fields, box);
254 int* numelems,
int fields,
const GBOX *box)
256 CBT4(topo, getNodeByFace, ids, numelems, fields, box);
261 double dist,
int* numelems,
int fields,
264 CBT5(topo, getEdgeWithinDistance2D, pt, dist, numelems, fields, limit);
270 CBT2(topo, insertEdges, edge, numelems);
280 CBT6(topo, updateEdges, sel_edge, sel_fields,
281 upd_edge, upd_fields,
282 exc_edge, exc_fields);
292 CBT6(topo, updateNodes, sel_node, sel_fields,
293 upd_node, upd_fields,
294 exc_node, exc_fields);
302 CBT2(topo, updateFacesById, faces, numfaces);
310 CBT3(topo, updateEdgesById, edges, numedges, upd_fields);
318 CBT3(topo, updateNodesById, nodes, numnodes, upd_fields);
326 CBT2(topo, deleteEdges, sel_edge, sel_fields);
332 CBT1(topo, getFaceContainingPoint, pt);
339 CBT3(topo, updateTopoGeomEdgeSplit, split_edge, new_edge1, new_edge2);
346 CBT3(topo, updateTopoGeomFaceSplit, split_face, new_face1, new_face2);
353 CBT3(topo, checkTopoGeomRemEdge, edge_id, face_left, face_right);
360 CBT3(topo, checkTopoGeomRemNode, node_id, eid1, eid2);
368 CBT3(topo, updateTopoGeomFaceHeal, face1, face2, newface);
376 CBT3(topo, updateTopoGeomEdgeHeal, edge1, edge2, newedge);
383 CBT3(topo, getRingEdges, edge, numedges, limit);
394 if ( exists == -1 ) {
406 if ( exists == -1 ) {
438 }
while ( changed && iterations <= maxiterations );
440 LWDEBUGF(1,
"It took %d/%d iterations to properly snap",
441 iterations, maxiterations);
450 for ( i=0; i<num_faces; ++i ) {
451 if ( faces[i].mbr )
lwfree(faces[i].mbr);
460 for ( i=0; i<num_edges; ++i ) {
470 for ( i=0; i<num_nodes; ++i ) {
508 lwnotice(
"Could not release backend topology memory: %s",
524 LWPOINT* pt,
int skipISOChecks,
int checkFace )
530 lwerror(
"Cannot add empty point as isolated node");
535 if ( ! skipISOChecks )
539 lwerror(
"SQL/MM Spatial exception - coincident node");
544 lwerror(
"SQL/MM Spatial exception - edge crosses node.");
549 if ( checkFace && ( face == -1 || ! skipISOChecks ) )
552 if ( foundInFace == -2 ) {
556 if ( foundInFace == -1 ) foundInFace = 0;
562 else if ( ! skipISOChecks && foundInFace != face ) {
564 lwerror(
"SQL/MM Spatial exception - within face %d (not %d)",
567 lwerror(
"SQL/MM Spatial exception - not within face");
587 LWPOINT* pt,
int skipISOChecks )
605 int i, num_nodes, num_edges;
609 GEOSGeometry *edgegg;
623 LWDEBUGF(1,
"lwt_be_getNodeWithinBox2D returned %d nodes", num_nodes);
624 if ( num_nodes == -1 ) {
628 for ( i=0; i<num_nodes; ++i )
632 if ( node->
node_id == start_node )
continue;
633 if ( node->
node_id == end_node )
continue;
640 GEOSGeom_destroy(edgegg);
642 lwerror(
"SQL/MM Spatial exception - geometry crosses a node");
651 LWDEBUGF(1,
"lwt_be_getEdgeWithinBox2D returned %d edges", num_edges);
652 if ( num_edges == -1 ) {
653 GEOSGeom_destroy(edgegg);
657 for ( i=0; i<num_edges; ++i )
665 if ( edge_id == myself )
continue;
667 if ( ! edge->
geom ) {
669 lwerror(
"Edge %d has NULL geometry!", edge_id);
675 GEOSGeom_destroy(edgegg);
681 LWDEBUGF(2,
"Edge %d converted to GEOS", edge_id);
685 relate = GEOSRelateBoundaryNodeRule(eegg, edgegg, 2);
687 GEOSGeom_destroy(eegg);
688 GEOSGeom_destroy(edgegg);
694 LWDEBUGF(2,
"Edge %d relate pattern is %s", edge_id, relate);
696 match = GEOSRelatePatternMatch(relate,
"F********");
699 GEOSGeom_destroy(eegg);
703 GEOSGeom_destroy(edgegg);
710 match = GEOSRelatePatternMatch(relate,
"1FFF*FFF2");
713 GEOSGeom_destroy(edgegg);
714 GEOSGeom_destroy(eegg);
725 match = GEOSRelatePatternMatch(relate,
"1********");
728 GEOSGeom_destroy(edgegg);
729 GEOSGeom_destroy(eegg);
734 lwerror(
"Spatial exception - geometry intersects edge %"
740 match = GEOSRelatePatternMatch(relate,
"T********");
743 GEOSGeom_destroy(edgegg);
744 GEOSGeom_destroy(eegg);
749 lwerror(
"SQL/MM Spatial exception - geometry crosses edge %"
755 LWDEBUGF(2,
"Edge %d analisys completed, it does no harm", edge_id);
758 GEOSGeom_destroy(eegg);
763 GEOSGeom_destroy(edgegg);
780 int skipISOChecks = 0;
786 if ( startNode == endNode )
788 lwerror(
"Closed edges would not be isolated, try lwt_AddEdgeNewFaces");
792 if ( ! skipISOChecks )
797 lwerror(
"SQL/MM Spatial exception - curve not simple");
811 node_ids[0] = startNode;
812 node_ids[1] = endNode;
820 else if ( num_nodes < 2 )
823 lwerror(
"SQL/MM Spatial exception - non-existent node");
826 for ( i=0; i<num_nodes; ++i )
832 lwerror(
"SQL/MM Spatial exception - not isolated node");
839 lwerror(
"SQL/MM Spatial exception - nodes in different faces");
843 if ( ! skipISOChecks )
853 lwerror(
"SQL/MM Spatial exception - "
854 "start node not geometry start point.");
866 lwerror(
"SQL/MM Spatial exception - "
867 "end node not geometry end point.");
876 if ( ! skipISOChecks )
896 if ( containing_face == -1 ) containing_face = 0;
909 }
else if ( ret == 0 ) {
910 lwerror(
"Insertion of split edge failed (no reason)");
920 updated_nodes[0].
node_id = startNode;
922 updated_nodes[1].
node_id = endNode;
943 LWDEBUG(1,
"calling lwt_be_getEdgeById");
945 LWDEBUGF(1,
"lwt_be_getEdgeById returned %p", *oldedge);
948 LWDEBUGF(1,
"lwt_be_getEdgeById returned NULL and set i=%d", i);
956 lwerror(
"SQL/MM Spatial exception - non-existent edge");
961 lwerror(
"Backend coding error: getEdgeById callback returned NULL "
962 "but numelements output parameter has value %d "
963 "(expected 0 or 1)", i);
972 if ( ! skipISOChecks )
974 LWDEBUG(1,
"calling lwt_be_ExistsCoincidentNode");
977 LWDEBUG(1,
"lwt_be_ExistsCoincidentNode returned");
979 lwerror(
"SQL/MM Spatial exception - coincident node");
982 LWDEBUG(1,
"lwt_be_ExistsCoincidentNode returned");
990 lwerror(
"could not split edge by point ?");
997 lwerror(
"lwgeom_as_lwcollection returned NULL");
1000 if (split_col->
ngeoms < 2) {
1003 lwerror(
"SQL/MM Spatial exception - point not on edge");
1011 LWDEBUGF(1,
"returning split col: %s", wkt);
1020 LWPOINT* pt,
int skipISOChecks )
1025 const LWGEOM *oldedge_geom;
1026 const LWGEOM *newedge_geom;
1031 split_col =
_lwt_EdgeSplit( topo, edge, pt, skipISOChecks, &oldedge );
1032 if ( ! split_col )
return -1;
1033 oldedge_geom = split_col->
geoms[0];
1034 newedge_geom = split_col->
geoms[1];
1037 ((
LWGEOM*)newedge_geom)->srid = split_col->
srid;
1054 lwerror(
"Backend coding error: "
1055 "insertNodes callback did not return node_id");
1061 if ( newedge1.
edge_id == -1 ) {
1076 if ( ! newedge1.
geom ) {
1079 lwerror(
"first geometry in lwgeom_split output is not a line");
1088 }
else if ( ret == 0 ) {
1091 lwerror(
"Insertion of split edge failed (no reason)");
1098 if ( ! updedge.
geom ) {
1101 lwerror(
"second geometry in lwgeom_split output is not a line");
1115 }
else if ( ret == 0 ) {
1118 lwerror(
"Edge being split (%d) disappeared during operations?", oldedge->
edge_id);
1120 }
else if ( ret > 1 ) {
1123 lwerror(
"More than a single edge found with id %d !", oldedge->
edge_id);
1177 LWPOINT* pt,
int skipISOChecks )
1182 const LWGEOM *oldedge_geom;
1183 const LWGEOM *newedge_geom;
1188 split_col =
_lwt_EdgeSplit( topo, edge, pt, skipISOChecks, &oldedge );
1189 if ( ! split_col )
return -1;
1190 oldedge_geom = split_col->
geoms[0];
1191 newedge_geom = split_col->
geoms[1];
1194 ((
LWGEOM*)newedge_geom)->srid = split_col->
srid;
1211 lwerror(
"Backend coding error: "
1212 "insertNodes callback did not return node_id");
1228 if ( newedges[0].edge_id == -1 ) {
1235 if ( newedges[1].edge_id == -1 ) {
1256 if ( ! newedges[0].geom ) {
1259 lwerror(
"first geometry in lwgeom_split output is not a line");
1277 if ( ! newedges[1].geom ) {
1280 lwerror(
"second geometry in lwgeom_split output is not a line");
1290 }
else if ( ret == 0 ) {
1293 lwerror(
"Insertion of split edge failed (no reason)");
1411 LWDEBUGF(1,
"first point is index %d", from);
1413 for ( i = from+inc; i != toofar; i += inc )
1415 LWDEBUGF(1,
"testing point %d", i);
1446 LWDEBUG(1,
"computing azimuth of first edge end");
1449 lwerror(
"Invalid edge (no two distinct vertices exist)");
1453 lwerror(
"error computing azimuth of first edgeend [%.15g %.15g,%.15g %.15g]",
1454 fp->
x, fp->
y, pt.
x, pt.
y);
1457 LWDEBUGF(1,
"azimuth of first edge end [%.15g %.15g,%.15g %.15g] is %g",
1458 fp->
x, fp->
y, pt.
x, pt.
y, fee->
myaz);
1461 LWDEBUG(1,
"computing azimuth of second edge end");
1464 lwerror(
"Invalid edge (no two distinct vertices exist)");
1468 lwerror(
"error computing azimuth of last edgeend [%.15g %.15g,%.15g %.15g]",
1469 lp->
x, lp->
y, pt.
x, pt.
y);
1472 LWDEBUGF(1,
"azimuth of last edge end [%.15g %.15g,%.15g %.15g] is %g",
1473 lp->
x, lp->
y, pt.
x, pt.
y, lee->
myaz);
1493 edgeend *other,
int myedge_id )
1498 double minaz, maxaz;
1506 if ( azdif < 0 ) azdif += 2 * M_PI;
1507 minaz = maxaz = azdif;
1509 LWDEBUGF(1,
"Other edge end has cwFace=%d and ccwFace=%d",
1516 " and adjacent to azimuth %g", node,
data->myaz);
1520 if ( numedges == -1 ) {
1525 LWDEBUGF(1,
"getEdgeByNode returned %d edges, minaz=%g, maxaz=%g",
1526 numedges, minaz, maxaz);
1529 for ( i = 0; i < numedges; ++i )
1539 if ( edge->
edge_id == myedge_id )
continue;
1552 " does not have two distinct points",
id);
1560 lwerror(
"Edge %d has no distinct vertices: [%.15g %.15g,%.15g %.15g]: ",
1566 ", edgeend is %g,%g-%g,%g",
1572 lwerror(
"error computing azimuth of edge %d first edgeend [%.15g %.15g,%.15g %.15g]",
1573 id, p1.
x, p1.
y, p2.
x, p2.
y);
1576 azdif = az -
data->myaz;
1578 ": %g (diff: %g)", edge->
edge_id, az, azdif);
1580 if ( azdif < 0 ) azdif += 2 * M_PI;
1581 if ( minaz == -1 ) {
1582 minaz = maxaz = azdif;
1589 " (face_right is new ccwFace, face_left is new cwFace)",
1593 if ( azdif < minaz ) {
1599 " (previous had minaz=%g, face_left is new cwFace)",
1604 else if ( azdif > maxaz ) {
1610 " (previous had maxaz=%g, face_right is new ccwFace)",
1622 lwerror(
"Edge %d has no distinct vertices: [%.15g %.15g,%.15g %.15g]: ",
1627 ", edgeend is %g,%g-%g,%g",
1633 lwerror(
"error computing azimuth of edge %d last edgeend [%.15g %.15g,%.15g %.15g]",
1634 id, p1.
x, p1.
y, p2.
x, p2.
y);
1637 azdif = az -
data->myaz;
1639 ": %g (diff: %g)", edge->
edge_id, az, azdif);
1640 if ( azdif < 0 ) azdif += 2 * M_PI;
1641 if ( minaz == -1 ) {
1642 minaz = maxaz = azdif;
1649 " (face_right is new cwFace, face_left is new ccwFace)",
1653 if ( azdif < minaz ) {
1659 " (previous had minaz=%g, face_right is new cwFace)",
1664 else if ( azdif > maxaz ) {
1668 ", outgoing, from start point, "
1670 " (previous had maxaz=%g, face_left is new ccwFace)",
1682 LWDEBUGF(1,
"edges adjacent to azimuth %g"
1685 data->myaz, node,
data->nextCW, minaz,
1686 data->nextCCW, maxaz);
1688 if ( myedge_id < 1 && numedges && data->cwFace !=
data->ccwFace )
1690 if (
data->cwFace != -1 &&
data->ccwFace != -1 ) {
1716 if ( pa->
npoints < 2 )
return 0;
1720 for (i=1; i<pa->
npoints-1; ++i)
1723 if (
p2d_same(&tp, &fp) )
continue;
1724 if (
p2d_same(&tp, &lp) )
continue;
1734 if (
p2d_same(&fp, &lp) )
return 0;
1736 ip->
x = fp.
x + ( (lp.
x - fp.
x) * 0.5 );
1737 ip->
y = fp.
y + ( (lp.
y - fp.
y) * 0.5 );
1752 for (i=0; i<num_signed_edge_ids; ++i) {
1753 int absid = llabs(signed_edge_ids[i]);
1756 for (j=0; j<numedges; ++j) {
1757 if ( edge_ids[j] == absid ) {
1762 if ( ! found ) edge_ids[numedges++] = absid;
1773 else if ( i != numedges )
1775 lwfree( signed_edge_ids );
1777 lwerror(
"Unexpected error: %d edges found when expecting %d", i, numedges);
1785 for ( i=0; i<num_signed_edge_ids; ++i )
1791 for ( j=0; j<numedges; ++j )
1793 if ( ring_edges[j].edge_id == llabs(eid) )
1795 edge = &(ring_edges[j]);
1802 lwerror(
"missing edge that was found in ring edges loop");
1860 int numfaceedges, i, j;
1861 int newface_outside;
1862 int num_signed_edge_ids;
1866 int forward_edges_count = 0;
1868 int backward_edges_count = 0;
1871 &num_signed_edge_ids, 0);
1872 if ( ! signed_edge_ids ) {
1877 LWDEBUGF(1,
"getRingEdges returned %d edges", num_signed_edge_ids);
1880 for (i=0; i<num_signed_edge_ids; ++i) {
1881 if ( signed_edge_ids[i] == -sedge ) {
1884 lwfree( signed_edge_ids );
1890 sedge, face, mbr_only);
1894 num_signed_edge_ids);
1896 lwfree( signed_edge_ids );
1905 lwfree( signed_edge_ids );
1907 " is geometrically not-closed", sedge);
1913 sedge, isccw ?
"counter" :
"");
1922 lwfree( signed_edge_ids );
1926 LWDEBUG(1,
"The left face of this clockwise ring is the universe, "
1927 "won't create a new face there");
1932 if ( mbr_only && face != 0 )
1938 updface.
mbr = (
GBOX *)shellbox;
1942 lwfree( signed_edge_ids );
1949 lwfree( signed_edge_ids );
1951 lwerror(
"Unexpected error: %d faces found when expecting 1", ret);
1955 lwfree( signed_edge_ids );
1963 if ( face != 0 && ! isccw)
1970 lwfree( signed_edge_ids );
1977 lwfree( signed_edge_ids );
1979 lwerror(
"Unexpected error: %d faces found when expecting 1", nfaces);
1982 newface.
mbr = oldface->
mbr;
1986 newface.
mbr = (
GBOX *)shellbox;
1993 lwfree( signed_edge_ids );
2000 lwfree( signed_edge_ids );
2002 lwerror(
"Unexpected error: %d faces inserted when expecting 1", ret);
2013 if ( face != 0 && ! isccw ) {
2015 LWDEBUG(1,
"New face is on the outside of the ring, updating rings in former shell");
2016 newface_outside = 1;
2019 LWDEBUG(1,
"New face is on the inside of the ring, updating forward edges in new ring");
2020 newface_outside = 0;
2033 if ( numfaceedges == -1 ) {
2034 lwfree( signed_edge_ids );
2038 LWDEBUGF(1,
"lwt_be_getEdgeByFace returned %d edges", numfaceedges);
2043 forward_edges_count = 0;
2045 backward_edges_count = 0;
2048 for ( i=0; i<numfaceedges; ++i )
2056 for ( j=0; j<num_signed_edge_ids; ++j )
2058 int seid = signed_edge_ids[j];
2066 if ( found == 2 )
break;
2068 else if ( -seid == e->
edge_id )
2071 LWDEBUGF(1,
"Edge %d is a backward edge of the new ring", e->
edge_id);
2075 if ( found == 2 )
break;
2078 if ( found )
continue;
2092 lwerror(
"Could not find interior point for edge %d: %s",
2105 if ( newface_outside )
2109 LWDEBUGF(1,
"Edge %d contained in an hole of the new face",
2118 LWDEBUGF(1,
"Edge %d not contained in the face shell",
2142 if ( forward_edges_count )
2145 forward_edges_count,
2149 lwfree( signed_edge_ids );
2153 if ( ret != forward_edges_count )
2155 lwfree( signed_edge_ids );
2156 lwerror(
"Unexpected error: %d edges updated when expecting %d",
2157 ret, forward_edges_count);
2163 if ( backward_edges_count )
2166 backward_edges_count,
2170 lwfree( signed_edge_ids );
2174 if ( ret != backward_edges_count )
2176 lwfree( signed_edge_ids );
2177 lwerror(
"Unexpected error: %d edges updated when expecting %d",
2178 ret, backward_edges_count);
2191 int numisonodes = 1;
2194 &numisonodes, fields, newface.
mbr);
2195 if ( numisonodes == -1 ) {
2196 lwfree( signed_edge_ids );
2200 if ( numisonodes ) {
2202 int nodes_to_update = 0;
2203 for (i=0; i<numisonodes; ++i)
2208 LWDEBUGF(1,
"Node %d is %scontained in new ring, newface is %s",
2210 newface_outside ?
"outside" :
"inside" );
2211 if ( newface_outside )
2215 LWDEBUGF(1,
"Node %d contained in an hole of the new face",
2224 LWDEBUGF(1,
"Node %d not contained in the face shell",
2235 if ( nodes_to_update )
2241 lwfree( signed_edge_ids );
2265 LWLINE *geom,
int skipChecks,
int modFace )
2274 const LWPOINT *start_node_geom = NULL;
2275 const LWPOINT *end_node_geom = NULL;
2289 lwerror(
"SQL/MM Spatial exception - curve not simple");
2296 newedge.
geom = geom;
2305 lwerror(
"Invalid edge (no two distinct vertices exist)");
2318 lwerror(
"Invalid edge (no two distinct vertices exist)");
2323 lwerror(
"error computing azimuth of first edgeend [%.15g %.15g,%.15g %.15g]",
2324 p1.
x, p1.
y, pn.
x, pn.
y);
2327 LWDEBUGF(1,
"edge's start node is %g,%g", p1.
x, p1.
y);
2335 lwerror(
"Invalid clean edge (no two distinct vertices exist) - should not happen");
2340 lwerror(
"error computing azimuth of last edgeend [%.15g %.15g,%.15g %.15g]",
2341 p2.
x, p2.
y, pn.
x, pn.
y);
2344 LWDEBUGF(1,
"edge's end node is %g,%g", p2.
x, p2.
y);
2351 if ( start_node != end_node ) {
2353 node_ids[0] = start_node;
2354 node_ids[1] = end_node;
2357 node_ids[0] = start_node;
2361 if ( num_nodes < 0 ) {
2365 for ( i=0; i<num_nodes; ++i )
2377 lwerror(
"SQL/MM Spatial exception - geometry crosses an edge"
2383 LWDEBUGF(1,
"Node %d, with geom %p (looking for %d and %d)",
2385 if ( node->
node_id == start_node ) {
2386 start_node_geom = node->
geom;
2388 if ( node->
node_id == end_node ) {
2389 end_node_geom = node->
geom;
2395 if ( ! start_node_geom )
2398 lwerror(
"SQL/MM Spatial exception - non-existent node");
2403 pa = start_node_geom->
point;
2408 lwerror(
"SQL/MM Spatial exception"
2409 " - start node not geometry start point."
2416 if ( ! end_node_geom )
2419 lwerror(
"SQL/MM Spatial exception - non-existent node");
2424 pa = end_node_geom->
point;
2429 lwerror(
"SQL/MM Spatial exception"
2430 " - end node not geometry end point."
2449 if ( newedge.
edge_id == -1 ) {
2455 int isclosed = start_node == end_node;
2458 isclosed ? &epan : NULL, -1 );
2463 LWDEBUGF(1,
"New edge %d is connected on start node, "
2464 "next_right is %d, prev_left is %d",
2476 LWDEBUGF(1,
"New edge %d is isolated on start node, "
2477 "next_right is %d, prev_left is %d",
2482 isclosed ? &span : NULL, -1 );
2487 LWDEBUGF(1,
"New edge %d is connected on end node, "
2488 "next_left is %d, prev_right is %d",
2494 lwerror(
"Side-location conflict: "
2495 "new edge starts in face"
2506 lwerror(
"Side-location conflict: "
2507 "new edge starts in face"
2518 LWDEBUGF(1,
"New edge %d is isolated on end node, "
2519 "next_left is %d, prev_right is %d",
2531 "faces mismatch: invalid topology ?",
2535 else if ( newedge.
face_left == -1 && modFace > -1 )
2537 lwerror(
"Could not derive edge face from linked primitives:"
2538 " invalid topology ?");
2550 }
else if ( ret == 0 ) {
2551 lwerror(
"Insertion of split edge failed (no reason)");
2559 if ( llabs(prev_left) != newedge.
edge_id )
2561 if ( prev_left > 0 )
2578 &updedge, updfields,
2588 if ( llabs(prev_right) != newedge.
edge_id )
2590 if ( prev_right > 0 )
2602 seledge.
edge_id = -prev_right;
2607 &updedge, updfields,
2649 if ( modFace > -1 ) {
2653 LWDEBUG(1,
"New edge is dangling, so it cannot split any face");
2665 if ( newface1 == 0 ) {
2666 LWDEBUG(1,
"New edge does not split any face");
2675 if ( newface == 0 ) {
2676 LWDEBUG(1,
"New edge does not split any face");
2686 if ( newface < 0 )
return newedge.
edge_id;
2725 LWLINE *geom,
int skipChecks )
2727 return _lwt_AddEdge( topo, start_node, end_node, geom, skipChecks, 1 );
2733 LWLINE *geom,
int skipChecks )
2735 return _lwt_AddEdge( topo, start_node, end_node, geom, skipChecks, 0 );
2744 int i, validedges = 0;
2746 for ( i=0; i<numfaceedges; ++i )
2760 if ( numfaceedges )
lwfree(geoms);
2761 LWDEBUG(1,
"_lwt_FaceByEdges returning empty polygon");
2778 LWDEBUGF(1,
"_lwt_FaceByEdges returning area: %s", wkt);
2798 lwerror(
"SQL/MM Spatial exception - universal face has no geometry");
2809 if ( numfaceedges == -1 ) {
2814 if ( numfaceedges == 0 )
2823 lwerror(
"SQL/MM Spatial exception - non-existent face.");
2828 lwerror(
"Corrupted topology: multiple face records have face_id=%"
2868 LWDEBUGF(1,
"Ring's 'from' point (%d) is %g,%g", from, p1.
x, p1.
y);
2872 for ( i=0; i<numedges; ++i )
2886 ") on both sides, skipping",
2894 " has only %"PRIu32
" points",
2911 LWDEBUGF(1,
"Rings's 'from' point is still %g,%g", p1.
x, p1.
y);
2914 LWDEBUG(1,
"p2d_same(p1,p2) returned true");
2916 " matches ring vertex %d", isoe->
edge_id, from);
2918 for ( j=1; j<epa->
npoints; ++j )
2924 if (
p2d_same(&p1, &p2) )
continue;
2927 LWDEBUGF(1,
"Ring's point %d is %g,%g",
2928 from+1, pt.
x, pt.
y);
2932 #if POSTGIS_DEBUG_LEVEL > 0
2935 " matches ring vertex %d", isoe->
edge_id, from+1);
2938 " does not match ring vertex %d", isoe->
edge_id, from+1);
2953 " matches ring vertex %d", isoe->
edge_id, from);
2955 for ( j=2; j<=epa->
npoints; j++ )
2961 if (
p2d_same(&p1, &p2) )
continue;
2964 LWDEBUGF(1,
"Ring's point %d is %g,%g",
2965 from+1, pt.
x, pt.
y);
2970 #if POSTGIS_DEBUG_LEVEL > 0
2973 " matches ring vertex %d", isoe->
edge_id, from+1);
2976 " does not match ring vertex %d", isoe->
edge_id, from+1);
2981 if ( match )
return i;
2997 ary[from++] = ary[to];
3035 if ( numfaceedges == -1 ) {
3039 if ( ! numfaceedges )
return 0;
3083 nseid = prevseid = 0;
3087 for ( i=0; i<facepoly->
nrings; ++i )
3096 while ( j < (int32_t) ring->
npoints-1 )
3098 LWDEBUGF(1,
"Looking for edge covering ring %d from vertex %d",
3108 lwerror(
"No edge (among %d) found to be defining geometry of face %"
3113 nextedge = &(edges[edgeno]);
3114 nextline = nextedge->
geom;
3117 " covers ring %d from vertex %d to %d",
3133 seid[nseid++] = nextedge->
face_left == face_id ?
3144 if ( (nseid - prevseid) > 1 )
3148 LWDEBUGF(1,
"Looking for smallest id among the %d edges "
3149 "composing ring %d", (nseid-prevseid), i);
3150 for ( j=prevseid; j<nseid; ++j )
3154 if ( ! minid ||
id < minid )
3161 " at position %d", minid, minidx);
3162 if ( minidx != prevseid )
3190 lwerror(
"SQL/MM Spatial exception - curve not simple");
3199 "lwt_be_getEdgeById returned NULL and set i=%d", i);
3207 lwerror(
"SQL/MM Spatial exception - non-existent edge %"
3213 lwerror(
"Backend coding error: getEdgeById callback returned NULL "
3214 "but numelements output parameter has value %d "
3215 "(expected 0 or 1)", i);
3221 "old edge has %d points, new edge has %d points",
3232 lwerror(
"SQL/MM Spatial exception - "
3233 "start node not geometry start point.");
3244 " has less than 2 vertices", oldedge->
edge_id);
3251 lwerror(
"Invalid edge: less than 2 vertices");
3258 lwerror(
"SQL/MM Spatial exception - "
3259 "end node not geometry end point.");
3275 lwerror(
"Invalid edge (no two distinct vertices exist)");
3284 lwerror(
"Edge twist at node POINT(%g %g)", p1.
x, p1.
y);
3290 oldedge->
end_node, geom, edge_id ) )
3297 LWDEBUG(1,
"lwt_ChangeEdgeGeom: "
3298 "edge crossing check passed ");
3316 LWDEBUGF(1,
"lwt_be_getNodeWithinBox2D returned %d nodes", numnodes);
3317 if ( numnodes == -1 ) {
3323 if ( numnodes > ( 1 + isclosed ? 0 : 1 ) )
3326 for (i=0; i<numnodes; ++i)
3339 lwerror(
"Edge motion collision at %s", wkt);
3347 LWDEBUG(1,
"nodes containment check passed");
3357 oldedge->
geom, &p1, &p2);
3360 isclosed ? &epan_pre : NULL, edge_id );
3362 isclosed ? &span_pre : NULL, edge_id );
3372 newedge.
geom = geom;
3383 lwerror(
"Unexpected error: %d edges updated when expecting 1", i);
3398 isclosed ? &epan_post : NULL, edge_id );
3400 isclosed ? &span_post : NULL, edge_id );
3415 lwerror(
"Edge changed disposition around start node %"
3426 lwerror(
"Edge changed disposition around end node %"
3443 int facestoupdate = 0;
3452 lwerror(
"lwt_ChangeEdgeGeom could not construct face %"
3461 LWDEBUGF(1,
"new geometry of face left (%d): %s", (
int)oldedge->
face_left, wkt);
3466 if ( ! nface1->
bbox )
3468 lwerror(
"Corrupted topology: face %d, left of edge %d, has no bbox",
3474 faces[facestoupdate++].
mbr = nface1->
bbox;
3483 lwerror(
"lwt_ChangeEdgeGeom could not construct face %"
3497 if ( ! nface2->
bbox )
3499 lwerror(
"Corrupted topology: face %d, right of edge %d, has no bbox",
3504 faces[facestoupdate++].
mbr = nface2->
bbox;
3506 LWDEBUGF(1,
"%d faces to update", facestoupdate);
3507 if ( facestoupdate )
3510 if ( i != facestoupdate )
3518 lwerror(
"Unexpected error: %d faces found when expecting 1", i);
3525 lwnotice(
"BBOX of changed edge did not change");
3528 LWDEBUG(1,
"all done, cleaning up edges");
3547 lwerror(
"SQL/MM Spatial exception - non-existent node");
3553 lwerror(
"SQL/MM Spatial exception - not isolated node");
3567 if ( ! node )
return -1;
3572 lwerror(
"SQL/MM Spatial exception - coincident node");
3579 lwerror(
"SQL/MM Spatial exception - edge crosses node.");
3608 if ( ! node )
return -1;
3620 lwerror(
"Unexpected error: %d nodes deleted when expecting 1", n);
3654 lwerror(
"SQL/MM Spatial exception - non-existent edge");
3660 lwerror(
"Corrupted topology: more than a single edge have id %"
3665 if ( edge[0].face_left != edge[0].face_right )
3668 lwerror(
"SQL/MM Spatial exception - not isolated edge");
3679 if ((n == -1) || (edge == NULL))
3684 for (i = 0; i < n; ++i)
3686 if (edge[i].edge_id !=
id)
3689 lwerror(
"SQL/MM Spatial exception - not isolated edge");
3704 lwerror(
"Unexpected error: %d edges deleted when expecting 1", n);
3711 if ( nid[1] != nid[0] ) {
3751 if ( ret == -1 )
return -1;
3759 if ( ret == -1 )
return -1;
3784 if ( ret == -1 )
return -1;
3798 int i, nedges, nfaces, fields;
3804 int nedge_right = 0;
3811 int fnode_edges = 0;
3813 int lnode_edges = 0;
3822 LWDEBUGF(1,
"lwt_be_getEdgeById returned NULL and set i=%d", i);
3830 lwerror(
"SQL/MM Spatial exception - non-existent edge %"
3836 lwerror(
"Backend coding error: getEdgeById callback returned NULL "
3837 "but numelements output parameter has value %d "
3838 "(expected 0 or 1)", i);
3850 LWDEBUG(1,
"Updating next_{right,left}_face of ring edges...");
3858 node_ids[nedges++] = edge->
end_node;
3864 if ( nedges == -1 ) {
3868 nedge_left = nedge_right = 0;
3869 for ( i=0; i<nedges; ++i )
3872 if ( e->
edge_id == edge_id )
continue;
3910 LWDEBUGF(1,
"updating %d 'next_left' edges", nedge_left);
3924 LWDEBUGF(1,
"updating %d 'next_right' edges", nedge_right);
3936 LWDEBUGF(1,
"releasing %d updateable edges in %p", nedges, upd_edge);
3954 LWDEBUG(1,
"floodface is universe");
3968 if ( nfaces == -1 ) {
3974 for ( i=0; i<nfaces; ++i )
3976 if ( faces[i].face_id == edge->
face_left )
3978 if ( ! box1 ) box1 = faces[i].
mbr;
3984 lwerror(
"corrupted topology: more than 1 face have face_id=%"
3989 else if ( faces[i].face_id == edge->
face_right )
3991 if ( ! box2 ) box2 = faces[i].
mbr;
3997 lwerror(
"corrupted topology: more than 1 face have face_id=%"
4007 lwerror(
"Backend coding error: getFaceById returned face "
4016 lwerror(
"corrupted topology: no face have face_id=%"
4025 lwerror(
"corrupted topology: no face have face_id=%"
4046 lwerror(
"Unexpected error: %d faces updated when expecting 1", i);
4065 lwerror(
"Unexpected error: %d faces inserted when expecting 1", i);
4129 if ( ! fnode_edges )
4170 return modFace ? floodface : newface.
face_id;
4200 int e2sign, e2freenode;
4204 size_t bufleft = 256;
4212 " with itself, try with another", eid1);
4219 if ((nedges == -1) || (edges == NULL))
4224 for ( i=0; i<nedges; ++i )
4226 if ( edges[i].edge_id == eid1 ) {
4229 lwerror(
"Corrupted topology: multiple edges have id %"
4235 else if ( edges[i].edge_id == eid2 ) {
4238 lwerror(
"Corrupted topology: multiple edges have id %"
4249 "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4257 "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4291 if ( commonnode != -1 )
4296 if ( num_node_edges == -1 ) {
4301 for (i=0; i<num_node_edges; ++i)
4304 if ( node_edges[i].edge_id == eid1 )
continue;
4305 if ( node_edges[i].edge_id == eid2 )
continue;
4308 if ( bufleft > 0 ) {
4310 ( ptr==buf ?
"" :
"," ), node_edges[i].edge_id);
4311 if (
r >= (
int) bufleft )
4329 if ( commonnode == -1 )
4342 if ( commonnode != -1 )
4347 if ( num_node_edges == -1 ) {
4352 for (i=0; i<num_node_edges; ++i)
4355 if ( node_edges[i].edge_id == eid1 )
continue;
4356 if ( node_edges[i].edge_id == eid2 )
continue;
4359 if ( bufleft > 0 ) {
4361 ( ptr==buf ?
"" :
"," ), node_edges[i].edge_id);
4362 if (
r >= (
int) bufleft )
4377 if ( num_node_edges )
lwfree(node_edges);
4381 if ( commonnode == -1 )
4386 lwerror(
"SQL/MM Spatial exception - other edges connected (%s)",
4391 lwerror(
"SQL/MM Spatial exception - non-connected edges");
4468 lwerror(
"Coding error: caseno=%d should never happen", caseno);
4494 lwerror(
"Unexpected error: %d edges updated when expecting 1", i);
4510 }
else if ( i == 0 ) {
4513 lwerror(
"Insertion of split edge failed (no reason)");
4625 eid1, eid2, newedge.
edge_id) )
4631 return modEdge ? commonnode : newedge.
edge_id;
4671 lwerror(
"Two or more nodes found");
4701 for (i=0; i<num;++i)
4712 " has null geometry", e->
edge_id);
4720 if ( dist > tol )
continue;
4726 lwerror(
"Two or more edges found");
4761 LWDEBUG(1,
"No face properly contains query point,"
4762 " looking for edges");
4774 for (i=0; i<num; ++i)
4785 " has null geometry", e->
edge_id);
4793 " is dangling, won't consider it", e->
edge_id);
4801 " is %g (tol=%g)", e->
edge_id, dist, tol);
4804 if ( dist > tol )
continue;
4813 lwerror(
"Two or more faces found");
4817 if (
id &&
id != eface )
4820 lwerror(
"Two or more faces found"
4837 static inline double
4840 double ret = 3.6 * pow(10, - ( 15 - log10(d?d:1.0) ) );
4866 if ( ! gbox )
return 0;
4877 #define _LWT_MINTOLERANCE( topo, geom ) ( \
4878 topo->precision ? topo->precision : _lwt_minTolerance(geom) )
4907 findFace,
int *moved)
4910 double mindist = FLT_MAX;
4937 LWDEBUGF(1,
"New point is within %.15g units of %d nodes", tol, num);
4942 for (i=0; i<num; ++i)
4944 sorted[i].
ptr = nodes+i;
4947 ((
LWT_ISO_NODE*)(sorted[i].ptr))->node_id, sorted[i].score);
4951 for (i=0; i<num; ++i)
4960 for ( i=0; i<num; ++i )
4967 if ( dist && dist >= tol )
continue;
4968 if ( !
id || dist < mindist )
4978 if ( moved ) *moved = mindist == 0 ? 0 : 1;
4999 LWDEBUGF(1,
"New point is within %.15g units of %d edges", tol, num);
5006 for (i=0; i<num; ++i)
5008 sorted[i].
ptr = edges+i;
5011 ((
LWT_ISO_EDGE*)(sorted[i].ptr))->edge_id, sorted[i].score);
5015 for (j=0, i=0; i<num; ++i)
5017 if ( sorted[i].score == sorted[0].score )