PostGIS 3.6.2dev-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 1893 of file lwgeom_topo.c.

1896{
1897 uint64_t numfaceedges, i, j;
1898 int newface_outside;
1899 uint64_t num_signed_edge_ids;
1900 LWT_ELEMID *signed_edge_ids;
1901 LWT_ISO_EDGE *edges;
1902 LWT_ISO_EDGE *forward_edges = NULL;
1903 int forward_edges_count = 0;
1904 LWT_ISO_EDGE *backward_edges = NULL;
1905 int backward_edges_count = 0;
1906
1907 signed_edge_ids = lwt_be_getRingEdges(topo, sedge, &num_signed_edge_ids, 0);
1908 if (!signed_edge_ids)
1909 {
1910 //PGTOPO_BE_ERRORF("no ring edges for edge %" LWTFMT_ELEMID, sedge);
1912 return -2;
1913 }
1914 LWDEBUGF(1, "getRingEdges returned %llu edges", num_signed_edge_ids);
1915
1916 /* You can't get to the other side of an edge forming a ring */
1917 for (i=0; i<num_signed_edge_ids; ++i) {
1918 if ( signed_edge_ids[i] == -sedge ) {
1919 /* No split here */
1920 LWDEBUG(1, "not a ring");
1921 lwfree( signed_edge_ids );
1922 return 0;
1923 }
1924 }
1925
1926 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " split face %" LWTFMT_ELEMID " (mbr_only:%d)",
1927 sedge, face, mbr_only);
1928
1929 /*
1930 * Construct a polygon using edges of the ring
1931 *
1932 * NOTE: this possibly includes dangling edges
1933 *
1934 */
1935 LWPOLY *shell = _lwt_MakeRingShell(topo, signed_edge_ids,
1936 num_signed_edge_ids);
1937 if ( ! shell ) {
1938 lwfree( signed_edge_ids );
1939 /* ring_edges should be NULL */
1940 lwerror("Could not create ring shell: %s", lwt_be_lastErrorMessage(topo->be_iface));
1941 return -2;
1942 }
1943 const POINTARRAY *pa = shell->rings[0];
1944 if ( ! ptarray_is_closed_2d(pa) )
1945 {
1946 lwpoly_free(shell);
1947 lwfree( signed_edge_ids );
1948 lwerror("Corrupted topology: ring of edge %" LWTFMT_ELEMID
1949 " is geometrically not-closed", sedge);
1950 return -2;
1951 }
1952
1953 int isccw = ptarray_isccw(pa);
1954 LWDEBUGF(1, "Ring of edge %" LWTFMT_ELEMID " is %sclockwise",
1955 sedge, isccw ? "counter" : "");
1956 const GBOX* shellbox = lwgeom_get_bbox(lwpoly_as_lwgeom(shell));
1957
1958 if ( face == 0 )
1959 {
1960 /* Edge split the universe face */
1961 if ( ! isccw )
1962 {
1963 lwpoly_free(shell);
1964 lwfree( signed_edge_ids );
1965 /* Face on the left side of this ring is the universe face.
1966 * Next call (for the other side) should create the split face
1967 */
1968 LWDEBUG(1, "The left face of this clockwise ring is the universe, "
1969 "won't create a new face there");
1970 return -1;
1971 }
1972 }
1973
1974 if ( mbr_only && face != 0 )
1975 {
1976 if ( isccw )
1977 {{
1978 LWT_ISO_FACE updface;
1979 updface.face_id = face;
1980 updface.mbr = (GBOX *)shellbox; /* const cast, we won't free it, later */
1981 int ret = lwt_be_updateFacesById( topo, &updface, 1 );
1982 if ( ret == -1 )
1983 {
1984 lwfree( signed_edge_ids );
1985 lwpoly_free(shell); /* NOTE: owns shellbox above */
1987 return -2;
1988 }
1989 if ( ret != 1 )
1990 {
1991 lwfree( signed_edge_ids );
1992 lwpoly_free(shell); /* NOTE: owns shellbox above */
1993 lwerror("Unexpected error: %d faces found when expecting 1", ret);
1994 return -2;
1995 }
1996 }}
1997 lwfree( signed_edge_ids );
1998 lwpoly_free(shell); /* NOTE: owns shellbox above */
1999 return -1; /* mbr only was requested */
2000 }
2001
2002 LWT_ISO_FACE *oldface = NULL;
2003 LWT_ISO_FACE newface;
2004 newface.face_id = -1;
2005 if ( face != 0 && ! isccw)
2006 {{
2007 /* Face created an hole in an outer face */
2008 uint64_t nfaces = 1;
2009 oldface = lwt_be_getFaceById(topo, &face, &nfaces, LWT_COL_FACE_ALL);
2010 if (nfaces == UINT64_MAX)
2011 {
2012 lwfree( signed_edge_ids );
2013 lwpoly_free(shell); /* NOTE: owns shellbox */
2015 return -2;
2016 }
2017 if ( nfaces != 1 )
2018 {
2019 lwfree( signed_edge_ids );
2020 lwpoly_free(shell); /* NOTE: owns shellbox */
2021 lwerror("Unexpected error: %" PRIu64 " faces found when expecting 1", nfaces);
2022 return -2;
2023 }
2024 newface.mbr = oldface->mbr;
2025 }}
2026 else
2027 {
2028 newface.mbr = (GBOX *)shellbox; /* const cast, we won't free it, later */
2029 }
2030
2031 /* Insert the new face */
2032 int ret = lwt_be_insertFaces( topo, &newface, 1 );
2033 if ( ret == -1 )
2034 {
2035 lwfree( signed_edge_ids );
2036 lwpoly_free(shell); /* NOTE: owns shellbox */
2038 return -2;
2039 }
2040 if ( ret != 1 )
2041 {
2042 lwfree( signed_edge_ids );
2043 lwpoly_free(shell); /* NOTE: owns shellbox */
2044 lwerror("Unexpected error: %d faces inserted when expecting 1", ret);
2045 return -2;
2046 }
2047 if ( oldface ) {
2048 newface.mbr = NULL; /* it is a reference to oldface mbr... */
2049 _lwt_release_faces(oldface, 1);
2050 }
2051
2052 /* Update side location of new face edges */
2053
2054 /* We want the new face to be on the left, if possible */
2055 if ( face != 0 && ! isccw ) { /* ring is clockwise in a real face */
2056 /* face shrunk, must update all non-contained edges and nodes */
2057 LWDEBUG(1, "New face is on the outside of the ring, updating rings in former shell");
2058 newface_outside = 1;
2059 /* newface is outside */
2060 } else {
2061 LWDEBUG(1, "New face is on the inside of the ring, updating forward edges in new ring");
2062 newface_outside = 0;
2063 /* newface is inside */
2064 }
2065
2066 /* Update edges bounding the old face */
2067 /* (1) fetch all edges where left_face or right_face is = oldface */
2068 int fields = LWT_COL_EDGE_EDGE_ID |
2072 ;
2073 numfaceedges = 1;
2074 edges = lwt_be_getEdgeByFace( topo, &face, &numfaceedges, fields, newface.mbr );
2075 if (numfaceedges == UINT64_MAX)
2076 {
2077 lwfree(signed_edge_ids);
2079 return -2;
2080 }
2081 LWDEBUGF(1, "_lwt_AddFaceSplit: lwt_be_getEdgeByFace(%" LWTFMT_ELEMID ") returned %llu edges", face, numfaceedges);
2082
2083 if ( numfaceedges )
2084 {
2085 forward_edges = lwalloc(sizeof(LWT_ISO_EDGE)*numfaceedges);
2086 forward_edges_count = 0;
2087 backward_edges = lwalloc(sizeof(LWT_ISO_EDGE)*numfaceedges);
2088 backward_edges_count = 0;
2089
2090 /* (2) loop over the results and: */
2091 for ( i=0; i<numfaceedges; ++i )
2092 {
2093 LWT_ISO_EDGE *e = &(edges[i]);
2094 int found = 0;
2095 int contains;
2096 POINT2D ep;
2097
2098 /* (2.1) skip edges whose ID is in the list of boundary edges */
2099 for ( j=0; j<num_signed_edge_ids; ++j )
2100 {
2101 int seid = signed_edge_ids[j]; /* signed ring edge id */
2102 if ( seid == e->edge_id )
2103 {
2104 /* IDEA: remove entry from signed_edge_ids, to speed next loop ? */
2105 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " is a known forward edge of the new ring", e->edge_id);
2106 forward_edges[forward_edges_count].edge_id = e->edge_id;
2107 forward_edges[forward_edges_count++].face_left = newface.face_id;
2108 found++;
2109 if ( found == 2 ) break; /* both edge sides are found on the ring */
2110 }
2111 else if ( -seid == e->edge_id )
2112 {
2113 /* IDEA: remove entry from signed_edge_ids, to speed next loop ? */
2114 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " is a known backward edge of the new ring", e->edge_id);
2115 backward_edges[backward_edges_count].edge_id = e->edge_id;
2116 backward_edges[backward_edges_count++].face_right = newface.face_id;
2117 found++;
2118 if ( found == 2 ) break; /* both edge sides are found on the ring */
2119 }
2120 }
2121 if ( found ) continue;
2122 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " is not a known edge of the new ring", e->edge_id);
2123
2124 /* Check if the edge is now binding a different face */
2125
2126 if ( ! getPoint2d_p(e->geom->points, 0, &ep) )
2127 {
2128 lwfree(signed_edge_ids);
2129 lwpoly_free(shell);
2130 lwfree(forward_edges); /* contents owned by edges */
2131 lwfree(backward_edges); /* contents owned by edges */
2132 _lwt_release_edges(edges, numfaceedges);
2133 lwerror("Edge %" LWTFMT_ELEMID " is empty", e->edge_id);
2134 return -2;
2135 }
2136
2139
2140 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " first point %s new ring",
2141 e->edge_id, (contains == LW_INSIDE ? "inside" :
2142 contains == LW_OUTSIDE ? "outside" : "on boundary of"));
2143
2144 /* (2.2) skip edges (NOT, if newface_outside) contained in ring */
2145 if ( newface_outside )
2146 {
2147 if ( contains != LW_OUTSIDE )
2148 {
2149 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " not outside of the new ring, not updating it",
2150 e->edge_id);
2151 continue;
2152 }
2153 }
2154 else
2155 {
2156 if ( contains != LW_INSIDE )
2157 {
2158 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " not inside the new ring, not updating it",
2159 e->edge_id);
2160 continue;
2161 }
2162 }
2163
2164 /* (2.3) push to forward_edges if left_face = oface */
2165 if ( e->face_left == face )
2166 {
2167 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " has new face on the left side", e->edge_id);
2168 forward_edges[forward_edges_count].edge_id = e->edge_id;
2169 forward_edges[forward_edges_count++].face_left = newface.face_id;
2170 }
2171
2172 /* (2.4) push to backward_edges if right_face = oface */
2173 if ( e->face_right == face )
2174 {
2175 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " has new face on the right side", e->edge_id);
2176 backward_edges[backward_edges_count].edge_id = e->edge_id;
2177 backward_edges[backward_edges_count++].face_right = newface.face_id;
2178 }
2179 }
2180
2181 /* Update forward edges */
2182 if ( forward_edges_count )
2183 {
2184 ret = lwt_be_updateEdgesById(topo, forward_edges,
2185 forward_edges_count,
2187 if ( ret == -1 )
2188 {
2189 lwfree( signed_edge_ids );
2191 return -2;
2192 }
2193 if ( ret != forward_edges_count )
2194 {
2195 lwfree( signed_edge_ids );
2196 lwerror("Unexpected error: %d edges updated when expecting %d",
2197 ret, forward_edges_count);
2198 return -2;
2199 }
2200 }
2201
2202 /* Update backward edges */
2203 if ( backward_edges_count )
2204 {
2205 ret = lwt_be_updateEdgesById(topo, backward_edges,
2206 backward_edges_count,
2208 if ( ret == -1 )
2209 {
2210 lwfree( signed_edge_ids );
2212 return -2;
2213 }
2214 if ( ret != backward_edges_count )
2215 {
2216 lwfree( signed_edge_ids );
2217 lwerror("Unexpected error: %d edges updated when expecting %d",
2218 ret, backward_edges_count);
2219 return -2;
2220 }
2221 }
2222
2223 lwfree(forward_edges);
2224 lwfree(backward_edges);
2225
2226 _lwt_release_edges(edges, numfaceedges);
2227 }
2228
2229 /* Update isolated nodes which are now in new face */
2230 uint64_t numisonodes = 1;
2232 LWT_ISO_NODE *nodes = lwt_be_getNodeByFace(topo, &face,
2233 &numisonodes, fields, newface.mbr);
2234 if (numisonodes == UINT64_MAX)
2235 {
2236 lwfree(signed_edge_ids);
2238 return -2;
2239 }
2240 if ( numisonodes ) {
2241 LWT_ISO_NODE *updated_nodes = lwalloc(sizeof(LWT_ISO_NODE)*numisonodes);
2242 int nodes_to_update = 0;
2243 for (i=0; i<numisonodes; ++i)
2244 {
2245 LWT_ISO_NODE *n = &(nodes[i]);
2246 const POINT2D *pt = getPoint2d_cp(n->geom->point, 0);
2247 int contains = ptarray_contains_point(pa, pt) == LW_INSIDE;
2248 LWDEBUGF(1, "Node %" LWTFMT_ELEMID " is %scontained in new ring, newface is %s",
2249 n->node_id, contains ? "" : "not ",
2250 newface_outside ? "outside" : "inside" );
2251 if ( newface_outside )
2252 {
2253 if ( contains )
2254 {
2255 LWDEBUGF(1, "Node %" LWTFMT_ELEMID " contained in an hole of the new face",
2256 n->node_id);
2257 continue;
2258 }
2259 }
2260 else
2261 {
2262 if ( ! contains )
2263 {
2264 LWDEBUGF(1, "Node %" LWTFMT_ELEMID " not contained in the face shell",
2265 n->node_id);
2266 continue;
2267 }
2268 }
2269 updated_nodes[nodes_to_update].node_id = n->node_id;
2270 updated_nodes[nodes_to_update++].containing_face =
2271 newface.face_id;
2272 LWDEBUGF(1, "Node %" LWTFMT_ELEMID " will be updated", n->node_id);
2273 }
2274 _lwt_release_nodes(nodes, numisonodes);
2275 if ( nodes_to_update )
2276 {
2277 int ret = lwt_be_updateNodesById(topo, updated_nodes,
2278 nodes_to_update,
2280 if ( ret == -1 ) {
2281 lwfree( signed_edge_ids );
2283 return -2;
2284 }
2285 }
2286 lwfree(updated_nodes);
2287 }
2288
2289 lwfree(signed_edge_ids);
2290 lwpoly_free(shell);
2291
2292 return newface.face_id;
2293}
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:743
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:329
#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:1174
#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: