PostGIS  2.5.0dev-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 2359 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().

2362 {
2363  LWT_ISO_EDGE newedge;
2364  LWGEOM *cleangeom;
2365  edgeend span; /* start point analisys */
2366  edgeend epan; /* end point analisys */
2367  POINT2D p1, pn, p2;
2368  POINTARRAY *pa;
2369  LWT_ELEMID node_ids[2];
2370  const LWPOINT *start_node_geom = NULL;
2371  const LWPOINT *end_node_geom = NULL;
2372  int num_nodes;
2373  LWT_ISO_NODE *endpoints;
2374  int i;
2375  int prev_left;
2376  int prev_right;
2377  LWT_ISO_EDGE seledge;
2378  LWT_ISO_EDGE updedge;
2379 
2380  if ( ! skipChecks )
2381  {
2382  /* curve must be simple */
2383  if ( ! lwgeom_is_simple(lwline_as_lwgeom(geom)) )
2384  {
2385  lwerror("SQL/MM Spatial exception - curve not simple");
2386  return -1;
2387  }
2388  }
2389 
2390  newedge.start_node = start_node;
2391  newedge.end_node = end_node;
2392  newedge.geom = geom;
2393  newedge.face_left = -1;
2394  newedge.face_right = -1;
2395  /* TODO: should do the repeated points removal in 2D space */
2396  cleangeom = lwgeom_remove_repeated_points( lwline_as_lwgeom(geom), 0 );
2397 
2398  pa = lwgeom_as_lwline(cleangeom)->points;
2399  if ( pa->npoints < 2 ) {
2400  lwgeom_free(cleangeom);
2401  lwerror("Invalid edge (no two distinct vertices exist)");
2402  return -1;
2403  }
2404 
2405  /* Initialize endpoint info (some of that ) */
2406  span.cwFace = span.ccwFace =
2407  epan.cwFace = epan.ccwFace = -1;
2408 
2409  /* Compute azimuth of first edge end on start node */
2410  getPoint2d_p(pa, 0, &p1);
2411  if ( ! _lwt_FirstDistinctVertex2D(pa, &p1, 0, 1, &pn) )
2412  {
2413  lwgeom_free(cleangeom);
2414  lwerror("Invalid edge (no two distinct vertices exist)");
2415  return -1;
2416  }
2417  if ( ! azimuth_pt_pt(&p1, &pn, &span.myaz) ) {
2418  lwgeom_free(cleangeom);
2419  lwerror("error computing azimuth of first edgeend [%.15g %.15g,%.15g %.15g]",
2420  p1.x, p1.y, pn.x, pn.y);
2421  return -1;
2422  }
2423  LWDEBUGF(1, "edge's start node is %g,%g", p1.x, p1.y);
2424 
2425  /* Compute azimuth of last edge end on end node */
2426  getPoint2d_p(pa, pa->npoints-1, &p2);
2427  if ( ! _lwt_FirstDistinctVertex2D(pa, &p2, pa->npoints-1, -1, &pn) )
2428  {
2429  lwgeom_free(cleangeom);
2430  /* This should never happen as we checked the edge while computing first edgend */
2431  lwerror("Invalid clean edge (no two distinct vertices exist) - should not happen");
2432  return -1;
2433  }
2434  lwgeom_free(cleangeom);
2435  if ( ! azimuth_pt_pt(&p2, &pn, &epan.myaz) ) {
2436  lwerror("error computing azimuth of last edgeend [%.15g %.15g,%.15g %.15g]",
2437  p2.x, p2.y, pn.x, pn.y);
2438  return -1;
2439  }
2440  LWDEBUGF(1, "edge's end node is %g,%g", p2.x, p2.y);
2441 
2442  /*
2443  * Check endpoints existence, match with Curve geometry
2444  * and get face information (if any)
2445  */
2446 
2447  if ( start_node != end_node ) {
2448  num_nodes = 2;
2449  node_ids[0] = start_node;
2450  node_ids[1] = end_node;
2451  } else {
2452  num_nodes = 1;
2453  node_ids[0] = start_node;
2454  }
2455 
2456  endpoints = lwt_be_getNodeById( topo, node_ids, &num_nodes, LWT_COL_NODE_ALL );
2457  if ( num_nodes < 0 ) {
2458  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2459  return -1;
2460  }
2461  for ( i=0; i<num_nodes; ++i )
2462  {
2463  LWT_ISO_NODE* node = &(endpoints[i]);
2464  if ( node->containing_face != -1 )
2465  {
2466  if ( newedge.face_left == -1 )
2467  {
2468  newedge.face_left = newedge.face_right = node->containing_face;
2469  }
2470  else if ( newedge.face_left != node->containing_face )
2471  {
2472  _lwt_release_nodes(endpoints, num_nodes);
2473  lwerror("SQL/MM Spatial exception - geometry crosses an edge"
2474  " (endnodes in faces %" LWTFMT_ELEMID " and %" LWTFMT_ELEMID ")",
2475  newedge.face_left, node->containing_face);
2476  }
2477  }
2478 
2479  LWDEBUGF(1, "Node %d, with geom %p (looking for %d and %d)",
2480  node->node_id, node->geom, start_node, end_node);
2481  if ( node->node_id == start_node ) {
2482  start_node_geom = node->geom;
2483  }
2484  if ( node->node_id == end_node ) {
2485  end_node_geom = node->geom;
2486  }
2487  }
2488 
2489  if ( ! skipChecks )
2490  {
2491  if ( ! start_node_geom )
2492  {
2493  if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
2494  lwerror("SQL/MM Spatial exception - non-existent node");
2495  return -1;
2496  }
2497  else
2498  {
2499  pa = start_node_geom->point;
2500  getPoint2d_p(pa, 0, &pn);
2501  if ( ! p2d_same(&pn, &p1) )
2502  {
2503  if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
2504  lwerror("SQL/MM Spatial exception"
2505  " - start node not geometry start point."
2506  //" - start node not geometry start point (%g,%g != %g,%g).", pn.x, pn.y, p1.x, p1.y
2507  );
2508  return -1;
2509  }
2510  }
2511 
2512  if ( ! end_node_geom )
2513  {
2514  if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
2515  lwerror("SQL/MM Spatial exception - non-existent node");
2516  return -1;
2517  }
2518  else
2519  {
2520  pa = end_node_geom->point;
2521  getPoint2d_p(pa, 0, &pn);
2522  if ( ! p2d_same(&pn, &p2) )
2523  {
2524  if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
2525  lwerror("SQL/MM Spatial exception"
2526  " - end node not geometry end point."
2527  //" - end node not geometry end point (%g,%g != %g,%g).", pn.x, pn.y, p2.x, p2.y
2528  );
2529  return -1;
2530  }
2531  }
2532 
2533  if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
2534 
2535  if ( _lwt_CheckEdgeCrossing( topo, start_node, end_node, geom, 0 ) )
2536  return -1;
2537 
2538  } /* ! skipChecks */
2539 
2540  /*
2541  * All checks passed, time to prepare the new edge
2542  */
2543 
2544  newedge.edge_id = lwt_be_getNextEdgeId( topo );
2545  if ( newedge.edge_id == -1 ) {
2546  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2547  return -1;
2548  }
2549 
2550  /* Find adjacent edges to each endpoint */
2551  int isclosed = start_node == end_node;
2552  int found;
2553  found = _lwt_FindAdjacentEdges( topo, start_node, &span,
2554  isclosed ? &epan : NULL, -1 );
2555  if ( found ) {
2556  span.was_isolated = 0;
2557  newedge.next_right = span.nextCW ? span.nextCW : -newedge.edge_id;
2558  prev_left = span.nextCCW ? -span.nextCCW : newedge.edge_id;
2559  LWDEBUGF(1, "New edge %d is connected on start node, "
2560  "next_right is %d, prev_left is %d",
2561  newedge.edge_id, newedge.next_right, prev_left);
2562  if ( newedge.face_right == -1 ) {
2563  newedge.face_right = span.cwFace;
2564  }
2565  if ( newedge.face_left == -1 ) {
2566  newedge.face_left = span.ccwFace;
2567  }
2568  } else {
2569  span.was_isolated = 1;
2570  newedge.next_right = isclosed ? -newedge.edge_id : newedge.edge_id;
2571  prev_left = isclosed ? newedge.edge_id : -newedge.edge_id;
2572  LWDEBUGF(1, "New edge %d is isolated on start node, "
2573  "next_right is %d, prev_left is %d",
2574  newedge.edge_id, newedge.next_right, prev_left);
2575  }
2576 
2577  found = _lwt_FindAdjacentEdges( topo, end_node, &epan,
2578  isclosed ? &span : NULL, -1 );
2579  if ( found ) {
2580  epan.was_isolated = 0;
2581  newedge.next_left = epan.nextCW ? epan.nextCW : newedge.edge_id;
2582  prev_right = epan.nextCCW ? -epan.nextCCW : -newedge.edge_id;
2583  LWDEBUGF(1, "New edge %d is connected on end node, "
2584  "next_left is %d, prev_right is %d",
2585  newedge.edge_id, newedge.next_left, prev_right);
2586  if ( newedge.face_right == -1 ) {
2587  newedge.face_right = span.ccwFace;
2588  } else if ( modFace != -1 && newedge.face_right != epan.ccwFace ) {
2589  /* side-location conflict */
2590  lwerror("Side-location conflict: "
2591  "new edge starts in face"
2592  " %" LWTFMT_ELEMID " and ends in face"
2593  " %" LWTFMT_ELEMID,
2594  newedge.face_right, epan.ccwFace
2595  );
2596  return -1;
2597  }
2598  if ( newedge.face_left == -1 ) {
2599  newedge.face_left = span.cwFace;
2600  } else if ( modFace != -1 && newedge.face_left != epan.cwFace ) {
2601  /* side-location conflict */
2602  lwerror("Side-location conflict: "
2603  "new edge starts in face"
2604  " %" LWTFMT_ELEMID " and ends in face"
2605  " %" LWTFMT_ELEMID,
2606  newedge.face_left, epan.cwFace
2607  );
2608  return -1;
2609  }
2610  } else {
2611  epan.was_isolated = 1;
2612  newedge.next_left = isclosed ? newedge.edge_id : -newedge.edge_id;
2613  prev_right = isclosed ? -newedge.edge_id : newedge.edge_id;
2614  LWDEBUGF(1, "New edge %d is isolated on end node, "
2615  "next_left is %d, prev_right is %d",
2616  newedge.edge_id, newedge.next_left, prev_right);
2617  }
2618 
2619  /*
2620  * If we don't have faces setup by now we must have encountered
2621  * a malformed topology (no containing_face on isolated nodes, no
2622  * left/right faces on adjacent edges or mismatching values)
2623  */
2624  if ( newedge.face_left != newedge.face_right )
2625  {
2626  lwerror("Left(%" LWTFMT_ELEMID ")/right(%" LWTFMT_ELEMID ")"
2627  "faces mismatch: invalid topology ?",
2628  newedge.face_left, newedge.face_right);
2629  return -1;
2630  }
2631  else if ( newedge.face_left == -1 && modFace > -1 )
2632  {
2633  lwerror("Could not derive edge face from linked primitives:"
2634  " invalid topology ?");
2635  return -1;
2636  }
2637 
2638  /*
2639  * Insert the new edge, and update all linking
2640  */
2641 
2642  int ret = lwt_be_insertEdges(topo, &newedge, 1);
2643  if ( ret == -1 ) {
2644  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2645  return -1;
2646  } else if ( ret == 0 ) {
2647  lwerror("Insertion of split edge failed (no reason)");
2648  return -1;
2649  }
2650 
2651  int updfields;
2652 
2653  /* Link prev_left to us
2654  * (if it's not us already) */
2655  if ( llabs(prev_left) != newedge.edge_id )
2656  {
2657  if ( prev_left > 0 )
2658  {
2659  /* its next_left_edge is us */
2660  updfields = LWT_COL_EDGE_NEXT_LEFT;
2661  updedge.next_left = newedge.edge_id;
2662  seledge.edge_id = prev_left;
2663  }
2664  else
2665  {
2666  /* its next_right_edge is us */
2667  updfields = LWT_COL_EDGE_NEXT_RIGHT;
2668  updedge.next_right = newedge.edge_id;
2669  seledge.edge_id = -prev_left;
2670  }
2671 
2672  ret = lwt_be_updateEdges(topo,
2673  &seledge, LWT_COL_EDGE_EDGE_ID,
2674  &updedge, updfields,
2675  NULL, 0);
2676  if ( ret == -1 ) {
2677  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2678  return -1;
2679  }
2680  }
2681 
2682  /* Link prev_right to us
2683  * (if it's not us already) */
2684  if ( llabs(prev_right) != newedge.edge_id )
2685  {
2686  if ( prev_right > 0 )
2687  {
2688  /* its next_left_edge is -us */
2689  updfields = LWT_COL_EDGE_NEXT_LEFT;
2690  updedge.next_left = -newedge.edge_id;
2691  seledge.edge_id = prev_right;
2692  }
2693  else
2694  {
2695  /* its next_right_edge is -us */
2696  updfields = LWT_COL_EDGE_NEXT_RIGHT;
2697  updedge.next_right = -newedge.edge_id;
2698  seledge.edge_id = -prev_right;
2699  }
2700 
2701  ret = lwt_be_updateEdges(topo,
2702  &seledge, LWT_COL_EDGE_EDGE_ID,
2703  &updedge, updfields,
2704  NULL, 0);
2705  if ( ret == -1 ) {
2706  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2707  return -1;
2708  }
2709  }
2710 
2711  /* NOT IN THE SPECS...
2712  * set containing_face = null for start_node and end_node
2713  * if they where isolated
2714  *
2715  */
2716  LWT_ISO_NODE updnode, selnode;
2717  updnode.containing_face = -1;
2718  if ( span.was_isolated )
2719  {
2720  selnode.node_id = start_node;
2721  ret = lwt_be_updateNodes(topo,
2722  &selnode, LWT_COL_NODE_NODE_ID,
2723  &updnode, LWT_COL_NODE_CONTAINING_FACE,
2724  NULL, 0);
2725  if ( ret == -1 ) {
2726  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2727  return -1;
2728  }
2729  }
2730  if ( epan.was_isolated )
2731  {
2732  selnode.node_id = end_node;
2733  ret = lwt_be_updateNodes(topo,
2734  &selnode, LWT_COL_NODE_NODE_ID,
2735  &updnode, LWT_COL_NODE_CONTAINING_FACE,
2736  NULL, 0);
2737  if ( ret == -1 ) {
2738  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2739  return -1;
2740  }
2741  }
2742 
2743  /* Check face splitting, if required */
2744 
2745  if ( modFace > -1 ) {
2746 
2747  if ( ! isclosed && ( epan.was_isolated || span.was_isolated ) )
2748  {
2749  LWDEBUG(1, "New edge is dangling, so it cannot split any face");
2750  return newedge.edge_id; /* no split */
2751  }
2752 
2753  int newface1 = -1;
2754 
2755  /* IDEA: avoid building edge ring if input is closed, which means we
2756  * know in advance it splits a face */
2757 
2758  if ( ! modFace )
2759  {
2760  newface1 = _lwt_AddFaceSplit( topo, -newedge.edge_id, newedge.face_left, 0 );
2761  if ( newface1 == 0 ) {
2762  LWDEBUG(1, "New edge does not split any face");
2763  return newedge.edge_id; /* no split */
2764  }
2765  }
2766 
2767  int newface = _lwt_AddFaceSplit( topo, newedge.edge_id,
2768  newedge.face_left, 0 );
2769  if ( modFace )
2770  {
2771  if ( newface == 0 ) {
2772  LWDEBUG(1, "New edge does not split any face");
2773  return newedge.edge_id; /* no split */
2774  }
2775 
2776  if ( newface < 0 )
2777  {
2778  /* face on the left is the universe face */
2779  /* must be forming a maximal ring in universal face */
2780  newface = _lwt_AddFaceSplit( topo, -newedge.edge_id,
2781  newedge.face_left, 0 );
2782  if ( newface < 0 ) return newedge.edge_id; /* no split */
2783  }
2784  else
2785  {
2786  _lwt_AddFaceSplit( topo, -newedge.edge_id, newedge.face_left, 1 );
2787  }
2788  }
2789 
2790  /*
2791  * Update topogeometries, if needed
2792  */
2793  if ( newedge.face_left != 0 )
2794  {
2795  ret = lwt_be_updateTopoGeomFaceSplit(topo, newedge.face_left,
2796  newface, newface1);
2797  if ( ret == 0 ) {
2798  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2799  return -1;
2800  }
2801 
2802  if ( ! modFace )
2803  {
2804  /* drop old face from the face table */
2805  ret = lwt_be_deleteFacesById(topo, &(newedge.face_left), 1);
2806  if ( ret == -1 ) {
2807  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
2808  return -1;
2809  }
2810  }
2811  }
2812 
2813  } // end of face split checking
2814 
2815  return newedge.edge_id;
2816 }
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:1422
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:1403
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:1883
LWT_ELEMID nextCCW
Definition: lwgeom_topo.c:1405
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:1409
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:1407
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:1519
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:1408
LWT_ELEMID nextCW
Definition: lwgeom_topo.c:1401
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:2426
#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: