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 ) {
436 #if GEOS_NUMERIC_VERSION < 30309 448 }
while ( changed && iterations <= maxiterations );
450 LWDEBUGF(1,
"It took %d/%d iterations to properly snap",
451 iterations, maxiterations);
460 for ( i=0; i<num_faces; ++i ) {
461 if ( faces[i].mbr )
lwfree(faces[i].mbr);
470 for ( i=0; i<num_edges; ++i ) {
480 for ( i=0; i<num_nodes; ++i ) {
518 lwnotice(
"Could not release backend topology memory: %s",
526 LWPOINT* pt,
int skipISOChecks )
530 if ( ! skipISOChecks )
534 lwerror(
"SQL/MM Spatial exception - coincident node");
539 lwerror(
"SQL/MM Spatial exception - edge crosses node.");
544 if ( face == -1 || ! skipISOChecks )
547 if ( foundInFace == -2 ) {
551 if ( foundInFace == -1 ) foundInFace = 0;
557 else if ( ! skipISOChecks && foundInFace != face ) {
559 lwerror(
"SQL/MM Spatial exception - within face %d (not %d)",
562 lwerror(
"SQL/MM Spatial exception - not within face");
593 int i, num_nodes, num_edges;
597 GEOSGeometry *edgegg;
598 const GEOSPreparedGeometry* prepared_edge;
607 prepared_edge = GEOSPrepare( edgegg );
608 if ( ! prepared_edge ) {
617 LWDEBUGF(1,
"lwt_be_getNodeWithinBox2D returned %d nodes", num_nodes);
618 if ( num_nodes == -1 ) {
619 GEOSPreparedGeom_destroy(prepared_edge);
620 GEOSGeom_destroy(edgegg);
624 for ( i=0; i<num_nodes; ++i )
627 GEOSGeometry *nodegg;
629 if ( node->
node_id == start_node )
continue;
630 if ( node->
node_id == end_node )
continue;
634 contains = GEOSPreparedContains( prepared_edge, nodegg );
635 GEOSGeom_destroy(nodegg);
638 GEOSPreparedGeom_destroy(prepared_edge);
639 GEOSGeom_destroy(edgegg);
646 GEOSPreparedGeom_destroy(prepared_edge);
647 GEOSGeom_destroy(edgegg);
649 lwerror(
"SQL/MM Spatial exception - geometry crosses a node");
658 LWDEBUGF(1,
"lwt_be_getEdgeWithinBox2D returned %d edges", num_edges);
659 if ( num_edges == -1 ) {
660 GEOSPreparedGeom_destroy(prepared_edge);
661 GEOSGeom_destroy(edgegg);
665 for ( i=0; i<num_edges; ++i )
673 if ( edge_id == myself )
continue;
675 if ( ! edge->
geom ) {
677 lwerror(
"Edge %d has NULL geometry!", edge_id);
683 GEOSPreparedGeom_destroy(prepared_edge);
684 GEOSGeom_destroy(edgegg);
690 LWDEBUGF(2,
"Edge %d converted to GEOS", edge_id);
694 relate = GEOSRelateBoundaryNodeRule(eegg, edgegg, 2);
696 GEOSGeom_destroy(eegg);
697 GEOSPreparedGeom_destroy(prepared_edge);
698 GEOSGeom_destroy(edgegg);
704 LWDEBUGF(2,
"Edge %d relate pattern is %s", edge_id, relate);
706 match = GEOSRelatePatternMatch(relate,
"F********");
709 GEOSGeom_destroy(eegg);
713 GEOSPreparedGeom_destroy(prepared_edge);
714 GEOSGeom_destroy(edgegg);
721 match = GEOSRelatePatternMatch(relate,
"1FFF*FFF2");
724 GEOSPreparedGeom_destroy(prepared_edge);
725 GEOSGeom_destroy(edgegg);
726 GEOSGeom_destroy(eegg);
737 match = GEOSRelatePatternMatch(relate,
"1********");
740 GEOSPreparedGeom_destroy(prepared_edge);
741 GEOSGeom_destroy(edgegg);
742 GEOSGeom_destroy(eegg);
747 lwerror(
"Spatial exception - geometry intersects edge %" 753 match = GEOSRelatePatternMatch(relate,
"T********");
756 GEOSPreparedGeom_destroy(prepared_edge);
757 GEOSGeom_destroy(edgegg);
758 GEOSGeom_destroy(eegg);
763 lwerror(
"SQL/MM Spatial exception - geometry crosses edge %" 769 LWDEBUGF(2,
"Edge %d analisys completed, it does no harm", edge_id);
772 GEOSGeom_destroy(eegg);
777 GEOSPreparedGeom_destroy(prepared_edge);
778 GEOSGeom_destroy(edgegg);
795 int skipISOChecks = 0;
801 if ( startNode == endNode )
803 lwerror(
"Closed edges would not be isolated, try lwt_AddEdgeNewFaces");
807 if ( ! skipISOChecks )
812 lwerror(
"SQL/MM Spatial exception - curve not simple");
826 node_ids[0] = startNode;
827 node_ids[1] = endNode;
835 else if ( num_nodes < 2 )
838 lwerror(
"SQL/MM Spatial exception - non-existent node");
841 for ( i=0; i<num_nodes; ++i )
847 lwerror(
"SQL/MM Spatial exception - not isolated node");
854 lwerror(
"SQL/MM Spatial exception - nodes in different faces");
858 if ( ! skipISOChecks )
868 lwerror(
"SQL/MM Spatial exception - " 869 "start node not geometry start point.");
881 lwerror(
"SQL/MM Spatial exception - " 882 "end node not geometry end point.");
891 if ( ! skipISOChecks )
911 if ( containing_face == -1 ) containing_face = 0;
924 }
else if ( ret == 0 ) {
925 lwerror(
"Insertion of split edge failed (no reason)");
935 updated_nodes[0].
node_id = startNode;
937 updated_nodes[1].
node_id = endNode;
958 LWDEBUG(1,
"calling lwt_be_getEdgeById");
960 LWDEBUGF(1,
"lwt_be_getEdgeById returned %p", *oldedge);
963 LWDEBUGF(1,
"lwt_be_getEdgeById returned NULL and set i=%d", i);
971 lwerror(
"SQL/MM Spatial exception - non-existent edge");
976 lwerror(
"Backend coding error: getEdgeById callback returned NULL " 977 "but numelements output parameter has value %d " 978 "(expected 0 or 1)", i);
987 if ( ! skipISOChecks )
989 LWDEBUG(1,
"calling lwt_be_ExistsCoincidentNode");
992 LWDEBUG(1,
"lwt_be_ExistsCoincidentNode returned");
994 lwerror(
"SQL/MM Spatial exception - coincident node");
997 LWDEBUG(1,
"lwt_be_ExistsCoincidentNode returned");
1005 lwerror(
"could not split edge by point ?");
1009 if ( ! split_col ) {
1012 lwerror(
"lwgeom_as_lwcollection returned NULL");
1015 if (split_col->
ngeoms < 2) {
1018 lwerror(
"SQL/MM Spatial exception - point not on edge");
1026 LWDEBUGF(1,
"returning split col: %s", wkt);
1035 LWPOINT* pt,
int skipISOChecks )
1040 const LWGEOM *oldedge_geom;
1041 const LWGEOM *newedge_geom;
1046 split_col =
_lwt_EdgeSplit( topo, edge, pt, skipISOChecks, &oldedge );
1047 if ( ! split_col )
return -1;
1048 oldedge_geom = split_col->
geoms[0];
1049 newedge_geom = split_col->
geoms[1];
1052 ((
LWGEOM*)newedge_geom)->srid = split_col->
srid;
1069 lwerror(
"Backend coding error: " 1070 "insertNodes callback did not return node_id");
1076 if ( newedge1.
edge_id == -1 ) {
1091 if ( ! newedge1.
geom ) {
1094 lwerror(
"first geometry in lwgeom_split output is not a line");
1103 }
else if ( ret == 0 ) {
1106 lwerror(
"Insertion of split edge failed (no reason)");
1113 if ( ! updedge.
geom ) {
1116 lwerror(
"second geometry in lwgeom_split output is not a line");
1130 }
else if ( ret == 0 ) {
1133 lwerror(
"Edge being split (%d) disappeared during operations?", oldedge->
edge_id);
1135 }
else if ( ret > 1 ) {
1138 lwerror(
"More than a single edge found with id %d !", oldedge->
edge_id);
1192 LWPOINT* pt,
int skipISOChecks )
1197 const LWGEOM *oldedge_geom;
1198 const LWGEOM *newedge_geom;
1203 split_col =
_lwt_EdgeSplit( topo, edge, pt, skipISOChecks, &oldedge );
1204 if ( ! split_col )
return -1;
1205 oldedge_geom = split_col->
geoms[0];
1206 newedge_geom = split_col->
geoms[1];
1209 ((
LWGEOM*)newedge_geom)->srid = split_col->
srid;
1226 lwerror(
"Backend coding error: " 1227 "insertNodes callback did not return node_id");
1243 if ( newedges[0].edge_id == -1 ) {
1250 if ( newedges[1].edge_id == -1 ) {
1271 if ( ! newedges[0].geom ) {
1274 lwerror(
"first geometry in lwgeom_split output is not a line");
1292 if ( ! newedges[1].geom ) {
1295 lwerror(
"second geometry in lwgeom_split output is not a line");
1305 }
else if ( ret == 0 ) {
1308 lwerror(
"Insertion of split edge failed (no reason)");
1426 LWDEBUGF(1,
"first point is index %d", from);
1428 for ( i = from+inc; i != toofar; i += inc )
1430 LWDEBUGF(1,
"testing point %d", i);
1461 LWDEBUG(1,
"computing azimuth of first edge end");
1464 lwerror(
"Invalid edge (no two distinct vertices exist)");
1468 lwerror(
"error computing azimuth of first edgeend [%.15g %.15g,%.15g %.15g]",
1469 fp->
x, fp->
y, pt.
x, pt.
y);
1472 LWDEBUGF(1,
"azimuth of first edge end [%.15g %.15g,%.15g %.15g] is %g",
1473 fp->
x, fp->
y, pt.
x, pt.
y, fee->
myaz);
1476 LWDEBUG(1,
"computing azimuth of second edge end");
1479 lwerror(
"Invalid edge (no two distinct vertices exist)");
1483 lwerror(
"error computing azimuth of last edgeend [%.15g %.15g,%.15g %.15g]",
1484 lp->
x, lp->
y, pt.
x, pt.
y);
1487 LWDEBUGF(1,
"azimuth of last edge end [%.15g %.15g,%.15g %.15g] is %g",
1488 lp->
x, lp->
y, pt.
x, pt.
y, lee->
myaz);
1508 edgeend *other,
int myedge_id )
1513 double minaz, maxaz;
1521 if ( azdif < 0 ) azdif += 2 * M_PI;
1522 minaz = maxaz = azdif;
1524 LWDEBUGF(1,
"Other edge end has cwFace=%d and ccwFace=%d",
1531 " and adjacent to azimuth %g", node, data->
myaz);
1535 if ( numedges == -1 ) {
1540 LWDEBUGF(1,
"getEdgeByNode returned %d edges, minaz=%g, maxaz=%g",
1541 numedges, minaz, maxaz);
1544 for ( i = 0; i < numedges; ++i )
1554 if ( edge->
edge_id == myedge_id )
continue;
1567 " does not have two distinct points",
id);
1575 lwerror(
"Edge %d has no distinct vertices: [%.15g %.15g,%.15g %.15g]: ",
1581 ", edgeend is %g,%g-%g,%g",
1587 lwerror(
"error computing azimuth of edge %d first edgeend [%.15g %.15g,%.15g %.15g]",
1588 id, p1.
x, p1.
y, p2.
x, p2.
y);
1591 azdif = az - data->
myaz;
1592 LWDEBUGF(1,
"azimuth of edge %" LWTFMT_ELEMID
1593 ": %g (diff: %g)", edge->
edge_id, az, azdif);
1595 if ( azdif < 0 ) azdif += 2 * M_PI;
1596 if ( minaz == -1 ) {
1597 minaz = maxaz = azdif;
1601 LWDEBUGF(1,
"new nextCW and nextCCW edge is %" LWTFMT_ELEMID
1603 "with face_left %" LWTFMT_ELEMID
" and face_right %" LWTFMT_ELEMID
1604 " (face_right is new ccwFace, face_left is new cwFace)",
1608 if ( azdif < minaz ) {
1611 LWDEBUGF(1,
"new nextCW edge is %" LWTFMT_ELEMID
1613 "with face_left %" LWTFMT_ELEMID
" and face_right %" LWTFMT_ELEMID
1614 " (previous had minaz=%g, face_left is new cwFace)",
1619 else if ( azdif > maxaz ) {
1622 LWDEBUGF(1,
"new nextCCW edge is %" LWTFMT_ELEMID
1624 "with face_left %" LWTFMT_ELEMID
" and face_right %" LWTFMT_ELEMID
1625 " (previous had maxaz=%g, face_right is new ccwFace)",
1637 lwerror(
"Edge %d has no distinct vertices: [%.15g %.15g,%.15g %.15g]: ",
1642 ", edgeend is %g,%g-%g,%g",
1648 lwerror(
"error computing azimuth of edge %d last edgeend [%.15g %.15g,%.15g %.15g]",
1649 id, p1.
x, p1.
y, p2.
x, p2.
y);
1652 azdif = az - data->
myaz;
1653 LWDEBUGF(1,
"azimuth of edge %" LWTFMT_ELEMID
1654 ": %g (diff: %g)", edge->
edge_id, az, azdif);
1655 if ( azdif < 0 ) azdif += 2 * M_PI;
1656 if ( minaz == -1 ) {
1657 minaz = maxaz = azdif;
1661 LWDEBUGF(1,
"new nextCW and nextCCW edge is %" LWTFMT_ELEMID
1663 "with face_left %" LWTFMT_ELEMID
" and face_right %" LWTFMT_ELEMID
1664 " (face_right is new cwFace, face_left is new ccwFace)",
1668 if ( azdif < minaz ) {
1671 LWDEBUGF(1,
"new nextCW edge is %" LWTFMT_ELEMID
1673 "with face_left %" LWTFMT_ELEMID
" and face_right %" LWTFMT_ELEMID
1674 " (previous had minaz=%g, face_right is new cwFace)",
1679 else if ( azdif > maxaz ) {
1682 LWDEBUGF(1,
"new nextCCW edge is %" LWTFMT_ELEMID
1683 ", outgoing, from start point, " 1684 "with face_left %" LWTFMT_ELEMID
" and face_right %" LWTFMT_ELEMID
1685 " (previous had maxaz=%g, face_left is new ccwFace)",
1697 LWDEBUGF(1,
"edges adjacent to azimuth %g" 1703 if ( myedge_id < 1 && numedges && data->
cwFace != data->
ccwFace )
1706 lwerror(
"Corrupted topology: adjacent edges %" LWTFMT_ELEMID
" and %" LWTFMT_ELEMID
1707 " bind different face (%" LWTFMT_ELEMID
" and %" LWTFMT_ELEMID
")",
1731 if ( pa->
npoints < 2 )
return 0;
1735 for (i=1; i<pa->
npoints-1; ++i)
1738 if (
p2d_same(&tp, &fp) )
continue;
1739 if (
p2d_same(&tp, &lp) )
continue;
1749 if (
p2d_same(&fp, &lp) )
return 0;
1751 ip->
x = fp.
x + ( (lp.
x - fp.
x) * 0.5 );
1752 ip->
y = fp.
y + ( (lp.
y - fp.
y) * 0.5 );
1779 int numedges, numfaceedges, i, j;
1780 int newface_outside;
1781 int num_signed_edge_ids;
1787 int forward_edges_count = 0;
1789 int backward_edges_count = 0;
1792 &num_signed_edge_ids, 0);
1793 if ( ! signed_edge_ids ) {
1798 LWDEBUGF(1,
"getRingEdges returned %d edges", num_signed_edge_ids);
1801 for (i=0; i<num_signed_edge_ids; ++i) {
1802 if ( signed_edge_ids[i] == -sedge ) {
1805 lwfree( signed_edge_ids );
1811 sedge, face, mbr_only);
1816 for (i=0; i<num_signed_edge_ids; ++i) {
1817 int absid = llabs(signed_edge_ids[i]);
1820 for (j=0; j<numedges; ++j) {
1821 if ( edge_ids[j] == absid ) {
1826 if ( ! found ) edge_ids[numedges++] = absid;
1834 lwfree( signed_edge_ids );
1839 else if ( i != numedges )
1841 lwfree( signed_edge_ids );
1843 lwerror(
"Unexpected error: %d edges found when expecting %d", i, numedges);
1851 for ( i=0; i<num_signed_edge_ids; ++i )
1854 LWDEBUGF(1,
"Edge %d in ring of edge %" LWTFMT_ELEMID
" is edge %" LWTFMT_ELEMID,
1858 for ( j=0; j<numedges; ++j )
1860 if ( ring_edges[j].edge_id == llabs(eid) )
1862 edge = &(ring_edges[j]);
1868 lwfree( signed_edge_ids );
1870 lwerror(
"missing edge that was found in ring edges loop");
1903 LWDEBUGF(1,
"Ring of edge %" LWTFMT_ELEMID
" is %sclockwise",
1904 sedge, isccw ?
"counter" :
"");
1913 lwfree( signed_edge_ids );
1918 LWDEBUG(1,
"The left face of this clockwise ring is the universe, " 1919 "won't create a new face there");
1924 if ( mbr_only && face != 0 )
1930 updface.
mbr = (
GBOX *)shellbox;
1934 lwfree( signed_edge_ids );
1942 lwfree( signed_edge_ids );
1945 lwerror(
"Unexpected error: %d faces found when expecting 1", ret);
1949 lwfree( signed_edge_ids );
1958 if ( face != 0 && ! isccw)
1965 lwfree( signed_edge_ids );
1973 lwfree( signed_edge_ids );
1976 lwerror(
"Unexpected error: %d faces found when expecting 1", nfaces);
1979 newface.
mbr = oldface->
mbr;
1983 newface.
mbr = (
GBOX *)shellbox;
1990 lwfree( signed_edge_ids );
1998 lwfree( signed_edge_ids );
2001 lwerror(
"Unexpected error: %d faces inserted when expecting 1", ret);
2012 if ( face != 0 && ! isccw ) {
2014 LWDEBUG(1,
"New face is on the outside of the ring, updating rings in former shell");
2015 newface_outside = 1;
2018 LWDEBUG(1,
"New face is on the inside of the ring, updating forward edges in new ring");
2019 newface_outside = 0;
2032 if ( numfaceedges == -1 ) {
2033 lwfree( signed_edge_ids );
2038 LWDEBUGF(1,
"lwt_be_getEdgeByFace returned %d edges", numfaceedges);
2039 GEOSGeometry *shellgg = 0;
2040 const GEOSPreparedGeometry* prepshell = 0;
2050 prepshell = GEOSPrepare( shellgg );
2051 if ( ! prepshell ) {
2052 GEOSGeom_destroy(shellgg);
2064 forward_edges_count = 0;
2066 backward_edges_count = 0;
2069 for ( i=0; i<numfaceedges; ++i )
2079 for ( j=0; j<num_signed_edge_ids; ++j )
2081 int seid = signed_edge_ids[j];
2089 if ( found == 2 )
break;
2091 else if ( -seid == e->
edge_id )
2094 LWDEBUGF(1,
"Edge %d is a backward edge of the new ring", e->
edge_id);
2098 if ( found == 2 )
break;
2101 if ( found )
continue;
2110 GEOSPreparedGeom_destroy(prepshell);
2111 GEOSGeom_destroy(shellgg);
2118 lwerror(
"Could not find interior point for edge %d: %s",
2127 GEOSPreparedGeom_destroy(prepshell);
2128 GEOSGeom_destroy(shellgg);
2135 lwerror(
"Could not convert edge geometry to GEOS: %s",
2143 contains = GEOSPreparedContains( prepshell, egg );
2144 GEOSGeom_destroy(egg);
2145 if ( contains == 2 )
2147 GEOSPreparedGeom_destroy(prepshell);
2148 GEOSGeom_destroy(shellgg);
2159 (contains?
"":
"not "));
2162 if ( newface_outside )
2166 LWDEBUGF(1,
"Edge %d contained in an hole of the new face",
2175 LWDEBUGF(1,
"Edge %d not contained in the face shell",
2199 if ( forward_edges_count )
2202 forward_edges_count,
2206 lwfree( signed_edge_ids );
2210 if ( ret != forward_edges_count )
2212 lwfree( signed_edge_ids );
2213 lwerror(
"Unexpected error: %d edges updated when expecting %d",
2214 ret, forward_edges_count);
2220 if ( backward_edges_count )
2223 backward_edges_count,
2227 lwfree( signed_edge_ids );
2231 if ( ret != backward_edges_count )
2233 lwfree( signed_edge_ids );
2234 lwerror(
"Unexpected error: %d edges updated when expecting %d",
2235 ret, backward_edges_count);
2249 int numisonodes = 1;
2252 &numisonodes, fields, newface.
mbr);
2253 if ( numisonodes == -1 ) {
2254 lwfree( signed_edge_ids );
2258 if ( numisonodes ) {
2260 int nodes_to_update = 0;
2261 for (i=0; i<numisonodes; ++i)
2269 if ( prepshell ) GEOSPreparedGeom_destroy(prepshell);
2270 if ( shellgg ) GEOSGeom_destroy(shellgg);
2273 lwerror(
"Could not convert node geometry to GEOS: %s",
2277 contains = GEOSPreparedContains( prepshell, ngg );
2278 GEOSGeom_destroy(ngg);
2279 if ( contains == 2 )
2282 if ( prepshell ) GEOSPreparedGeom_destroy(prepshell);
2283 if ( shellgg ) GEOSGeom_destroy(shellgg);
2289 LWDEBUGF(1,
"Node %d is %scontained in new ring, newface is %s",
2290 n->
node_id, contains ?
"" :
"not ",
2291 newface_outside ?
"outside" :
"inside" );
2292 if ( newface_outside )
2296 LWDEBUGF(1,
"Node %d contained in an hole of the new face",
2305 LWDEBUGF(1,
"Node %d not contained in the face shell",
2316 if ( nodes_to_update )
2322 lwfree( signed_edge_ids );
2330 GEOSPreparedGeom_destroy(prepshell);
2331 GEOSGeom_destroy(shellgg);
2341 LWLINE *geom,
int skipChecks,
int modFace )
2350 const LWPOINT *start_node_geom = NULL;
2351 const LWPOINT *end_node_geom = NULL;
2365 lwerror(
"SQL/MM Spatial exception - curve not simple");
2372 newedge.
geom = geom;
2381 lwerror(
"Invalid edge (no two distinct vertices exist)");
2394 lwerror(
"Invalid edge (no two distinct vertices exist)");
2399 lwerror(
"error computing azimuth of first edgeend [%.15g %.15g,%.15g %.15g]",
2400 p1.
x, p1.
y, pn.
x, pn.
y);
2403 LWDEBUGF(1,
"edge's start node is %g,%g", p1.
x, p1.
y);
2411 lwerror(
"Invalid clean edge (no two distinct vertices exist) - should not happen");
2416 lwerror(
"error computing azimuth of last edgeend [%.15g %.15g,%.15g %.15g]",
2417 p2.
x, p2.
y, pn.
x, pn.
y);
2420 LWDEBUGF(1,
"edge's end node is %g,%g", p2.
x, p2.
y);
2427 if ( start_node != end_node ) {
2429 node_ids[0] = start_node;
2430 node_ids[1] = end_node;
2433 node_ids[0] = start_node;
2437 if ( num_nodes < 0 ) {
2441 for ( i=0; i<num_nodes; ++i )
2453 lwerror(
"SQL/MM Spatial exception - geometry crosses an edge" 2459 LWDEBUGF(1,
"Node %d, with geom %p (looking for %d and %d)",
2461 if ( node->
node_id == start_node ) {
2462 start_node_geom = node->
geom;
2464 if ( node->
node_id == end_node ) {
2465 end_node_geom = node->
geom;
2471 if ( ! start_node_geom )
2474 lwerror(
"SQL/MM Spatial exception - non-existent node");
2479 pa = start_node_geom->
point;
2484 lwerror(
"SQL/MM Spatial exception" 2485 " - start node not geometry start point." 2492 if ( ! end_node_geom )
2495 lwerror(
"SQL/MM Spatial exception - non-existent node");
2500 pa = end_node_geom->
point;
2505 lwerror(
"SQL/MM Spatial exception" 2506 " - end node not geometry end point." 2525 if ( newedge.
edge_id == -1 ) {
2531 int isclosed = start_node == end_node;
2534 isclosed ? &epan : NULL, -1 );
2539 LWDEBUGF(1,
"New edge %d is connected on start node, " 2540 "next_right is %d, prev_left is %d",
2552 LWDEBUGF(1,
"New edge %d is isolated on start node, " 2553 "next_right is %d, prev_left is %d",
2558 isclosed ? &span : NULL, -1 );
2563 LWDEBUGF(1,
"New edge %d is connected on end node, " 2564 "next_left is %d, prev_right is %d",
2570 lwerror(
"Side-location conflict: " 2571 "new edge starts in face" 2582 lwerror(
"Side-location conflict: " 2583 "new edge starts in face" 2594 LWDEBUGF(1,
"New edge %d is isolated on end node, " 2595 "next_left is %d, prev_right is %d",
2607 "faces mismatch: invalid topology ?",
2613 lwerror(
"Could not derive edge face from linked primitives:" 2614 " invalid topology ?");
2626 }
else if ( ret == 0 ) {
2627 lwerror(
"Insertion of split edge failed (no reason)");
2635 if ( llabs(prev_left) != newedge.
edge_id )
2637 if ( prev_left > 0 )
2654 &updedge, updfields,
2664 if ( llabs(prev_right) != newedge.
edge_id )
2666 if ( prev_right > 0 )
2678 seledge.
edge_id = -prev_right;
2683 &updedge, updfields,
2727 LWDEBUG(1,
"New edge is dangling, so it cannot split any face");
2739 if ( newface1 == 0 ) {
2740 LWDEBUG(1,
"New edge does not split any face");
2749 if ( newface == 0 ) {
2750 LWDEBUG(1,
"New edge does not split any face");
2760 if ( newface < 0 )
return newedge.
edge_id;
2797 LWLINE *geom,
int skipChecks )
2799 return _lwt_AddEdge( topo, start_node, end_node, geom, skipChecks, 1 );
2805 LWLINE *geom,
int skipChecks )
2807 return _lwt_AddEdge( topo, start_node, end_node, geom, skipChecks, 0 );
2816 int i, validedges = 0;
2818 for ( i=0; i<numfaceedges; ++i )
2832 if ( numfaceedges )
lwfree(geoms);
2833 LWDEBUG(1,
"_lwt_FaceByEdges returning empty polygon");
2850 LWDEBUGF(1,
"_lwt_FaceByEdges returning area: %s", wkt);
2870 lwerror(
"SQL/MM Spatial exception - universal face has no geometry");
2881 if ( numfaceedges == -1 ) {
2886 if ( numfaceedges == 0 )
2895 lwerror(
"SQL/MM Spatial exception - non-existent face.");
2900 lwerror(
"Corrupted topology: multiple face records have face_id=%" 2940 LWDEBUGF(1,
"Ring's 'from' point (%d) is %g,%g", from, p1.
x, p1.
y);
2944 for ( i=0; i<numedges; ++i )
2958 ") on both sides, skipping",
2975 LWDEBUGF(1,
"Rings's 'from' point is still %g,%g", p1.
x, p1.
y);
2978 LWDEBUG(1,
"p2d_same(p1,p2) returned true");
2980 " matches ring vertex %d", isoe->
edge_id, from);
2982 for ( j=1; j<epa->
npoints; ++j )
2988 if (
p2d_same(&p1, &p2) )
continue;
2991 LWDEBUGF(1,
"Ring's point %d is %g,%g",
2992 from+1, pt.
x, pt.
y);
2996 #if POSTGIS_DEBUG_LEVEL > 0 2999 " matches ring vertex %d", isoe->
edge_id, from+1);
3002 " does not match ring vertex %d", isoe->
edge_id, from+1);
3017 " matches ring vertex %d", isoe->
edge_id, from);
3019 for ( j=epa->
npoints-2; j>=0; --j )
3025 if (
p2d_same(&p1, &p2) )
continue;
3028 LWDEBUGF(1,
"Ring's point %d is %g,%g",
3029 from+1, pt.
x, pt.
y);
3034 #if POSTGIS_DEBUG_LEVEL > 0 3037 " matches ring vertex %d", isoe->
edge_id, from+1);
3040 " does not match ring vertex %d", isoe->
edge_id, from+1);
3045 if ( match )
return i;
3061 ary[from++] = ary[to];
3098 if ( numfaceedges == -1 ) {
3102 if ( ! numfaceedges )
return 0;
3146 nseid = prevseid = 0;
3150 for ( i=0; i<facepoly->
nrings; ++i )
3159 while ( j < ring->npoints-1 )
3161 LWDEBUGF(1,
"Looking for edge covering ring %d from vertex %d",
3171 lwerror(
"No edge (among %d) found to be defining geometry of face %" 3176 nextedge = &(edges[edgeno]);
3177 nextline = nextedge->
geom;
3180 " covers ring %d from vertex %d to %d",
3196 seid[nseid++] = nextedge->
face_left == face_id ?
3207 if ( (nseid - prevseid) > 1 )
3211 LWDEBUGF(1,
"Looking for smallest id among the %d edges " 3212 "composing ring %d", (nseid-prevseid), i);
3213 for ( j=prevseid; j<nseid; ++j )
3217 if ( ! minid ||
id < minid )
3224 " at position %d", minid, minidx);
3225 if ( minidx != prevseid )
3241 static GEOSGeometry *
3272 lwerror(
"Could not append point to pointarray");
3282 lwerror(
"Could not make edge motion area valid");
3290 lwerror(
"Could not convert old edge area geometry to GEOS: %s",
3309 lwerror(
"SQL/MM Spatial exception - curve not simple");
3318 "lwt_be_getEdgeById returned NULL and set i=%d", i);
3326 lwerror(
"SQL/MM Spatial exception - non-existent edge %" 3332 lwerror(
"Backend coding error: getEdgeById callback returned NULL " 3333 "but numelements output parameter has value %d " 3334 "(expected 0 or 1)", i);
3340 "old edge has %d points, new edge has %d points",
3351 lwerror(
"SQL/MM Spatial exception - " 3352 "start node not geometry start point.");
3363 " has less than 2 vertices", oldedge->
edge_id);
3370 lwerror(
"Invalid edge: less than 2 vertices");
3377 lwerror(
"SQL/MM Spatial exception - " 3378 "end node not geometry end point.");
3394 lwerror(
"Invalid edge (no two distinct vertices exist)");
3403 lwerror(
"Edge twist at node POINT(%g %g)", p1.
x, p1.
y);
3409 oldedge->
end_node, geom, edge_id ) )
3416 LWDEBUG(1,
"lwt_ChangeEdgeGeom: " 3417 "edge crossing check passed ");
3435 LWDEBUGF(1,
"lwt_be_getNodeWithinBox2D returned %d nodes", numnodes);
3436 if ( numnodes == -1 ) {
3442 if ( numnodes > ( 1 + isclosed ? 0 : 1 ) )
3444 GEOSGeometry *oarea, *narea;
3445 const GEOSPreparedGeometry *oareap, *nareap;
3453 lwerror(
"Could not compute edge motion area for old edge");
3460 GEOSGeom_destroy(oarea);
3462 lwerror(
"Could not compute edge motion area for new edge");
3467 oareap = GEOSPrepare( oarea );
3468 nareap = GEOSPrepare( narea );
3469 for (i=0; i<numnodes; ++i)
3479 ocont = GEOSPreparedContains( oareap, ngg );
3480 ncont = GEOSPreparedContains( nareap, ngg );
3481 GEOSGeom_destroy(ngg);
3482 if (ocont == 2 || ncont == 2)
3485 GEOSPreparedGeom_destroy(oareap);
3486 GEOSGeom_destroy(oarea);
3487 GEOSPreparedGeom_destroy(nareap);
3488 GEOSGeom_destroy(narea);
3494 GEOSPreparedGeom_destroy(oareap);
3495 GEOSGeom_destroy(oarea);
3496 GEOSPreparedGeom_destroy(nareap);
3497 GEOSGeom_destroy(narea);
3500 lwerror(
"Edge motion collision at %s", wkt);
3505 GEOSPreparedGeom_destroy(oareap);
3506 GEOSGeom_destroy(oarea);
3507 GEOSPreparedGeom_destroy(nareap);
3508 GEOSGeom_destroy(narea);
3512 LWDEBUG(1,
"nodes containment check passed");
3522 oldedge->
geom, &p1, &p2);
3525 isclosed ? &epan_pre : NULL, edge_id );
3527 isclosed ? &span_pre : NULL, edge_id );
3537 newedge.
geom = geom;
3548 lwerror(
"Unexpected error: %d edges updated when expecting 1", i);
3563 isclosed ? &epan_post : NULL, edge_id );
3565 isclosed ? &span_post : NULL, edge_id );
3567 LWDEBUGF(1,
"edges adjacent to new edge are %" LWTFMT_ELEMID
3568 " and %" LWTFMT_ELEMID
" (first point), %" LWTFMT_ELEMID
3569 " and %" LWTFMT_ELEMID
" (last point)",
3580 lwerror(
"Edge changed disposition around start node %" 3581 LWTFMT_ELEMID, nid);
3591 lwerror(
"Edge changed disposition around end node %" 3592 LWTFMT_ELEMID, nid);
3604 int facestoupdate = 0;
3613 lwerror(
"lwt_ChangeEdgeGeom could not construct face %" 3614 LWTFMT_ELEMID
", on the left of edge %" LWTFMT_ELEMID,
3622 LWDEBUGF(1,
"new geometry of face left (%d): %s", (
int)oldedge->
face_left, wkt);
3629 faces[facestoupdate++].
mbr = nface1->
bbox;
3638 lwerror(
"lwt_ChangeEdgeGeom could not construct face %" 3639 LWTFMT_ELEMID
", on the right of edge %" LWTFMT_ELEMID,
3653 faces[facestoupdate++].
mbr = nface2->
bbox;
3655 LWDEBUGF(1,
"%d faces to update", facestoupdate);
3656 if ( facestoupdate )
3659 if ( i != facestoupdate )
3667 lwerror(
"Unexpected error: %d faces found when expecting 1", i);
3674 LWDEBUG(1,
"all done, cleaning up edges");
3693 lwerror(
"SQL/MM Spatial exception - non-existent node");
3699 lwerror(
"SQL/MM Spatial exception - not isolated node");
3713 if ( ! node )
return -1;
3718 lwerror(
"SQL/MM Spatial exception - coincident node");
3725 lwerror(
"SQL/MM Spatial exception - edge crosses node.");
3754 if ( ! node )
return -1;
3766 lwerror(
"Unexpected error: %d nodes deleted when expecting 1", n);
3800 lwerror(
"SQL/MM Spatial exception - non-existent edge");
3806 lwerror(
"Corrupted topology: more than a single edge have id %" 3811 if ( edge[0].face_left != edge[0].face_right )
3814 lwerror(
"SQL/MM Spatial exception - not isolated edge");
3830 for ( i=0; i<n; ++i )
3832 if ( edge[i].edge_id ==
id )
continue;
3834 lwerror(
"SQL/MM Spatial exception - not isolated edge");
3837 if ( edge )
lwfree(edge);
3848 lwerror(
"Unexpected error: %d edges deleted when expecting 1", n);
3855 if ( nid[1] != nid[0] ) {
3895 if ( ret == -1 )
return -1;
3903 if ( ret == -1 )
return -1;
3928 if ( ret == -1 )
return -1;
3942 int i, nedges, nfaces, fields;
3948 int nedge_right = 0;
3955 int fnode_edges = 0;
3957 int lnode_edges = 0;
3966 LWDEBUGF(1,
"lwt_be_getEdgeById returned NULL and set i=%d", i);
3974 lwerror(
"SQL/MM Spatial exception - non-existent edge %" 3980 lwerror(
"Backend coding error: getEdgeById callback returned NULL " 3981 "but numelements output parameter has value %d " 3982 "(expected 0 or 1)", i);
3994 LWDEBUG(1,
"Updating next_{right,left}_face of ring edges...");
4002 node_ids[nedges++] = edge->
end_node;
4008 if ( nedges == -1 ) {
4012 nedge_left = nedge_right = 0;
4013 for ( i=0; i<nedges; ++i )
4016 if ( e->
edge_id == edge_id )
continue;
4054 LWDEBUGF(1,
"updating %d 'next_left' edges", nedge_left);
4068 LWDEBUGF(1,
"updating %d 'next_right' edges", nedge_right);
4080 LWDEBUGF(1,
"releasing %d updateable edges in %p", nedges, upd_edge);
4098 LWDEBUG(1,
"floodface is universe");
4112 if ( nfaces == -1 ) {
4118 for ( i=0; i<nfaces; ++i )
4120 if ( faces[i].face_id == edge->
face_left )
4122 if ( ! box1 ) box1 = faces[i].
mbr;
4128 lwerror(
"corrupted topology: more than 1 face have face_id=%" 4133 else if ( faces[i].face_id == edge->
face_right )
4135 if ( ! box2 ) box2 = faces[i].
mbr;
4141 lwerror(
"corrupted topology: more than 1 face have face_id=%" 4151 lwerror(
"Backend coding error: getFaceById returned face " 4160 lwerror(
"corrupted topology: no face have face_id=%" 4169 lwerror(
"corrupted topology: no face have face_id=%" 4190 lwerror(
"Unexpected error: %d faces updated when expecting 1", i);
4209 lwerror(
"Unexpected error: %d faces inserted when expecting 1", i);
4273 if ( ! fnode_edges )
4314 return modFace ? floodface : newface.
face_id;
4344 int e2sign, e2freenode;
4348 size_t bufleft = 256;
4356 " with itself, try with another", eid1);
4368 for ( i=0; i<nedges; ++i )
4370 if ( edges[i].edge_id == eid1 ) {
4373 lwerror(
"Corrupted topology: multiple edges have id %" 4379 else if ( edges[i].edge_id == eid2 ) {
4382 lwerror(
"Corrupted topology: multiple edges have id %" 4392 lwerror(
"SQL/MM Spatial exception - non-existent edge %" 4399 lwerror(
"SQL/MM Spatial exception - non-existent edge %" 4433 if ( commonnode != -1 )
4438 if ( num_node_edges == -1 ) {
4443 for (i=0; i<num_node_edges; ++i)
4446 if ( node_edges[i].edge_id == eid1 )
continue;
4447 if ( node_edges[i].edge_id == eid2 )
continue;
4452 ( ptr==buf ?
"" :
"," ), node_edges[i].edge_id);
4471 if ( commonnode == -1 )
4484 if ( commonnode != -1 )
4489 if ( num_node_edges == -1 ) {
4494 for (i=0; i<num_node_edges; ++i)
4497 if ( node_edges[i].edge_id == eid1 )
continue;
4498 if ( node_edges[i].edge_id == eid2 )
continue;
4503 ( ptr==buf ?
"" :
"," ), node_edges[i].edge_id);
4519 if ( num_node_edges )
lwfree(node_edges);
4523 if ( commonnode == -1 )
4528 lwerror(
"SQL/MM Spatial exception - other edges connected (%s)",
4533 lwerror(
"SQL/MM Spatial exception - non-connected edges");
4610 lwerror(
"Coding error: caseno=%d should never happen", caseno);
4636 lwerror(
"Unexpected error: %d edges updated when expecting 1", i);
4652 }
else if ( i == 0 ) {
4655 lwerror(
"Insertion of split edge failed (no reason)");
4767 eid1, eid2, newedge.
edge_id) )
4773 return modEdge ? commonnode : newedge.
edge_id;
4813 lwerror(
"Two or more nodes found");
4843 for (i=0; i<num;++i)
4854 " has null geometry", e->
edge_id);
4862 if ( dist > tol )
continue;
4868 lwerror(
"Two or more edges found");
4903 LWDEBUG(1,
"No face properly contains query point," 4904 " looking for edges");
4916 for (i=0; i<num; ++i)
4927 " has null geometry", e->
edge_id);
4935 " is dangling, won't consider it", e->
edge_id);
4943 " is %g (tol=%g)", e->
edge_id, dist, tol);
4946 if ( dist > tol )
continue;
4955 lwerror(
"Two or more faces found");
4959 if (
id &&
id != eface )
4962 lwerror(
"Two or more faces found" 4988 if ( ! gbox )
return 0;
4994 ret = 3.6 * pow(10, - ( 15 - log10(max?max:1.0) ) );
4999 #define _LWT_MINTOLERANCE( topo, geom ) ( \ 5000 topo->precision ? topo->precision : _lwt_minTolerance(geom) ) 5024 double mindist = FLT_MAX;
5051 LWDEBUGF(1,
"New point is within %.15g units of %d nodes", tol, num);
5056 for (i=0; i<num; ++i)
5058 sorted[i].
ptr = nodes+i;
5061 ((
LWT_ISO_NODE*)(sorted[i].ptr))->node_id, sorted[i].score);
5065 for (i=0; i<num; ++i)
5074 for ( i=0; i<num; ++i )
5080 if ( dist >= tol )
continue;
5081 if ( !
id || dist < mindist )
5111 LWDEBUGF(1,
"New point is within %.15g units of %d edges", tol, num);
5118 for (i=0; i<num; ++i)
5120 sorted[i].
ptr = edges+i;
5123 ((
LWT_ISO_EDGE*)(sorted[i].ptr))->edge_id, sorted[i].score);
5127 for (j=0, i=0; i<num; ++i)
5129 if ( sorted[i].score == sorted[0].score )
5144 for (i=0; i<num; ++i)
5151 GEOSGeometry *prjg, *gg;
5190 GEOSGeom_destroy(prjg);
5194 contains = GEOSContains(gg, prjg);
5195 GEOSGeom_destroy(prjg);
5196 GEOSGeom_destroy(gg);
5197 if ( contains == 2 )
5212 " does not contain projected point to it",
5219 LWDEBUG(1,
"But there's another to check");
5234 LWDEBUGF(1,
"Edge snapped with tolerance %g", snaptol);
5237 #if POSTGIS_DEBUG_LEVEL > 0 5242 LWDEBUGF(1,
"Edge %s snapped became %s", wkt1, wkt2);
5255 LWDEBUGF(1,
"Edge first point is %g %g, " 5256 "snapline first point is %g %g",
5257 p1.
x, p1.
y, p2.
x, p2.
y);
5258 if ( p1.
x != p2.
x || p1.
y != p2.
y )
5260 LWDEBUG(1,
"Snapping moved first point, re-adding it");
5269 #if POSTGIS_DEBUG_LEVEL > 0 5273 LWDEBUGF(1,
"Tweaked snapline became %s", wkt1);
5278 #if POSTGIS_DEBUG_LEVEL > 0 5280 LWDEBUG(1,
"Snapping did not move first point");
5290 lwerror(
"lwt_ChangeEdgeGeom failed");
5295 #if POSTGIS_DEBUG_LEVEL > 0 5301 LWDEBUGF(1,
"Edge %s contains projected point %s", wkt1, wkt2);
5314 lwerror(
"lwt_ModEdgeSplit failed");
5345 lwerror(
"lwt_AddIsoNode failed");
5363 GEOSGeometry *edgeg;
5383 for (i=0; i<num; ++i)
5392 GEOSGeom_destroy(edgeg);
5397 equals = GEOSEquals(gg, edgeg);
5398 GEOSGeom_destroy(gg);
5401 GEOSGeom_destroy(edgeg);
5409 GEOSGeom_destroy(edgeg);
5414 GEOSGeom_destroy(edgeg);
5429 LWPOINT *start_point, *end_point;
5438 LWDEBUGF(1,
"_lwtAddLineEdge with tolerance %g", tol);
5441 if ( ! start_point )
5443 lwnotice(
"Empty component of noded line");
5448 if ( nid[0] == -1 )
return -1;
5453 lwerror(
"could not get last point of line " 5454 "after successfully getting first point !?");
5459 if ( nid[1] == -1 )
return -1;
5466 nn = nid[0] == nid[1] ? 1 : 2;
5474 start_point = NULL; end_point = NULL;
5475 for (i=0; i<nn; ++i)
5477 if ( node[i].node_id == nid[0] ) start_point = node[i].
geom;
5478 if ( node[i].node_id == nid[1] ) end_point = node[i].
geom;
5480 if ( ! start_point || ! end_point )
5512 LWDEBUG(1,
"Made-valid snapped edge collapsed");
5524 lwerror(
"lwcollection_extract(LINETYPE) returned a non-line?");
5533 LWDEBUGF(1,
"Made-valid snapped edge collapsed to %s",
5561 LWDEBUGG(1, tmp2,
"Repeated-point removed");
5605 if ( ! col->
ngeoms )
return bg;
5607 for (i=0; i<col->
ngeoms; ++i)
5638 LWDEBUGF(1,
"Working tolerance:%.15g", tol);
5646 LWDEBUGG(1, tmp,
"Repeated-point removed");
5647 }}
else tmp=(
LWGEOM*)line;
5652 if ( ! noded )
return NULL;
5659 LWDEBUGF(1,
"BOX expanded by %g is %.15g %.15g, %.15g %.15g",
5670 LWDEBUGF(1,
"Line has %d points, its bbox intersects %d edges bboxes", line->points->npoints, num);
5676 for (i=0; i<num; ++i)
5683 if ( dist >= tol )
continue;
5686 LWDEBUGF(2,
"Found %d lines closer than tolerance (%g)", nn, tol);
5694 LWDEBUGF(1,
"Line intersects %d edges", nn);
5699 LWDEBUGG(1, iedges,
"Collected edges");
5700 LWDEBUGF(1,
"Snapping noded, with srid=%d " 5701 "to interesecting edges, with srid=%d",
5706 LWDEBUGF(1,
"Diffing snapped, with srid=%d " 5707 "and interesecting edges, with srid=%d",
5711 LWDEBUGF(1,
"Intersecting snapped, with srid=%d " 5712 "and interesecting edges, with srid=%d",
5717 LWDEBUGF(1,
"Linemerging set1, with srid=%d", set1->
srid);
5722 LWDEBUGF(1,
"Unioning noded, with srid=%d " 5723 "and set2, with srid=%d", noded->
srid, set2->
srid);
5746 LWDEBUGF(1,
"Line bbox intersects %d nodes bboxes", num);
5752 for (i=0; i<num; ++i)
5757 if ( dist >= tol )
continue;
5766 LWDEBUGF(1,
"Line intersects %d nodes", nn);
5772 LWDEBUGG(1, inodes,
"Collected nodes");
5779 LWDEBUGG(1, noded,
"Node-snapped");
5798 LWDEBUGG(1, noded,
"Unary-unioned");
5805 LWDEBUGG(1, noded,
"Finally-noded");
5811 LWDEBUG(1,
"Noded line was a collection");
5817 LWDEBUG(1,
"Noded line was a single geom");
5818 geomsbuf[0] = noded;
5823 LWDEBUGF(1,
"Line was split into %d edges", ngeoms);
5831 for ( i=0; i<ngeoms; ++i )
5837 #if POSTGIS_DEBUG_LEVEL > 0 5841 LWDEBUGF(1,
"Component %d of split line is: %s", i, wkt1);
5856 LWDEBUGF(1,
"Component %d of split line collapsed", i);
5865 LWDEBUGG(1, noded,
"Noded before free");
5884 const GEOSPreparedGeometry *ppoly;
5885 GEOSGeometry *polyg;
5889 LWDEBUGF(1,
"Working tolerance:%.15g", tol);
5892 for ( i=0; i<poly->nrings; ++i )
5905 lwerror(
"Error adding ring %d of polygon", i);
5920 if ( nfacesinbox == -1 )
5937 ppoly = GEOSPrepare(polyg);
5939 for ( i=0; i<nfacesinbox; ++i )
5943 GEOSGeometry *fgg, *sp;
5951 GEOSPreparedGeom_destroy(ppoly);
5952 GEOSGeom_destroy(polyg);
5963 GEOSPreparedGeom_destroy(ppoly);
5964 GEOSGeom_destroy(polyg);
5969 sp = GEOSPointOnSurface(fgg);
5970 GEOSGeom_destroy(fgg);
5973 GEOSPreparedGeom_destroy(ppoly);
5974 GEOSGeom_destroy(polyg);
5979 covers = GEOSPreparedCovers( ppoly, sp );
5980 GEOSGeom_destroy(sp);
5983 GEOSPreparedGeom_destroy(ppoly);
5984 GEOSGeom_destroy(polyg);
5997 GEOSPreparedGeom_destroy(ppoly);
5998 GEOSGeom_destroy(polyg);
static int _lwt_CheckEdgeCrossing(LWT_TOPOLOGY *topo, LWT_ELEMID start_node, LWT_ELEMID end_node, const LWLINE *geom, LWT_ELEMID myself)
void ptarray_set_point4d(POINTARRAY *pa, int n, const POINT4D *p4d)
static LWT_ELEMID _lwt_GetEqualEdge(LWT_TOPOLOGY *topo, LWLINE *edge)
static void _lwt_release_nodes(LWT_ISO_NODE *nodes, int num_nodes)
static int _lwt_GetInteriorEdgePoint(const LWLINE *edge, POINT2D *ip)
static LWT_ISO_FACE * lwt_be_getFaceById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
int lwt_ChangeEdgeGeom(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, LWLINE *geom)
Changes the shape of an edge without affecting the topology structure.
static void _lwt_ReverseElemidArray(LWT_ELEMID *ary, int from, int to)
#define LWT_COL_NODE_CONTAINING_FACE
LWT_ELEMID lwt_AddPoint(LWT_TOPOLOGY *topo, LWPOINT *point, double tol)
Adds a point to the topology.
static int lwt_be_insertFaces(LWT_TOPOLOGY *topo, LWT_ISO_FACE *face, int numelems)
LWT_TOPOLOGY * lwt_LoadTopology(LWT_BE_IFACE *iface, const char *name)
Loads an existing topology by name from the database.
LWT_BE_IFACE * lwt_CreateBackendIface(const LWT_BE_DATA *data)
Create a new backend interface.
LWT_ELEMID lwt_RemEdgeModFace(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id)
Remove an edge, possibly merging two faces (replacing one with the other)
static int lwt_be_topoGetSRID(LWT_TOPOLOGY *topo)
#define LWT_COL_EDGE_FACE_LEFT
LWT_ELEMID containing_face
LWT_ELEMID lwt_NewEdgeHeal(LWT_TOPOLOGY *topo, LWT_ELEMID e1, LWT_ELEMID e2)
Merge two edges, replacing both with a new one.
#define CBT4(to, method, a1, a2, a3, a4)
#define LWT_COL_FACE_FACE_ID
Face fields.
LWGEOM * lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
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)
Datum covers(PG_FUNCTION_ARGS)
LWT_ELEMID lwt_GetNodeByPoint(LWT_TOPOLOGY *topo, LWPOINT *pt, double tol)
Retrieve the id of a node at a point location.
LWCOLLECTION * lwcollection_extract(LWCOLLECTION *col, int type)
Takes a potentially heterogeneous collection and returns a homogeneous collection consisting only of ...
static int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
LWCOLLECTION * lwcollection_construct(uint8_t type, int srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
static int lwt_be_updateTopoGeomEdgeHeal(LWT_TOPOLOGY *topo, LWT_ELEMID edge1, LWT_ELEMID edge2, LWT_ELEMID newedge)
static LWT_ELEMID _lwt_RemEdge(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, int modFace)
double lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
static int _lwt_UpdateNodeFaceRef(LWT_TOPOLOGY *topo, LWT_ELEMID of, LWT_ELEMID nf)
int lwt_be_ExistsEdgeIntersectingPoint(LWT_TOPOLOGY *topo, LWPOINT *pt)
#define LWT_COL_EDGE_FACE_RIGHT
LWT_ELEMID lwt_GetEdgeByPoint(LWT_TOPOLOGY *topo, LWPOINT *pt, double tol)
Find the edge-id of an edge that intersects a given point.
LWPOINT * lwpoint_make2d(int srid, double x, double y)
int lwt_GetFaceEdges(LWT_TOPOLOGY *topo, LWT_ELEMID face_id, LWT_ELEMID **out)
Return the list of directed edges bounding a face.
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom)
int lwt_be_insertNodes(LWT_TOPOLOGY *topo, LWT_ISO_NODE *node, int numelems)
void lwpoint_free(LWPOINT *pt)
void lwgeom_free(LWGEOM *geom)
void ptarray_free(POINTARRAY *pa)
struct scored_pointer_t scored_pointer
int lwt_be_deleteEdges(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *sel_edge, int sel_fields)
static int _lwt_FirstDistinctVertex2D(const POINTARRAY *pa, POINT2D *ref, int from, int dir, POINT2D *op)
static int compare_scored_pointer(const void *si1, const void *si2)
LWT_ISO_NODE * lwt_be_getNodeWithinDistance2D(LWT_TOPOLOGY *topo, LWPOINT *pt, double dist, int *numelems, int fields, int limit)
void lwline_free(LWLINE *line)
Datum contains(PG_FUNCTION_ARGS)
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
static int lwt_be_updateTopoGeomFaceSplit(LWT_TOPOLOGY *topo, LWT_ELEMID split_face, LWT_ELEMID new_face1, LWT_ELEMID new_face2)
#define LWT_COL_EDGE_START_NODE
#define LWDEBUG(level, msg)
#define LW_ON_INTERRUPT(x)
int lwt_be_freeTopology(LWT_TOPOLOGY *topo)
static int lwt_be_checkTopoGeomRemNode(LWT_TOPOLOGY *topo, LWT_ELEMID node_id, LWT_ELEMID eid1, LWT_ELEMID eid2)
const LWT_BE_CALLBACKS * cb
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
static LWT_ELEMID _lwt_AddFaceSplit(LWT_TOPOLOGY *topo, LWT_ELEMID sedge, LWT_ELEMID face, int mbr_only)
LWT_ISO_EDGE * lwt_be_getEdgeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
#define _LWT_MINTOLERANCE(topo, geom)
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
void lwline_setPoint4d(LWLINE *line, uint32_t which, POINT4D *newpoint)
static double lwt_be_topoGetPrecision(LWT_TOPOLOGY *topo)
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 LWT_ELEMID _lwt_AddLineEdge(LWT_TOPOLOGY *topo, LWLINE *edge, double tol)
#define CBT1(to, method, a1)
static LWCOLLECTION * _lwt_EdgeSplit(LWT_TOPOLOGY *topo, LWT_ELEMID edge, LWPOINT *pt, int skipISOChecks, LWT_ISO_EDGE **oldedge)
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.
void lwt_FreeTopology(LWT_TOPOLOGY *topo)
Release memory associated with an LWT_TOPOLOGY.
static LWT_ISO_EDGE * lwt_be_getEdgeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields, const GBOX *box)
struct LWT_BE_DATA_T LWT_BE_DATA
Backend private data pointer.
int p2d_same(const POINT2D *p1, const POINT2D *p2)
void lwt_FreeBackendIface(LWT_BE_IFACE *iface)
Release memory associated with an LWT_BE_IFACE.
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
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.
int ptarray_isccw(const POINTARRAY *pa)
static int lwt_be_updateFacesById(LWT_TOPOLOGY *topo, const LWT_ISO_FACE *faces, int numfaces)
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
void lwt_BackendIfaceRegisterCallbacks(LWT_BE_IFACE *iface, const LWT_BE_CALLBACKS *cb)
Register backend callbacks into the opaque iface handler.
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)
int lwt_RemIsoEdge(LWT_TOPOLOGY *topo, LWT_ELEMID id)
Remove an isolated edge.
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE, then a duplicate point will not be added.
static LWGEOM * _lwt_FaceByEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edges, int numfaceedges)
LWGEOM * lwgeom_make_valid(LWGEOM *geom)
Attempts to make an invalid geometries valid w/out losing points.
void lwgeom_geos_error(const char *fmt,...)
LWGEOM * lwgeom_node(const LWGEOM *lwgeom_in)
static LWT_ELEMID _lwt_AddEdge(LWT_TOPOLOGY *topo, LWT_ELEMID start_node, LWT_ELEMID end_node, LWLINE *geom, int skipChecks, int modFace)
static int lwt_be_deleteNodesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int numelems)
LWPOLY * lwpoly_construct(int srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
LWT_ELEMID * lwt_AddPolygon(LWT_TOPOLOGY *topo, LWPOLY *poly, double tol, int *nfaces)
Adds a polygon to the topology.
void lwpoly_free(LWPOLY *poly)
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.
#define LW_TRUE
Return types for functions with status returns.
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
#define CBT6(to, method, a1, a2, a3, a4, a5, a6)
const LWT_BE_IFACE * be_iface
#define CBT5(to, method, a1, a2, a3, a4, a5)
LWGEOM * lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2)
static double _lwt_minTolerance(LWGEOM *g)
#define LWT_COL_EDGE_END_NODE
static int lwt_be_updateTopoGeomFaceHeal(LWT_TOPOLOGY *topo, LWT_ELEMID face1, LWT_ELEMID face2, LWT_ELEMID newface)
static LWT_ISO_NODE * lwt_be_getNodeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields, const GBOX *box)
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance)
Append a POINTARRAY, pa2 to the end of an existing POINTARRAY, pa1.
static GEOSGeometry * _lwt_EdgeMotionArea(LWLINE *geom, int isclosed)
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
static LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, int *numelems, int fields, int limit)
int lwt_be_ExistsCoincidentNode(LWT_TOPOLOGY *topo, LWPOINT *pt)
LWGEOM * lwgeom_difference(const LWGEOM *geom1, const LWGEOM *geom2)
int ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, int where)
Insert a point into an existing POINTARRAY.
int getPoint2d_p(const POINTARRAY *pa, int n, POINT2D *point)
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, int autofix)
#define CBT3(to, method, a1, a2, a3)
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_be_deleteFacesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int numelems)
int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout)
Update the output GBOX to be large enough to include both inputs.
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
static LWT_ELEMID * lwt_be_getRingEdges(LWT_TOPOLOGY *topo, LWT_ELEMID edge, int *numedges, int limit)
LWT_ELEMID lwt_AddIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID face, LWPOINT *pt, int skipISOChecks)
Add an isolated node.
static int lwt_be_updateNodesById(LWT_TOPOLOGY *topo, const LWT_ISO_NODE *nodes, int numnodes, int upd_fields)
LWT_BE_TOPOLOGY * be_topo
#define LWDEBUGG(level, geom, msg)
static LWT_ELEMID _lwt_HealEdges(LWT_TOPOLOGY *topo, LWT_ELEMID eid1, LWT_ELEMID eid2, int modEdge)
LWGEOM * lwgeom_snap(const LWGEOM *geom1, const LWGEOM *geom2, double tolerance)
Snap vertices and segments of a geometry to another using a given tolerance.
LWT_ELEMID lwt_be_getNextEdgeId(LWT_TOPOLOGY *topo)
#define LWT_COL_EDGE_EDGE_ID
Edge fields.
static void _lwt_RotateElemidArray(LWT_ELEMID *ary, int from, int to, int rotidx)
void lwcollection_release(LWCOLLECTION *lwcollection)
static LWT_ISO_NODE * _lwt_GetIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID nid)
#define LWT_COL_NODE_NODE_ID
Node fields.
LWGEOM * lwline_remove_repeated_points(const LWLINE *in, double tolerance)
struct LWT_BE_TOPOLOGY_T LWT_BE_TOPOLOGY
Topology handler.
LWT_ELEMID lwt_GetFaceByPoint(LWT_TOPOLOGY *topo, LWPOINT *pt, double tol)
Find the face-id of a face containing a given point.
void lwgeom_reverse(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
#define LWT_COL_EDGE_NEXT_LEFT
LWGEOM * lwgeom_buildarea(const LWGEOM *geom)
Take a geometry and return an areal geometry (Polygon or MultiPolygon).
Structure containing base backend callbacks.
static int _lwt_FindAdjacentEdges(LWT_TOPOLOGY *topo, LWT_ELEMID node, edgeend *data, edgeend *other, int myedge_id)
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
int lwt_be_insertEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, int numelems)
LWGEOM * lwgeom_unaryunion(const LWGEOM *geom1)
static int _lwt_UpdateEdgeFaceRef(LWT_TOPOLOGY *topo, LWT_ELEMID of, LWT_ELEMID nf)
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
#define LWT_COL_EDGE_NEXT_RIGHT
LWT_ELEMID lwt_RemEdgeNewFace(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id)
Remove an edge, possibly merging two faces (replacing both with a new one)
LWT_ELEMID lwt_ModEdgeHeal(LWT_TOPOLOGY *topo, LWT_ELEMID e1, LWT_ELEMID e2)
Merge two edges, modifying the first and deleting the second.
static LWGEOM * _lwt_split_by_nodes(const LWGEOM *g, const LWGEOM *nodes)
int lwgeom_is_simple(const LWGEOM *lwgeom)
LWPOLY * lwpoly_construct_empty(int srid, char hasz, char hasm)
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initialazing min distance calculation.
void ptarray_reverse(POINTARRAY *pa)
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)
LWT_ISO_EDGE * lwt_be_getEdgeWithinDistance2D(LWT_TOPOLOGY *topo, LWPOINT *pt, double dist, int *numelems, int fields, int limit)
LWPOINT * lwline_get_lwpoint(const LWLINE *line, int where)
Returns freshly allocated LWPOINT that corresponds to the index where.
#define LWT_COL_NODE_GEOM
void lwcollection_free(LWCOLLECTION *col)
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
LWT_INT64 LWT_ELEMID
Identifier of topology element.
LWGEOM * lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
Remove repeated points!
static LWT_ISO_EDGE * lwt_be_getEdgeByNode(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
LWT_ISO_NODE * lwt_be_getNodeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
LWGEOM * lwgeom_union(const LWGEOM *geom1, const LWGEOM *geom2)
#define LWT_COL_EDGE_GEOM
void * lwalloc(size_t size)
static int _lwt_InitEdgeEndByLine(edgeend *fee, edgeend *lee, LWLINE *edge, POINT2D *fp, POINT2D *lp)
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
static int _lwt_FindNextRingEdge(const POINTARRAY *ring, int from, const LWT_ISO_EDGE *edges, int numedges)
#define CB1(be, method, a1)
int lwgeom_count_vertices(const LWGEOM *geom)
Count the total number of vertices in any LWGEOM.
static int lwt_be_topoHasZ(LWT_TOPOLOGY *topo)
#define CBT2(to, method, a1, a2)
int azimuth_pt_pt(const POINT2D *p1, const POINT2D *p2, double *ret)
Compute the azimuth of segment AB in radians.
static LWGEOM * _lwt_toposnap(LWGEOM *src, LWGEOM *tgt, double tol)
#define LWDEBUGF(level, msg,...)
LWT_ELEMID lwt_be_getFaceContainingPoint(LWT_TOPOLOGY *topo, LWPOINT *pt)
static LWT_ISO_EDGE * lwt_be_getEdgeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, int *numelems, int fields, int limit)
int lwt_be_updateTopoGeomEdgeSplit(LWT_TOPOLOGY *topo, LWT_ELEMID split_edge, LWT_ELEMID new_edge1, LWT_ELEMID new_edge2)
static LWT_ISO_NODE * lwt_be_getNodeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, int *numelems, int fields, int limit)
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
int lwt_RemoveIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID nid)
Remove an isolated node.
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
static int lwt_be_checkTopoGeomRemEdge(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, LWT_ELEMID face_left, LWT_ELEMID face_right)
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
LWGEOM * lwgeom_linemerge(const LWGEOM *geom1)
int lwt_MoveIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID nid, LWPOINT *pt)
Move an isolated node.
LWT_BE_TOPOLOGY * lwt_be_loadTopologyByName(LWT_BE_IFACE *be, const char *name)
LWGEOM * lwgeom_split(const LWGEOM *lwgeom_in, const LWGEOM *blade_in)
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)