PostGIS  2.5.0beta2dev-r@@SVN_REVISION@@

◆ _lwt_AddEdge()

static LWT_ELEMID _lwt_AddEdge ( LWT_TOPOLOGY topo,
LWT_ELEMID  start_node,
LWT_ELEMID  end_node,
LWLINE geom,
int  skipChecks,
int  modFace 
)
static
Parameters
modFacecan be 0 - have two new faces replace a splitted face 1 - modify a splitted face, adding a new one -1 - do not check at all for face splitting

Definition at line 2255 of file lwgeom_topo.c.

References _lwt_AddFaceSplit(), _lwt_CheckEdgeCrossing(), _lwt_FindAdjacentEdges(), _lwt_FirstDistinctVertex2D(), _lwt_release_nodes(), azimuth_pt_pt(), LWT_TOPOLOGY_T::be_iface, edgeend_t::ccwFace, LWT_ISO_NODE::containing_face, edgeend_t::cwFace, LWT_ISO_EDGE::edge_id, LWT_ISO_EDGE::end_node, LWT_ISO_EDGE::face_left, LWT_ISO_EDGE::face_right, LWT_ISO_NODE::geom, LWT_ISO_EDGE::geom, getPoint2d_p(), LWDEBUG, LWDEBUGF, lwerror(), lwgeom_as_lwline(), lwgeom_free(), lwgeom_is_simple(), lwgeom_remove_repeated_points(), lwline_as_lwgeom(), lwt_be_deleteFacesById(), lwt_be_getNextEdgeId(), lwt_be_getNodeById(), lwt_be_insertEdges(), lwt_be_lastErrorMessage(), lwt_be_updateEdges(), lwt_be_updateNodes(), lwt_be_updateTopoGeomFaceSplit(), LWT_COL_EDGE_EDGE_ID, LWT_COL_EDGE_NEXT_LEFT, LWT_COL_EDGE_NEXT_RIGHT, LWT_COL_NODE_ALL, LWT_COL_NODE_CONTAINING_FACE, LWT_COL_NODE_NODE_ID, LWTFMT_ELEMID, edgeend_t::myaz, LWT_ISO_EDGE::next_left, LWT_ISO_EDGE::next_right, edgeend_t::nextCCW, edgeend_t::nextCW, LWT_ISO_NODE::node_id, POINTARRAY::npoints, p2d_same(), LWPOINT::point, LWLINE::points, LWT_ISO_EDGE::start_node, edgeend_t::was_isolated, POINT2D::x, and POINT2D::y.

Referenced by _lwt_AddLineEdge(), lwt_AddEdgeModFace(), and lwt_AddEdgeNewFaces().

2258 {
2259  LWT_ISO_EDGE newedge;
2260  LWGEOM *cleangeom;
2261  edgeend span; /* start point analisys */
2262  edgeend epan; /* end point analisys */
2263  POINT2D p1, pn, p2;
2264  POINTARRAY *pa;
2265  LWT_ELEMID node_ids[2];
2266  const LWPOINT *start_node_geom = NULL;
2267  const LWPOINT *end_node_geom = NULL;
2268  int num_nodes;
2269  LWT_ISO_NODE *endpoints;
2270  int i;
2271  int prev_left;
2272  int prev_right;
2273  LWT_ISO_EDGE seledge;
2274  LWT_ISO_EDGE updedge;
2275 
2276  if ( ! skipChecks )
2277  {
2278  /* curve must be simple */
2279  if ( ! lwgeom_is_simple(lwline_as_lwgeom(geom)) )
2280  {
2281  lwerror("SQL/MM Spatial exception - curve not simple");
2282  return -1;
2283  }
2284  }
2285 
2286  newedge.start_node = start_node;
2287  newedge.end_node = end_node;
2288  newedge.geom = geom;
2289  newedge.face_left = -1;
2290  newedge.face_right = -1;
2291  /* TODO: should do the repeated points removal in 2D space */
2292  cleangeom = lwgeom_remove_repeated_points( lwline_as_lwgeom(geom), 0 );
2293 
2294  pa = lwgeom_as_lwline(cleangeom)->points;
2295  if ( pa->npoints < 2 ) {
2296  lwgeom_free(cleangeom);
2297  lwerror("Invalid edge (no two distinct vertices exist)");
2298  return -1;
2299  }
2300 
2301  /* Initialize endpoint info (some of that ) */
2302  span.cwFace = span.ccwFace =
2303  epan.cwFace = epan.ccwFace = -1;
2304 
2305  /* Compute azimuth of first edge end on start node */
2306  getPoint2d_p(pa, 0, &p1);
2307  if ( ! _lwt_FirstDistinctVertex2D(pa, &p1, 0, 1, &pn) )
2308  {
2309  lwgeom_free(cleangeom);
2310  lwerror("Invalid edge (no two distinct vertices exist)");
2311  return -1;
2312  }
2313  if ( ! azimuth_pt_pt(&p1, &pn, &span.myaz) ) {
2314  lwgeom_free(cleangeom);
2315  lwerror("error computing azimuth of first edgeend [%.15g %.15g,%.15g %.15g]",
2316  p1.x, p1.y, pn.x, pn.y);
2317  return -1;
2318  }
2319  LWDEBUGF(1, "edge's start node is %g,%g", p1.x, p1.y);
2320 
2321  /* Compute azimuth of last edge end on end node */
2322  getPoint2d_p(pa, pa->npoints-1, &p2);
2323  if ( ! _lwt_FirstDistinctVertex2D(pa, &p2, pa->npoints-1, -1, &pn) )
2324  {
2325  lwgeom_free(cleangeom);
2326  /* This should never happen as we checked the edge while computing first edgend */
2327  lwerror("Invalid clean edge (no two distinct vertices exist) - should not happen");
2328  return -1;
2329  }
2330  lwgeom_free(cleangeom);
2331  if ( ! azimuth_pt_pt(&p2, &pn, &epan.myaz) ) {
2332  lwerror("error computing azimuth of last edgeend [%.15g %.15g,%.15g %.15g]",
2333  p2.x, p2.y, pn.x, pn.y);
2334  return -1;
2335  }
2336  LWDEBUGF(1, "edge's end node is %g,%g", p2.x, p2.y);
2337 
2338  /*
2339  * Check endpoints existence, match with Curve geometry
2340  * and get face information (if any)
2341  */
2342 
2343  if ( start_node != end_node ) {
2344  num_nodes = 2;
2345  node_ids[0] = start_node;
2346  node_ids[1] = end_node;
2347  } else {
2348  num_nodes = 1;
2349  node_ids[0] = start_node;
2350  }
2351 
2352  endpoints = lwt_be_getNodeById( topo, node_ids, &num_nodes, LWT_COL_NODE_ALL );
2353  if ( num_nodes < 0 ) {
2354  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2355  return -1;
2356  }
2357  for ( i=0; i<num_nodes; ++i )
2358  {
2359  LWT_ISO_NODE* node = &(endpoints[i]);
2360  if ( node->containing_face != -1 )
2361  {
2362  if ( newedge.face_left == -1 )
2363  {
2364  newedge.face_left = newedge.face_right = node->containing_face;
2365  }
2366  else if ( newedge.face_left != node->containing_face )
2367  {
2368  _lwt_release_nodes(endpoints, num_nodes);
2369  lwerror("SQL/MM Spatial exception - geometry crosses an edge"
2370  " (endnodes in faces %" LWTFMT_ELEMID " and %" LWTFMT_ELEMID ")",
2371  newedge.face_left, node->containing_face);
2372  }
2373  }
2374 
2375  LWDEBUGF(1, "Node %d, with geom %p (looking for %d and %d)",
2376  node->node_id, node->geom, start_node, end_node);
2377  if ( node->node_id == start_node ) {
2378  start_node_geom = node->geom;
2379  }
2380  if ( node->node_id == end_node ) {
2381  end_node_geom = node->geom;
2382  }
2383  }
2384 
2385  if ( ! skipChecks )
2386  {
2387  if ( ! start_node_geom )
2388  {
2389  if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
2390  lwerror("SQL/MM Spatial exception - non-existent node");
2391  return -1;
2392  }
2393  else
2394  {
2395  pa = start_node_geom->point;
2396  getPoint2d_p(pa, 0, &pn);
2397  if ( ! p2d_same(&pn, &p1) )
2398  {
2399  if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
2400  lwerror("SQL/MM Spatial exception"
2401  " - start node not geometry start point."
2402  //" - start node not geometry start point (%g,%g != %g,%g).", pn.x, pn.y, p1.x, p1.y
2403  );
2404  return -1;
2405  }
2406  }
2407 
2408  if ( ! end_node_geom )
2409  {
2410  if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
2411  lwerror("SQL/MM Spatial exception - non-existent node");
2412  return -1;
2413  }
2414  else
2415  {
2416  pa = end_node_geom->point;
2417  getPoint2d_p(pa, 0, &pn);
2418  if ( ! p2d_same(&pn, &p2) )
2419  {
2420  if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
2421  lwerror("SQL/MM Spatial exception"
2422  " - end node not geometry end point."
2423  //" - end node not geometry end point (%g,%g != %g,%g).", pn.x, pn.y, p2.x, p2.y
2424  );
2425  return -1;
2426  }
2427  }
2428 
2429  if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
2430 
2431  if ( _lwt_CheckEdgeCrossing( topo, start_node, end_node, geom, 0 ) )
2432  return -1;
2433 
2434  } /* ! skipChecks */
2435 
2436  /*
2437  * All checks passed, time to prepare the new edge
2438  */
2439 
2440  newedge.edge_id = lwt_be_getNextEdgeId( topo );
2441  if ( newedge.edge_id == -1 ) {
2442  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2443  return -1;
2444  }
2445 
2446  /* Find adjacent edges to each endpoint */
2447  int isclosed = start_node == end_node;
2448  int found;
2449  found = _lwt_FindAdjacentEdges( topo, start_node, &span,
2450  isclosed ? &epan : NULL, -1 );
2451  if ( found ) {
2452  span.was_isolated = 0;
2453  newedge.next_right = span.nextCW ? span.nextCW : -newedge.edge_id;
2454  prev_left = span.nextCCW ? -span.nextCCW : newedge.edge_id;
2455  LWDEBUGF(1, "New edge %d is connected on start node, "
2456  "next_right is %d, prev_left is %d",
2457  newedge.edge_id, newedge.next_right, prev_left);
2458  if ( newedge.face_right == -1 ) {
2459  newedge.face_right = span.cwFace;
2460  }
2461  if ( newedge.face_left == -1 ) {
2462  newedge.face_left = span.ccwFace;
2463  }
2464  } else {
2465  span.was_isolated = 1;
2466  newedge.next_right = isclosed ? -newedge.edge_id : newedge.edge_id;
2467  prev_left = isclosed ? newedge.edge_id : -newedge.edge_id;
2468  LWDEBUGF(1, "New edge %d is isolated on start node, "
2469  "next_right is %d, prev_left is %d",
2470  newedge.edge_id, newedge.next_right, prev_left);
2471  }
2472 
2473  found = _lwt_FindAdjacentEdges( topo, end_node, &epan,
2474  isclosed ? &span : NULL, -1 );
2475  if ( found ) {
2476  epan.was_isolated = 0;
2477  newedge.next_left = epan.nextCW ? epan.nextCW : newedge.edge_id;
2478  prev_right = epan.nextCCW ? -epan.nextCCW : -newedge.edge_id;
2479  LWDEBUGF(1, "New edge %d is connected on end node, "
2480  "next_left is %d, prev_right is %d",
2481  newedge.edge_id, newedge.next_left, prev_right);
2482  if ( newedge.face_right == -1 ) {
2483  newedge.face_right = span.ccwFace;
2484  } else if ( modFace != -1 && newedge.face_right != epan.ccwFace ) {
2485  /* side-location conflict */
2486  lwerror("Side-location conflict: "
2487  "new edge starts in face"
2488  " %" LWTFMT_ELEMID " and ends in face"
2489  " %" LWTFMT_ELEMID,
2490  newedge.face_right, epan.ccwFace
2491  );
2492  return -1;
2493  }
2494  if ( newedge.face_left == -1 ) {
2495  newedge.face_left = span.cwFace;
2496  } else if ( modFace != -1 && newedge.face_left != epan.cwFace ) {
2497  /* side-location conflict */
2498  lwerror("Side-location conflict: "
2499  "new edge starts in face"
2500  " %" LWTFMT_ELEMID " and ends in face"
2501  " %" LWTFMT_ELEMID,
2502  newedge.face_left, epan.cwFace
2503  );
2504  return -1;
2505  }
2506  } else {
2507  epan.was_isolated = 1;
2508  newedge.next_left = isclosed ? newedge.edge_id : -newedge.edge_id;
2509  prev_right = isclosed ? -newedge.edge_id : newedge.edge_id;
2510  LWDEBUGF(1, "New edge %d is isolated on end node, "
2511  "next_left is %d, prev_right is %d",
2512  newedge.edge_id, newedge.next_left, prev_right);
2513  }
2514 
2515  /*
2516  * If we don't have faces setup by now we must have encountered
2517  * a malformed topology (no containing_face on isolated nodes, no
2518  * left/right faces on adjacent edges or mismatching values)
2519  */
2520  if ( newedge.face_left != newedge.face_right )
2521  {
2522  lwerror("Left(%" LWTFMT_ELEMID ")/right(%" LWTFMT_ELEMID ")"
2523  "faces mismatch: invalid topology ?",
2524  newedge.face_left, newedge.face_right);
2525  return -1;
2526  }
2527  else if ( newedge.face_left == -1 && modFace > -1 )
2528  {
2529  lwerror("Could not derive edge face from linked primitives:"
2530  " invalid topology ?");
2531  return -1;
2532  }
2533 
2534  /*
2535  * Insert the new edge, and update all linking
2536  */
2537 
2538  int ret = lwt_be_insertEdges(topo, &newedge, 1);
2539  if ( ret == -1 ) {
2540  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2541  return -1;
2542  } else if ( ret == 0 ) {
2543  lwerror("Insertion of split edge failed (no reason)");
2544  return -1;
2545  }
2546 
2547  int updfields;
2548 
2549  /* Link prev_left to us
2550  * (if it's not us already) */
2551  if ( llabs(prev_left) != newedge.edge_id )
2552  {
2553  if ( prev_left > 0 )
2554  {
2555  /* its next_left_edge is us */
2556  updfields = LWT_COL_EDGE_NEXT_LEFT;
2557  updedge.next_left = newedge.edge_id;
2558  seledge.edge_id = prev_left;
2559  }
2560  else
2561  {
2562  /* its next_right_edge is us */
2563  updfields = LWT_COL_EDGE_NEXT_RIGHT;
2564  updedge.next_right = newedge.edge_id;
2565  seledge.edge_id = -prev_left;
2566  }
2567 
2568  ret = lwt_be_updateEdges(topo,
2569  &seledge, LWT_COL_EDGE_EDGE_ID,
2570  &updedge, updfields,
2571  NULL, 0);
2572  if ( ret == -1 ) {
2573  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2574  return -1;
2575  }
2576  }
2577 
2578  /* Link prev_right to us
2579  * (if it's not us already) */
2580  if ( llabs(prev_right) != newedge.edge_id )
2581  {
2582  if ( prev_right > 0 )
2583  {
2584  /* its next_left_edge is -us */
2585  updfields = LWT_COL_EDGE_NEXT_LEFT;
2586  updedge.next_left = -newedge.edge_id;
2587  seledge.edge_id = prev_right;
2588  }
2589  else
2590  {
2591  /* its next_right_edge is -us */
2592  updfields = LWT_COL_EDGE_NEXT_RIGHT;
2593  updedge.next_right = -newedge.edge_id;
2594  seledge.edge_id = -prev_right;
2595  }
2596 
2597  ret = lwt_be_updateEdges(topo,
2598  &seledge, LWT_COL_EDGE_EDGE_ID,
2599  &updedge, updfields,
2600  NULL, 0);
2601  if ( ret == -1 ) {
2602  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2603  return -1;
2604  }
2605  }
2606 
2607  /* NOT IN THE SPECS...
2608  * set containing_face = null for start_node and end_node
2609  * if they where isolated
2610  *
2611  */
2612  LWT_ISO_NODE updnode, selnode;
2613  updnode.containing_face = -1;
2614  if ( span.was_isolated )
2615  {
2616  selnode.node_id = start_node;
2617  ret = lwt_be_updateNodes(topo,
2618  &selnode, LWT_COL_NODE_NODE_ID,
2619  &updnode, LWT_COL_NODE_CONTAINING_FACE,
2620  NULL, 0);
2621  if ( ret == -1 ) {
2622  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2623  return -1;
2624  }
2625  }
2626  if ( epan.was_isolated )
2627  {
2628  selnode.node_id = end_node;
2629  ret = lwt_be_updateNodes(topo,
2630  &selnode, LWT_COL_NODE_NODE_ID,
2631  &updnode, LWT_COL_NODE_CONTAINING_FACE,
2632  NULL, 0);
2633  if ( ret == -1 ) {
2634  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2635  return -1;
2636  }
2637  }
2638 
2639  /* Check face splitting, if required */
2640 
2641  if ( modFace > -1 ) {
2642 
2643  if ( ! isclosed && ( epan.was_isolated || span.was_isolated ) )
2644  {
2645  LWDEBUG(1, "New edge is dangling, so it cannot split any face");
2646  return newedge.edge_id; /* no split */
2647  }
2648 
2649  int newface1 = -1;
2650 
2651  /* IDEA: avoid building edge ring if input is closed, which means we
2652  * know in advance it splits a face */
2653 
2654  if ( ! modFace )
2655  {
2656  newface1 = _lwt_AddFaceSplit( topo, -newedge.edge_id, newedge.face_left, 0 );
2657  if ( newface1 == 0 ) {
2658  LWDEBUG(1, "New edge does not split any face");
2659  return newedge.edge_id; /* no split */
2660  }
2661  }
2662 
2663  int newface = _lwt_AddFaceSplit( topo, newedge.edge_id,
2664  newedge.face_left, 0 );
2665  if ( modFace )
2666  {
2667  if ( newface == 0 ) {
2668  LWDEBUG(1, "New edge does not split any face");
2669  return newedge.edge_id; /* no split */
2670  }
2671 
2672  if ( newface < 0 )
2673  {
2674  /* face on the left is the universe face */
2675  /* must be forming a maximal ring in universal face */
2676  newface = _lwt_AddFaceSplit( topo, -newedge.edge_id,
2677  newedge.face_left, 0 );
2678  if ( newface < 0 ) return newedge.edge_id; /* no split */
2679  }
2680  else
2681  {
2682  _lwt_AddFaceSplit( topo, -newedge.edge_id, newedge.face_left, 1 );
2683  }
2684  }
2685 
2686  /*
2687  * Update topogeometries, if needed
2688  */
2689  if ( newedge.face_left != 0 )
2690  {
2691  ret = lwt_be_updateTopoGeomFaceSplit(topo, newedge.face_left,
2692  newface, newface1);
2693  if ( ret == 0 ) {
2694  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2695  return -1;
2696  }
2697 
2698  if ( ! modFace )
2699  {
2700  /* drop old face from the face table */
2701  ret = lwt_be_deleteFacesById(topo, &(newedge.face_left), 1);
2702  if ( ret == -1 ) {
2703  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2704  return -1;
2705  }
2706  }
2707  }
2708 
2709  } // end of face split checking
2710 
2711  return newedge.edge_id;
2712 }
static int _lwt_CheckEdgeCrossing(LWT_TOPOLOGY *topo, LWT_ELEMID start_node, LWT_ELEMID end_node, const LWLINE *geom, LWT_ELEMID myself)
Definition: lwgeom_topo.c:601
static void _lwt_release_nodes(LWT_ISO_NODE *nodes, int num_nodes)
Definition: lwgeom_topo.c:467
LWT_ELEMID face_left
#define LWT_COL_NODE_CONTAINING_FACE
LWT_ELEMID containing_face
LWPOINT * geom
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1144
static int _lwt_FirstDistinctVertex2D(const POINTARRAY *pa, POINT2D *ref, int from, int dir, POINT2D *op)
Definition: lwgeom_topo.c:1395
static int lwt_be_updateTopoGeomFaceSplit(LWT_TOPOLOGY *topo, LWT_ELEMID split_face, LWT_ELEMID new_face1, LWT_ELEMID new_face2)
Definition: lwgeom_topo.c:343
LWT_ELEMID cwFace
Definition: lwgeom_topo.c:1376
LWLINE * geom
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
static LWT_ELEMID _lwt_AddFaceSplit(LWT_TOPOLOGY *topo, LWT_ELEMID sedge, LWT_ELEMID face, int mbr_only)
Definition: lwgeom_topo.c:1856
LWT_ELEMID nextCCW
Definition: lwgeom_topo.c:1378
POINTARRAY * point
Definition: liblwgeom.h:413
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)
Definition: lwgeom_topo.c:286
LWT_ELEMID next_left
double x
Definition: liblwgeom.h:330
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:49
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:330
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)
Definition: lwgeom_topo.c:274
double myaz
Definition: lwgeom_topo.c:1382
const LWT_BE_IFACE * be_iface
LWT_ELEMID face_right
LWT_ELEMID node_id
double y
Definition: liblwgeom.h:330
LWT_ELEMID edge_id
static int lwt_be_deleteFacesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int numelems)
Definition: lwgeom_topo.c:207
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:170
LWT_ELEMID ccwFace
Definition: lwgeom_topo.c:1380
LWT_ELEMID lwt_be_getNextEdgeId(LWT_TOPOLOGY *topo)
Definition: lwgeom_topo.c:219
#define LWT_COL_EDGE_EDGE_ID
Edge fields.
#define LWT_COL_NODE_NODE_ID
Node fields.
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition: lwgeom_api.c:338
#define LWT_COL_EDGE_NEXT_LEFT
static int _lwt_FindAdjacentEdges(LWT_TOPOLOGY *topo, LWT_ELEMID node, edgeend *data, edgeend *other, int myedge_id)
Definition: lwgeom_topo.c:1492
int lwt_be_insertEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, int numelems)
Definition: lwgeom_topo.c:268
#define LWT_COL_NODE_ALL
#define LWT_COL_EDGE_NEXT_RIGHT
LWT_ELEMID start_node
int lwgeom_is_simple(const LWGEOM *lwgeom)
LWT_ELEMID next_right
LWT_INT64 LWT_ELEMID
Identifier of topology element.
LWGEOM * lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
Definition: lwgeom.c:1503
LWT_ISO_NODE * lwt_be_getNodeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:156
int was_isolated
Definition: lwgeom_topo.c:1381
LWT_ELEMID nextCW
Definition: lwgeom_topo.c:1374
LWT_ELEMID end_node
int azimuth_pt_pt(const POINT2D *p1, const POINT2D *p2, double *ret)
Compute the azimuth of segment AB in radians.
Definition: measures.c:2416
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
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
POINTARRAY * points
Definition: liblwgeom.h:424
uint32_t npoints
Definition: liblwgeom.h:373
Here is the call graph for this function:
Here is the caller graph for this function: