PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ _lwt_AddFaceSplit()

static LWT_ELEMID _lwt_AddFaceSplit ( LWT_TOPOLOGY topo,
LWT_ELEMID  sedge,
LWT_ELEMID  face,
int  mbr_only 
)
static

Definition at line 2010 of file lwgeom_topo.c.

2013{
2014 uint64_t numfaceedges, i, j;
2015 int newface_outside;
2016 uint64_t num_signed_edge_ids;
2017 LWT_ELEMID *signed_edge_ids;
2018 LWT_ISO_EDGE *edges;
2019 LWT_ISO_EDGE *forward_edges = NULL;
2020 int forward_edges_count = 0;
2021 LWT_ISO_EDGE *backward_edges = NULL;
2022 int backward_edges_count = 0;
2023
2024 signed_edge_ids = lwt_be_getRingEdges(topo, sedge, &num_signed_edge_ids, 0);
2025 if (!signed_edge_ids)
2026 {
2027 //PGTOPO_BE_ERRORF("no ring edges for edge %" LWTFMT_ELEMID, sedge);
2029 return -2;
2030 }
2031 LWDEBUGF(1, "getRingEdges returned %llu edges", num_signed_edge_ids);
2032
2033 /* You can't get to the other side of an edge forming a ring */
2034 for (i=0; i<num_signed_edge_ids; ++i) {
2035 if ( signed_edge_ids[i] == -sedge ) {
2036 /* No split here */
2037 LWDEBUG(1, "not a ring");
2038 lwfree( signed_edge_ids );
2039 return 0;
2040 }
2041 }
2042
2043 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " split face %" LWTFMT_ELEMID " (mbr_only:%d)",
2044 sedge, face, mbr_only);
2045
2046 /*
2047 * Construct a polygon using edges of the ring
2048 *
2049 * NOTE: this possibly includes dangling edges
2050 *
2051 */
2052 LWPOLY *shell = _lwt_MakeRingShell(topo, signed_edge_ids,
2053 num_signed_edge_ids);
2054 if ( ! shell ) {
2055 lwfree( signed_edge_ids );
2056 /* ring_edges should be NULL */
2057 lwerror("Could not create ring shell: %s", lwt_be_lastErrorMessage(topo->be_iface));
2058 return -2;
2059 }
2060 const POINTARRAY *pa = shell->rings[0];
2061 if ( ! ptarray_is_closed_2d(pa) )
2062 {
2063 lwpoly_free(shell);
2064 lwfree( signed_edge_ids );
2065 lwerror("Corrupted topology: ring of edge %" LWTFMT_ELEMID
2066 " is geometrically not-closed", sedge);
2067 return -2;
2068 }
2069
2070 int isccw = ptarray_isccw(pa);
2071 LWDEBUGF(1, "Ring of edge %" LWTFMT_ELEMID " is %sclockwise",
2072 sedge, isccw ? "counter" : "");
2073 const GBOX* shellbox = lwgeom_get_bbox(lwpoly_as_lwgeom(shell));
2074
2075 if ( face == 0 )
2076 {
2077 /* Edge split the universe face */
2078 if ( ! isccw )
2079 {
2080 lwpoly_free(shell);
2081 lwfree( signed_edge_ids );
2082 /* Face on the left side of this ring is the universe face.
2083 * Next call (for the other side) should create the split face
2084 */
2085 LWDEBUG(1, "The left face of this clockwise ring is the universe, "
2086 "won't create a new face there");
2087 return -1;
2088 }
2089 }
2090
2091 if ( mbr_only && face != 0 )
2092 {
2093 if ( isccw )
2094 {{
2095 LWT_ISO_FACE updface;
2096 updface.face_id = face;
2097 updface.mbr = (GBOX *)shellbox; /* const cast, we won't free it, later */
2098 int ret = lwt_be_updateFacesById( topo, &updface, 1 );
2099 if ( ret == -1 )
2100 {
2101 lwfree( signed_edge_ids );
2102 lwpoly_free(shell); /* NOTE: owns shellbox above */
2104 return -2;
2105 }
2106 if ( ret != 1 )
2107 {
2108 lwfree( signed_edge_ids );
2109 lwpoly_free(shell); /* NOTE: owns shellbox above */
2110 lwerror("Unexpected error: %d faces found when expecting 1", ret);
2111 return -2;
2112 }
2113 }}
2114 lwfree( signed_edge_ids );
2115 lwpoly_free(shell); /* NOTE: owns shellbox above */
2116 return -1; /* mbr only was requested */
2117 }
2118
2119 LWT_ISO_FACE *oldface = NULL;
2120 LWT_ISO_FACE newface;
2121 newface.face_id = -1;
2122 if ( face != 0 && ! isccw)
2123 {{
2124 /* Face created an hole in an outer face */
2125 uint64_t nfaces = 1;
2126 oldface = lwt_be_getFaceById(topo, &face, &nfaces, LWT_COL_FACE_ALL);
2127 if (nfaces == UINT64_MAX)
2128 {
2129 lwfree( signed_edge_ids );
2130 lwpoly_free(shell); /* NOTE: owns shellbox */
2132 return -2;
2133 }
2134 if ( nfaces != 1 )
2135 {
2136 lwfree( signed_edge_ids );
2137 lwpoly_free(shell); /* NOTE: owns shellbox */
2138 lwerror("Unexpected error: %" PRIu64 " faces found when expecting 1", nfaces);
2139 return -2;
2140 }
2141 newface.mbr = oldface->mbr;
2142 }}
2143 else
2144 {
2145 newface.mbr = (GBOX *)shellbox; /* const cast, we won't free it, later */
2146 }
2147
2148 /* Insert the new face */
2149 int ret = lwt_be_insertFaces( topo, &newface, 1 );
2150 if ( ret == -1 )
2151 {
2152 lwfree( signed_edge_ids );
2153 lwpoly_free(shell); /* NOTE: owns shellbox */
2155 return -2;
2156 }
2157 if ( ret != 1 )
2158 {
2159 lwfree( signed_edge_ids );
2160 lwpoly_free(shell); /* NOTE: owns shellbox */
2161 lwerror("Unexpected error: %d faces inserted when expecting 1", ret);
2162 return -2;
2163 }
2164 if ( oldface ) {
2165 newface.mbr = NULL; /* it is a reference to oldface mbr... */
2166 _lwt_release_faces(oldface, 1);
2167 }
2168
2169 /* Update side location of new face edges */
2170
2171 /* We want the new face to be on the left, if possible */
2172 if ( face != 0 && ! isccw ) { /* ring is clockwise in a real face */
2173 /* face shrunk, must update all non-contained edges and nodes */
2174 LWDEBUG(1, "New face is on the outside of the ring, updating rings in former shell");
2175 newface_outside = 1;
2176 /* newface is outside */
2177 } else {
2178 LWDEBUG(1, "New face is on the inside of the ring, updating forward edges in new ring");
2179 newface_outside = 0;
2180 /* newface is inside */
2181 }
2182
2183 /* Update edges bounding the old face */
2184 /* (1) fetch all edges where left_face or right_face is = oldface */
2185 int fields = LWT_COL_EDGE_EDGE_ID |
2189 ;
2190 numfaceedges = 1;
2191 edges = lwt_be_getEdgeByFace( topo, &face, &numfaceedges, fields, newface.mbr );
2192 if (numfaceedges == UINT64_MAX)
2193 {
2194 lwfree(signed_edge_ids);
2196 return -2;
2197 }
2198 LWDEBUGF(1, "_lwt_AddFaceSplit: lwt_be_getEdgeByFace(%" LWTFMT_ELEMID ") returned %llu edges", face, numfaceedges);
2199
2200 if ( numfaceedges )
2201 {
2202 forward_edges = lwalloc(sizeof(LWT_ISO_EDGE)*numfaceedges);
2203 forward_edges_count = 0;
2204 backward_edges = lwalloc(sizeof(LWT_ISO_EDGE)*numfaceedges);
2205 backward_edges_count = 0;
2206
2207 /* (2) loop over the results and: */
2208 for ( i=0; i<numfaceedges; ++i )
2209 {
2210 LWT_ISO_EDGE *e = &(edges[i]);
2211 int found = 0;
2212 int contains;
2213 POINT2D ep;
2214
2215 /* (2.1) skip edges whose ID is in the list of boundary edges */
2216 for ( j=0; j<num_signed_edge_ids; ++j )
2217 {
2218 int seid = signed_edge_ids[j]; /* signed ring edge id */
2219 if ( seid == e->edge_id )
2220 {
2221 /* IDEA: remove entry from signed_edge_ids, to speed next loop ? */
2222 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " is a known forward edge of the new ring", e->edge_id);
2223 forward_edges[forward_edges_count].edge_id = e->edge_id;
2224 forward_edges[forward_edges_count++].face_left = newface.face_id;
2225 found++;
2226 if ( found == 2 ) break; /* both edge sides are found on the ring */
2227 }
2228 else if ( -seid == e->edge_id )
2229 {
2230 /* IDEA: remove entry from signed_edge_ids, to speed next loop ? */
2231 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " is a known backward edge of the new ring", e->edge_id);
2232 backward_edges[backward_edges_count].edge_id = e->edge_id;
2233 backward_edges[backward_edges_count++].face_right = newface.face_id;
2234 found++;
2235 if ( found == 2 ) break; /* both edge sides are found on the ring */
2236 }
2237 }
2238 if ( found ) continue;
2239 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " is not a known edge of the new ring", e->edge_id);
2240
2241 /* Check if the edge is now binding a different face */
2242
2243 if ( ! getPoint2d_p(e->geom->points, 0, &ep) )
2244 {
2245 lwfree(signed_edge_ids);
2246 lwpoly_free(shell);
2247 lwfree(forward_edges); /* contents owned by edges */
2248 lwfree(backward_edges); /* contents owned by edges */
2249 _lwt_release_edges(edges, numfaceedges);
2250 lwerror("Edge %" LWTFMT_ELEMID " is empty", e->edge_id);
2251 return -2;
2252 }
2253
2256
2257 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " first point %s new ring",
2258 e->edge_id, (contains == LW_INSIDE ? "inside" :
2259 contains == LW_OUTSIDE ? "outside" : "on boundary of"));
2260
2261 /* (2.2) skip edges (NOT, if newface_outside) contained in ring */
2262 if ( newface_outside )
2263 {
2264 if ( contains != LW_OUTSIDE )
2265 {
2266 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " not outside of the new ring, not updating it",
2267 e->edge_id);
2268 continue;
2269 }
2270 }
2271 else
2272 {
2273 if ( contains != LW_INSIDE )
2274 {
2275 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " not inside the new ring, not updating it",
2276 e->edge_id);
2277 continue;
2278 }
2279 }
2280
2281 /* (2.3) push to forward_edges if left_face = oface */
2282 if ( e->face_left == face )
2283 {
2284 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " has new face on the left side", e->edge_id);
2285 forward_edges[forward_edges_count].edge_id = e->edge_id;
2286 forward_edges[forward_edges_count++].face_left = newface.face_id;
2287 }
2288
2289 /* (2.4) push to backward_edges if right_face = oface */
2290 if ( e->face_right == face )
2291 {
2292 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " has new face on the right side", e->edge_id);
2293 backward_edges[backward_edges_count].edge_id = e->edge_id;
2294 backward_edges[backward_edges_count++].face_right = newface.face_id;
2295 }
2296 }
2297
2298 /* Update forward edges */
2299 if ( forward_edges_count )
2300 {
2301 ret = lwt_be_updateEdgesById(topo, forward_edges,
2302 forward_edges_count,
2304 if ( ret == -1 )
2305 {
2306 lwfree( signed_edge_ids );
2308 return -2;
2309 }
2310 if ( ret != forward_edges_count )
2311 {
2312 lwfree( signed_edge_ids );
2313 lwerror("Unexpected error: %d edges updated when expecting %d",
2314 ret, forward_edges_count);
2315 return -2;
2316 }
2317 }
2318
2319 /* Update backward edges */
2320 if ( backward_edges_count )
2321 {
2322 ret = lwt_be_updateEdgesById(topo, backward_edges,
2323 backward_edges_count,
2325 if ( ret == -1 )
2326 {
2327 lwfree( signed_edge_ids );
2329 return -2;
2330 }
2331 if ( ret != backward_edges_count )
2332 {
2333 lwfree( signed_edge_ids );
2334 lwerror("Unexpected error: %d edges updated when expecting %d",
2335 ret, backward_edges_count);
2336 return -2;
2337 }
2338 }
2339
2340 lwfree(forward_edges);
2341 lwfree(backward_edges);
2342
2343 _lwt_release_edges(edges, numfaceedges);
2344 }
2345
2346 /* Update isolated nodes which are now in new face */
2347 uint64_t numisonodes = 1;
2349 LWT_ISO_NODE *nodes = lwt_be_getNodeByFace(topo, &face,
2350 &numisonodes, fields, newface.mbr);
2351 if (numisonodes == UINT64_MAX)
2352 {
2353 lwfree(signed_edge_ids);
2355 return -2;
2356 }
2357 if ( numisonodes ) {
2358 LWT_ISO_NODE *updated_nodes = lwalloc(sizeof(LWT_ISO_NODE)*numisonodes);
2359 int nodes_to_update = 0;
2360 for (i=0; i<numisonodes; ++i)
2361 {
2362 LWT_ISO_NODE *n = &(nodes[i]);
2363 const POINT2D *pt = getPoint2d_cp(n->geom->point, 0);
2364 int contains = ptarray_contains_point(pa, pt) == LW_INSIDE;
2365 LWDEBUGF(1, "Node %" LWTFMT_ELEMID " is %scontained in new ring, newface is %s",
2366 n->node_id, contains ? "" : "not ",
2367 newface_outside ? "outside" : "inside" );
2368 if ( newface_outside )
2369 {
2370 if ( contains )
2371 {
2372 LWDEBUGF(1, "Node %" LWTFMT_ELEMID " contained in an hole of the new face",
2373 n->node_id);
2374 continue;
2375 }
2376 }
2377 else
2378 {
2379 if ( ! contains )
2380 {
2381 LWDEBUGF(1, "Node %" LWTFMT_ELEMID " not contained in the face shell",
2382 n->node_id);
2383 continue;
2384 }
2385 }
2386 updated_nodes[nodes_to_update].node_id = n->node_id;
2387 updated_nodes[nodes_to_update++].containing_face =
2388 newface.face_id;
2389 LWDEBUGF(1, "Node %" LWTFMT_ELEMID " will be updated", n->node_id);
2390 }
2391 _lwt_release_nodes(nodes, numisonodes);
2392 if ( nodes_to_update )
2393 {
2394 int ret = lwt_be_updateNodesById(topo, updated_nodes,
2395 nodes_to_update,
2397 if ( ret == -1 ) {
2398 lwfree( signed_edge_ids );
2400 return -2;
2401 }
2402 }
2403 lwfree(updated_nodes);
2404 }
2405
2406 lwfree(signed_edge_ids);
2407 lwpoly_free(shell);
2408
2409 return newface.face_id;
2410}
int gbox_contains_point2d(const GBOX *g, const POINT2D *p)
Definition gbox.c:362
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition lwgeom_api.c:342
void * lwalloc(size_t size)
Definition lwutil.c:227
void lwfree(void *mem)
Definition lwutil.c:248
int ptarray_is_closed_2d(const POINTARRAY *pa)
Definition ptarray.c:710
void lwpoly_free(LWPOLY *poly)
Definition lwpoly.c:175
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition lwgeom.c:771
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:357
#define LW_INSIDE
Constants for point-in-polygon return values.
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...
Definition ptarray.c:755
#define LW_OUTSIDE
int ptarray_isccw(const POINTARRAY *pa)
Definition ptarray.c:1182
#define LWT_COL_EDGE_FACE_RIGHT
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_FACE_ALL
#define LWT_COL_EDGE_FACE_LEFT
#define LWT_COL_NODE_CONTAINING_FACE
#define LWT_COL_EDGE_EDGE_ID
Edge fields.
#define LWT_COL_NODE_GEOM
#define LWT_COL_NODE_NODE_ID
Node fields.
#define LWT_COL_EDGE_GEOM
#define PGTOPO_BE_ERROR()
#define LWTFMT_ELEMID
Datum contains(PG_FUNCTION_ARGS)
#define LWDEBUG(level, msg)
Definition lwgeom_log.h:101
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static uint64_t lwt_be_updateFacesById(LWT_TOPOLOGY *topo, const LWT_ISO_FACE *faces, uint64_t numfaces)
void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
static int lwt_be_updateNodesById(LWT_TOPOLOGY *topo, const LWT_ISO_NODE *nodes, int numnodes, int upd_fields)
static void _lwt_release_nodes(LWT_ISO_NODE *nodes, int num_nodes)
static LWT_ELEMID * lwt_be_getRingEdges(LWT_TOPOLOGY *topo, LWT_ELEMID edge, uint64_t *numedges, uint64_t limit)
static LWT_ISO_FACE * lwt_be_getFaceById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
static LWT_ISO_EDGE * lwt_be_getEdgeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields, const GBOX *box)
void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
static LWPOLY * _lwt_MakeRingShell(LWT_TOPOLOGY *topo, LWT_ELEMID *signed_edge_ids, uint64_t num_signed_edge_ids)
int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
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)
int lwt_be_insertFaces(LWT_TOPOLOGY *topo, LWT_ISO_FACE *face, uint64_t numelems)
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:97
POINTARRAY * points
Definition liblwgeom.h:483
POINTARRAY * point
Definition liblwgeom.h:471
POINTARRAY ** rings
Definition liblwgeom.h:519
LWT_ELEMID face_right
LWT_ELEMID face_left
LWT_ELEMID edge_id
LWT_ELEMID face_id
LWT_ELEMID node_id
LWT_ELEMID containing_face
LWPOINT * geom
const LWT_BE_IFACE * be_iface

References _lwt_MakeRingShell(), _lwt_release_edges(), _lwt_release_faces(), _lwt_release_nodes(), LWT_TOPOLOGY_T::be_iface, LWT_ISO_NODE::containing_face, contains(), LWT_ISO_EDGE::edge_id, LWT_ISO_FACE::face_id, LWT_ISO_EDGE::face_left, LWT_ISO_EDGE::face_right, gbox_contains_point2d(), LWT_ISO_NODE::geom, LWT_ISO_EDGE::geom, getPoint2d_cp(), getPoint2d_p(), LW_INSIDE, LW_OUTSIDE, LW_TRUE, lwalloc(), LWDEBUG, LWDEBUGF, lwerror(), lwfree(), lwgeom_get_bbox(), lwpoly_as_lwgeom(), lwpoly_free(), lwt_be_getEdgeByFace(), lwt_be_getFaceById(), lwt_be_getNodeByFace(), lwt_be_getRingEdges(), lwt_be_insertFaces(), lwt_be_lastErrorMessage(), lwt_be_updateEdgesById(), lwt_be_updateFacesById(), lwt_be_updateNodesById(), LWT_COL_EDGE_EDGE_ID, LWT_COL_EDGE_FACE_LEFT, LWT_COL_EDGE_FACE_RIGHT, LWT_COL_EDGE_GEOM, LWT_COL_FACE_ALL, LWT_COL_NODE_CONTAINING_FACE, LWT_COL_NODE_GEOM, LWT_COL_NODE_NODE_ID, LWTFMT_ELEMID, LWT_ISO_FACE::mbr, LWT_ISO_NODE::node_id, PGTOPO_BE_ERROR, LWPOINT::point, LWLINE::points, ptarray_contains_point(), ptarray_is_closed_2d(), ptarray_isccw(), and LWPOLY::rings.

Referenced by _lwt_AddEdge(), and _lwt_SnapEdgeToExistingNode().

Here is the call graph for this function:
Here is the caller graph for this function: