PostGIS  2.5.0dev-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 4372 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_in_place(), r, LWT_TOPOLOGY_T::srid, and LWT_ISO_EDGE::start_node.

Referenced by lwt_ModEdgeHeal(), and lwt_NewEdgeHeal().

4374 {
4375  LWT_ELEMID ids[2];
4376  LWT_ELEMID commonnode = -1;
4377  int caseno = 0;
4378  LWT_ISO_EDGE *node_edges;
4379  int num_node_edges;
4380  LWT_ISO_EDGE *edges;
4381  LWT_ISO_EDGE *e1 = NULL;
4382  LWT_ISO_EDGE *e2 = NULL;
4383  LWT_ISO_EDGE newedge, updedge, seledge;
4384  int nedges, i;
4385  int e1freenode;
4386  int e2sign, e2freenode;
4387  POINTARRAY *pa;
4388  char buf[256];
4389  char *ptr;
4390  size_t bufleft = 256;
4391 
4392  ptr = buf;
4393 
4394  /* NOT IN THE SPECS: see if the same edge is given twice.. */
4395  if ( eid1 == eid2 )
4396  {
4397  lwerror("Cannot heal edge %" LWTFMT_ELEMID
4398  " with itself, try with another", eid1);
4399  return -1;
4400  }
4401  ids[0] = eid1;
4402  ids[1] = eid2;
4403  nedges = 2;
4404  edges = lwt_be_getEdgeById(topo, ids, &nedges, LWT_COL_EDGE_ALL);
4405  if ((nedges == -1) || (edges == NULL))
4406  {
4407  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4408  return -1;
4409  }
4410  for ( i=0; i<nedges; ++i )
4411  {
4412  if ( edges[i].edge_id == eid1 ) {
4413  if ( e1 ) {
4414  _lwt_release_edges(edges, nedges);
4415  lwerror("Corrupted topology: multiple edges have id %"
4416  LWTFMT_ELEMID, eid1);
4417  return -1;
4418  }
4419  e1 = &(edges[i]);
4420  }
4421  else if ( edges[i].edge_id == eid2 ) {
4422  if ( e2 ) {
4423  _lwt_release_edges(edges, nedges);
4424  lwerror("Corrupted topology: multiple edges have id %"
4425  LWTFMT_ELEMID, eid2);
4426  return -1;
4427  }
4428  e2 = &(edges[i]);
4429  }
4430  }
4431  if ( ! e1 )
4432  {
4433  _lwt_release_edges(edges, nedges);
4434  lwerror(
4435  "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4436  eid1);
4437  return -1;
4438  }
4439  if ( ! e2 )
4440  {
4441  _lwt_release_edges(edges, nedges);
4442  lwerror(
4443  "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4444  eid2);
4445  return -1;
4446  }
4447 
4448  /* NOT IN THE SPECS: See if any of the two edges are closed. */
4449  if ( e1->start_node == e1->end_node )
4450  {
4451  _lwt_release_edges(edges, nedges);
4452  lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4453  LWTFMT_ELEMID, eid1, eid2);
4454  return -1;
4455  }
4456  if ( e2->start_node == e2->end_node )
4457  {
4458  _lwt_release_edges(edges, nedges);
4459  lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4460  LWTFMT_ELEMID, eid2, eid1);
4461  return -1;
4462  }
4463 
4464  /* Find common node */
4465 
4466  if ( e1->end_node == e2->start_node )
4467  {
4468  commonnode = e1->end_node;
4469  caseno = 1;
4470  }
4471  else if ( e1->end_node == e2->end_node )
4472  {
4473  commonnode = e1->end_node;
4474  caseno = 2;
4475  }
4476  /* Check if any other edge is connected to the common node, if found */
4477  if ( commonnode != -1 )
4478  {
4479  num_node_edges = 1;
4480  node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4481  &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4482  if ( num_node_edges == -1 ) {
4483  _lwt_release_edges(edges, nedges);
4484  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4485  return -1;
4486  }
4487  for (i=0; i<num_node_edges; ++i)
4488  {
4489  int r;
4490  if ( node_edges[i].edge_id == eid1 ) continue;
4491  if ( node_edges[i].edge_id == eid2 ) continue;
4492  commonnode = -1;
4493  /* append to string, for error message */
4494  if ( bufleft > 0 ) {
4495  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4496  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4497  if ( r >= (int) bufleft )
4498  {
4499  bufleft = 0;
4500  buf[252] = '.';
4501  buf[253] = '.';
4502  buf[254] = '.';
4503  buf[255] = '\0';
4504  }
4505  else
4506  {
4507  bufleft -= r;
4508  ptr += r;
4509  }
4510  }
4511  }
4512  lwfree(node_edges);
4513  }
4514 
4515  if ( commonnode == -1 )
4516  {
4517  if ( e1->start_node == e2->start_node )
4518  {
4519  commonnode = e1->start_node;
4520  caseno = 3;
4521  }
4522  else if ( e1->start_node == e2->end_node )
4523  {
4524  commonnode = e1->start_node;
4525  caseno = 4;
4526  }
4527  /* Check if any other edge is connected to the common node, if found */
4528  if ( commonnode != -1 )
4529  {
4530  num_node_edges = 1;
4531  node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4532  &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4533  if ( num_node_edges == -1 ) {
4534  _lwt_release_edges(edges, nedges);
4535  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4536  return -1;
4537  }
4538  for (i=0; i<num_node_edges; ++i)
4539  {
4540  int r;
4541  if ( node_edges[i].edge_id == eid1 ) continue;
4542  if ( node_edges[i].edge_id == eid2 ) continue;
4543  commonnode = -1;
4544  /* append to string, for error message */
4545  if ( bufleft > 0 ) {
4546  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4547  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4548  if ( r >= (int) bufleft )
4549  {
4550  bufleft = 0;
4551  buf[252] = '.';
4552  buf[253] = '.';
4553  buf[254] = '.';
4554  buf[255] = '\0';
4555  }
4556  else
4557  {
4558  bufleft -= r;
4559  ptr += r;
4560  }
4561  }
4562  }
4563  if ( num_node_edges ) lwfree(node_edges);
4564  }
4565  }
4566 
4567  if ( commonnode == -1 )
4568  {
4569  _lwt_release_edges(edges, nedges);
4570  if ( ptr != buf )
4571  {
4572  lwerror("SQL/MM Spatial exception - other edges connected (%s)",
4573  buf);
4574  }
4575  else
4576  {
4577  lwerror("SQL/MM Spatial exception - non-connected edges");
4578  }
4579  return -1;
4580  }
4581 
4582  if ( ! lwt_be_checkTopoGeomRemNode(topo, commonnode,
4583  eid1, eid2 ) )
4584  {
4585  _lwt_release_edges(edges, nedges);
4587  return -1;
4588  }
4589 
4590  /* Construct the geometry of the new edge */
4591  switch (caseno)
4592  {
4593  case 1: /* e1.end = e2.start */
4594  pa = ptarray_clone_deep(e1->geom->points);
4595  //pa = ptarray_merge(pa, e2->geom->points);
4596  ptarray_append_ptarray(pa, e2->geom->points, 0);
4597  newedge.start_node = e1->start_node;
4598  newedge.end_node = e2->end_node;
4599  newedge.next_left = e2->next_left;
4600  newedge.next_right = e1->next_right;
4601  e1freenode = 1;
4602  e2freenode = -1;
4603  e2sign = 1;
4604  break;
4605  case 2: /* e1.end = e2.end */
4606  {
4607  POINTARRAY *pa2;
4608  pa2 = ptarray_clone_deep(e2->geom->points);
4610  pa = ptarray_clone_deep(e1->geom->points);
4611  //pa = ptarray_merge(e1->geom->points, pa);
4612  ptarray_append_ptarray(pa, pa2, 0);
4613  ptarray_free(pa2);
4614  newedge.start_node = e1->start_node;
4615  newedge.end_node = e2->start_node;
4616  newedge.next_left = e2->next_right;
4617  newedge.next_right = e1->next_right;
4618  e1freenode = 1;
4619  e2freenode = 1;
4620  e2sign = -1;
4621  break;
4622  }
4623  case 3: /* e1.start = e2.start */
4624  pa = ptarray_clone_deep(e2->geom->points);
4626  //pa = ptarray_merge(pa, e1->geom->points);
4627  ptarray_append_ptarray(pa, e1->geom->points, 0);
4628  newedge.end_node = e1->end_node;
4629  newedge.start_node = e2->end_node;
4630  newedge.next_left = e1->next_left;
4631  newedge.next_right = e2->next_left;
4632  e1freenode = -1;
4633  e2freenode = -1;
4634  e2sign = -1;
4635  break;
4636  case 4: /* e1.start = e2.end */
4637  pa = ptarray_clone_deep(e2->geom->points);
4638  //pa = ptarray_merge(pa, e1->geom->points);
4639  ptarray_append_ptarray(pa, e1->geom->points, 0);
4640  newedge.end_node = e1->end_node;
4641  newedge.start_node = e2->start_node;
4642  newedge.next_left = e1->next_left;
4643  newedge.next_right = e2->next_right;
4644  e1freenode = -1;
4645  e2freenode = 1;
4646  e2sign = 1;
4647  break;
4648  default:
4649  pa = NULL;
4650  e1freenode = 0;
4651  e2freenode = 0;
4652  e2sign = 0;
4653  _lwt_release_edges(edges, nedges);
4654  lwerror("Coding error: caseno=%d should never happen", caseno);
4655  break;
4656  }
4657  newedge.geom = lwline_construct(topo->srid, NULL, pa);
4658 
4659  if ( modEdge )
4660  {
4661  /* Update data of the first edge */
4662  newedge.edge_id = eid1;
4663  i = lwt_be_updateEdgesById(topo, &newedge, 1,
4669  if ( i == -1 )
4670  {
4671  lwline_free(newedge.geom);
4672  _lwt_release_edges(edges, nedges);
4673  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4674  return -1;
4675  }
4676  else if ( i != 1 )
4677  {
4678  lwline_free(newedge.geom);
4679  if ( edges ) _lwt_release_edges(edges, nedges);
4680  lwerror("Unexpected error: %d edges updated when expecting 1", i);
4681  return -1;
4682  }
4683  }
4684  else
4685  {
4686  /* Add new edge */
4687  newedge.edge_id = -1;
4688  newedge.face_left = e1->face_left;
4689  newedge.face_right = e1->face_right;
4690  i = lwt_be_insertEdges(topo, &newedge, 1);
4691  if ( i == -1 ) {
4692  lwline_free(newedge.geom);
4693  _lwt_release_edges(edges, nedges);
4694  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4695  return -1;
4696  } else if ( i == 0 ) {
4697  lwline_free(newedge.geom);
4698  _lwt_release_edges(edges, nedges);
4699  lwerror("Insertion of split edge failed (no reason)");
4700  return -1;
4701  }
4702  }
4703  lwline_free(newedge.geom);
4704 
4705  /*
4706  -- Update next_left_edge/next_right_edge for
4707  -- any edge having them still pointing at the edge being removed
4708  -- (eid2 only when modEdge, or both otherwise)
4709  --
4710  -- NOTE:
4711  -- e#freenode is 1 when edge# end node was the common node
4712  -- and -1 otherwise. This gives the sign of possibly found references
4713  -- to its "free" (non connected to other edge) endnode.
4714  -- e2sign is -1 if edge1 direction is opposite to edge2 direction,
4715  -- or 1 otherwise.
4716  --
4717  */
4718 
4719  /* update edges connected to e2's boundary from their end node */
4720  seledge.next_left = e2freenode * eid2;
4721  updedge.next_left = e2freenode * newedge.edge_id * e2sign;
4722  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT,
4723  &updedge, LWT_COL_EDGE_NEXT_LEFT,
4724  NULL, 0);
4725  if ( i == -1 )
4726  {
4727  _lwt_release_edges(edges, nedges);
4728  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4729  return -1;
4730  }
4731 
4732  /* update edges connected to e2's boundary from their start node */
4733  seledge.next_right = e2freenode * eid2;
4734  updedge.next_right = e2freenode * newedge.edge_id * e2sign;
4735  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT,
4736  &updedge, LWT_COL_EDGE_NEXT_RIGHT,
4737  NULL, 0);
4738  if ( i == -1 )
4739  {
4740  _lwt_release_edges(edges, nedges);
4741  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4742  return -1;
4743  }
4744 
4745  if ( ! modEdge )
4746  {
4747  /* update edges connected to e1's boundary from their end node */
4748  seledge.next_left = e1freenode * eid1;
4749  updedge.next_left = e1freenode * newedge.edge_id;
4750  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT,
4751  &updedge, LWT_COL_EDGE_NEXT_LEFT,
4752  NULL, 0);
4753  if ( i == -1 )
4754  {
4755  _lwt_release_edges(edges, nedges);
4756  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4757  return -1;
4758  }
4759 
4760  /* update edges connected to e1's boundary from their start node */
4761  seledge.next_right = e1freenode * eid1;
4762  updedge.next_right = e1freenode * newedge.edge_id;
4763  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT,
4764  &updedge, LWT_COL_EDGE_NEXT_RIGHT,
4765  NULL, 0);
4766  if ( i == -1 )
4767  {
4768  _lwt_release_edges(edges, nedges);
4769  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4770  return -1;
4771  }
4772  }
4773 
4774  /* delete the edges (only second on modEdge or both) */
4776  if ( i == -1 )
4777  {
4778  _lwt_release_edges(edges, nedges);
4779  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4780  return -1;
4781  }
4782  if ( ! modEdge ) {
4784  if ( i == -1 )
4785  {
4786  _lwt_release_edges(edges, nedges);
4787  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4788  return -1;
4789  }
4790  }
4791 
4792  _lwt_release_edges(edges, nedges);
4793 
4794  /* delete the common node */
4795  i = lwt_be_deleteNodesById( topo, &commonnode, 1 );
4796  if ( i == -1 )
4797  {
4798  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4799  return -1;
4800  }
4801 
4802  /*
4803  --
4804  -- NOT IN THE SPECS:
4805  -- Drop composition rows involving second
4806  -- edge, as the first edge took its space,
4807  -- and all affected TopoGeom have been previously checked
4808  -- for being composed by both edges.
4809  */
4810  if ( ! lwt_be_updateTopoGeomEdgeHeal(topo,
4811  eid1, eid2, newedge.edge_id) )
4812  {
4814  return -1;
4815  }
4816 
4817  return modEdge ? commonnode : newedge.edge_id;
4818 }
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:328
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:628
#define LWT_COL_EDGE_ALL
LWT_ELEMID edge_id
void ptarray_reverse_in_place(POINTARRAY *pa)
Definition: ptarray.c:341
#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:457
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:424
Here is the call graph for this function:
Here is the caller graph for this function: