PostGIS  3.3.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 4372 of file lwgeom_topo.c.

4374 {
4375  LWT_ELEMID ids[2];
4376  LWT_ELEMID commonnode = -1;
4377  int caseno = 0;
4378  LWT_ISO_EDGE *node_edges;
4379  uint64_t 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  uint64_t 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 == UINT64_MAX) || (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 == UINT64_MAX)
4483  {
4484  _lwt_release_edges(edges, nedges);
4485  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4486  return -1;
4487  }
4488  for (i=0; i<num_node_edges; ++i)
4489  {
4490  int r;
4491  if ( node_edges[i].edge_id == eid1 ) continue;
4492  if ( node_edges[i].edge_id == eid2 ) continue;
4493  commonnode = -1;
4494  /* append to string, for error message */
4495  if ( bufleft > 0 ) {
4496  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4497  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4498  if ( r >= (int) bufleft )
4499  {
4500  bufleft = 0;
4501  buf[252] = '.';
4502  buf[253] = '.';
4503  buf[254] = '.';
4504  buf[255] = '\0';
4505  }
4506  else
4507  {
4508  bufleft -= r;
4509  ptr += r;
4510  }
4511  }
4512  }
4513  lwfree(node_edges);
4514  }
4515 
4516  if ( commonnode == -1 )
4517  {
4518  if ( e1->start_node == e2->start_node )
4519  {
4520  commonnode = e1->start_node;
4521  caseno = 3;
4522  }
4523  else if ( e1->start_node == e2->end_node )
4524  {
4525  commonnode = e1->start_node;
4526  caseno = 4;
4527  }
4528  /* Check if any other edge is connected to the common node, if found */
4529  if ( commonnode != -1 )
4530  {
4531  num_node_edges = 1;
4532  node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4533  &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4534  if (num_node_edges == UINT64_MAX)
4535  {
4536  _lwt_release_edges(edges, nedges);
4537  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4538  return -1;
4539  }
4540  for (i=0; i<num_node_edges; ++i)
4541  {
4542  int r;
4543  if ( node_edges[i].edge_id == eid1 ) continue;
4544  if ( node_edges[i].edge_id == eid2 ) continue;
4545  commonnode = -1;
4546  /* append to string, for error message */
4547  if ( bufleft > 0 ) {
4548  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4549  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4550  if ( r >= (int) bufleft )
4551  {
4552  bufleft = 0;
4553  buf[252] = '.';
4554  buf[253] = '.';
4555  buf[254] = '.';
4556  buf[255] = '\0';
4557  }
4558  else
4559  {
4560  bufleft -= r;
4561  ptr += r;
4562  }
4563  }
4564  }
4565  if ( num_node_edges ) lwfree(node_edges);
4566  }
4567  }
4568 
4569  if ( commonnode == -1 )
4570  {
4571  _lwt_release_edges(edges, nedges);
4572  if ( ptr != buf )
4573  {
4574  lwerror("SQL/MM Spatial exception - other edges connected (%s)",
4575  buf);
4576  }
4577  else
4578  {
4579  lwerror("SQL/MM Spatial exception - non-connected edges");
4580  }
4581  return -1;
4582  }
4583 
4584  if ( ! lwt_be_checkTopoGeomRemNode(topo, commonnode,
4585  eid1, eid2 ) )
4586  {
4587  _lwt_release_edges(edges, nedges);
4589  return -1;
4590  }
4591 
4592  /* Construct the geometry of the new edge */
4593  switch (caseno)
4594  {
4595  case 1: /* e1.end = e2.start */
4596  pa = ptarray_clone_deep(e1->geom->points);
4597  //pa = ptarray_merge(pa, e2->geom->points);
4598  ptarray_append_ptarray(pa, e2->geom->points, 0);
4599  newedge.start_node = e1->start_node;
4600  newedge.end_node = e2->end_node;
4601  newedge.next_left = e2->next_left;
4602  newedge.next_right = e1->next_right;
4603  e1freenode = 1;
4604  e2freenode = -1;
4605  e2sign = 1;
4606  break;
4607  case 2: /* e1.end = e2.end */
4608  {
4609  POINTARRAY *pa2;
4610  pa2 = ptarray_clone_deep(e2->geom->points);
4612  pa = ptarray_clone_deep(e1->geom->points);
4613  //pa = ptarray_merge(e1->geom->points, pa);
4614  ptarray_append_ptarray(pa, pa2, 0);
4615  ptarray_free(pa2);
4616  newedge.start_node = e1->start_node;
4617  newedge.end_node = e2->start_node;
4618  newedge.next_left = e2->next_right;
4619  newedge.next_right = e1->next_right;
4620  e1freenode = 1;
4621  e2freenode = 1;
4622  e2sign = -1;
4623  break;
4624  }
4625  case 3: /* e1.start = e2.start */
4626  pa = ptarray_clone_deep(e2->geom->points);
4628  //pa = ptarray_merge(pa, e1->geom->points);
4629  ptarray_append_ptarray(pa, e1->geom->points, 0);
4630  newedge.end_node = e1->end_node;
4631  newedge.start_node = e2->end_node;
4632  newedge.next_left = e1->next_left;
4633  newedge.next_right = e2->next_left;
4634  e1freenode = -1;
4635  e2freenode = -1;
4636  e2sign = -1;
4637  break;
4638  case 4: /* e1.start = e2.end */
4639  pa = ptarray_clone_deep(e2->geom->points);
4640  //pa = ptarray_merge(pa, e1->geom->points);
4641  ptarray_append_ptarray(pa, e1->geom->points, 0);
4642  newedge.end_node = e1->end_node;
4643  newedge.start_node = e2->start_node;
4644  newedge.next_left = e1->next_left;
4645  newedge.next_right = e2->next_right;
4646  e1freenode = -1;
4647  e2freenode = 1;
4648  e2sign = 1;
4649  break;
4650  default:
4651  pa = NULL;
4652  e1freenode = 0;
4653  e2freenode = 0;
4654  e2sign = 0;
4655  _lwt_release_edges(edges, nedges);
4656  lwerror("Coding error: caseno=%d should never happen", caseno);
4657  return -1;
4658  break;
4659  }
4660  newedge.geom = lwline_construct(topo->srid, NULL, pa);
4661 
4662  if ( modEdge )
4663  {
4664  /* Update data of the first edge */
4665  newedge.edge_id = eid1;
4666  int result = lwt_be_updateEdgesById(topo,
4667  &newedge,
4668  1,
4671  if (result == -1)
4672  {
4673  lwline_free(newedge.geom);
4674  _lwt_release_edges(edges, nedges);
4675  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4676  return -1;
4677  }
4678  else if (result != 1)
4679  {
4680  lwline_free(newedge.geom);
4681  if ( edges ) _lwt_release_edges(edges, nedges);
4682  lwerror("Unexpected error: %d edges updated when expecting 1", i);
4683  return -1;
4684  }
4685  }
4686  else
4687  {
4688  /* Add new edge */
4689  newedge.edge_id = -1;
4690  newedge.face_left = e1->face_left;
4691  newedge.face_right = e1->face_right;
4692  int result = lwt_be_insertEdges(topo, &newedge, 1);
4693  if (result == -1)
4694  {
4695  lwline_free(newedge.geom);
4696  _lwt_release_edges(edges, nedges);
4697  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4698  return -1;
4699  }
4700  else if (result == 0)
4701  {
4702  lwline_free(newedge.geom);
4703  _lwt_release_edges(edges, nedges);
4704  lwerror("Insertion of split edge failed (no reason)");
4705  return -1;
4706  }
4707  }
4708  lwline_free(newedge.geom);
4709 
4710  /*
4711  -- Update next_left_edge/next_right_edge for
4712  -- any edge having them still pointing at the edge being removed
4713  -- (eid2 only when modEdge, or both otherwise)
4714  --
4715  -- NOTE:
4716  -- e#freenode is 1 when edge# end node was the common node
4717  -- and -1 otherwise. This gives the sign of possibly found references
4718  -- to its "free" (non connected to other edge) endnode.
4719  -- e2sign is -1 if edge1 direction is opposite to edge2 direction,
4720  -- or 1 otherwise.
4721  --
4722  */
4723 
4724  /* update edges connected to e2's boundary from their end node */
4725  seledge.next_left = e2freenode * eid2;
4726  updedge.next_left = e2freenode * newedge.edge_id * e2sign;
4727  int result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT, &updedge, LWT_COL_EDGE_NEXT_LEFT, NULL, 0);
4728  if (result == -1)
4729  {
4730  _lwt_release_edges(edges, nedges);
4731  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4732  return -1;
4733  }
4734 
4735  /* update edges connected to e2's boundary from their start node */
4736  seledge.next_right = e2freenode * eid2;
4737  updedge.next_right = e2freenode * newedge.edge_id * e2sign;
4738  result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT, &updedge, LWT_COL_EDGE_NEXT_RIGHT, NULL, 0);
4739  if (result == -1)
4740  {
4741  _lwt_release_edges(edges, nedges);
4742  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4743  return -1;
4744  }
4745 
4746  if ( ! modEdge )
4747  {
4748  /* update edges connected to e1's boundary from their end node */
4749  seledge.next_left = e1freenode * eid1;
4750  updedge.next_left = e1freenode * newedge.edge_id;
4751  result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT, &updedge, LWT_COL_EDGE_NEXT_LEFT, NULL, 0);
4752  if (result == -1)
4753  {
4754  _lwt_release_edges(edges, nedges);
4755  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4756  return -1;
4757  }
4758 
4759  /* update edges connected to e1's boundary from their start node */
4760  seledge.next_right = e1freenode * eid1;
4761  updedge.next_right = e1freenode * newedge.edge_id;
4762  result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT, &updedge, LWT_COL_EDGE_NEXT_RIGHT, NULL, 0);
4763  if (result == -1)
4764  {
4765  _lwt_release_edges(edges, nedges);
4766  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4767  return -1;
4768  }
4769  }
4770 
4771  /* delete the edges (only second on modEdge or both) */
4773  if (result == -1)
4774  {
4775  _lwt_release_edges(edges, nedges);
4776  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4777  return -1;
4778  }
4779  if ( ! modEdge ) {
4781  if (result == -1)
4782  {
4783  _lwt_release_edges(edges, nedges);
4784  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4785  return -1;
4786  }
4787  }
4788 
4789  _lwt_release_edges(edges, nedges);
4790 
4791  /* delete the common node */
4792  i = lwt_be_deleteNodesById( topo, &commonnode, 1 );
4793  if (result == -1)
4794  {
4795  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4796  return -1;
4797  }
4798 
4799  /*
4800  --
4801  -- NOT IN THE SPECS:
4802  -- Drop composition rows involving second
4803  -- edge, as the first edge took its space,
4804  -- and all affected TopoGeom have been previously checked
4805  -- for being composed by both edges.
4806  */
4807  if ( ! lwt_be_updateTopoGeomEdgeHeal(topo,
4808  eid1, eid2, newedge.edge_id) )
4809  {
4811  return -1;
4812  }
4813 
4814  return modEdge ? commonnode : newedge.edge_id;
4815 }
char * r
Definition: cu_in_wkt.c:24
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
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:177
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
Definition: ptarray.c:634
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
void lwfree(void *mem)
Definition: lwutil.c:242
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:327
void lwline_free(LWLINE *line)
Definition: lwline.c:67
void ptarray_reverse_in_place(POINTARRAY *pa)
Definition: ptarray.c:339
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_EDGE_START_NODE
#define LWT_COL_EDGE_NEXT_RIGHT
#define LWT_COL_EDGE_EDGE_ID
Edge fields.
#define LWT_COL_EDGE_ALL
#define LWT_COL_EDGE_END_NODE
#define LWT_COL_EDGE_NEXT_LEFT
#define LWT_COL_EDGE_GEOM
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:119
static int lwt_be_deleteNodesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t numelems)
Definition: lwgeom_topo.c:208
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_be_updateTopoGeomEdgeHeal(LWT_TOPOLOGY *topo, LWT_ELEMID edge1, LWT_ELEMID edge2, LWT_ELEMID newedge)
Definition: lwgeom_topo.c:370
static LWT_ISO_EDGE * lwt_be_getEdgeByNode(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
Definition: lwgeom_topo.c:232
static int lwt_be_checkTopoGeomRemNode(LWT_TOPOLOGY *topo, LWT_ELEMID node_id, LWT_ELEMID eid1, LWT_ELEMID eid2)
Definition: lwgeom_topo.c:349
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:267
int lwt_be_deleteEdges(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *sel_edge, int sel_fields)
Definition: lwgeom_topo.c:315
int lwt_be_insertEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, uint64_t numelems)
Definition: lwgeom_topo.c:261
#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
POINTARRAY * points
Definition: liblwgeom.h:498
LWT_ELEMID face_right
LWT_ELEMID next_right
LWT_ELEMID end_node
LWT_ELEMID face_left
LWLINE * geom
LWT_ELEMID next_left
LWT_ELEMID edge_id
LWT_ELEMID start_node
const LWT_BE_IFACE * be_iface

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, result, LWT_TOPOLOGY_T::srid, and LWT_ISO_EDGE::start_node.

Referenced by lwt_ModEdgeHeal(), and lwt_NewEdgeHeal().

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