PostGIS  3.3.9dev-r@@SVN_REVISION@@

◆ lwt_ChangeEdgeGeom()

int lwt_ChangeEdgeGeom ( LWT_TOPOLOGY topo,
LWT_ELEMID  edge,
LWLINE curve 
)

Changes the shape of an edge without affecting the topology structure.

For ST_ChangeEdgeGeom

Parameters
topothe topology to operate on
curvethe edge geometry
Returns
0 on success, -1 on error (liblwgeom error handler will be invoked with error message)

Definition at line 3266 of file lwgeom_topo.c.

3267 {
3268  LWT_ISO_EDGE *oldedge;
3269  LWT_ISO_EDGE newedge;
3270  POINT2D p1, p2, pt;
3271  uint64_t i;
3272  int isclosed = 0;
3273  int leftRingIsCCW = -1;
3274 
3275  /* curve must be simple */
3276  if ( ! lwgeom_is_simple(lwline_as_lwgeom(geom)) )
3277  {
3278  lwerror("SQL/MM Spatial exception - curve not simple");
3279  return -1;
3280  }
3281 
3282  i = 1;
3283  oldedge = lwt_be_getEdgeById(topo, &edge_id, &i, LWT_COL_EDGE_ALL);
3284  if ( ! oldedge )
3285  {
3286  LWDEBUGF(1, "lwt_ChangeEdgeGeom: "
3287  "lwt_be_getEdgeById returned NULL and set i=%d", i);
3288  if (i == UINT64_MAX)
3289  {
3290  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3291  return -1;
3292  }
3293  else if ( i == 0 )
3294  {
3295  lwerror("SQL/MM Spatial exception - non-existent edge %"
3296  LWTFMT_ELEMID, edge_id);
3297  return -1;
3298  }
3299  else
3300  {
3301  lwerror("Backend coding error: getEdgeById callback returned NULL "
3302  "but numelements output parameter has value %d "
3303  "(expected 0 or 1)", i);
3304  return -1;
3305  }
3306  }
3307 
3308  LWDEBUGF(1, "lwt_ChangeEdgeGeom: "
3309  "old edge has %d points, new edge has %d points",
3310  oldedge->geom->points->npoints, geom->points->npoints);
3311 
3312  /*
3313  * e) Check StartPoint consistency
3314  */
3315  getPoint2d_p(oldedge->geom->points, 0, &p1);
3316  getPoint2d_p(geom->points, 0, &pt);
3317  if ( ! P2D_SAME_STRICT(&p1, &pt) )
3318  {
3319  _lwt_release_edges(oldedge, 1);
3320  lwerror("SQL/MM Spatial exception - "
3321  "start node not geometry start point.");
3322  return -1;
3323  }
3324 
3325  /*
3326  * f) Check EndPoint consistency
3327  */
3328  if ( oldedge->geom->points->npoints < 2 )
3329  {
3330  _lwt_release_edges(oldedge, 1);
3331  lwerror("Corrupted topology: edge %" LWTFMT_ELEMID
3332  " has less than 2 vertices", oldedge->edge_id);
3333  return -1;
3334  }
3335  getPoint2d_p(oldedge->geom->points, oldedge->geom->points->npoints-1, &p2);
3336  if ( geom->points->npoints < 2 )
3337  {
3338  _lwt_release_edges(oldedge, 1);
3339  lwerror("Invalid edge: less than 2 vertices");
3340  return -1;
3341  }
3342  getPoint2d_p(geom->points, geom->points->npoints-1, &pt);
3343  if ( ! P2D_SAME_STRICT(&pt, &p2) )
3344  {
3345  _lwt_release_edges(oldedge, 1);
3346  lwerror("SQL/MM Spatial exception - "
3347  "end node not geometry end point.");
3348  return -1;
3349  }
3350 
3351  /* Not in the specs:
3352  * if the edge is closed, check we didn't change winding !
3353  * (should be part of isomorphism checking)
3354  */
3355  if ( oldedge->start_node == oldedge->end_node )
3356  {
3357  isclosed = 1;
3358 #if 1 /* TODO: this is actually bogus as a test */
3359  /* check for valid edge (distinct vertices must exist) */
3360  if ( ! _lwt_GetInteriorEdgePoint(geom, &pt) )
3361  {
3362  _lwt_release_edges(oldedge, 1);
3363  lwerror("Invalid edge (no two distinct vertices exist)");
3364  return -1;
3365  }
3366 #endif
3367 
3368  if ( ptarray_isccw(oldedge->geom->points) !=
3369  ptarray_isccw(geom->points) )
3370  {
3371  _lwt_release_edges(oldedge, 1);
3372  lwerror("Edge twist at node POINT(%g %g)", p1.x, p1.y);
3373  return -1;
3374  }
3375  }
3376 
3377  if ( _lwt_CheckEdgeCrossing(topo, oldedge->start_node,
3378  oldedge->end_node, geom, edge_id ) )
3379  {
3380  /* would have called lwerror already, leaking :( */
3381  _lwt_release_edges(oldedge, 1);
3382  return -1;
3383  }
3384 
3385  LWDEBUG(1, "lwt_ChangeEdgeGeom: "
3386  "edge crossing check passed ");
3387 
3388  /*
3389  * Not in the specs:
3390  * Check topological isomorphism
3391  */
3392 
3393  /* Check that the "motion range" doesn't include any node */
3394  // 1. compute combined bbox of old and new edge
3395  GBOX mbox; /* motion box */
3396  lwgeom_add_bbox((LWGEOM*)oldedge->geom); /* just in case */
3397  lwgeom_add_bbox((LWGEOM*)geom); /* just in case */
3398  gbox_union(oldedge->geom->bbox, geom->bbox, &mbox);
3399  // 2. fetch all nodes in the combined box
3400  LWT_ISO_NODE *nodes;
3401  uint64_t numnodes;
3402  nodes = lwt_be_getNodeWithinBox2D(topo, &mbox, &numnodes,
3403  LWT_COL_NODE_ALL, 0);
3404  LWDEBUGF(1, "lwt_be_getNodeWithinBox2D returned %d nodes", numnodes);
3405  if (numnodes == UINT64_MAX)
3406  {
3407  _lwt_release_edges(oldedge, 1);
3408  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3409  return -1;
3410  }
3411  // 3. if any node beside endnodes are found:
3412  if ( numnodes > ( 1 + isclosed ? 0 : 1 ) )
3413  {{
3414  // 3.2. bail out if any node is in one and not the other
3415  for (i=0; i<numnodes; ++i)
3416  {
3417  LWT_ISO_NODE *n = &(nodes[i]);
3418  if ( n->node_id == oldedge->start_node ) continue;
3419  if ( n->node_id == oldedge->end_node ) continue;
3420  const POINT2D *pt = getPoint2d_cp(n->geom->point, 0);
3421  int ocont = ptarray_contains_point_partial(oldedge->geom->points, pt, isclosed, NULL) == LW_INSIDE;
3422  int ncont = ptarray_contains_point_partial(geom->points, pt, isclosed, NULL) == LW_INSIDE;
3423  if (ocont != ncont)
3424  {
3425  size_t sz;
3426  char *wkt = lwgeom_to_wkt(lwpoint_as_lwgeom(n->geom), WKT_ISO, 15, &sz);
3427  _lwt_release_nodes(nodes, numnodes);
3428  lwerror("Edge motion collision at %s", wkt);
3429  lwfree(wkt); /* would not necessarely reach this point */
3430  return -1;
3431  }
3432  }
3433  }}
3434  if ( numnodes ) _lwt_release_nodes(nodes, numnodes);
3435 
3436  LWDEBUG(1, "nodes containment check passed");
3437 
3438  /*
3439  * Check edge adjacency before
3440  * TODO: can be optimized to gather azimuths of all edge ends once
3441  */
3442 
3443  edgeend span_pre, epan_pre;
3444  /* initialize span_pre.myaz and epan_pre.myaz with existing edge */
3445  int res = _lwt_InitEdgeEndByLine(&span_pre, &epan_pre, oldedge->geom, &p1, &p2);
3446  if (res)
3447  return -1; /* lwerror should have been raised */
3448  _lwt_FindAdjacentEdges( topo, oldedge->start_node, &span_pre,
3449  isclosed ? &epan_pre : NULL, edge_id );
3450  _lwt_FindAdjacentEdges( topo, oldedge->end_node, &epan_pre,
3451  isclosed ? &span_pre : NULL, edge_id );
3452 
3453  LWDEBUGF(1, "edges adjacent to old edge are %" LWTFMT_ELEMID
3454  " and %" LWTFMT_ELEMID " (first point), %" LWTFMT_ELEMID
3455  " and %" LWTFMT_ELEMID " (last point)",
3456  span_pre.nextCW, span_pre.nextCCW,
3457  epan_pre.nextCW, epan_pre.nextCCW);
3458 
3459  /* If the same edge is both on CW and CCW direction on both start
3460  * and end points we need to verify winding of the left and right
3461  * rings to verify we didn't twist.
3462  * See https://trac.osgeo.org/postgis/ticket/5787
3463  *
3464  * NOTE: this could probably replace the "isclosed" test.
3465  *
3466  * NOTE: if either start or end node had different CW and CCW
3467  * edges a twist would be cought in the previous check.
3468  */
3469  if ( ! isclosed &&
3470  oldedge->face_left != oldedge->face_right &&
3471  span_pre.nextCW == span_pre.nextCCW &&
3472  epan_pre.nextCW == epan_pre.nextCCW )
3473  {{
3474  uint64_t num_signed_edge_ids;
3475  LWT_ELEMID *signed_edge_ids;
3476  LWPOLY *shell;
3477 
3478  LWDEBUG(1, "Twist check before");
3479  signed_edge_ids = lwt_be_getRingEdges(topo, edge_id, &num_signed_edge_ids, 0);
3480  /* Get winding of left face ring */
3481  if (!signed_edge_ids)
3482  {
3483  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3484  return -1;
3485  }
3486  LWDEBUGF(1, "getRingEdges returned %d edges", num_signed_edge_ids);
3487 
3488  shell = _lwt_MakeRingShell(topo, signed_edge_ids, num_signed_edge_ids);
3489  if ( ! shell ) {
3490  lwfree( signed_edge_ids );
3491  /* ring_edges should be NULL */
3492  lwerror("Could not create ring shell: %s", lwt_be_lastErrorMessage(topo->be_iface));
3493  return -1;
3494  }
3495 
3496  const POINTARRAY *pa = shell->rings[0];
3497  if ( ! ptarray_is_closed_2d(pa) )
3498  {
3499  lwpoly_free(shell);
3500  lwfree( signed_edge_ids );
3501  lwerror("Corrupted topology: ring of edge %" LWTFMT_ELEMID
3502  " is geometrically not-closed", edge_id);
3503  return -1;
3504  }
3505 
3506  leftRingIsCCW = ptarray_isccw(pa);
3507  lwpoly_free(shell);
3508  lwfree( signed_edge_ids );
3509 
3510  LWDEBUGF(1, "Ring of edge %" LWTFMT_ELEMID " is %sclockwise", edge_id, leftRingIsCCW ? "counter" : "");
3511  }}
3512 
3513 
3514  /* update edge geometry */
3515  newedge.edge_id = edge_id;
3516  newedge.geom = geom;
3517  res = lwt_be_updateEdgesById(topo, &newedge, 1, LWT_COL_EDGE_GEOM);
3518  if (res == -1)
3519  {
3520  _lwt_release_edges(oldedge, 1);
3521  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3522  return -1;
3523  }
3524  if (!res)
3525  {
3526  _lwt_release_edges(oldedge, 1);
3527  lwerror("Unexpected error: %d edges updated when expecting 1", i);
3528  return -1;
3529  }
3530 
3531  /*
3532  * Check edge adjacency after
3533  */
3534  edgeend span_post, epan_post;
3535  /* initialize epan_post.myaz and epan_post.myaz */
3536  res = _lwt_InitEdgeEndByLine(&span_post, &epan_post, geom, &p1, &p2);
3537  if (res)
3538  return -1; /* lwerror should have been raised */
3539  _lwt_FindAdjacentEdges( topo, oldedge->start_node, &span_post,
3540  isclosed ? &epan_post : NULL, edge_id );
3541  _lwt_FindAdjacentEdges( topo, oldedge->end_node, &epan_post,
3542  isclosed ? &span_post : NULL, edge_id );
3543 
3544  LWDEBUGF(1, "edges adjacent to new edge are %" LWTFMT_ELEMID
3545  " and %" LWTFMT_ELEMID " (first point), %" LWTFMT_ELEMID
3546  " and %" LWTFMT_ELEMID " (last point)",
3547  span_pre.nextCW, span_pre.nextCCW,
3548  epan_pre.nextCW, epan_pre.nextCCW);
3549 
3550 
3551  /* Bail out if next CW or CCW edge on start node changed */
3552  if ( span_pre.nextCW != span_post.nextCW ||
3553  span_pre.nextCCW != span_post.nextCCW )
3554  {{
3555  LWT_ELEMID nid = oldedge->start_node;
3556  _lwt_release_edges(oldedge, 1);
3557  lwerror("Edge changed disposition around start node %"
3558  LWTFMT_ELEMID, nid);
3559  return -1;
3560  }}
3561 
3562  /* Bail out if next CW or CCW edge on end node changed */
3563  if ( epan_pre.nextCW != epan_post.nextCW ||
3564  epan_pre.nextCCW != epan_post.nextCCW )
3565  {{
3566  LWT_ELEMID nid = oldedge->end_node;
3567  _lwt_release_edges(oldedge, 1);
3568  lwerror("Edge changed disposition around end node %"
3569  LWTFMT_ELEMID, nid);
3570  return -1;
3571  }}
3572 
3573  /* Check winding of left face ring did not change */
3574  if ( leftRingIsCCW != -1 )
3575  {{
3576  uint64_t num_signed_edge_ids;
3577  LWT_ELEMID *signed_edge_ids;
3578  LWPOLY *shell;
3579  int isCCW;
3580 
3581  LWDEBUG(1, "Twist check after");
3582  signed_edge_ids = lwt_be_getRingEdges(topo, edge_id, &num_signed_edge_ids, 0);
3583  /* Get winding of left face ring */
3584  if (!signed_edge_ids)
3585  {
3586  //PGTOPO_BE_ERRORF("no ring edges for edge %" LWTFMT_ELEMID, sedge);
3587  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3588  return -1;
3589  }
3590  LWDEBUGF(1, "getRingEdges returned %d edges", num_signed_edge_ids);
3591 
3592  shell = _lwt_MakeRingShell(topo, signed_edge_ids, num_signed_edge_ids);
3593  if ( ! shell ) {
3594  lwfree( signed_edge_ids );
3595  /* ring_edges should be NULL */
3596  lwerror("Could not create ring shell: %s", lwt_be_lastErrorMessage(topo->be_iface));
3597  return -1;
3598  }
3599 
3600  const POINTARRAY *pa = shell->rings[0];
3601  if ( ! ptarray_is_closed_2d(pa) )
3602  {
3603  lwpoly_free(shell);
3604  lwfree( signed_edge_ids );
3605  lwerror("Corrupted topology: ring of edge %" LWTFMT_ELEMID
3606  " is geometrically not-closed", edge_id);
3607  return -1;
3608  }
3609 
3610  isCCW = ptarray_isccw(pa);
3611  lwpoly_free(shell);
3612  lwfree( signed_edge_ids );
3613 
3614  if ( isCCW != leftRingIsCCW )
3615  {
3616  _lwt_release_edges(oldedge, 1);
3617  lwerror("Edge ring changes winding");
3618  return -1;
3619  }
3620  }}
3621 
3622  /*
3623  -- Update faces MBR of left and right faces
3624  -- TODO: think about ways to optimize this part, like see if
3625  -- the old edge geometry participated in the definition
3626  -- of the current MBR (for shrinking) or the new edge MBR
3627  -- would be larger than the old face MBR...
3628  --
3629  */
3630  LWGEOM *oldgeom = lwline_as_lwgeom(oldedge->geom);
3631  LWGEOM *newgeom = lwline_as_lwgeom(geom);
3632  lwgeom_refresh_bbox(oldgeom); /* Ensure we use a fit mbr, see #5709 -- TODO: fix this at lower level */
3633  lwgeom_refresh_bbox(newgeom); /* Ensure we use a fit mbr, see #5709 -- TODO: fix this at lower level */
3634  const GBOX* oldbox = lwgeom_get_bbox(oldgeom);
3635  const GBOX* newbox = lwgeom_get_bbox(newgeom);
3636  if ( ! gbox_same(oldbox, newbox) )
3637  {
3638  GBOX* updatedBox;
3639  uint64_t facestoupdate = 0;
3640  LWT_ISO_FACE faces[2];
3641  if ( oldedge->face_left > 0 )
3642  {
3643  updatedBox = lwt_be_computeFaceMBR(topo, oldedge->face_left);
3644  if ( ! updatedBox )
3645  {
3646  lwerror("Corrupted topology: face %d, left of edge %d, has no bbox",
3647  oldedge->face_left, edge_id);
3648  return -1;
3649  }
3650  faces[facestoupdate].face_id = oldedge->face_left;
3651  /* ownership transferred to faces[] */
3652  faces[facestoupdate++].mbr = updatedBox;
3653  }
3654  if ( oldedge->face_right > 0
3655  /* no need to update twice the same face.. */
3656  && oldedge->face_right != oldedge->face_left )
3657  {
3658  updatedBox = lwt_be_computeFaceMBR(topo, oldedge->face_right);
3659  if ( ! updatedBox )
3660  {
3661  lwerror("Corrupted topology: face %d, right of edge %d, has no bbox",
3662  oldedge->face_right, edge_id);
3663  return -1;
3664  }
3665  faces[facestoupdate].face_id = oldedge->face_right;
3666  /* ownership transferred to faces[] */
3667  faces[facestoupdate++].mbr = updatedBox;
3668  }
3669  LWDEBUGF(1, "%d faces to update", facestoupdate);
3670  if ( facestoupdate )
3671  {
3672  uint64_t updatedFaces = lwt_be_updateFacesById(topo, &(faces[0]), facestoupdate);
3673  if (updatedFaces != facestoupdate)
3674  {
3675  while ( facestoupdate-- ) lwfree(faces[facestoupdate].mbr);
3676  _lwt_release_edges(oldedge, 1);
3677  if (updatedFaces == UINT64_MAX)
3678  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3679  else
3680  lwerror("Unexpected error: %d faces updated when expecting 1", updatedFaces);
3681  return -1;
3682  }
3683  }
3684  while ( facestoupdate-- ) lwfree(faces[facestoupdate].mbr);
3685  }
3686  else
3687  {
3688  LWDEBUG(1, "BBOX of changed edge did not change");
3689  }
3690 
3691  LWDEBUG(1, "all done, cleaning up edges");
3692 
3693  _lwt_release_edges(oldedge, 1);
3694  return 0; /* success */
3695 }
int gbox_same(const GBOX *g1, const GBOX *g2)
Check if 2 given Gbox are the same.
Definition: gbox.c:164
int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout)
Update the output GBOX to be large enough to include both inputs.
Definition: gbox.c:135
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
Definition: lwgeom.c:707
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
int lwgeom_is_simple(const LWGEOM *lwgeom)
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition: lwgeom_api.c:343
void lwfree(void *mem)
Definition: lwutil.c:242
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:344
#define WKT_ISO
Definition: liblwgeom.h:2166
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:708
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
int ptarray_is_closed_2d(const POINTARRAY *pa)
Definition: ptarray.c:701
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:175
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:695
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
Definition: ptarray.c:746
#define LW_INSIDE
Constants for point-in-polygon return values.
int ptarray_isccw(const POINTARRAY *pa)
Definition: ptarray.c:1034
#define P2D_SAME_STRICT(a, b)
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_EDGE_ALL
#define LWT_COL_EDGE_GEOM
#define LWT_COL_NODE_ALL
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
static LWT_ELEMID * lwt_be_getRingEdges(LWT_TOPOLOGY *topo, LWT_ELEMID edge, uint64_t *numedges, uint64_t limit)
Definition: lwgeom_topo.c:378
static uint64_t lwt_be_updateFacesById(LWT_TOPOLOGY *topo, const LWT_ISO_FACE *faces, uint64_t numfaces)
Definition: lwgeom_topo.c:291
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:119
static int _lwt_InitEdgeEndByLine(edgeend *fee, edgeend *lee, LWLINE *edge, POINT2D *fp, POINT2D *lp)
Definition: lwgeom_topo.c:1478
LWT_ISO_EDGE * lwt_be_getEdgeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
Definition: lwgeom_topo.c:220
static int _lwt_GetInteriorEdgePoint(const LWLINE *edge, POINT2D *ip)
Definition: lwgeom_topo.c:1755
static LWPOLY * _lwt_MakeRingShell(LWT_TOPOLOGY *topo, LWT_ELEMID *signed_edge_ids, uint64_t num_signed_edge_ids)
Definition: lwgeom_topo.c:1788
static GBOX * lwt_be_computeFaceMBR(const LWT_TOPOLOGY *topo, LWT_ELEMID face)
Definition: lwgeom_topo.c:416
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:611
static void _lwt_release_nodes(LWT_ISO_NODE *nodes, int num_nodes)
Definition: lwgeom_topo.c:475
static int _lwt_FindAdjacentEdges(LWT_TOPOLOGY *topo, LWT_ELEMID node, edgeend *data, edgeend *other, int myedge_id)
Definition: lwgeom_topo.c:1536
static LWT_ISO_NODE * lwt_be_getNodeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
Definition: lwgeom_topo.c:172
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:43
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:465
static int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
Definition: lwgeom_topo.c:299
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:101
tuple res
Definition: window.py:79
GBOX * bbox
Definition: liblwgeom.h:497
POINTARRAY * points
Definition: liblwgeom.h:498
POINTARRAY * point
Definition: liblwgeom.h:486
POINTARRAY ** rings
Definition: liblwgeom.h:534
LWT_ELEMID face_right
LWT_ELEMID end_node
LWT_ELEMID face_left
LWLINE * geom
LWT_ELEMID edge_id
LWT_ELEMID start_node
LWT_ELEMID face_id
LWT_ELEMID node_id
LWPOINT * geom
const LWT_BE_IFACE * be_iface
double y
Definition: liblwgeom.h:405
double x
Definition: liblwgeom.h:405
uint32_t npoints
Definition: liblwgeom.h:442
LWT_ELEMID nextCCW
Definition: lwgeom_topo.c:1422
LWT_ELEMID nextCW
Definition: lwgeom_topo.c:1418

References _lwt_CheckEdgeCrossing(), _lwt_FindAdjacentEdges(), _lwt_GetInteriorEdgePoint(), _lwt_InitEdgeEndByLine(), _lwt_MakeRingShell(), _lwt_release_edges(), _lwt_release_nodes(), LWLINE::bbox, LWT_TOPOLOGY_T::be_iface, LWT_ISO_EDGE::edge_id, LWT_ISO_EDGE::end_node, LWT_ISO_FACE::face_id, LWT_ISO_EDGE::face_left, LWT_ISO_EDGE::face_right, gbox_same(), gbox_union(), LWT_ISO_NODE::geom, LWT_ISO_EDGE::geom, getPoint2d_cp(), getPoint2d_p(), LW_INSIDE, LWDEBUG, LWDEBUGF, lwerror(), lwfree(), lwgeom_add_bbox(), lwgeom_get_bbox(), lwgeom_is_simple(), lwgeom_refresh_bbox(), lwgeom_to_wkt(), lwline_as_lwgeom(), lwpoint_as_lwgeom(), lwpoly_free(), lwt_be_computeFaceMBR(), lwt_be_getEdgeById(), lwt_be_getNodeWithinBox2D(), lwt_be_getRingEdges(), lwt_be_lastErrorMessage(), lwt_be_updateEdgesById(), lwt_be_updateFacesById(), LWT_COL_EDGE_ALL, LWT_COL_EDGE_GEOM, LWT_COL_NODE_ALL, LWTFMT_ELEMID, LWT_ISO_FACE::mbr, edgeend_t::nextCCW, edgeend_t::nextCW, LWT_ISO_NODE::node_id, POINTARRAY::npoints, P2D_SAME_STRICT, LWPOINT::point, LWLINE::points, ptarray_contains_point_partial(), ptarray_is_closed_2d(), ptarray_isccw(), window::res, LWPOLY::rings, LWT_ISO_EDGE::start_node, WKT_ISO, POINT2D::x, and POINT2D::y.

Referenced by _lwt_AddPoint().

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