PostGIS  2.5.0dev-r@@SVN_REVISION@@
static LWT_ELEMID _lwt_AddFaceSplit ( LWT_TOPOLOGY topo,
LWT_ELEMID  sedge,
LWT_ELEMID  face,
int  mbr_only 
)
static

Definition at line 1883 of file lwgeom_topo.c.

References _lwt_GetInteriorEdgePoint(), _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, LWT_ISO_NODE::geom, LWT_ISO_EDGE::geom, lwalloc(), LWDEBUG, LWDEBUGF, lwerror(), lwfree(), LWGEOM2GEOS(), lwgeom_geos_errmsg, lwgeom_get_bbox(), lwpoint_as_lwgeom(), lwpoint_free(), lwpoint_make2d(), 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, ptarray_isccw(), LWPOLY::rings, POINT2D::x, and POINT2D::y.

Referenced by _lwt_AddEdge().

1886 {
1887  int numfaceedges, i, j;
1888  int newface_outside;
1889  int num_signed_edge_ids;
1890  LWT_ELEMID *signed_edge_ids;
1891  LWT_ISO_EDGE *edges;
1892  LWT_ISO_EDGE *forward_edges = NULL;
1893  int forward_edges_count = 0;
1894  LWT_ISO_EDGE *backward_edges = NULL;
1895  int backward_edges_count = 0;
1896 
1897  signed_edge_ids = lwt_be_getRingEdges(topo, sedge,
1898  &num_signed_edge_ids, 0);
1899  if ( ! signed_edge_ids ) {
1900  lwerror("Backend error (no ring edges for edge %" LWTFMT_ELEMID "): %s",
1901  sedge, lwt_be_lastErrorMessage(topo->be_iface));
1902  return -2;
1903  }
1904  LWDEBUGF(1, "getRingEdges returned %d edges", num_signed_edge_ids);
1905 
1906  /* You can't get to the other side of an edge forming a ring */
1907  for (i=0; i<num_signed_edge_ids; ++i) {
1908  if ( signed_edge_ids[i] == -sedge ) {
1909  /* No split here */
1910  LWDEBUG(1, "not a ring");
1911  lwfree( signed_edge_ids );
1912  return 0;
1913  }
1914  }
1915 
1916  LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " split face %" LWTFMT_ELEMID " (mbr_only:%d)",
1917  sedge, face, mbr_only);
1918 
1919  /* Construct a polygon using edges of the ring */
1920  LWPOLY *shell = _lwt_MakeRingShell(topo, signed_edge_ids,
1921  num_signed_edge_ids);
1922  if ( ! shell ) {
1923  lwfree( signed_edge_ids );
1924  /* ring_edges should be NULL */
1925  lwerror("Could not create ring shell: %s", lwt_be_lastErrorMessage(topo->be_iface));
1926  return -2;
1927  }
1928  const POINTARRAY *pa = shell->rings[0];
1929 
1930  int isccw = ptarray_isccw(pa);
1931  LWDEBUGF(1, "Ring of edge %" LWTFMT_ELEMID " is %sclockwise",
1932  sedge, isccw ? "counter" : "");
1933  const GBOX* shellbox = lwgeom_get_bbox(lwpoly_as_lwgeom(shell));
1934 
1935  if ( face == 0 )
1936  {
1937  /* Edge split the universe face */
1938  if ( ! isccw )
1939  {
1940  lwpoly_free(shell);
1941  lwfree( signed_edge_ids );
1942  /* Face on the left side of this ring is the universe face.
1943  * Next call (for the other side) should create the split face
1944  */
1945  LWDEBUG(1, "The left face of this clockwise ring is the universe, "
1946  "won't create a new face there");
1947  return -1;
1948  }
1949  }
1950 
1951  if ( mbr_only && face != 0 )
1952  {
1953  if ( isccw )
1954  {{
1955  LWT_ISO_FACE updface;
1956  updface.face_id = face;
1957  updface.mbr = (GBOX *)shellbox; /* const cast, we won't free it, later */
1958  int ret = lwt_be_updateFacesById( topo, &updface, 1 );
1959  if ( ret == -1 )
1960  {
1961  lwfree( signed_edge_ids );
1962  lwpoly_free(shell); /* NOTE: owns shellbox above */
1963  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
1964  return -2;
1965  }
1966  if ( ret != 1 )
1967  {
1968  lwfree( signed_edge_ids );
1969  lwpoly_free(shell); /* NOTE: owns shellbox above */
1970  lwerror("Unexpected error: %d faces found when expecting 1", ret);
1971  return -2;
1972  }
1973  }}
1974  lwfree( signed_edge_ids );
1975  lwpoly_free(shell); /* NOTE: owns shellbox above */
1976  return -1; /* mbr only was requested */
1977  }
1978 
1979  LWT_ISO_FACE *oldface = NULL;
1980  LWT_ISO_FACE newface;
1981  newface.face_id = -1;
1982  if ( face != 0 && ! isccw)
1983  {{
1984  /* Face created an hole in an outer face */
1985  int nfaces = 1;
1986  oldface = lwt_be_getFaceById(topo, &face, &nfaces, LWT_COL_FACE_ALL);
1987  if ( nfaces == -1 )
1988  {
1989  lwfree( signed_edge_ids );
1990  lwpoly_free(shell); /* NOTE: owns shellbox */
1991  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
1992  return -2;
1993  }
1994  if ( nfaces != 1 )
1995  {
1996  lwfree( signed_edge_ids );
1997  lwpoly_free(shell); /* NOTE: owns shellbox */
1998  lwerror("Unexpected error: %d faces found when expecting 1", nfaces);
1999  return -2;
2000  }
2001  newface.mbr = oldface->mbr;
2002  }}
2003  else
2004  {
2005  newface.mbr = (GBOX *)shellbox; /* const cast, we won't free it, later */
2006  }
2007 
2008  /* Insert the new face */
2009  int ret = lwt_be_insertFaces( topo, &newface, 1 );
2010  if ( ret == -1 )
2011  {
2012  lwfree( signed_edge_ids );
2013  lwpoly_free(shell); /* NOTE: owns shellbox */
2014  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2015  return -2;
2016  }
2017  if ( ret != 1 )
2018  {
2019  lwfree( signed_edge_ids );
2020  lwpoly_free(shell); /* NOTE: owns shellbox */
2021  lwerror("Unexpected error: %d faces inserted when expecting 1", ret);
2022  return -2;
2023  }
2024  if ( oldface ) {
2025  newface.mbr = NULL; /* it is a reference to oldface mbr... */
2026  _lwt_release_faces(oldface, 1);
2027  }
2028 
2029  /* Update side location of new face edges */
2030 
2031  /* We want the new face to be on the left, if possible */
2032  if ( face != 0 && ! isccw ) { /* ring is clockwise in a real face */
2033  /* face shrinked, must update all non-contained edges and nodes */
2034  LWDEBUG(1, "New face is on the outside of the ring, updating rings in former shell");
2035  newface_outside = 1;
2036  /* newface is outside */
2037  } else {
2038  LWDEBUG(1, "New face is on the inside of the ring, updating forward edges in new ring");
2039  newface_outside = 0;
2040  /* newface is inside */
2041  }
2042 
2043  /* Update edges bounding the old face */
2044  /* (1) fetch all edges where left_face or right_face is = oldface */
2045  int fields = LWT_COL_EDGE_EDGE_ID |
2049  ;
2050  numfaceedges = 1;
2051  edges = lwt_be_getEdgeByFace( topo, &face, &numfaceedges, fields, newface.mbr );
2052  if ( numfaceedges == -1 ) {
2053  lwfree( signed_edge_ids );
2054  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2055  return -2;
2056  }
2057  LWDEBUGF(1, "lwt_be_getEdgeByFace returned %d edges", numfaceedges);
2058  GEOSGeometry *shellgg = 0;
2059  const GEOSPreparedGeometry* prepshell = 0;
2060  shellgg = LWGEOM2GEOS( lwpoly_as_lwgeom(shell), 0);
2061  if ( ! shellgg ) {
2062  lwpoly_free(shell);
2063  lwfree(signed_edge_ids);
2064  _lwt_release_edges(edges, numfaceedges);
2065  lwerror("Could not convert shell geometry to GEOS: %s", lwgeom_geos_errmsg);
2066  return -2;
2067  }
2068  prepshell = GEOSPrepare( shellgg );
2069  if ( ! prepshell ) {
2070  GEOSGeom_destroy(shellgg);
2071  lwpoly_free(shell);
2072  lwfree(signed_edge_ids);
2073  _lwt_release_edges(edges, numfaceedges);
2074  lwerror("Could not prepare shell geometry: %s", lwgeom_geos_errmsg);
2075  return -2;
2076  }
2077 
2078  if ( numfaceedges )
2079  {
2080  forward_edges = lwalloc(sizeof(LWT_ISO_EDGE)*numfaceedges);
2081  forward_edges_count = 0;
2082  backward_edges = lwalloc(sizeof(LWT_ISO_EDGE)*numfaceedges);
2083  backward_edges_count = 0;
2084 
2085  /* (2) loop over the results and: */
2086  for ( i=0; i<numfaceedges; ++i )
2087  {
2088  LWT_ISO_EDGE *e = &(edges[i]);
2089  int found = 0;
2090  int contains;
2091  GEOSGeometry *egg;
2092  LWPOINT *epgeom;
2093  POINT2D ep;
2094 
2095  /* (2.1) skip edges whose ID is in the list of boundary edges ? */
2096  for ( j=0; j<num_signed_edge_ids; ++j )
2097  {
2098  int seid = signed_edge_ids[j];
2099  if ( seid == e->edge_id )
2100  {
2101  /* IDEA: remove entry from signed_edge_ids ? */
2102  LWDEBUGF(1, "Edge %d is a forward edge of the new ring", e->edge_id);
2103  forward_edges[forward_edges_count].edge_id = e->edge_id;
2104  forward_edges[forward_edges_count++].face_left = newface.face_id;
2105  found++;
2106  if ( found == 2 ) break;
2107  }
2108  else if ( -seid == e->edge_id )
2109  {
2110  /* IDEA: remove entry from signed_edge_ids ? */
2111  LWDEBUGF(1, "Edge %d is a backward edge of the new ring", e->edge_id);
2112  backward_edges[backward_edges_count].edge_id = e->edge_id;
2113  backward_edges[backward_edges_count++].face_right = newface.face_id;
2114  found++;
2115  if ( found == 2 ) break;
2116  }
2117  }
2118  if ( found ) continue;
2119 
2120  /* We need to check only a single point
2121  * (to avoid collapsed elements of the shell polygon
2122  * giving false positive).
2123  * The point but must not be an endpoint.
2124  */
2125  if ( ! _lwt_GetInteriorEdgePoint(e->geom, &ep) )
2126  {
2127  GEOSPreparedGeom_destroy(prepshell);
2128  GEOSGeom_destroy(shellgg);
2129  lwfree(signed_edge_ids);
2130  lwpoly_free(shell);
2131  lwfree(forward_edges); /* contents owned by edges */
2132  lwfree(backward_edges); /* contents owned by edges */
2133  _lwt_release_edges(edges, numfaceedges);
2134  lwerror("Could not find interior point for edge %d: %s",
2136  return -2;
2137  }
2138 
2139  epgeom = lwpoint_make2d(0, ep.x, ep.y);
2140  egg = LWGEOM2GEOS( lwpoint_as_lwgeom(epgeom) , 0);
2141  lwpoint_free(epgeom);
2142  if ( ! egg ) {
2143  GEOSPreparedGeom_destroy(prepshell);
2144  GEOSGeom_destroy(shellgg);
2145  lwfree(signed_edge_ids);
2146  lwpoly_free(shell);
2147  lwfree(forward_edges); /* contents owned by edges */
2148  lwfree(backward_edges); /* contents owned by edges */
2149  _lwt_release_edges(edges, numfaceedges);
2150  lwerror("Could not convert edge geometry to GEOS: %s",
2152  return -2;
2153  }
2154  /* IDEA: can be optimized by computing this on our side rather
2155  * than on GEOS (saves conversion of big edges) */
2156  /* IDEA: check that bounding box shortcut is taken, or use
2157  * shellbox to do it here */
2158  contains = GEOSPreparedContains( prepshell, egg );
2159  GEOSGeom_destroy(egg);
2160  if ( contains == 2 )
2161  {
2162  GEOSPreparedGeom_destroy(prepshell);
2163  GEOSGeom_destroy(shellgg);
2164  lwfree(signed_edge_ids);
2165  lwpoly_free(shell);
2166  lwfree(forward_edges); /* contents owned by edges */
2167  lwfree(backward_edges); /* contents owned by edges */
2168  _lwt_release_edges(edges, numfaceedges);
2169  lwerror("GEOS exception on PreparedContains: %s", lwgeom_geos_errmsg);
2170  return -2;
2171  }
2172  LWDEBUGF(1, "Edge %d %scontained in new ring", e->edge_id,
2173  (contains?"":"not "));
2174 
2175  /* (2.2) skip edges (NOT, if newface_outside) contained in shell */
2176  if ( newface_outside )
2177  {
2178  if ( contains )
2179  {
2180  LWDEBUGF(1, "Edge %d contained in an hole of the new face",
2181  e->edge_id);
2182  continue;
2183  }
2184  }
2185  else
2186  {
2187  if ( ! contains )
2188  {
2189  LWDEBUGF(1, "Edge %d not contained in the face shell",
2190  e->edge_id);
2191  continue;
2192  }
2193  }
2194 
2195  /* (2.3) push to forward_edges if left_face = oface */
2196  if ( e->face_left == face )
2197  {
2198  LWDEBUGF(1, "Edge %d has new face on the left side", e->edge_id);
2199  forward_edges[forward_edges_count].edge_id = e->edge_id;
2200  forward_edges[forward_edges_count++].face_left = newface.face_id;
2201  }
2202 
2203  /* (2.4) push to backward_edges if right_face = oface */
2204  if ( e->face_right == face )
2205  {
2206  LWDEBUGF(1, "Edge %d has new face on the right side", e->edge_id);
2207  backward_edges[backward_edges_count].edge_id = e->edge_id;
2208  backward_edges[backward_edges_count++].face_right = newface.face_id;
2209  }
2210  }
2211 
2212  /* Update forward edges */
2213  if ( forward_edges_count )
2214  {
2215  ret = lwt_be_updateEdgesById(topo, forward_edges,
2216  forward_edges_count,
2218  if ( ret == -1 )
2219  {
2220  lwfree( signed_edge_ids );
2221  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2222  return -2;
2223  }
2224  if ( ret != forward_edges_count )
2225  {
2226  lwfree( signed_edge_ids );
2227  lwerror("Unexpected error: %d edges updated when expecting %d",
2228  ret, forward_edges_count);
2229  return -2;
2230  }
2231  }
2232 
2233  /* Update backward edges */
2234  if ( backward_edges_count )
2235  {
2236  ret = lwt_be_updateEdgesById(topo, backward_edges,
2237  backward_edges_count,
2239  if ( ret == -1 )
2240  {
2241  lwfree( signed_edge_ids );
2242  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2243  return -2;
2244  }
2245  if ( ret != backward_edges_count )
2246  {
2247  lwfree( signed_edge_ids );
2248  lwerror("Unexpected error: %d edges updated when expecting %d",
2249  ret, backward_edges_count);
2250  return -2;
2251  }
2252  }
2253 
2254  lwfree(forward_edges);
2255  lwfree(backward_edges);
2256 
2257  }
2258 
2259  _lwt_release_edges(edges, numfaceedges);
2260 
2261  /* Update isolated nodes which are now in new face */
2262  int numisonodes = 1;
2264  LWT_ISO_NODE *nodes = lwt_be_getNodeByFace(topo, &face,
2265  &numisonodes, fields, newface.mbr);
2266  if ( numisonodes == -1 ) {
2267  lwfree( signed_edge_ids );
2268  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2269  return -2;
2270  }
2271  if ( numisonodes ) {
2272  LWT_ISO_NODE *updated_nodes = lwalloc(sizeof(LWT_ISO_NODE)*numisonodes);
2273  int nodes_to_update = 0;
2274  for (i=0; i<numisonodes; ++i)
2275  {
2276  LWT_ISO_NODE *n = &(nodes[i]);
2277  GEOSGeometry *ngg;
2278  ngg = LWGEOM2GEOS( lwpoint_as_lwgeom(n->geom), 0 );
2279  int contains;
2280  if ( ! ngg ) {
2281  _lwt_release_nodes(nodes, numisonodes);
2282  if ( prepshell ) GEOSPreparedGeom_destroy(prepshell);
2283  if ( shellgg ) GEOSGeom_destroy(shellgg);
2284  lwfree(signed_edge_ids);
2285  lwpoly_free(shell);
2286  lwerror("Could not convert node geometry to GEOS: %s",
2288  return -2;
2289  }
2290  contains = GEOSPreparedContains( prepshell, ngg );
2291  GEOSGeom_destroy(ngg);
2292  if ( contains == 2 )
2293  {
2294  _lwt_release_nodes(nodes, numisonodes);
2295  if ( prepshell ) GEOSPreparedGeom_destroy(prepshell);
2296  if ( shellgg ) GEOSGeom_destroy(shellgg);
2297  lwfree(signed_edge_ids);
2298  lwpoly_free(shell);
2299  lwerror("GEOS exception on PreparedContains: %s", lwgeom_geos_errmsg);
2300  return -2;
2301  }
2302  LWDEBUGF(1, "Node %d is %scontained in new ring, newface is %s",
2303  n->node_id, contains ? "" : "not ",
2304  newface_outside ? "outside" : "inside" );
2305  if ( newface_outside )
2306  {
2307  if ( contains )
2308  {
2309  LWDEBUGF(1, "Node %d contained in an hole of the new face",
2310  n->node_id);
2311  continue;
2312  }
2313  }
2314  else
2315  {
2316  if ( ! contains )
2317  {
2318  LWDEBUGF(1, "Node %d not contained in the face shell",
2319  n->node_id);
2320  continue;
2321  }
2322  }
2323  updated_nodes[nodes_to_update].node_id = n->node_id;
2324  updated_nodes[nodes_to_update++].containing_face =
2325  newface.face_id;
2326  LWDEBUGF(1, "Node %d will be updated", n->node_id);
2327  }
2328  _lwt_release_nodes(nodes, numisonodes);
2329  if ( nodes_to_update )
2330  {
2331  int ret = lwt_be_updateNodesById(topo, updated_nodes,
2332  nodes_to_update,
2334  if ( ret == -1 ) {
2335  lwfree( signed_edge_ids );
2336  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2337  return -2;
2338  }
2339  }
2340  lwfree(updated_nodes);
2341  }
2342 
2343  GEOSPreparedGeom_destroy(prepshell);
2344  GEOSGeom_destroy(shellgg);
2345  lwfree(signed_edge_ids);
2346  lwpoly_free(shell);
2347 
2348  return newface.face_id;
2349 }
static void _lwt_release_nodes(LWT_ISO_NODE *nodes, int num_nodes)
Definition: lwgeom_topo.c:467
static int _lwt_GetInteriorEdgePoint(const LWLINE *edge, POINT2D *ip)
Definition: lwgeom_topo.c:1737
static LWT_ISO_FACE * lwt_be_getFaceById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:232
LWT_ELEMID face_left
#define LWT_COL_NODE_CONTAINING_FACE
static int lwt_be_insertFaces(LWT_TOPOLOGY *topo, LWT_ISO_FACE *face, int numelems)
Definition: lwgeom_topo.c:201
#define LWT_COL_EDGE_FACE_LEFT
LWT_ELEMID containing_face
static int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
Definition: lwgeom_topo.c:306
LWPOINT * geom
int ptarray_isccw(const POINTARRAY *pa)
Definition: ptarray.c:1021
void lwfree(void *mem)
Definition: lwutil.c:244
#define LWT_COL_EDGE_FACE_RIGHT
LWPOINT * lwpoint_make2d(int srid, double x, double y)
Definition: lwpoint.c:163
void lwpoint_free(LWPOINT *pt)
Definition: lwpoint.c:213
Datum contains(PG_FUNCTION_ARGS)
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
LWLINE * geom
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:319
double x
Definition: liblwgeom.h:327
static LWT_ISO_EDGE * lwt_be_getEdgeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields, const GBOX *box)
Definition: lwgeom_topo.c:246
static int lwt_be_updateFacesById(LWT_TOPOLOGY *topo, const LWT_ISO_FACE *faces, int numfaces)
Definition: lwgeom_topo.c:298
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:173
const LWT_BE_IFACE * be_iface
LWT_ELEMID face_id
static LWT_ISO_NODE * lwt_be_getNodeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields, const GBOX *box)
Definition: lwgeom_topo.c:253
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:727
POINTARRAY ** rings
Definition: liblwgeom.h:456
LWT_ELEMID face_right
LWT_ELEMID node_id
double y
Definition: liblwgeom.h:327
LWT_ELEMID edge_id
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, int autofix)
static LWT_ELEMID * lwt_be_getRingEdges(LWT_TOPOLOGY *topo, LWT_ELEMID edge, int *numedges, int limit)
Definition: lwgeom_topo.c:380
static int lwt_be_updateNodesById(LWT_TOPOLOGY *topo, const LWT_ISO_NODE *nodes, int numnodes, int upd_fields)
Definition: lwgeom_topo.c:314
#define LWT_COL_EDGE_EDGE_ID
Edge fields.
#define LWT_COL_FACE_ALL
#define LWT_COL_NODE_NODE_ID
Node fields.
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:457
static LWPOLY * _lwt_MakeRingShell(LWT_TOPOLOGY *topo, LWT_ELEMID *signed_edge_ids, int num_signed_edge_ids)
Definition: lwgeom_topo.c:1770
#define LWT_COL_NODE_GEOM
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:334
LWT_INT64 LWT_ELEMID
Identifier of topology element.
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:447
#define LWT_COL_EDGE_GEOM
void * lwalloc(size_t size)
Definition: lwutil.c:229
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
uint32_t e
Definition: geobuf.h:57
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:120
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:44

Here is the call graph for this function:

Here is the caller graph for this function: