PostGIS  2.4.9dev-r@@SVN_REVISION@@

◆ _lwt_HealEdges()

static LWT_ELEMID _lwt_HealEdges ( LWT_TOPOLOGY topo,
LWT_ELEMID  eid1,
LWT_ELEMID  eid2,
int  modEdge 
)
static

Definition at line 4330 of file lwgeom_topo.c.

References _lwt_release_edges(), LWT_TOPOLOGY_T::be_iface, LWT_ISO_EDGE::edge_id, LWT_ISO_EDGE::end_node, LWT_ISO_EDGE::face_left, LWT_ISO_EDGE::face_right, LWT_ISO_EDGE::geom, lwerror(), lwfree(), lwline_construct(), lwline_free(), lwt_be_checkTopoGeomRemNode(), lwt_be_deleteEdges(), lwt_be_deleteNodesById(), lwt_be_getEdgeById(), lwt_be_getEdgeByNode(), lwt_be_insertEdges(), lwt_be_lastErrorMessage(), lwt_be_updateEdges(), lwt_be_updateEdgesById(), lwt_be_updateTopoGeomEdgeHeal(), LWT_COL_EDGE_ALL, LWT_COL_EDGE_EDGE_ID, LWT_COL_EDGE_END_NODE, LWT_COL_EDGE_GEOM, LWT_COL_EDGE_NEXT_LEFT, LWT_COL_EDGE_NEXT_RIGHT, LWT_COL_EDGE_START_NODE, LWTFMT_ELEMID, LWT_ISO_EDGE::next_left, LWT_ISO_EDGE::next_right, LWLINE::points, ptarray_append_ptarray(), ptarray_clone_deep(), ptarray_free(), ptarray_reverse(), r, LWT_TOPOLOGY_T::srid, and LWT_ISO_EDGE::start_node.

Referenced by lwt_ModEdgeHeal(), and lwt_NewEdgeHeal().

4332 {
4333  LWT_ELEMID ids[2];
4334  LWT_ELEMID commonnode = -1;
4335  int caseno = 0;
4336  LWT_ISO_EDGE *node_edges;
4337  int num_node_edges;
4338  LWT_ISO_EDGE *edges;
4339  LWT_ISO_EDGE *e1 = NULL;
4340  LWT_ISO_EDGE *e2 = NULL;
4341  LWT_ISO_EDGE newedge, updedge, seledge;
4342  int nedges, i;
4343  int e1freenode;
4344  int e2sign, e2freenode;
4345  POINTARRAY *pa;
4346  char buf[256];
4347  char *ptr;
4348  size_t bufleft = 256;
4349 
4350  ptr = buf;
4351 
4352  /* NOT IN THE SPECS: see if the same edge is given twice.. */
4353  if ( eid1 == eid2 )
4354  {
4355  lwerror("Cannot heal edge %" LWTFMT_ELEMID
4356  " with itself, try with another", eid1);
4357  return -1;
4358  }
4359  ids[0] = eid1;
4360  ids[1] = eid2;
4361  nedges = 2;
4362  edges = lwt_be_getEdgeById(topo, ids, &nedges, LWT_COL_EDGE_ALL);
4363  if ( nedges == -1 )
4364  {
4365  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4366  return -1;
4367  }
4368  for ( i=0; i<nedges; ++i )
4369  {
4370  if ( edges[i].edge_id == eid1 ) {
4371  if ( e1 ) {
4372  _lwt_release_edges(edges, nedges);
4373  lwerror("Corrupted topology: multiple edges have id %"
4374  LWTFMT_ELEMID, eid1);
4375  return -1;
4376  }
4377  e1 = &(edges[i]);
4378  }
4379  else if ( edges[i].edge_id == eid2 ) {
4380  if ( e2 ) {
4381  _lwt_release_edges(edges, nedges);
4382  lwerror("Corrupted topology: multiple edges have id %"
4383  LWTFMT_ELEMID, eid2);
4384  return -1;
4385  }
4386  e2 = &(edges[i]);
4387  }
4388  }
4389  if ( ! e1 )
4390  {
4391  if ( edges ) _lwt_release_edges(edges, nedges);
4392  lwerror("SQL/MM Spatial exception - non-existent edge %"
4393  LWTFMT_ELEMID, eid1);
4394  return -1;
4395  }
4396  if ( ! e2 )
4397  {
4398  if ( edges ) _lwt_release_edges(edges, nedges);
4399  lwerror("SQL/MM Spatial exception - non-existent edge %"
4400  LWTFMT_ELEMID, eid2);
4401  return -1;
4402  }
4403 
4404  /* NOT IN THE SPECS: See if any of the two edges are closed. */
4405  if ( e1->start_node == e1->end_node )
4406  {
4407  _lwt_release_edges(edges, nedges);
4408  lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4409  LWTFMT_ELEMID, eid1, eid2);
4410  return -1;
4411  }
4412  if ( e2->start_node == e2->end_node )
4413  {
4414  _lwt_release_edges(edges, nedges);
4415  lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4416  LWTFMT_ELEMID, eid2, eid1);
4417  return -1;
4418  }
4419 
4420  /* Find common node */
4421 
4422  if ( e1->end_node == e2->start_node )
4423  {
4424  commonnode = e1->end_node;
4425  caseno = 1;
4426  }
4427  else if ( e1->end_node == e2->end_node )
4428  {
4429  commonnode = e1->end_node;
4430  caseno = 2;
4431  }
4432  /* Check if any other edge is connected to the common node, if found */
4433  if ( commonnode != -1 )
4434  {
4435  num_node_edges = 1;
4436  node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4437  &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4438  if ( num_node_edges == -1 ) {
4439  _lwt_release_edges(edges, nedges);
4440  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4441  return -1;
4442  }
4443  for (i=0; i<num_node_edges; ++i)
4444  {
4445  int r;
4446  if ( node_edges[i].edge_id == eid1 ) continue;
4447  if ( node_edges[i].edge_id == eid2 ) continue;
4448  commonnode = -1;
4449  /* append to string, for error message */
4450  if ( bufleft ) {
4451  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4452  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4453  if ( r >= bufleft )
4454  {
4455  bufleft = 0;
4456  buf[252] = '.';
4457  buf[253] = '.';
4458  buf[254] = '.';
4459  buf[255] = '\0';
4460  }
4461  else
4462  {
4463  bufleft -= r;
4464  ptr += r;
4465  }
4466  }
4467  }
4468  lwfree(node_edges);
4469  }
4470 
4471  if ( commonnode == -1 )
4472  {
4473  if ( e1->start_node == e2->start_node )
4474  {
4475  commonnode = e1->start_node;
4476  caseno = 3;
4477  }
4478  else if ( e1->start_node == e2->end_node )
4479  {
4480  commonnode = e1->start_node;
4481  caseno = 4;
4482  }
4483  /* Check if any other edge is connected to the common node, if found */
4484  if ( commonnode != -1 )
4485  {
4486  num_node_edges = 1;
4487  node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4488  &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4489  if ( num_node_edges == -1 ) {
4490  _lwt_release_edges(edges, nedges);
4491  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4492  return -1;
4493  }
4494  for (i=0; i<num_node_edges; ++i)
4495  {
4496  int r;
4497  if ( node_edges[i].edge_id == eid1 ) continue;
4498  if ( node_edges[i].edge_id == eid2 ) continue;
4499  commonnode = -1;
4500  /* append to string, for error message */
4501  if ( bufleft ) {
4502  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4503  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4504  if ( r >= bufleft )
4505  {
4506  bufleft = 0;
4507  buf[252] = '.';
4508  buf[253] = '.';
4509  buf[254] = '.';
4510  buf[255] = '\0';
4511  }
4512  else
4513  {
4514  bufleft -= r;
4515  ptr += r;
4516  }
4517  }
4518  }
4519  if ( num_node_edges ) lwfree(node_edges);
4520  }
4521  }
4522 
4523  if ( commonnode == -1 )
4524  {
4525  _lwt_release_edges(edges, nedges);
4526  if ( ptr != buf )
4527  {
4528  lwerror("SQL/MM Spatial exception - other edges connected (%s)",
4529  buf);
4530  }
4531  else
4532  {
4533  lwerror("SQL/MM Spatial exception - non-connected edges");
4534  }
4535  return -1;
4536  }
4537 
4538  if ( ! lwt_be_checkTopoGeomRemNode(topo, commonnode,
4539  eid1, eid2 ) )
4540  {
4541  _lwt_release_edges(edges, nedges);
4543  return -1;
4544  }
4545 
4546  /* Construct the geometry of the new edge */
4547  switch (caseno)
4548  {
4549  case 1: /* e1.end = e2.start */
4550  pa = ptarray_clone_deep(e1->geom->points);
4551  //pa = ptarray_merge(pa, e2->geom->points);
4552  ptarray_append_ptarray(pa, e2->geom->points, 0);
4553  newedge.start_node = e1->start_node;
4554  newedge.end_node = e2->end_node;
4555  newedge.next_left = e2->next_left;
4556  newedge.next_right = e1->next_right;
4557  e1freenode = 1;
4558  e2freenode = -1;
4559  e2sign = 1;
4560  break;
4561  case 2: /* e1.end = e2.end */
4562  {
4563  POINTARRAY *pa2;
4564  pa2 = ptarray_clone_deep(e2->geom->points);
4565  ptarray_reverse(pa2);
4566  pa = ptarray_clone_deep(e1->geom->points);
4567  //pa = ptarray_merge(e1->geom->points, pa);
4568  ptarray_append_ptarray(pa, pa2, 0);
4569  ptarray_free(pa2);
4570  newedge.start_node = e1->start_node;
4571  newedge.end_node = e2->start_node;
4572  newedge.next_left = e2->next_right;
4573  newedge.next_right = e1->next_right;
4574  e1freenode = 1;
4575  e2freenode = 1;
4576  e2sign = -1;
4577  break;
4578  }
4579  case 3: /* e1.start = e2.start */
4580  pa = ptarray_clone_deep(e2->geom->points);
4581  ptarray_reverse(pa);
4582  //pa = ptarray_merge(pa, e1->geom->points);
4583  ptarray_append_ptarray(pa, e1->geom->points, 0);
4584  newedge.end_node = e1->end_node;
4585  newedge.start_node = e2->end_node;
4586  newedge.next_left = e1->next_left;
4587  newedge.next_right = e2->next_left;
4588  e1freenode = -1;
4589  e2freenode = -1;
4590  e2sign = -1;
4591  break;
4592  case 4: /* e1.start = e2.end */
4593  pa = ptarray_clone_deep(e2->geom->points);
4594  //pa = ptarray_merge(pa, e1->geom->points);
4595  ptarray_append_ptarray(pa, e1->geom->points, 0);
4596  newedge.end_node = e1->end_node;
4597  newedge.start_node = e2->start_node;
4598  newedge.next_left = e1->next_left;
4599  newedge.next_right = e2->next_right;
4600  e1freenode = -1;
4601  e2freenode = 1;
4602  e2sign = 1;
4603  break;
4604  default:
4605  pa = NULL;
4606  e1freenode = 0;
4607  e2freenode = 0;
4608  e2sign = 0;
4609  _lwt_release_edges(edges, nedges);
4610  lwerror("Coding error: caseno=%d should never happen", caseno);
4611  break;
4612  }
4613  newedge.geom = lwline_construct(topo->srid, NULL, pa);
4614 
4615  if ( modEdge )
4616  {
4617  /* Update data of the first edge */
4618  newedge.edge_id = eid1;
4619  i = lwt_be_updateEdgesById(topo, &newedge, 1,
4625  if ( i == -1 )
4626  {
4627  lwline_free(newedge.geom);
4628  _lwt_release_edges(edges, nedges);
4629  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4630  return -1;
4631  }
4632  else if ( i != 1 )
4633  {
4634  lwline_free(newedge.geom);
4635  if ( edges ) _lwt_release_edges(edges, nedges);
4636  lwerror("Unexpected error: %d edges updated when expecting 1", i);
4637  return -1;
4638  }
4639  }
4640  else
4641  {
4642  /* Add new edge */
4643  newedge.edge_id = -1;
4644  newedge.face_left = e1->face_left;
4645  newedge.face_right = e1->face_right;
4646  i = lwt_be_insertEdges(topo, &newedge, 1);
4647  if ( i == -1 ) {
4648  lwline_free(newedge.geom);
4649  _lwt_release_edges(edges, nedges);
4650  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4651  return -1;
4652  } else if ( i == 0 ) {
4653  lwline_free(newedge.geom);
4654  _lwt_release_edges(edges, nedges);
4655  lwerror("Insertion of split edge failed (no reason)");
4656  return -1;
4657  }
4658  }
4659  lwline_free(newedge.geom);
4660 
4661  /*
4662  -- Update next_left_edge/next_right_edge for
4663  -- any edge having them still pointing at the edge being removed
4664  -- (eid2 only when modEdge, or both otherwise)
4665  --
4666  -- NOTE:
4667  -- e#freenode is 1 when edge# end node was the common node
4668  -- and -1 otherwise. This gives the sign of possibly found references
4669  -- to its "free" (non connected to other edge) endnode.
4670  -- e2sign is -1 if edge1 direction is opposite to edge2 direction,
4671  -- or 1 otherwise.
4672  --
4673  */
4674 
4675  /* update edges connected to e2's boundary from their end node */
4676  seledge.next_left = e2freenode * eid2;
4677  updedge.next_left = e2freenode * newedge.edge_id * e2sign;
4678  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT,
4679  &updedge, LWT_COL_EDGE_NEXT_LEFT,
4680  NULL, 0);
4681  if ( i == -1 )
4682  {
4683  _lwt_release_edges(edges, nedges);
4684  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4685  return -1;
4686  }
4687 
4688  /* update edges connected to e2's boundary from their start node */
4689  seledge.next_right = e2freenode * eid2;
4690  updedge.next_right = e2freenode * newedge.edge_id * e2sign;
4691  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT,
4692  &updedge, LWT_COL_EDGE_NEXT_RIGHT,
4693  NULL, 0);
4694  if ( i == -1 )
4695  {
4696  _lwt_release_edges(edges, nedges);
4697  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4698  return -1;
4699  }
4700 
4701  if ( ! modEdge )
4702  {
4703  /* update edges connected to e1's boundary from their end node */
4704  seledge.next_left = e1freenode * eid1;
4705  updedge.next_left = e1freenode * newedge.edge_id;
4706  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT,
4707  &updedge, LWT_COL_EDGE_NEXT_LEFT,
4708  NULL, 0);
4709  if ( i == -1 )
4710  {
4711  _lwt_release_edges(edges, nedges);
4712  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4713  return -1;
4714  }
4715 
4716  /* update edges connected to e1's boundary from their start node */
4717  seledge.next_right = e1freenode * eid1;
4718  updedge.next_right = e1freenode * newedge.edge_id;
4719  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT,
4720  &updedge, LWT_COL_EDGE_NEXT_RIGHT,
4721  NULL, 0);
4722  if ( i == -1 )
4723  {
4724  _lwt_release_edges(edges, nedges);
4725  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4726  return -1;
4727  }
4728  }
4729 
4730  /* delete the edges (only second on modEdge or both) */
4732  if ( i == -1 )
4733  {
4734  _lwt_release_edges(edges, nedges);
4735  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4736  return -1;
4737  }
4738  if ( ! modEdge ) {
4740  if ( i == -1 )
4741  {
4742  _lwt_release_edges(edges, nedges);
4743  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4744  return -1;
4745  }
4746  }
4747 
4748  _lwt_release_edges(edges, nedges);
4749 
4750  /* delete the common node */
4751  i = lwt_be_deleteNodesById( topo, &commonnode, 1 );
4752  if ( i == -1 )
4753  {
4754  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4755  return -1;
4756  }
4757 
4758  /*
4759  --
4760  -- NOT IN THE SPECS:
4761  -- Drop composition rows involving second
4762  -- edge, as the first edge took its space,
4763  -- and all affected TopoGeom have been previously checked
4764  -- for being composed by both edges.
4765  */
4766  if ( ! lwt_be_updateTopoGeomEdgeHeal(topo,
4767  eid1, eid2, newedge.edge_id) )
4768  {
4770  return -1;
4771  }
4772 
4773  return modEdge ? commonnode : newedge.edge_id;
4774 }
LWT_ELEMID face_left
static int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
Definition: lwgeom_topo.c:306
char * r
Definition: cu_in_wkt.c:24
void lwfree(void *mem)
Definition: lwutil.c:244
static int lwt_be_updateTopoGeomEdgeHeal(LWT_TOPOLOGY *topo, LWT_ELEMID edge1, LWT_ELEMID edge2, LWT_ELEMID newedge)
Definition: lwgeom_topo.c:372
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:330
int lwt_be_deleteEdges(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *sel_edge, int sel_fields)
Definition: lwgeom_topo.c:322
void lwline_free(LWLINE *line)
Definition: lwline.c:76
#define LWT_COL_EDGE_START_NODE
LWLINE * geom
static int lwt_be_checkTopoGeomRemNode(LWT_TOPOLOGY *topo, LWT_ELEMID node_id, LWT_ELEMID eid1, LWT_ELEMID eid2)
Definition: lwgeom_topo.c:357
LWT_ISO_EDGE * lwt_be_getEdgeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:225
LWT_ELEMID next_left
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
static int lwt_be_deleteNodesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int numelems)
Definition: lwgeom_topo.c:213
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
const LWT_BE_IFACE * be_iface
#define LWT_COL_EDGE_END_NODE
int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance)
Append a POINTARRAY, pa2 to the end of an existing POINTARRAY, pa1.
Definition: ptarray.c:187
LWT_ELEMID face_right
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
Definition: ptarray.c:630
#define LWT_COL_EDGE_ALL
LWT_ELEMID edge_id
#define LWT_COL_EDGE_EDGE_ID
Edge fields.
#define LWT_COL_EDGE_NEXT_LEFT
int lwt_be_insertEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, int numelems)
Definition: lwgeom_topo.c:268
#define LWT_COL_EDGE_NEXT_RIGHT
LWT_ELEMID start_node
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:467
void ptarray_reverse(POINTARRAY *pa)
Definition: ptarray.c:343
LWT_ELEMID next_right
LWT_INT64 LWT_ELEMID
Identifier of topology element.
static LWT_ISO_EDGE * lwt_be_getEdgeByNode(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:239
#define LWT_COL_EDGE_GEOM
LWT_ELEMID end_node
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:422
Here is the call graph for this function:
Here is the caller graph for this function: