26#include "../postgis_config.h"
36#include "lwgeom_geos.h"
52 GEOSGeometry *surface_pt;
53 const GEOSCoordSequence *seq;
55 isect = GEOSIntersection(g1, g2);
59 surface_pt = GEOSPointOnSurface(isect);
60 GEOSGeom_destroy(isect);
64 seq = GEOSGeom_getCoordSeq(surface_pt);
67 GEOSGeom_destroy(surface_pt);
71 if (!GEOSCoordSeq_getSize(seq, &n) || !n)
73 GEOSGeom_destroy(surface_pt);
77 if (!GEOSCoordSeq_getX(seq, 0, &pt.
x) || !GEOSCoordSeq_getY(seq, 0, &pt.
y))
79 GEOSGeom_destroy(surface_pt);
83 GEOSGeom_destroy(surface_pt);
84 snprintf(buf, bufsize,
" at POINT(%.15g %.15g)", pt.
x, pt.
y);
97 snprintf(buf, bufsize,
" at POINT(%.15g %.15g)", p.
x, p.
y);
132#define CHECKCB(be, method) do { \
133 if ( ! (be)->cb || ! (be)->cb->method ) \
134 lwerror("Callback " # method " not registered by backend"); \
137#define CB0(be, method) \
138 CHECKCB(be, method);\
139 return (be)->cb->method((be)->data)
141#define CB1(be, method, a1) \
142 CHECKCB(be, method);\
143 return (be)->cb->method((be)->data, a1)
145#define CBT0(to, method) \
146 CHECKCB((to)->be_iface, method);\
147 return (to)->be_iface->cb->method((to)->be_topo)
149#define CBT1(to, method, a1) \
150 CHECKCB((to)->be_iface, method);\
151 return (to)->be_iface->cb->method((to)->be_topo, a1)
153#define CBT2(to, method, a1, a2) \
154 CHECKCB((to)->be_iface, method);\
155 return (to)->be_iface->cb->method((to)->be_topo, a1, a2)
157#define CBT3(to, method, a1, a2, a3) \
158 CHECKCB((to)->be_iface, method);\
159 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3)
161#define CBT4(to, method, a1, a2, a3, a4) \
162 CHECKCB((to)->be_iface, method);\
163 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3, a4)
165#define CBT5(to, method, a1, a2, a3, a4, a5) \
166 CHECKCB((to)->be_iface, method);\
167 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3, a4, a5)
169#define CBT6(to, method, a1, a2, a3, a4, a5, a6) \
170 CHECKCB((to)->be_iface, method);\
171 return (to)->be_iface->cb->method((to)->be_topo, a1, a2, a3, a4, a5, a6)
176 CB0(be, lastErrorMessage);
182 CB1(be, loadTopologyByName, name);
188 CBT0(topo, topoGetSRID);
194 CBT0(topo, topoGetPrecision);
200 CBT0(topo, topoHasZ);
206 CBT0(topo, freeTopology);
212 CBT3(topo, getNodeById, ids, numelems, fields);
223 CBT5(topo, getNodeWithinDistance2D, pt, dist, numelems, fields, limit);
229 CBT4(topo, getNodeWithinBox2D, box, numelems, fields, limit);
235 CBT4(topo, getEdgeWithinBox2D, box, numelems, fields, limit);
241 CBT4(topo, getFaceWithinBox2D, box, numelems, fields, limit);
247 CBT2(topo, insertNodes, node, numelems);
253 CBT2(topo, insertFaces, face, numelems);
259 CBT2(topo, deleteFacesById, ids, numelems);
265 CBT2(topo, deleteNodesById, ids, numelems);
271 CBT0(topo, getNextEdgeId);
277 CBT3(topo, getEdgeById, ids, numelems, fields);
283 CBT3(topo, getFaceById, ids, numelems, fields);
289 CBT3(topo, getEdgeByNode, ids, numelems, fields);
295 CBT4(topo, getEdgeByFace, ids, numelems, fields, box);
301 CBT4(topo, getNodeByFace, ids, numelems, fields, box);
312 CBT5(topo, getEdgeWithinDistance2D, pt, dist, numelems, fields, limit);
318 CBT2(topo, insertEdges, edge, numelems);
328 CBT6(topo, updateEdges, sel_edge, sel_fields,
329 upd_edge, upd_fields,
330 exc_edge, exc_fields);
340 CBT6(topo, updateNodes, sel_node, sel_fields,
341 upd_node, upd_fields,
342 exc_node, exc_fields);
350 CBT2(topo, updateFacesById, faces, numfaces);
358 CBT3(topo, updateEdgesById, edges, numedges, upd_fields);
366 CBT3(topo, updateNodesById, nodes, numnodes, upd_fields);
374 CBT2(topo, deleteEdges, sel_edge, sel_fields);
380 CBT3(topo, updateTopoGeomEdgeSplit, split_edge, new_edge1, new_edge2);
387 CBT3(topo, updateTopoGeomFaceSplit, split_face, new_face1, new_face2);
394 CBT3(topo, checkTopoGeomRemEdge, edge_id, face_left, face_right);
400 CBT1(topo, checkTopoGeomRemIsoEdge, edge_id);
407 CBT3(topo, checkTopoGeomRemNode, node_id, eid1, eid2);
413 CBT1(topo, checkTopoGeomRemIsoNode, node_id);
421 CBT3(topo, updateTopoGeomFaceHeal, face1, face2, newface);
429 CBT3(topo, updateTopoGeomEdgeHeal, edge1, edge2, newedge);
435 CBT3(topo, getRingEdges, edge, numedges, limit);
443 if (exists == UINT64_MAX)
456 if (exists == UINT64_MAX)
467 CBT3(topo, getClosestEdge, pt, numelems, fields);
473 CBT1(topo, computeFaceMBR, face);
501 }
while ( changed && iterations <= maxiterations );
503 LWDEBUGF(1,
"It took %d/%d iterations to properly snap",
504 iterations, maxiterations);
513 for ( i=0; i<num_faces; ++i ) {
514 if ( faces[i].mbr )
lwfree(faces[i].mbr);
523 for ( i=0; i<num_edges; ++i ) {
533 for ( i=0; i<num_nodes; ++i ) {
571 lwnotice(
"Could not release backend topology memory: %s",
587 LWPOINT* pt,
int skipISOChecks,
int checkFace )
590 char locinfo[128] =
"";
595 lwerror(
"Cannot add empty point as isolated node");
600 if ( ! skipISOChecks )
604 lwerror(
"SQL/MM Spatial exception - coincident node%s", locsuffix);
609 lwerror(
"SQL/MM Spatial exception - edge crosses node.%s", locsuffix);
614 if ( checkFace && ( face == -1 || ! skipISOChecks ) )
617 if ( foundInFace == -1 ) {
621 if ( foundInFace == -1 ) foundInFace = 0;
627 else if ( ! skipISOChecks && foundInFace != face ) {
629 lwerror(
"SQL/MM Spatial exception - within face %d (not %d)",
632 lwerror(
"SQL/MM Spatial exception - not within face");
652 LWPOINT* pt,
int skipISOChecks )
672 uint64_t i, num_nodes, num_edges;
676 GEOSGeometry *edgegg;
691 LWDEBUGF(1,
"lwt_be_getNodeWithinBox2D returned %llu nodes", num_nodes);
692 if (num_nodes == UINT64_MAX)
697 for ( i=0; i<num_nodes; ++i )
701 if (node->
node_id == start_node)
709 GEOSGeom_destroy(edgegg);
711 lwerror(
"SQL/MM Spatial exception - geometry crosses a node");
719 char locinfo[128] =
"";
720 snprintf(locinfo,
sizeof(locinfo),
" at POINT(%.15g %.15g)", p.
x, p.
y);
721 GEOSGeom_destroy(edgegg);
723 lwerror(
"SQL/MM Spatial exception - geometry crosses a node%s", locinfo);
732 LWDEBUGF(1,
"lwt_be_getEdgeWithinBox2D returned %llu edges", num_edges);
733 if (num_edges == UINT64_MAX)
735 GEOSGeom_destroy(edgegg);
739 for ( i=0; i<num_edges; ++i )
747 if ( edge_id == myself )
continue;
749 if ( ! edge->
geom ) {
757 GEOSGeom_destroy(edgegg);
767 relate = GEOSRelateBoundaryNodeRule(eegg, edgegg, 2);
769 GEOSGeom_destroy(eegg);
770 GEOSGeom_destroy(edgegg);
778 match = GEOSRelatePatternMatch(relate,
"FF*F*****");
782 GEOSGeom_destroy(eegg);
785 GEOSGeom_destroy(edgegg);
792 match = GEOSRelatePatternMatch(relate,
"1FFF*FFF2");
794 char locinfo[128] =
"";
795 const char *locsuffix = match == 2 ?
""
798 GEOSGeom_destroy(eegg);
799 GEOSGeom_destroy(edgegg);
813 match = GEOSRelatePatternMatch(relate,
"1********");
815 char locinfo[128] =
"";
816 const char *locsuffix = match == 2 ?
""
819 GEOSGeom_destroy(eegg);
820 GEOSGeom_destroy(edgegg);
829 lwerror(
"Spatial exception - geometry intersects edge %" LWTFMT_ELEMID "%s", edge_id, locsuffix);
834 match = GEOSRelatePatternMatch(relate,
"T********");
836 char locinfo[128] =
"";
837 const char *locsuffix = match == 2 ?
""
840 GEOSGeom_destroy(eegg);
841 GEOSGeom_destroy(edgegg);
851 "SQL/MM Spatial exception - geometry crosses edge %" LWTFMT_ELEMID "%s", edge_id, locsuffix);
856 match = GEOSRelatePatternMatch(relate,
"*T*******");
858 char locinfo[128] =
"";
859 const char *locsuffix = match == 2 ?
""
862 GEOSGeom_destroy(eegg);
863 GEOSGeom_destroy(edgegg);
879 match = GEOSRelatePatternMatch(relate,
"***T*****");
881 char locinfo[128] =
"";
882 const char *locsuffix = match == 2 ?
""
885 GEOSGeom_destroy(eegg);
886 GEOSGeom_destroy(edgegg);
895 lwerror(
"Spatial exception - boundary of edge %" LWTFMT_ELEMID " touches interior of geometry%s",
905 GEOSGeom_destroy(eegg);
907 LWDEBUGF(1,
"No edge crossing detected among the %llu candidate edges", num_edges);
911 GEOSGeom_destroy(edgegg);
928 int skipISOChecks = 0;
934 if (startNode == endNode)
936 lwerror(
"Closed edges would not be isolated, try lwt_AddEdgeNewFaces");
940 if ( ! skipISOChecks )
945 lwerror(
"SQL/MM Spatial exception - curve not simple");
959 node_ids[0] = startNode;
960 node_ids[1] = endNode;
963 if (num_nodes == UINT64_MAX)
968 else if ( num_nodes < 2 )
971 lwerror(
"SQL/MM Spatial exception - non-existent node");
974 for ( i=0; i<num_nodes; ++i )
980 lwerror(
"SQL/MM Spatial exception - not isolated node");
987 lwerror(
"SQL/MM Spatial exception - nodes in different faces");
991 if ( ! skipISOChecks )
1001 lwerror(
"SQL/MM Spatial exception - "
1002 "start node not geometry start point.");
1014 lwerror(
"SQL/MM Spatial exception - "
1015 "end node not geometry end point.");
1024 if ( ! skipISOChecks )
1038 if ( newedge.
edge_id == -1 ) {
1044 if ( containing_face == -1 ) containing_face = 0;
1057 }
else if ( ret == 0 ) {
1058 lwerror(
"Insertion of split edge failed (no reason)");
1068 updated_nodes[0].
node_id = startNode;
1070 updated_nodes[1].
node_id = endNode;
1091 LWDEBUG(1,
"calling lwt_be_getEdgeById");
1093 LWDEBUGF(1,
"lwt_be_getEdgeById returned %p", *oldedge);
1097 LWDEBUGF(1,
"lwt_be_getEdgeById returned NULL and set i=%llu", i);
1098 if (i == UINT64_MAX)
1105 lwerror(
"SQL/MM Spatial exception - non-existent edge");
1110 lwerror(
"Backend coding error: getEdgeById callback returned NULL "
1111 "but numelements output parameter has value %" PRIu64
1112 "(expected 0 or 1)", i);
1121 if ( ! skipISOChecks )
1123 LWDEBUG(1,
"calling lwt_be_ExistsCoincidentNode");
1126 LWDEBUG(1,
"lwt_be_ExistsCoincidentNode returned");
1128 lwerror(
"SQL/MM Spatial exception - coincident node");
1131 LWDEBUG(1,
"lwt_be_ExistsCoincidentNode returned");
1139 lwerror(
"could not split edge by point ?");
1143 if ( ! split_col ) {
1146 lwerror(
"lwgeom_as_lwcollection returned NULL");
1149 if (split_col->
ngeoms < 2) {
1153 lwerror(
"SQL/MM Spatial exception - point not on edge");
1157#if POSTGIS_DEBUG_LEVEL > 1
1161 LWDEBUGF(1,
"returning split col: %s", wkt);
1170 LWPOINT* pt,
int skipISOChecks )
1175 const LWGEOM *oldedge_geom;
1176 const LWGEOM *newedge_geom;
1181 split_col =
_lwt_EdgeSplit( topo, edge, pt, skipISOChecks, &oldedge );
1182 if ( ! split_col )
return -1;
1183 oldedge_geom = split_col->
geoms[0];
1184 newedge_geom = split_col->
geoms[1];
1187 ((
LWGEOM*)newedge_geom)->srid = split_col->
srid;
1204 lwerror(
"Backend coding error: "
1205 "insertNodes callback did not return node_id");
1211 if ( newedge1.
edge_id == -1 ) {
1226 if ( ! newedge1.
geom ) {
1229 lwerror(
"first geometry in lwgeom_split output is not a line");
1238 }
else if ( ret == 0 ) {
1241 lwerror(
"Insertion of split edge failed (no reason)");
1248 if ( ! updedge.
geom ) {
1251 lwerror(
"second geometry in lwgeom_split output is not a line");
1265 }
else if ( ret == 0 ) {
1270 }
else if ( ret > 1 ) {
1327 LWPOINT* pt,
int skipISOChecks )
1332 const LWGEOM *oldedge_geom;
1333 const LWGEOM *newedge_geom;
1338 split_col =
_lwt_EdgeSplit( topo, edge, pt, skipISOChecks, &oldedge );
1339 if ( ! split_col )
return -1;
1340 oldedge_geom = split_col->
geoms[0];
1341 newedge_geom = split_col->
geoms[1];
1344 ((
LWGEOM*)newedge_geom)->srid = split_col->
srid;
1361 lwerror(
"Backend coding error: "
1362 "insertNodes callback did not return node_id");
1378 if ( newedges[0].edge_id == -1 ) {
1385 if ( newedges[1].edge_id == -1 ) {
1406 if ( ! newedges[0].geom ) {
1409 lwerror(
"first geometry in lwgeom_split output is not a line");
1427 if ( ! newedges[1].geom ) {
1430 lwerror(
"second geometry in lwgeom_split output is not a line");
1440 }
else if ( ret == 0 ) {
1443 lwerror(
"Insertion of split edge failed (no reason)");
1561 LWDEBUGF(2,
"first point is index %d", from);
1563 for ( i = from+inc; i != toofar; i += inc )
1565 LWDEBUGF(2,
"testing point %d", i);
1595 LWDEBUG(1,
"computing azimuth of first edge end");
1598 lwerror(
"Invalid edge (no two distinct vertices exist)");
1602 lwerror(
"error computing azimuth of first edgeend [%.15g %.15g,%.15g %.15g]",
1603 fp->
x, fp->
y, pt.
x, pt.
y);
1606 LWDEBUGF(1,
"azimuth of first edge end [%.15g %.15g,%.15g %.15g] is %g",
1607 fp->
x, fp->
y, pt.
x, pt.
y, fee->
myaz);
1610 LWDEBUG(1,
"computing azimuth of second edge end");
1613 lwerror(
"Invalid edge (no two distinct vertices exist)");
1617 lwerror(
"error computing azimuth of last edgeend [%.15g %.15g,%.15g %.15g]",
1618 lp->
x, lp->
y, pt.
x, pt.
y);
1621 LWDEBUGF(1,
"azimuth of last edge end [%.15g %.15g,%.15g %.15g] is %g",
1622 lp->
x, lp->
y, pt.
x, pt.
y, lee->
myaz);
1645 uint64_t numedges = 1;
1647 double minaz, maxaz;
1650 data->nextCW = data->nextCCW = 0;
1651 data->cwFace = data->ccwFace = -1;
1654 azdif = other->
myaz - data->myaz;
1655 if ( azdif < 0 ) azdif += 2 * M_PI;
1656 minaz = maxaz = azdif;
1666 " and adjacent to azimuth %g", node, data->myaz);
1670 if (numedges == UINT64_MAX)
1676 LWDEBUGF(1,
"getEdgeByNode returned %llu edges, minaz=%g, maxaz=%g",
1677 numedges, minaz, maxaz);
1680 for ( i = 0; i < numedges; ++i )
1690 if ( edge->
edge_id == myedge_id )
continue;
1703 " does not have two distinct points",
id);
1717 ", edgeend is [%.15g %.15g,%.15g %.15g]",
1723 lwerror(
"error computing azimuth of edge %"
1725 id, p1.
x, p1.
y, p2.
x, p2.
y);
1728 azdif = az - data->myaz;
1730 ": %.15g (diff: %.15g)", edge->
edge_id, az, azdif);
1732 if ( azdif < 0 ) azdif += 2 * M_PI;
1733 if ( minaz == -1 ) {
1734 minaz = maxaz = azdif;
1735 data->nextCW = data->nextCCW = edge->
edge_id;
1741 " (face_right is new ccwFace, face_left is new cwFace)",
1745 if ( azdif < minaz ) {
1751 " (previous had minaz=%g, face_left is new cwFace)",
1756 else if ( azdif > maxaz ) {
1757 data->nextCCW = edge->
edge_id;
1762 " (previous had maxaz=%g, face_right is new ccwFace)",
1779 ", edgeend is [%.15g %.15g,%.15g %.15g]",
1785 lwerror(
"error computing azimuth of edge %"
1787 id, p1.
x, p1.
y, p2.
x, p2.
y);
1790 azdif = az - data->myaz;
1792 ": %.15g (diff: %.15g)", edge->
edge_id, az, azdif);
1793 if ( azdif < 0 ) azdif += 2 * M_PI;
1794 if ( minaz == -1 ) {
1795 minaz = maxaz = azdif;
1796 data->nextCW = data->nextCCW = -edge->
edge_id;
1802 " (face_right is new cwFace, face_left is new ccwFace)",
1806 if ( azdif < minaz ) {
1807 data->nextCW = -edge->
edge_id;
1812 " (previous had minaz=%g, face_right is new cwFace)",
1817 else if ( azdif > maxaz ) {
1818 data->nextCCW = -edge->
edge_id;
1821 ", outgoing, from start point, "
1823 " (previous had maxaz=%g, face_left is new ccwFace)",
1835 LWDEBUGF(1,
"edges adjacent to azimuth %g"
1838 data->myaz, node, data->nextCW, minaz,
1839 data->nextCCW, maxaz);
1841 if ( myedge_id < 1 && numedges && data->cwFace != data->ccwFace )
1843 if ( data->cwFace != -1 && data->ccwFace != -1 ) {
1846 data->nextCW, data->nextCCW,
1847 data->cwFace, data->ccwFace);
1869 if ( pa->
npoints < 2 )
return 0;
1873 for (i=1; i<pa->
npoints-1; ++i)
1889 ip->
x = fp.
x + ( (lp.
x - fp.
x) * 0.5 );
1890 ip->
y = fp.
y + ( (lp.
y - fp.
y) * 0.5 );
1899 uint64_t numedges, i, j;
1905 for (i=0; i<num_signed_edge_ids; ++i) {
1906 int absid = llabs(signed_edge_ids[i]);
1909 for (j=0; j<numedges; ++j) {
1910 if ( edge_ids[j] == absid ) {
1915 if ( ! found ) edge_ids[numedges++] = absid;
1921 if (i == UINT64_MAX)
1926 else if ( i != numedges )
1928 lwfree( signed_edge_ids );
1931 " edges found when expecting %" PRIu64, i, numedges);
1939 for ( i=0; i<num_signed_edge_ids; ++i )
1945 for ( j=0; j<numedges; ++j )
1947 if ( ring_edges[j].edge_id == llabs(eid) )
1949 edge = &(ring_edges[j]);
1956 lwerror(
"missing edge that was found in ring edges loop");
2014 uint64_t numfaceedges, i, j;
2015 int newface_outside;
2016 uint64_t num_signed_edge_ids;
2020 int forward_edges_count = 0;
2022 int backward_edges_count = 0;
2025 if (!signed_edge_ids)
2031 LWDEBUGF(1,
"getRingEdges returned %llu edges", num_signed_edge_ids);
2034 for (i=0; i<num_signed_edge_ids; ++i) {
2035 if ( signed_edge_ids[i] == -sedge ) {
2038 lwfree( signed_edge_ids );
2044 sedge, face, mbr_only);
2053 num_signed_edge_ids);
2055 lwfree( signed_edge_ids );
2064 lwfree( signed_edge_ids );
2066 " is geometrically not-closed", sedge);
2072 sedge, isccw ?
"counter" :
"");
2081 lwfree( signed_edge_ids );
2085 LWDEBUG(1,
"The left face of this clockwise ring is the universe, "
2086 "won't create a new face there");
2091 if ( mbr_only && face != 0 )
2097 updface.
mbr = (
GBOX *)shellbox;
2101 lwfree( signed_edge_ids );
2108 lwfree( signed_edge_ids );
2110 lwerror(
"Unexpected error: %d faces found when expecting 1", ret);
2114 lwfree( signed_edge_ids );
2122 if ( face != 0 && ! isccw)
2125 uint64_t nfaces = 1;
2127 if (nfaces == UINT64_MAX)
2129 lwfree( signed_edge_ids );
2136 lwfree( signed_edge_ids );
2138 lwerror(
"Unexpected error: %" PRIu64
" faces found when expecting 1", nfaces);
2141 newface.
mbr = oldface->
mbr;
2145 newface.
mbr = (
GBOX *)shellbox;
2152 lwfree( signed_edge_ids );
2159 lwfree( signed_edge_ids );
2161 lwerror(
"Unexpected error: %d faces inserted when expecting 1", ret);
2172 if ( face != 0 && ! isccw ) {
2174 LWDEBUG(1,
"New face is on the outside of the ring, updating rings in former shell");
2175 newface_outside = 1;
2178 LWDEBUG(1,
"New face is on the inside of the ring, updating forward edges in new ring");
2179 newface_outside = 0;
2192 if (numfaceedges == UINT64_MAX)
2198 LWDEBUGF(1,
"_lwt_AddFaceSplit: lwt_be_getEdgeByFace(%" LWTFMT_ELEMID ") returned %llu edges", face, numfaceedges);
2203 forward_edges_count = 0;
2205 backward_edges_count = 0;
2208 for ( i=0; i<numfaceedges; ++i )
2216 for ( j=0; j<num_signed_edge_ids; ++j )
2218 int seid = signed_edge_ids[j];
2226 if ( found == 2 )
break;
2228 else if ( -seid == e->
edge_id )
2235 if ( found == 2 )
break;
2238 if ( found )
continue;
2262 if ( newface_outside )
2299 if ( forward_edges_count )
2302 forward_edges_count,
2306 lwfree( signed_edge_ids );
2310 if ( ret != forward_edges_count )
2312 lwfree( signed_edge_ids );
2313 lwerror(
"Unexpected error: %d edges updated when expecting %d",
2314 ret, forward_edges_count);
2320 if ( backward_edges_count )
2323 backward_edges_count,
2327 lwfree( signed_edge_ids );
2331 if ( ret != backward_edges_count )
2333 lwfree( signed_edge_ids );
2334 lwerror(
"Unexpected error: %d edges updated when expecting %d",
2335 ret, backward_edges_count);
2347 uint64_t numisonodes = 1;
2350 &numisonodes, fields, newface.
mbr);
2351 if (numisonodes == UINT64_MAX)
2357 if ( numisonodes ) {
2359 int nodes_to_update = 0;
2360 for (i=0; i<numisonodes; ++i)
2367 newface_outside ?
"outside" :
"inside" );
2368 if ( newface_outside )
2392 if ( nodes_to_update )
2398 lwfree( signed_edge_ids );
2422 LWLINE *geom,
int skipChecks,
int modFace )
2431 const LWPOINT *start_node_geom = NULL;
2432 const LWPOINT *end_node_geom = NULL;
2446 lwerror(
"SQL/MM Spatial exception - curve not simple");
2453 newedge.
geom = geom;
2462 lwerror(
"Invalid edge (no two distinct vertices exist)");
2475 lwerror(
"Invalid edge (no two distinct vertices exist)");
2480 lwerror(
"error computing azimuth of first edgeend [%.15g %.15g,%.15g %.15g]",
2481 p1.
x, p1.
y, pn.
x, pn.
y);
2484 LWDEBUGF(1,
"edge's start node is %g,%g", p1.
x, p1.
y);
2492 lwerror(
"Invalid clean edge (no two distinct vertices exist) - should not happen");
2497 lwerror(
"error computing azimuth of last edgeend [%.15g %.15g,%.15g %.15g]",
2498 p2.
x, p2.
y, pn.
x, pn.
y);
2501 LWDEBUGF(1,
"edge's end node is %g,%g", p2.
x, p2.
y);
2508 if ( start_node != end_node ) {
2510 node_ids[0] = start_node;
2511 node_ids[1] = end_node;
2514 node_ids[0] = start_node;
2518 if (num_nodes == UINT64_MAX)
2523 for ( i=0; i<num_nodes; ++i )
2535 lwerror(
"SQL/MM Spatial exception - geometry crosses an edge"
2544 if ( node->
node_id == start_node ) {
2545 start_node_geom = node->
geom;
2547 if ( node->
node_id == end_node ) {
2548 end_node_geom = node->
geom;
2554 if ( ! start_node_geom )
2557 lwerror(
"SQL/MM Spatial exception - non-existent node");
2562 pa = start_node_geom->
point;
2567 lwerror(
"SQL/MM Spatial exception"
2568 " - start node not geometry start point."
2575 if ( ! end_node_geom )
2578 lwerror(
"SQL/MM Spatial exception - non-existent node");
2583 pa = end_node_geom->
point;
2588 lwerror(
"SQL/MM Spatial exception"
2589 " - end node not geometry end point."
2608 if ( newedge.
edge_id == -1 ) {
2614 int isclosed = start_node == end_node;
2617 isclosed ? &epan : NULL, -1 );
2626 if ( modFace != -1 )
2646 isclosed ? &span : NULL, -1 );
2655 if ( modFace != -1 )
2661 lwerror(
"Side-location conflict: "
2662 "new edge starts in face"
2673 lwerror(
"Side-location conflict: "
2674 "new edge starts in face"
2702 " faces mismatch: invalid topology ?",
2708 lwerror(
"Could not derive edge face from linked primitives:"
2709 " invalid topology ?");
2722 }
else if ( ret == 0 ) {
2723 lwerror(
"Insertion of split edge failed (no reason)");
2731 if ( llabs(prev_left) != newedge.
edge_id )
2733 if ( prev_left > 0 )
2750 &updedge, updfields,
2760 if ( llabs(prev_right) != newedge.
edge_id )
2762 if ( prev_right > 0 )
2774 seledge.
edge_id = -prev_right;
2779 &updedge, updfields,
2821 if ( modFace > -1 ) {
2825 LWDEBUG(1,
"New edge is dangling, so it cannot split any face");
2837 if ( newface1 == 0 ) {
2838 LWDEBUG(1,
"New edge does not split any face");
2847 if ( newface == 0 ) {
2848 LWDEBUG(1,
"New edge does not split any face");
2858 if ( newface < 0 )
return newedge.
edge_id;
2897 LWLINE *geom,
int skipChecks )
2899 return _lwt_AddEdge( topo, start_node, end_node, geom, skipChecks, 1 );
2905 LWLINE *geom,
int skipChecks )
2907 return _lwt_AddEdge( topo, start_node, end_node, geom, skipChecks, 0 );
2916 int i, validedges = 0;
2918 for ( i=0; i<numfaceedges; ++i )
2932 if ( numfaceedges )
lwfree(geoms);
2933 LWDEBUG(1,
"_lwt_FaceByEdges returning empty polygon");
2950 LWDEBUGF(1,
"_lwt_FaceByEdges returning area: %s", wkt);
2960 uint64_t numfaceedges;
2970 lwerror(
"SQL/MM Spatial exception - universal face has no geometry");
2982 if (numfaceedges == UINT64_MAX)
2987 LWDEBUGF(1,
"lwt_GetFaceGeometry: lwt_be_getEdgeByFace returned %llu edges", numfaceedges);
2989 if ( numfaceedges == 0 )
2993 if (i == UINT64_MAX)
2999 lwerror(
"SQL/MM Spatial exception - non-existent face.");
3004 lwerror(
"Corrupted topology: multiple face records have face_id=%"
3010 lwnotice(
"Corrupted topology: face %"
3027 lwnotice(
"Corrupted topology: face %"
3062 LWDEBUGF(1,
"Ring's 'from' point (%d) is %g,%g", from, p1.
x, p1.
y);
3066 for ( i=0; i<numedges; ++i )
3080 ") on both sides, skipping",
3088 " has only %"PRIu32
" points",
3105 LWDEBUGF(1,
"Rings's 'from' point is still %g,%g", p1.
x, p1.
y);
3108 LWDEBUG(1,
"P2D_SAME_STRICT(p1,p2) returned true");
3110 " matches ring vertex %d", isoe->
edge_id, from);
3112 for ( j=1; j<epa->
npoints; ++j )
3121 LWDEBUGF(1,
"Ring's point %d is %g,%g",
3122 from+1, pt.
x, pt.
y);
3126#if POSTGIS_DEBUG_LEVEL > 0
3129 " matches ring vertex %d", isoe->
edge_id, from+1);
3132 " does not match ring vertex %d", isoe->
edge_id, from+1);
3147 " matches ring vertex %d", isoe->
edge_id, from);
3149 for ( j=2; j<=epa->
npoints; j++ )
3158 LWDEBUGF(1,
"Ring's point %d is %g,%g",
3159 from+1, pt.
x, pt.
y);
3164#if POSTGIS_DEBUG_LEVEL > 0
3167 " matches ring vertex %d", isoe->
edge_id, from+1);
3170 " does not match ring vertex %d", isoe->
edge_id, from+1);
3175 if ( match )
return i;
3191 ary[from++] = ary[to];
3214 uint64_t numfaceedges;
3229 if (numfaceedges == UINT64_MAX)
3234 if ( ! numfaceedges )
return 0;
3235 LWDEBUGF(1,
"lwt_GetFaceEdges: lwt_be_getEdgeByFace returned %llu edges", numfaceedges);
3244 lwerror(
"Corrupted topology: unable to build geometry of face %"
3245 LWTFMT_ELEMID " from its %"PRIu64
" edges", face_id, numfaceedges);
3281 nseid = prevseid = 0;
3285 for ( i=0; i<facepoly->
nrings; ++i )
3294 while ( j < (int32_t) ring->
npoints-1 )
3296 LWDEBUGF(1,
"Looking for edge covering ring %d from vertex %d",
3306 lwerror(
"No edge (among %" PRIu64
") found to be defining geometry of face %"
3311 nextedge = &(edges[edgeno]);
3312 nextline = nextedge->
geom;
3315 " covers ring %d from vertex %d to %d",
3331 seid[nseid++] = nextedge->
face_left == face_id ?
3342 if ( (nseid - prevseid) > 1 )
3346 LWDEBUGF(1,
"Looking for smallest id among the %d edges "
3347 "composing ring %d", (nseid-prevseid), i);
3348 for ( j=prevseid; j<nseid; ++j )
3352 if ( ! minid ||
id < minid )
3359 " at position %d", minid, minidx);
3360 if ( minidx != prevseid )
3384 int leftRingIsCCW = -1;
3389 lwerror(
"SQL/MM Spatial exception - curve not simple");
3398 "lwt_be_getEdgeById returned NULL and set i=%llu", i);
3399 if (i == UINT64_MAX)
3406 lwerror(
"SQL/MM Spatial exception - non-existent edge %"
3412 lwerror(
"Backend coding error: getEdgeById callback returned NULL "
3413 "but numelements output parameter has value %" PRIu64
" "
3414 "(expected 0 or 1)", i);
3420 "old edge has %d points, new edge has %d points",
3431 lwerror(
"SQL/MM Spatial exception - "
3432 "start node not geometry start point.");
3443 " has less than 2 vertices", oldedge->
edge_id);
3450 lwerror(
"Invalid edge: less than 2 vertices");
3457 lwerror(
"SQL/MM Spatial exception - "
3458 "end node not geometry end point.");
3474 lwerror(
"Invalid edge (no two distinct vertices exist)");
3483 lwerror(
"Edge twist at node POINT(%g %g)", p1.
x, p1.
y);
3489 oldedge->
end_node, geom, edge_id ) )
3496 LWDEBUG(1,
"lwt_ChangeEdgeGeom: "
3497 "edge crossing check passed ");
3515 LWDEBUGF(1,
"lwt_be_getNodeWithinBox2D returned %llu nodes", numnodes);
3516 if (numnodes == UINT64_MAX)
3523 if ( numnodes > ( 1 + isclosed ? 0 : 1 ) )
3526 for (i=0; i<numnodes; ++i)
3539 lwerror(
"Edge motion collision at %s", wkt);
3547 LWDEBUG(1,
"nodes containment check passed");
3560 isclosed ? &epan_pre : NULL, edge_id );
3562 isclosed ? &span_pre : NULL, edge_id );
3585 uint64_t num_signed_edge_ids;
3589 LWDEBUG(1,
"Twist check before");
3592 if (!signed_edge_ids)
3598 LWDEBUGF(1,
"getRingEdges returned %llu edges", num_signed_edge_ids);
3602 lwfree( signed_edge_ids );
3612 lwfree( signed_edge_ids );
3614 " is geometrically not-closed", edge_id);
3620 lwfree( signed_edge_ids );
3622 LWDEBUGF(1,
"Ring of edge %" LWTFMT_ELEMID " is %sclockwise", edge_id, leftRingIsCCW ?
"counter" :
"");
3628 newedge.
geom = geom;
3639 lwerror(
"Unexpected error: %" PRIu64
" edges updated when expecting 1", i);
3652 isclosed ? &epan_post : NULL, edge_id );
3654 isclosed ? &span_post : NULL, edge_id );
3669 lwerror(
"Edge changed disposition around start node %"
3680 lwerror(
"Edge changed disposition around end node %"
3686 if ( leftRingIsCCW != -1 )
3688 uint64_t num_signed_edge_ids;
3693 LWDEBUG(1,
"Twist check after");
3696 if (!signed_edge_ids)
3702 LWDEBUGF(1,
"getRingEdges returned %llu edges", num_signed_edge_ids);
3706 lwfree( signed_edge_ids );
3716 lwfree( signed_edge_ids );
3718 " is geometrically not-closed", edge_id);
3724 lwfree( signed_edge_ids );
3726 if ( isCCW != leftRingIsCCW )
3729 lwerror(
"Edge ring changes winding");
3751 uint64_t facestoupdate = 0;
3765 faces[facestoupdate++].
mbr = updatedBox;
3774 lwerror(
"Corrupted topology: face %"
3781 faces[facestoupdate++].
mbr = updatedBox;
3783 LWDEBUGF(1,
"%llu faces to update", facestoupdate);
3784 if ( facestoupdate )
3787 if (updatedFaces != facestoupdate)
3789 while ( facestoupdate-- )
lwfree(faces[facestoupdate].mbr);
3791 if (updatedFaces == UINT64_MAX)
3794 lwerror(
"Unexpected error: %" PRIu64
" faces updated when expecting 1", updatedFaces);
3798 while ( facestoupdate-- )
lwfree(faces[facestoupdate].mbr);
3802 LWDEBUG(1,
"BBOX of changed edge did not change");
3805 LWDEBUG(1,
"all done, cleaning up edges");
3819 if (n == UINT64_MAX)
3825 lwerror(
"SQL/MM Spatial exception - non-existent node");
3831 lwerror(
"SQL/MM Spatial exception - not isolated node");
3846 if ( ! node )
return -1;
3851 lwerror(
"SQL/MM Spatial exception - coincident node");
3858 lwerror(
"SQL/MM Spatial exception - edge crosses node.");
3865 if ( newPointFace == -1 ) {
3872 lwerror(
"Cannot move isolated node across faces");
3897 if ( ! node )
return -1;
3909 lwerror(
"Unexpected error: %d nodes deleted when expecting 1", n);
3946 lwerror(
"SQL/MM Spatial exception - non-existent edge");
3952 lwerror(
"Corrupted topology: more than a single edge have id %"
3957 if ( edge[0].face_left != edge[0].face_right )
3960 lwerror(
"SQL/MM Spatial exception - not isolated edge");
3971 if ((n == UINT64_MAX) || (edge == NULL))
3976 for (i = 0; i < n; ++i)
3978 if (edge[i].edge_id !=
id)
3981 lwerror(
"SQL/MM Spatial exception - not isolated edge");
3989 if (n == UINT64_MAX)
3996 lwerror(
"Unexpected error: %" PRIu64
" edges deleted when expecting 1", n);
4003 if ( nid[1] != nid[0] ) {
4010 if (n == UINT64_MAX)
4048 if ( ret == -1 )
return -1;
4056 if ( ret == -1 )
return -1;
4081 if ( ret == -1 )
return -1;
4095 uint64_t i, nedges, nfaces, fields;
4101 int nedge_right = 0;
4108 int fnode_edges = 0;
4110 int lnode_edges = 0;
4120 LWDEBUGF(1,
"lwt_be_getEdgeById returned NULL and set i=%llu", i);
4121 if (i == UINT64_MAX)
4134 "Backend coding error: getEdgeById callback returned NULL "
4135 "but numelements output parameter has value %" PRIu64
" "
4136 "(expected 0 or 1)",
4149 LWDEBUG(1,
"Updating next_{right,left}_face of ring edges...");
4157 node_ids[nedges++] = edge->
end_node;
4163 if (nedges == UINT64_MAX)
4168 nedge_left = nedge_right = 0;
4169 for ( i=0; i<nedges; ++i )
4172 if ( e->
edge_id == edge_id )
continue;
4210 LWDEBUGF(1,
"updating %d 'next_left' edges", nedge_left);
4223 LWDEBUGF(1,
"updating %d 'next_right' edges", nedge_right);
4234 LWDEBUGF(1,
"releasing %llu updateable edges in %p", nedges, upd_edge);
4252 LWDEBUG(1,
"floodface is universe");
4266 if (nfaces == UINT64_MAX)
4273 for ( i=0; i<nfaces; ++i )
4275 if ( faces[i].face_id == edge->
face_left )
4277 if ( ! box1 ) box1 = faces[i].
mbr;
4283 lwerror(
"corrupted topology: more than 1 face have face_id=%"
4288 else if ( faces[i].face_id == edge->
face_right )
4290 if ( ! box2 ) box2 = faces[i].
mbr;
4296 lwerror(
"corrupted topology: more than 1 face have face_id=%"
4306 lwerror(
"Backend coding error: getFaceById returned face "
4315 lwerror(
"corrupted topology: no face have face_id=%"
4324 lwerror(
"corrupted topology: no face have face_id=%"
4345 lwerror(
"Unexpected error: %" PRIu64
" faces updated when expecting 1", i);
4364 lwerror(
"Unexpected error: %d faces inserted when expecting 1",
result);
4429 if ( ! fnode_edges )
4471 return modFace ? floodface : newface.
face_id;
4494 uint64_t num_node_edges;
4501 int e2sign, e2freenode;
4505 size_t bufleft = 256;
4513 " with itself, try with another", eid1);
4520 if ((nedges == UINT64_MAX) || (edges == NULL))
4525 for ( i=0; i<nedges; ++i )
4527 if ( edges[i].edge_id == eid1 ) {
4530 lwerror(
"Corrupted topology: multiple edges have id %"
4536 else if ( edges[i].edge_id == eid2 ) {
4539 lwerror(
"Corrupted topology: multiple edges have id %"
4550 "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4558 "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4592 if ( commonnode != -1 )
4597 if (num_node_edges == UINT64_MAX)
4603 for (i=0; i<num_node_edges; ++i)
4606 if ( node_edges[i].edge_id == eid1 )
continue;
4607 if ( node_edges[i].edge_id == eid2 )
continue;
4610 if ( bufleft > 0 ) {
4612 ( ptr==buf ?
"" :
"," ), node_edges[i].edge_id);
4613 if (
r >= (
int) bufleft )
4631 if ( commonnode == -1 )
4644 if ( commonnode != -1 )
4649 if (num_node_edges == UINT64_MAX)
4655 for (i=0; i<num_node_edges; ++i)
4658 if ( node_edges[i].edge_id == eid1 )
continue;
4659 if ( node_edges[i].edge_id == eid2 )
continue;
4662 if ( bufleft > 0 ) {
4664 ( ptr==buf ?
"" :
"," ), node_edges[i].edge_id);
4665 if (
r >= (
int) bufleft )
4680 if ( num_node_edges )
lwfree(node_edges);
4684 if ( commonnode == -1 )
4689 lwerror(
"SQL/MM Spatial exception - other edges connected (%s)",
4694 lwerror(
"SQL/MM Spatial exception - non-connected edges");
4771 lwerror(
"Coding error: caseno=%d should never happen", caseno);
4797 lwerror(
"Unexpected error: %" PRIu64
" edges updated when expecting 1", i);
4819 lwerror(
"Insertion of split edge failed (no reason)");
4923 eid1, eid2, newedge.
edge_id) )
4929 return modEdge ? commonnode : newedge.
edge_id;
4959 if (num == UINT64_MAX)
4969 lwerror(
"Two or more nodes found");
4994 if (num == UINT64_MAX)
4999 for (i=0; i<num;++i)
5010 " has null geometry", e->
edge_id);
5018 if ( dist > tol )
continue;
5024 lwerror(
"Two or more edges found");
5063 LWDEBUG(1,
"No face properly contains query point,"
5064 " looking for edges");
5071 if (num == UINT64_MAX)
5076 for (i=0; i<num; ++i)
5087 " has null geometry", e->
edge_id);
5095 " is dangling, won't consider it", e->
edge_id);
5103 " is %g (tol=%g)", e->
edge_id, dist, tol);
5106 if ( dist > tol )
continue;
5115 lwerror(
"Two or more faces found");
5119 if (
id &&
id != eface )
5122 lwerror(
"Two or more faces found"
5142 double ret = 3.6 * pow(10, - ( 15 - log10(d?d:1.0) ) );
5168 if ( ! gbox )
return 0;
5179#define _LWT_MINTOLERANCE( topo, geom ) ( \
5180 topo->precision ? topo->precision : _lwt_minTolerance(geom) )
5214 GEOSGeometry *edgeg;
5218 if (num == UINT64_MAX)
5234 for (i=0; i<num; ++i)
5243 GEOSGeom_destroy(edgeg);
5248 equals = GEOSEquals(gg, edgeg);
5249 GEOSGeom_destroy(gg);
5252 GEOSGeom_destroy(edgeg);
5294 GEOSGeom_destroy(edgeg);
5299 GEOSGeom_destroy(edgeg);
5340 LWDEBUGG(1, motionPoly,
"Motion range");
5345 GEOSGeometry *motionPolyG = NULL;
5346 for ( uint64_t t=0; t<splitNodeEdges->
numEdges; t++ )
5350 if ( e == existingEdge )
continue;
5351 if ( e == edge )
continue;
5352 if ( ! motionPolyG ) {
5354 if ( ! motionPolyG )
5363 GEOSGeom_destroy(motionPolyG);
5369 char *relate = GEOSRelate( motionPolyG, eg );
5370 GEOSGeom_destroy(eg);
5373 GEOSGeom_destroy(motionPolyG);
5379 int match = GEOSRelatePatternMatch(relate,
"FF*F*****");
5383 GEOSGeom_destroy(motionPolyG);
5390 GEOSGeom_destroy(motionPolyG);
5399 if ( motionPolyG ) GEOSGeom_destroy(motionPolyG);
5426 if ( splitC->
ngeoms != 2 )
5428 lwerror(
"Split of edge resulted in %d components", splitC->
ngeoms);
5433 if ( ! firstNodeEdges ) {
5434 lwerror(
"No edges found in DB to be incident to split edge's first node");
5438 if ( ! lastNodeEdges ) {
5439 lwerror(
"No edges found in DB to be incident to split edge's last node");
5443 if ( ! splitNodeEdges ) {
5444 lwerror(
"No edges found in DB to be incident to split node");
5449 for ( uint64_t t=0; t<firstNodeEdges->
numEdges; t++ )
5453 edge = &(firstNodeEdges->
edges[t]);
5482 for ( n=0; n<2; ++n)
5487 if ( existingEdgeId == -1 )
5492 existingEdges[n] = NULL;
5493 if ( existingEdgeId == 0 )
5495 LWDEBUGF(1,
"Split component %llu is a new edge, computing edgeEndInfo", n);
5511 lwerror(
"No distinct vertices found on second part of split edge");
5525 lwerror(
"No distinct vertices found on first part of split edge");
5529 if ( !
azimuth_pt_pt(pt, &op, &(splitNodeEdgeEnds[n].myaz)) ) {
5530 lwerror(
"error computing azimuth of split endpoint [%.15g %.15g,%.15g %.15g]",
5536 LWDEBUGF(1,
"Azimuth of split component %llu edgeend [%.15g %.15g,%.15g %.15g] is %.15g",
5537 n, op.
x, op.
y, pt->
x, pt->
y, splitNodeEdgeEnds[n].
myaz);
5540 lwerror(
"Unexpected backend return: _lwt_FindAdjacentEdges(%"
5541 LWTFMT_ELEMID ") found no edges when we previously split edge %"
5554 " (%s)", n, existingEdgeId, forward ?
"forward" :
"backward" );
5556 for ( uint64_t t=0; t<splitNodeEdges->
numEdges; t++ )
5558 if ( splitNodeEdges->
edges[t].
edge_id == existingEdgeId )
5560 existingEdges[n] = &(splitNodeEdges->
edges[t]);
5564 if (existingEdges[n] == NULL)
5566 lwerror(
"could not find edge %" LWTFMT_ELEMID " in database, but _lwt_GetEqualEdges said it was there", existingEdgeId );
5571 replacedBy[n] = existingEdgeId;
5579 if ( ( replacedBy[0] != 0 && replacedBy[1] == 0 ) ||
5580 ( replacedBy[1] != 0 && replacedBy[0] == 0 ) )
5585 edgeend *splitNodeEdgeEndInfo;
5586 LWLINE *newSplitEdgeLine;
5587 int splitNodeNewEdgeOutgoing;
5589 if ( replacedBy[1] == 0 )
5592 existingEdge = existingEdges[0];
5594 splitNodeEdgeEndInfo = &(splitNodeEdgeEnds[1]);
5595 splitNodeNewEdgeOutgoing = 1;
5600 existingEdge = existingEdges[1];
5602 splitNodeEdgeEndInfo = &(splitNodeEdgeEnds[0]);
5603 splitNodeNewEdgeOutgoing = 0;
5635 if ( splitNodeNewEdgeOutgoing ) {
5645 splitNodeEdgeEndInfo->
nextCCW,
5649 if ( splitNodeEdgeEndInfo->
nextCCW > 0 )
5678 &updatedEdge, updateFlags,
5683 }
else if ( ret == 0 ) {
5686 }
else if ( ret > 1 ) {
5687 lwerror(
"More than a single edge found with id %"
5696 if ( splitNodeNewEdgeOutgoing ) {
5704 splitNodeEdgeEndInfo->
nextCW, sideFace
5707 if ( splitNodeEdgeEndInfo->
nextCW > 0 )
5713 ", outgoing next CW of new split edge on split node",
5722 ", incoming next CW of new split edge on split node",
5728 &updatedEdge, updateFlags,
5733 }
else if ( ret == 0 ) {
5736 }
else if ( ret > 1 ) {
5737 lwerror(
"More than a single edge found with edge_id %"
5750 int nextCCWEdgeIsIncoming = 0;
5751 int collapsedEdgeIsIncoming;
5756 if ( replacedBy[0] ) {
5757 commonNodeEdges = firstNodeEdges;
5759 collapsedEdgeIsIncoming = 0;
5761 commonNodeEdges = lastNodeEdges;
5763 collapsedEdgeIsIncoming = 1;
5771 LWDEBUGF(1,
"Looking for next CCW edge of split edge %"
5773 " having %llu attached edges",
5775 commonNodeID, commonNodeEdges->
numEdges
5779 for ( uint64_t t=0; t<commonNodeEdges->
numEdges; t++ )
5793 if ( et->
next_right == signedCollapsedEdgeID )
5796 nextCCWEdgeIsIncoming = 0;
5800 else if ( et->
end_node == commonNodeID )
5802 if ( et->
next_left == signedCollapsedEdgeID )
5805 nextCCWEdgeIsIncoming = 1;
5810 if ( ! nextCCWEdge )
5818 LWDEBUGF(1,
"Next CCW edge of split edge %"
5823 nextCCWEdgeIsIncoming ?
"incoming" :
"outgoing",
5829 LWDEBUG(1,
"Next CCW edge is existing/collapse edge, will not update here");
5846 if ( nextCCWEdgeIsIncoming ) {
5849 LWDEBUGF(1,
"Updating next_left of incoming next CCW edge %"
5858 LWDEBUGF(1,
"Updating next_right of outgoing next CCW edge %"
5867 &updatedEdge, updateFlags,
5872 }
else if ( ret == 0 ) {
5875 }
else if ( ret > 1 ) {
5876 lwerror(
"More than a single edge found with next_left %"
5895 LWDEBUGF(1,
"Will update next_left of existing edge %"
5905 LWDEBUGF(1,
"Will update next_right of existing edge %"
5915 LWDEBUGF(1,
"Will update next_left of existing edge %"
5925 LWDEBUGF(1,
"Will update next_right of existing edge %"
5935 &updatedEdge, updateFlags,
5940 }
else if ( ret == 0 ) {
5943 }
else if ( ret > 1 ) {
5944 lwerror(
"More than a single edge found with id %"
5957 updatedEdge.
geom = newSplitEdgeLine;
5959 if ( splitNodeNewEdgeOutgoing ) {
5988 &updatedEdge, updateFlags,
5993 }
else if ( ret == 0 ) {
5996 }
else if ( ret > 1 ) {
5997 lwerror(
"More than a single edge found with id %"
6086 else if ( replacedBy[0] == 0 && replacedBy[1] == 0 )
6094 if ( newEdge.
edge_id == -1 ) {
6118 for ( uint64_t t=0; t<splitNodeEdges->
numEdges; t++ )
6140 int splitFaceOnLeft = 1;
6143 splitFaceOnLeft = 0;
6171 }
else if ( ret == 0 ) {
6174 }
else if ( ret > 1 ) {
6175 lwerror(
"More than a single edge found with id %"
6199 &updatedEdge, updateFlags,
6204 }
else if ( ret == 0 ) {
6207 }
else if ( ret > 1 ) {
6208 lwerror(
"More than a single edge found with id %"
6233 &updatedEdge, updateFlags,
6238 }
else if ( ret == 0 ) {
6241 }
else if ( ret > 1 ) {
6242 lwerror(
"More than a single edge found with id %"
6251 for ( uint64_t t=0; t<lastNodeEdges->
numEdges; t++ )
6273 if ( updateFlags != 0 )
6280 &updatedEdge, updateFlags,
6285 }
else if ( ret == 0 ) {
6288 }
else if ( ret > 1 ) {
6289 lwerror(
"More than a single edge found with id %"
6299 if ( splitFaceOnLeft ) {
6323 -newEdge.
edge_id, newFaceId1);
6348 newFaceId1, newFaceId2, oldFaceId);
6349 if ( newFaceId1 || newFaceId2 )
6353 newFaceId1 ? newFaceId1 : oldFaceId,
6354 newFaceId2 ? newFaceId2 : oldFaceId
6361 if ( newFaceId1 && newFaceId2 )
6375 else if ( replacedBy[0] != 0 && replacedBy[1] != 0 )
6409 for ( uint64_t t=0; t<firstNodeEdges->
numEdges; t++ )
6438 if ( updateFlags != 0 )
6445 &updatedEdge, updateFlags,
6450 }
else if ( ret == 0 ) {
6453 }
else if ( ret > 1 ) {
6454 lwerror(
"More than a single edge found with id %"
6462 for ( uint64_t t=0; t<lastNodeEdges->
numEdges; t++ )
6489 if ( updateFlags != 0 )
6496 &updatedEdge, updateFlags,
6501 }
else if ( ret == 0 ) {
6504 }
else if ( ret > 1 ) {
6505 lwerror(
"More than a single edge found with id %"
6531 &updatedEdge, updateFlags,
6536 }
else if ( ret == 0 ) {
6539 }
else if ( ret > 1 ) {
6540 lwerror(
"More than a single edge found with id %"
6565 &updatedEdge, updateFlags,
6570 }
else if ( ret == 0 ) {
6573 }
else if ( ret > 1 ) {
6574 lwerror(
"More than a single edge found with id %"
6644 for (i=0; i<num; ++i)
6651 if ( dist >= tol )
continue;
6653 sorted[j++].
score = dist;
6664 for (j=0, i=0; i<num; ++i)
6666 if ( sorted[i].score == sorted[0].score )
6682 if ( moved ) *moved =
lwgeom_same(prj, lwpoint) ? 0 : 1;
6705 LWDEBUGG(1, prj,
"Projected point");
6709 for (i=0; i<num; ++i)
6725 lwerror(
"Something went wrong with _lwt_SnapEdgeToExistingNode");
6742 " does not contain projected point to it",
6750 LWDEBUG(1,
"But there's another to check");
6759 LWDEBUGF(1,
"Edge snapped with tolerance %g", tol);
6762#if POSTGIS_DEBUG_LEVEL > 0
6767 LWDEBUGF(1,
"Edge %s snapped became %s", wkt1, wkt2);
6780 LWDEBUGF(1,
"Edge first point is %g %g, "
6781 "snapline first point is %g %g",
6782 p1.
x, p1.
y, p2.
x, p2.
y);
6783 if ( p1.
x != p2.
x || p1.
y != p2.
y )
6785 LWDEBUG(1,
"Snapping moved first point, re-adding it");
6793#if POSTGIS_DEBUG_LEVEL > 0
6797 LWDEBUGF(1,
"Tweaked snapline became %s", wkt1);
6802#if POSTGIS_DEBUG_LEVEL > 0
6804 LWDEBUG(1,
"Snapping did not move first point");
6813 lwerror(
"lwt_ChangeEdgeGeom failed");
6818#if POSTGIS_DEBUG_LEVEL > 0
6824 LWDEBUGF(1,
"Edge %s contains projected point %s", wkt1, wkt2);
6836 lwerror(
"lwt_ModEdgeSplit failed");
6857 if ( edges2 )
lwfree(edges2);
6872 findFace,
int *moved,
int *numSplitEdges)
6875 double mindist = FLT_MAX;
6896 if (num == UINT64_MAX)
6902 if ( numSplitEdges ) *numSplitEdges = 0;
6906 LWDEBUGF(1,
"New point is within %.15g units of %llu nodes", tol, num);
6911 for (i=0; i<num; ++i)
6913 sorted[i].
ptr = nodes+i;
6916 ((
LWT_ISO_NODE*)(sorted[i].ptr))->node_id, sorted[i].score);
6920 for (i=0; i<num; ++i)
6929 for ( i=0; i<num; ++i )
6936 if ( dist && dist >= tol )
continue;
6937 if ( !
id || dist < mindist )
6947 if ( moved ) *moved = mindist == 0 ? 0 : 1;
6961 if (num == UINT64_MAX)
6966 LWDEBUGF(1,
"New point is within %.15g units of %llu edges", tol, num);
6971 if ( numSplitEdges ) *numSplitEdges = num;
6979 if ( moved ) *moved = 0;
6984 lwerror(
"lwt_AddIsoNode failed");
7021 int handleFaceSplit,
int *forward,
int *numNewEdges )
7024 LWPOINT *start_point, *end_point;
7032 int pointSplitEdges = -666;
7034 if ( numNewEdges ) *numNewEdges = 0;
7037 LWDEBUGF(1,
"_lwtAddLineEdge with tolerance %g", tol);
7040 if ( ! start_point )
7042 lwnotice(
"Empty component of noded line");
7047 handleFaceSplit, &mm, &pointSplitEdges );
7049 if ( nid[0] == -1 )
return -1;
7050 if ( numNewEdges ) *numNewEdges += pointSplitEdges;
7052 LWDEBUGF(1,
"node for start point added or found to be %" LWTFMT_ELEMID " (moved ? %d; split %d edges)", nid[0], mm, pointSplitEdges);
7058 lwerror(
"could not get last point of line "
7059 "after successfully getting first point !?");
7064 handleFaceSplit, &mm, &pointSplitEdges );
7066 if ( nid[1] == -1 )
return -1;
7067 if ( numNewEdges ) *numNewEdges += pointSplitEdges;
7069 LWDEBUGF(1,
"node for end point added or found to be %" LWTFMT_ELEMID " (moved ? %d; split %d edges)", nid[1], mm, pointSplitEdges);
7078 LWDEBUG(1,
"One or both line endpoints moved by snap, updating line");
7080 nn = nid[0] == nid[1] ? 1 : 2;
7083 if (nn == UINT64_MAX)
7088 start_point = NULL; end_point = NULL;
7089 for (i=0; i<nn; ++i)
7091 if ( node[i].node_id == nid[0] ) start_point = node[i].
geom;
7092 if ( node[i].node_id == nid[1] ) end_point = node[i].
geom;
7094 if ( ! start_point || ! end_point )
7117 LWDEBUGG(2, tmp,
"Made-valid after snap to drifted endpoints");
7126 if ( colex->
ngeoms == 0 )
7130 LWDEBUG(1,
"Made-valid snapped edge collapsed");
7142 lwerror(
"lwcollection_extract(LINETYPE) returned a non-line?");
7151 LWDEBUGF(1,
"Made-valid snapped edge collapsed to %s",
7182 LWDEBUGG(2, tmp2,
"Repeated-point removed");
7191 LWDEBUG(1,
"Repeated-point removed edge collapsed");
7213 id =
_lwt_AddEdge( topo, nid[0], nid[1], edge, 0, handleFaceSplit ? 1 : -1 );
7222 if ( numNewEdges ) ++*numNewEdges;
7238 if ( ! col->
ngeoms )
return bg;
7240 for (i=0; i<col->
ngeoms; ++i)
7254 int handleFaceSplit,
int maxNewEdges)
7264 uint64_t num, numedges = 0, numnodes = 0;
7265 int num_new_edges = 0;
7269 int input_was_closed = 0;
7280 input_was_closed = 1;
7282 LWDEBUGF(1,
"Input line is closed, original point is %g,%g", originalStartPoint.
x, originalStartPoint.
y);
7289 LWDEBUGF(1,
"Working tolerance:%.15g", tol);
7297 LWDEBUGG(1, tmp,
"Repeated-point removed");
7298 }}
else tmp=(
LWGEOM*)line;
7303 if ( ! noded )
return NULL;
7310 LWDEBUGF(1,
"BOX expanded by %g is %.15g %.15g, %.15g %.15g",
7314 int nearbyindex = 0;
7315 int nearbycount = 0;
7319 if (numedges == UINT64_MAX)
7325 LWDEBUGF(1,
"Line has %u points, its bbox intersects %llu edges bboxes",
7332 nearbycount += numedges;
7334 for (i=0; i<numedges; ++i)
7342 if ( 0 == GEOSDistanceIndexed(edge_g, noded_g, &dist) ) {
7343 GEOSGeom_destroy(edge_g);
7344 GEOSGeom_destroy(noded_g);
7349 GEOSGeom_destroy(edge_g);
7350 if ( dist && dist >= tol )
continue;
7351 nearby[nearbyindex++] = g;
7353 LWDEBUGF(1,
"Found %d edges closer than tolerance (%g)", nearbyindex, tol);
7354 GEOSGeom_destroy(noded_g);
7356 int nearbyedgecount = nearbyindex;
7363 if (numnodes == UINT64_MAX)
7369 LWDEBUGF(1,
"Line bbox intersects %llu nodes bboxes", numnodes);
7373 nearbycount = nearbyedgecount + numnodes;
7380 for (i=0; i<numnodes; ++i)
7387 if ( dist && dist >= tol )
7392 nearby[nearbyindex++] = g;
7395 LWDEBUGF(1,
"Found %d isolated nodes closer than tolerance (%g)", nn, tol);
7397 int nearbynodecount = nearbyindex - nearbyedgecount;
7398 nearbycount = nearbyindex;
7400 LWDEBUGF(1,
"Number of nearby elements is %d", nearbycount);
7409 NULL, nearbycount, nearby);
7412 LWDEBUGG(1, elems,
"Collected nearby elements");
7417 LWDEBUGG(1, noded,
"Elements-snapped");
7418 if ( input_was_closed )
7425 LWDEBUGF(1,
"Closed input line start point after snap %g,%g", originalStartPoint.
x, originalStartPoint.
y);
7440 LWDEBUGG(1, noded,
"Unary-unioned");
7444 if ( nearbyedgecount )
7450 LWDEBUGF(1,
"Line intersects %d edges", nearbyedgecount);
7453 NULL, nearbyedgecount, nearby);
7455 LWDEBUGG(1, iedges,
"Collected edges");
7457 LWDEBUGF(1,
"Diffing noded, with srid=%d "
7458 "and intersecting edges, with srid=%d",
7463 LWDEBUGF(1,
"Intersecting noded, with srid=%d "
7464 "and intersecting edges, with srid=%d",
7484 LWDEBUG(1,
"Linemerging intersection");
7494 LWDEBUG(1,
"Unioning difference and (linemerged) intersection");
7496 LWDEBUGG(1, noded,
"Diff-Xset Unioned");
7503 if ( input_was_closed )
7515 LWDEBUGG(1, noded,
"Diff-Xset Unioned cannot be scrolled");
7528 if ( nearbyedgecount )
7530 nearbycount += nearbyedgecount * 2;
7532 for (
int i=0; i<nearbyedgecount; i++)
7544 if ( nearbynodecount )
7547 NULL, nearbynodecount,
7548 nearby + nearbyedgecount);
7560 LWDEBUG(1,
"Freeing up nearby elements");
7563 if ( nearby )
lwfree(nearby);
7567 LWDEBUGG(2, noded,
"Finally-noded");
7573 LWDEBUG(1,
"Noded line was a collection");
7579 LWDEBUG(1,
"Noded line was a single geom");
7580 geomsbuf[0] = noded;
7585 LWDEBUGF(1,
"Line was split into %d edges", ngeoms);
7593 for ( i=0; i<ngeoms; ++i )
7600#if POSTGIS_DEBUG_LEVEL > 0
7604 LWDEBUGF(1,
"Component %llu of split line is: %s", i, wkt1);
7611 num_new_edges += edgeNewEdges;
7613 if ( forward == -1 )
7619 " (forward ? %d), reported to create %d new edges (total new edges: %d)",
7620 id, forward, edgeNewEdges, num_new_edges);
7628 if ( maxNewEdges >= 0 && num_new_edges > maxNewEdges )
7632 lwerror(
"Adding line to topology requires creating more edges than the requested limit of %d", maxNewEdges);
7638 LWDEBUGF(1,
"Component %llu of split line collapsed", i);
7643 i, forward ?
"forward" :
"backward", id);
7644 ids[num++] = forward ? id : -id;
7647 LWDEBUGG(2, noded,
"Noded before free");
7659 return _lwt_AddLine(topo, line, tol, nedges, 1, max_new_edges);
7681 ids =
lwt_AddLine(topo, line, tol, &nedges, max_new_edges);
7682 if ( nedges > 0 )
lwfree(ids);
7691 for ( i=0; i<poly->
nrings; ++i )
7710 uint64_t nfacesinbox;
7714 const GEOSPreparedGeometry *ppoly;
7715 GEOSGeometry *polyg;
7726 LWDEBUGF(1,
"Working tolerance:%.15g", tol);
7738 if (nfacesinbox == UINT64_MAX)
7755 ppoly = GEOSPrepare(polyg);
7757 for ( j=0; j<nfacesinbox; ++j )
7761 GEOSGeometry *fgg, *sp;
7769 GEOSPreparedGeom_destroy(ppoly);
7770 GEOSGeom_destroy(polyg);
7781 GEOSPreparedGeom_destroy(ppoly);
7782 GEOSGeom_destroy(polyg);
7787 sp = GEOSPointOnSurface(fgg);
7788 GEOSGeom_destroy(fgg);
7791 GEOSPreparedGeom_destroy(ppoly);
7792 GEOSGeom_destroy(polyg);
7797 covers = GEOSPreparedCovers( ppoly, sp );
7798 GEOSGeom_destroy(sp);
7801 GEOSPreparedGeom_destroy(ppoly);
7802 GEOSGeom_destroy(polyg);
7815 GEOSPreparedGeom_destroy(ppoly);
7816 GEOSGeom_destroy(polyg);
7832 uint64_t numedges, i;
7834 const POINT2D *closestPointOnEdge = NULL;
7835 uint32_t closestSegmentIndex;
7836 int closestSegmentSide;
7837 uint32_t closestPointVertex;
7838 const POINT2D *closestSegmentP0, *closestSegmentP1;
7851 if (numedges == UINT64_MAX)
7897 closestSegmentP0->
x,
7898 closestSegmentP0->
y,
7899 closestSegmentP1->
x,
7917 const POINT2D *p = queryPoint;
7918 const POINT2D *A = closestSegmentP0;
7919 const POINT2D *B = closestSegmentP1;
7920 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) );
7923 closestPointOnEdge = A;
7924 closestPointVertex = closestSegmentIndex;
7925 if ( closestSegmentIndex == 0 )
7932 closestPointOnEdge = B;
7933 closestPointVertex = closestSegmentIndex + 1;
7936 closestNode = closestEdge->
end_node;
7944 if ( closestNode != 0 )
7960 lwerror(
"Two or more faces found");
7963 containingFace = closestEdge->
face_left;
7968 if (numedges == UINT64_MAX)
7975 for (i=0; i<numedges; ++i)
7977 if ( edges[i].face_left != containingFace ||
7978 edges[i].face_right != containingFace )
7982 lwerror(
"Two or more faces found");
7989 ") returns no edges when we previously found edge %"
7991 closestNode, closestEdge->
edge_id);
7996 LWDEBUGF(1,
"lwt_be_getEdgeByNode returned %" PRIu64
" edges", numedges);
7999 return containingFace;
8007 lwerror(
"error computing azimuth of query point [%.15g %.15g,%.15g %.15g]",
8008 closestPointOnEdge->
x, closestPointOnEdge->
y,
8009 queryPoint->
x, queryPoint->
y);
8018 lwerror(
"Unexpected backend return: _lwt_FindAdjacentEdges(%"
8020 ") found no edges when we previously found edge %"
8022 closestNode, closestEdge->
edge_id);
8032 LWDEBUG(1,
"Closest point is NOT a node");
8039 " on both sides", closestEdge->
face_left);
8041 containingFace = closestEdge->
face_left;
8043 return containingFace;
8050 lwerror(
"Two or more faces found");
8058 LWDEBUGF(1,
"Closest point is vertex %d of closest segment", closestPointVertex);
8069 uint32_t prevVertexIndex = closestPointVertex > 0 ?
8070 closestPointVertex - 1u :
8078 LWDEBUGF(1,
"Previous vertex %u is POINT(%.15g %.15g)",
8084 uint32_t nextVertexIndex = closestPointVertex == closestEdge->
geom->
points->
npoints - 1u ?
8086 closestPointVertex + 1u;
8093 LWDEBUGF(1,
"Next vertex %u is POINT(%.15g %.15g)",
8104 if ( !
azimuth_pt_pt(closestPointOnEdge, prevVertex, &azS0)) {
8105 lwerror(
"error computing azimuth of segment to closest point [%.15g %.15g,%.15g %.15g]",
8106 closestPointOnEdge->
x, closestPointOnEdge->
y,
8107 prevVertex->
x, prevVertex->
y);
8111 if ( !
azimuth_pt_pt(closestPointOnEdge, nextVertex, &azS1)) {
8112 lwerror(
"error computing azimuth of segment from closest point [%.15g %.15g,%.15g %.15g]",
8113 closestPointOnEdge->
x, closestPointOnEdge->
y,
8114 nextVertex->
x, nextVertex->
y);
8118 if ( !
azimuth_pt_pt(closestPointOnEdge, queryPoint, &azSL) ) {
8119 lwerror(
"error computing azimuth of queryPoint [%.15g %.15g,%.15g %.15g]",
8120 closestPointOnEdge->
x, closestPointOnEdge->
y,
8121 queryPoint->
x, queryPoint->
y);
8126 double angle_S0_S1 = azS1 - azS0;
8127 if ( angle_S0_S1 < 0 ) angle_S0_S1 += 2 * M_PI;
8129 double angle_S0_SL = azSL - azS0;
8130 if ( angle_S0_SL < 0 ) angle_S0_SL += 2 * M_PI;
8132 LWDEBUGF(1,
"Azimuths from closest (vertex) point: P:%g, N:%g (+%g), Q:%g (+%g)",
8137 if ( angle_S0_SL < angle_S0_S1 )
8140 containingFace = closestEdge->
face_left;
8153 LWDEBUGF(1,
"Closest point is internal to closest segment, calling lw_segment_side((%g,%g),(%g,%g),(%g,%g)",
8154 closestSegmentP0->
x,
8155 closestSegmentP0->
y,
8156 closestSegmentP1->
x,
8157 closestSegmentP1->
y,
8162 closestSegmentSide =
lw_segment_side(closestSegmentP0, closestSegmentP1, queryPoint);
8163 LWDEBUGF(1,
"Side of closest segment query point falls on: %d (%s)",
8164 closestSegmentSide, closestSegmentSide == -1 ?
"left" : closestSegmentSide == 1 ?
"right" :
"collinear" );
8166 if ( closestSegmentSide == -1 )
8168 containingFace = closestEdge->
face_left;
8170 else if ( closestSegmentSide == 1 )
8176 lwerror(
"Unexpected collinearity reported from lw_segment_side");
8184 return containingFace;
8212 for (i=0; i<coll->
ngeoms; i++)
8219 lwerror(
"%s: Unsupported geometry type: %s", __func__,
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.
int gbox_contains_point2d(const GBOX *g, const POINT2D *p)
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
void lwgeom_geos_error(const char *fmt,...)
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
char lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
geom1 same as geom2 iff
LWGEOM * lwgeom_unaryunion(const LWGEOM *geom1)
int ptarray_closest_segment_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
void * lwrealloc(void *mem, size_t size)
LWGEOM * lwgeom_split(const LWGEOM *lwgeom_in, const LWGEOM *blade_in)
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)
int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance)
Append a POINTARRAY, pa2 to the end of an existing POINTARRAY, pa1.
LWGEOM * lwgeom_linemerge(const LWGEOM *geom1)
void lwpoint_free(LWPOINT *pt)
void lwgeom_free(LWGEOM *geom)
LWPOINT * lwline_get_lwpoint(const LWLINE *line, uint32_t where)
Returns freshly allocated LWPOINT that corresponds to the index where.
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom, double zval)
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
LWGEOM * lwgeom_snap(const LWGEOM *geom1, const LWGEOM *geom2, double tolerance)
Snap vertices and segments of a geometry to another using a given tolerance.
int lwgeom_is_simple(const LWGEOM *lwgeom)
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
void * lwalloc(size_t size)
LWGEOM * lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2)
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
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.
double lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
LWGEOM * lwgeom_difference(const LWGEOM *geom1, const LWGEOM *geom2)
void lwcollection_release(LWCOLLECTION *lwcollection)
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing min distance calculation.
void lwcollection_free(LWCOLLECTION *col)
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
void ptarray_free(POINTARRAY *pa)
LWPOLY * lwpoly_construct(int32_t srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
void lwline_setPoint4d(LWLINE *line, uint32_t which, POINT4D *newpoint)
LWGEOM * lwgeom_union(const LWGEOM *geom1, const LWGEOM *geom2)
int ptarray_is_closed_2d(const POINTARRAY *pa)
void lwpoly_free(LWPOLY *poly)
#define LW_TRUE
Return types for functions with status returns.
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
LWPOLY * lwpoly_construct_empty(int32_t srid, char hasz, char hasm)
LWGEOM * lwgeom_buildarea(const LWGEOM *geom)
Take a geometry and return an areal geometry (Polygon or MultiPolygon).
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
LWCOLLECTION * lwcollection_extract(const LWCOLLECTION *col, uint32_t type)
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
void lwline_free(LWLINE *line)
LWGEOM * lwgeom_make_valid(LWGEOM *geom)
Attempts to make an invalid geometries valid w/out losing points.
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
LWGEOM * lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
void lwgeom_reverse_in_place(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
LWGEOM * lwline_remove_repeated_points(const LWLINE *in, double tolerance)
#define LW_INSIDE
Constants for point-in-polygon return values.
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)
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)
The following is based on the "Fast Winding Number Inclusion of a Point in a Polygon" algorithm by Da...
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()
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
#define P2D_SAME_STRICT(a, b)
#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
#define PGTOPO_BE_ERROR()
Datum contains(PG_FUNCTION_ARGS)
Datum covers(PG_FUNCTION_ARGS)
#define LWDEBUG(level, msg)
#define LWDEBUGF(level, msg,...)
void lwnotice(const char *fmt,...) __attribute__((format(printf
Write a notice out to the notice handler.
#define LWDEBUGGF(level, geom, fmt,...)
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
#define LWDEBUGG(level, geom, msg)
LWT_ELEMID lwt_AddPoint(LWT_TOPOLOGY *topo, LWPOINT *point, double tol)
Adds a point to the topology.
LWT_ELEMID lwt_be_ExistsCoincidentNode(LWT_TOPOLOGY *topo, const LWPOINT *pt)
LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
static LWGEOM * _lwt_toposnap(LWGEOM *src, LWGEOM *tgt, double tol)
LWT_ELEMID lwt_be_ExistsEdgeIntersectingPoint(LWT_TOPOLOGY *topo, const LWPOINT *pt)
#define CBT2(to, method, a1, a2)
static LWT_ELEMID * _lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges, int handleFaceSplit, int maxNewEdges)
LWT_ISO_EDGE * lwt_be_getEdgeWithinDistance2D(LWT_TOPOLOGY *topo, const LWPOINT *pt, double dist, uint64_t *numelems, int fields, int64_t limit)
static GBOX * lwt_be_computeFaceMBR(const LWT_TOPOLOGY *topo, LWT_ELEMID face)
static uint64_t lwt_be_updateFacesById(LWT_TOPOLOGY *topo, const LWT_ISO_FACE *faces, uint64_t numfaces)
void lwt_BackendIfaceRegisterCallbacks(LWT_BE_IFACE *iface, const LWT_BE_CALLBACKS *cb)
Register backend callbacks into the opaque iface handler.
static int _lwt_FindNextRingEdge(const POINTARRAY *ring, int from, const LWT_ISO_EDGE *edges, int numedges)
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.
#define CB1(be, method, a1)
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)
static int _lwt_SnapEdgeToExistingNode(LWT_TOPOLOGY *topo, LWT_ISO_NODE *node, LWT_ISO_EDGE *edge, double tol)
static double lwt_be_topoGetPrecision(LWT_TOPOLOGY *topo)
void lwt_LoadGeometry(LWT_TOPOLOGY *topo, LWGEOM *geom, double tol)
Load a geometry into the topology.
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)
static LWT_ISO_EDGE * lwt_be_getClosestEdge(const LWT_TOPOLOGY *topo, const LWPOINT *pt, uint64_t *numelems, int fields)
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_SnapEdge_checkMotion(LWT_TOPOLOGY *topo, const LWCOLLECTION *splitC, const LWT_ISO_EDGE *edge, LWT_ISO_EDGE *existingEdge, const LWT_NODE_EDGES *splitNodeEdges)
Check the motion of a snapped edge, invoke lwerror if the movement hits any other edge or node.
static int lwt_be_checkTopoGeomRemIsoEdge(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id)
#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_ISO_EDGE * lwt_be_getEdgeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
LWT_ELEMID * lwt_AddPolygon(LWT_TOPOLOGY *topo, LWPOLY *poly, double tol, int *nfaces)
Adds a polygon to the topology.
static void lwt_LoadLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int max_new_edges)
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)
static void lwt_LoadPoint(LWT_TOPOLOGY *topo, LWPOINT *point, double tol)
LWT_ELEMID lwt_be_getNextEdgeId(LWT_TOPOLOGY *topo)
LWT_ELEMID * lwt_AddLineNoFace(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology without determining generated faces.
static LWT_ISO_NODE * _lwt_GetIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID nid)
static LWT_ELEMID _lwt_AddIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID face, LWPOINT *pt, int skipISOChecks, int checkFace)
void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
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.
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)
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges, int max_new_edges)
Adds a linestring to the topology.
static int lwt_be_updateNodesById(LWT_TOPOLOGY *topo, const LWT_ISO_NODE *nodes, int numnodes, int upd_fields)
LWT_ISO_NODE * lwt_be_getNodeWithinDistance2D(LWT_TOPOLOGY *topo, const LWPOINT *pt, double dist, uint64_t *numelems, int fields, int64_t limit)
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)
int lwt_be_updateTopoGeomEdgeSplit(LWT_TOPOLOGY *topo, LWT_ELEMID split_edge, LWT_ELEMID new_edge1, LWT_ELEMID new_edge2)
LWT_TOPOLOGY * lwt_LoadTopology(LWT_BE_IFACE *iface, const char *name)
Loads an existing topology by name from the database.
static double _lwt_minTolerance(LWGEOM *g)
static LWT_ELEMID _lwt_AddPoint(LWT_TOPOLOGY *topo, LWPOINT *point, double tol, int findFace, int *moved, int *numSplitEdges)
int lwt_be_insertNodes(LWT_TOPOLOGY *topo, LWT_ISO_NODE *node, uint64_t numelems)
void _lwt_LoadGeometryRecursive(LWT_TOPOLOGY *topo, LWGEOM *geom, double tol)
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_ELEMID * lwt_be_getRingEdges(LWT_TOPOLOGY *topo, LWT_ELEMID edge, uint64_t *numedges, uint64_t limit)
LWT_BE_TOPOLOGY * lwt_be_loadTopologyByName(LWT_BE_IFACE *be, const char *name)
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 LWT_ELEMID _lwt_GetEqualEdge(LWT_TOPOLOGY *topo, LWLINE *edge, int *forward)
LWT_BE_IFACE * lwt_CreateBackendIface(const LWT_BE_DATA *data)
Create a new backend interface.
static void _lwt_RotateElemidArray(LWT_ELEMID *ary, int from, int to, int rotidx)
static LWT_ISO_FACE * lwt_be_getFaceById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
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)
int lwt_be_deleteEdges(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *sel_edge, int sel_fields)
static LWT_ISO_EDGE * lwt_be_getEdgeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields, const GBOX *box)
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 LWGEOM * _lwt_split_by_nodes(const LWGEOM *g, const LWGEOM *nodes)
void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
static int lwt_be_topoHasZ(LWT_TOPOLOGY *topo)
LWT_ELEMID lwt_ModEdgeHeal(LWT_TOPOLOGY *topo, LWT_ELEMID e1, LWT_ELEMID e2)
Merge two edges, modifying the first and deleting the second.
static LWPOLY * _lwt_MakeRingShell(LWT_TOPOLOGY *topo, LWT_ELEMID *signed_edge_ids, uint64_t num_signed_edge_ids)
static void lwt_LoadPolygon(LWT_TOPOLOGY *topo, const LWPOLY *poly, double tol)
static bool _lwt_describe_point(const LWPOINT *pt, char *buf, size_t bufsize)
static LWT_ELEMID _lwt_AddFaceSplit(LWT_TOPOLOGY *topo, LWT_ELEMID sedge, LWT_ELEMID face, int mbr_only)
int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
static int lwt_be_checkTopoGeomRemIsoNode(LWT_TOPOLOGY *topo, LWT_ELEMID node_id)
#define _LWT_MINTOLERANCE(topo, geom)
#define CBT6(to, method, a1, a2, a3, a4, a5, a6)
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.
#define CBT5(to, method, a1, a2, a3, a4, a5)
int lwt_be_insertEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, uint64_t numelems)
static LWT_ELEMID _lwt_HealEdges(LWT_TOPOLOGY *topo, LWT_ELEMID eid1, LWT_ELEMID eid2, int modEdge)
LWT_ISO_EDGE * lwt_be_getEdgeByNode(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
static LWT_ELEMID _lwt_SplitAllEdgesToNewNode(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edges, uint64_t num, LWPOINT *point, double tol, int *moved)
static LWT_ISO_NODE * lwt_be_getNodeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields, const GBOX *box)
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
static LWT_ISO_NODE * lwt_be_getNodeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
static int _lwt_FirstDistinctVertex2D(const POINTARRAY *pa, const POINT2D *ref, int from, int dir, POINT2D *op)
struct scored_pointer_t scored_pointer
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)
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
static void _lwt_ReverseElemidArray(LWT_ELEMID *ary, int from, int to)
LWT_ISO_NODE * lwt_be_getNodeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
int lwt_RemIsoEdge(LWT_TOPOLOGY *topo, LWT_ELEMID id)
Remove an isolated edge.
static bool _lwt_describe_intersection_point(const GEOSGeometry *g1, const GEOSGeometry *g2, char *buf, size_t bufsize)
int lwt_be_insertFaces(LWT_TOPOLOGY *topo, LWT_ISO_FACE *face, uint64_t numelems)
static LWT_ELEMID _lwt_AddLineEdge(LWT_TOPOLOGY *topo, LWLINE *edge, double tol, int handleFaceSplit, int *forward, int *numNewEdges)
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)
int lwt_ChangeEdgeGeom(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, LWLINE *geom)
Changes the shape of an edge without affecting the topology structure.
static LWT_ELEMID _lwt_RemEdge(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, int modFace)
LWT_ISO_EDGE * lwt_be_getEdgeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
static LWCOLLECTION * _lwt_EdgeSplit(LWT_TOPOLOGY *topo, LWT_ELEMID edge, LWPOINT *pt, int skipISOChecks, LWT_ISO_EDGE **oldedge)
static LWGEOM * _lwt_FaceByEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edges, int numfaceedges)
static int _lwt_FindAdjacentEdges(LWT_TOPOLOGY *topo, LWT_ELEMID node, edgeend *data, edgeend *other, LWT_ELEMID myedge_id)
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
static uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
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 const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
const LWT_EDGEEND * lwt_edgeEndStar_getNextCW(LWT_EDGEEND_STAR *star, LWT_ISO_EDGE *edge, int outgoing)
LWT_EDGEEND_STAR * lwt_edgeEndStar_init(LWT_ELEMID nodeID)
const LWT_EDGEEND * lwt_edgeEndStar_getNextCCW(LWT_EDGEEND_STAR *star, LWT_ISO_EDGE *edge, int outgoing)
void lwt_EdgeEndStar_debugPrint(const LWT_EDGEEND_STAR *star)
void lwt_edgeEndStar_addEdge(LWT_EDGEEND_STAR *star, const LWT_ISO_EDGE *edge)
LWT_NODE_EDGES * lwt_nodeEdges_loadFromDB(LWT_TOPOLOGY *topo, LWT_ELEMID node_id, int fields)
Structure containing base backend callbacks.
const LWT_BE_CALLBACKS * cb
const LWT_ISO_EDGE * edge
LWT_ELEMID containing_face
LWT_BE_TOPOLOGY * be_topo
const LWT_BE_IFACE * be_iface