PostGIS  3.2.2dev-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 4291 of file lwgeom_topo.c.

4293 {
4294  LWT_ELEMID ids[2];
4295  LWT_ELEMID commonnode = -1;
4296  int caseno = 0;
4297  LWT_ISO_EDGE *node_edges;
4298  uint64_t num_node_edges;
4299  LWT_ISO_EDGE *edges;
4300  LWT_ISO_EDGE *e1 = NULL;
4301  LWT_ISO_EDGE *e2 = NULL;
4302  LWT_ISO_EDGE newedge, updedge, seledge;
4303  uint64_t nedges, i;
4304  int e1freenode;
4305  int e2sign, e2freenode;
4306  POINTARRAY *pa;
4307  char buf[256];
4308  char *ptr;
4309  size_t bufleft = 256;
4310 
4311  ptr = buf;
4312 
4313  /* NOT IN THE SPECS: see if the same edge is given twice.. */
4314  if ( eid1 == eid2 )
4315  {
4316  lwerror("Cannot heal edge %" LWTFMT_ELEMID
4317  " with itself, try with another", eid1);
4318  return -1;
4319  }
4320  ids[0] = eid1;
4321  ids[1] = eid2;
4322  nedges = 2;
4323  edges = lwt_be_getEdgeById(topo, ids, &nedges, LWT_COL_EDGE_ALL);
4324  if ((nedges == UINT64_MAX) || (edges == NULL))
4325  {
4326  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4327  return -1;
4328  }
4329  for ( i=0; i<nedges; ++i )
4330  {
4331  if ( edges[i].edge_id == eid1 ) {
4332  if ( e1 ) {
4333  _lwt_release_edges(edges, nedges);
4334  lwerror("Corrupted topology: multiple edges have id %"
4335  LWTFMT_ELEMID, eid1);
4336  return -1;
4337  }
4338  e1 = &(edges[i]);
4339  }
4340  else if ( edges[i].edge_id == eid2 ) {
4341  if ( e2 ) {
4342  _lwt_release_edges(edges, nedges);
4343  lwerror("Corrupted topology: multiple edges have id %"
4344  LWTFMT_ELEMID, eid2);
4345  return -1;
4346  }
4347  e2 = &(edges[i]);
4348  }
4349  }
4350  if ( ! e1 )
4351  {
4352  _lwt_release_edges(edges, nedges);
4353  lwerror(
4354  "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4355  eid1);
4356  return -1;
4357  }
4358  if ( ! e2 )
4359  {
4360  _lwt_release_edges(edges, nedges);
4361  lwerror(
4362  "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4363  eid2);
4364  return -1;
4365  }
4366 
4367  /* NOT IN THE SPECS: See if any of the two edges are closed. */
4368  if ( e1->start_node == e1->end_node )
4369  {
4370  _lwt_release_edges(edges, nedges);
4371  lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4372  LWTFMT_ELEMID, eid1, eid2);
4373  return -1;
4374  }
4375  if ( e2->start_node == e2->end_node )
4376  {
4377  _lwt_release_edges(edges, nedges);
4378  lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4379  LWTFMT_ELEMID, eid2, eid1);
4380  return -1;
4381  }
4382 
4383  /* Find common node */
4384 
4385  if ( e1->end_node == e2->start_node )
4386  {
4387  commonnode = e1->end_node;
4388  caseno = 1;
4389  }
4390  else if ( e1->end_node == e2->end_node )
4391  {
4392  commonnode = e1->end_node;
4393  caseno = 2;
4394  }
4395  /* Check if any other edge is connected to the common node, if found */
4396  if ( commonnode != -1 )
4397  {
4398  num_node_edges = 1;
4399  node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4400  &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4401  if (num_node_edges == UINT64_MAX)
4402  {
4403  _lwt_release_edges(edges, nedges);
4404  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4405  return -1;
4406  }
4407  for (i=0; i<num_node_edges; ++i)
4408  {
4409  int r;
4410  if ( node_edges[i].edge_id == eid1 ) continue;
4411  if ( node_edges[i].edge_id == eid2 ) continue;
4412  commonnode = -1;
4413  /* append to string, for error message */
4414  if ( bufleft > 0 ) {
4415  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4416  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4417  if ( r >= (int) bufleft )
4418  {
4419  bufleft = 0;
4420  buf[252] = '.';
4421  buf[253] = '.';
4422  buf[254] = '.';
4423  buf[255] = '\0';
4424  }
4425  else
4426  {
4427  bufleft -= r;
4428  ptr += r;
4429  }
4430  }
4431  }
4432  lwfree(node_edges);
4433  }
4434 
4435  if ( commonnode == -1 )
4436  {
4437  if ( e1->start_node == e2->start_node )
4438  {
4439  commonnode = e1->start_node;
4440  caseno = 3;
4441  }
4442  else if ( e1->start_node == e2->end_node )
4443  {
4444  commonnode = e1->start_node;
4445  caseno = 4;
4446  }
4447  /* Check if any other edge is connected to the common node, if found */
4448  if ( commonnode != -1 )
4449  {
4450  num_node_edges = 1;
4451  node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4452  &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4453  if (num_node_edges == UINT64_MAX)
4454  {
4455  _lwt_release_edges(edges, nedges);
4456  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4457  return -1;
4458  }
4459  for (i=0; i<num_node_edges; ++i)
4460  {
4461  int r;
4462  if ( node_edges[i].edge_id == eid1 ) continue;
4463  if ( node_edges[i].edge_id == eid2 ) continue;
4464  commonnode = -1;
4465  /* append to string, for error message */
4466  if ( bufleft > 0 ) {
4467  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4468  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4469  if ( r >= (int) bufleft )
4470  {
4471  bufleft = 0;
4472  buf[252] = '.';
4473  buf[253] = '.';
4474  buf[254] = '.';
4475  buf[255] = '\0';
4476  }
4477  else
4478  {
4479  bufleft -= r;
4480  ptr += r;
4481  }
4482  }
4483  }
4484  if ( num_node_edges ) lwfree(node_edges);
4485  }
4486  }
4487 
4488  if ( commonnode == -1 )
4489  {
4490  _lwt_release_edges(edges, nedges);
4491  if ( ptr != buf )
4492  {
4493  lwerror("SQL/MM Spatial exception - other edges connected (%s)",
4494  buf);
4495  }
4496  else
4497  {
4498  lwerror("SQL/MM Spatial exception - non-connected edges");
4499  }
4500  return -1;
4501  }
4502 
4503  if ( ! lwt_be_checkTopoGeomRemNode(topo, commonnode,
4504  eid1, eid2 ) )
4505  {
4506  _lwt_release_edges(edges, nedges);
4508  return -1;
4509  }
4510 
4511  /* Construct the geometry of the new edge */
4512  switch (caseno)
4513  {
4514  case 1: /* e1.end = e2.start */
4515  pa = ptarray_clone_deep(e1->geom->points);
4516  //pa = ptarray_merge(pa, e2->geom->points);
4517  ptarray_append_ptarray(pa, e2->geom->points, 0);
4518  newedge.start_node = e1->start_node;
4519  newedge.end_node = e2->end_node;
4520  newedge.next_left = e2->next_left;
4521  newedge.next_right = e1->next_right;
4522  e1freenode = 1;
4523  e2freenode = -1;
4524  e2sign = 1;
4525  break;
4526  case 2: /* e1.end = e2.end */
4527  {
4528  POINTARRAY *pa2;
4529  pa2 = ptarray_clone_deep(e2->geom->points);
4531  pa = ptarray_clone_deep(e1->geom->points);
4532  //pa = ptarray_merge(e1->geom->points, pa);
4533  ptarray_append_ptarray(pa, pa2, 0);
4534  ptarray_free(pa2);
4535  newedge.start_node = e1->start_node;
4536  newedge.end_node = e2->start_node;
4537  newedge.next_left = e2->next_right;
4538  newedge.next_right = e1->next_right;
4539  e1freenode = 1;
4540  e2freenode = 1;
4541  e2sign = -1;
4542  break;
4543  }
4544  case 3: /* e1.start = e2.start */
4545  pa = ptarray_clone_deep(e2->geom->points);
4547  //pa = ptarray_merge(pa, e1->geom->points);
4548  ptarray_append_ptarray(pa, e1->geom->points, 0);
4549  newedge.end_node = e1->end_node;
4550  newedge.start_node = e2->end_node;
4551  newedge.next_left = e1->next_left;
4552  newedge.next_right = e2->next_left;
4553  e1freenode = -1;
4554  e2freenode = -1;
4555  e2sign = -1;
4556  break;
4557  case 4: /* e1.start = e2.end */
4558  pa = ptarray_clone_deep(e2->geom->points);
4559  //pa = ptarray_merge(pa, e1->geom->points);
4560  ptarray_append_ptarray(pa, e1->geom->points, 0);
4561  newedge.end_node = e1->end_node;
4562  newedge.start_node = e2->start_node;
4563  newedge.next_left = e1->next_left;
4564  newedge.next_right = e2->next_right;
4565  e1freenode = -1;
4566  e2freenode = 1;
4567  e2sign = 1;
4568  break;
4569  default:
4570  pa = NULL;
4571  e1freenode = 0;
4572  e2freenode = 0;
4573  e2sign = 0;
4574  _lwt_release_edges(edges, nedges);
4575  lwerror("Coding error: caseno=%d should never happen", caseno);
4576  return -1;
4577  break;
4578  }
4579  newedge.geom = lwline_construct(topo->srid, NULL, pa);
4580 
4581  if ( modEdge )
4582  {
4583  /* Update data of the first edge */
4584  newedge.edge_id = eid1;
4585  int result = lwt_be_updateEdgesById(topo,
4586  &newedge,
4587  1,
4590  if (result == -1)
4591  {
4592  lwline_free(newedge.geom);
4593  _lwt_release_edges(edges, nedges);
4594  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4595  return -1;
4596  }
4597  else if (result != 1)
4598  {
4599  lwline_free(newedge.geom);
4600  if ( edges ) _lwt_release_edges(edges, nedges);
4601  lwerror("Unexpected error: %d edges updated when expecting 1", i);
4602  return -1;
4603  }
4604  }
4605  else
4606  {
4607  /* Add new edge */
4608  newedge.edge_id = -1;
4609  newedge.face_left = e1->face_left;
4610  newedge.face_right = e1->face_right;
4611  int result = lwt_be_insertEdges(topo, &newedge, 1);
4612  if (result == -1)
4613  {
4614  lwline_free(newedge.geom);
4615  _lwt_release_edges(edges, nedges);
4616  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4617  return -1;
4618  }
4619  else if (result == 0)
4620  {
4621  lwline_free(newedge.geom);
4622  _lwt_release_edges(edges, nedges);
4623  lwerror("Insertion of split edge failed (no reason)");
4624  return -1;
4625  }
4626  }
4627  lwline_free(newedge.geom);
4628 
4629  /*
4630  -- Update next_left_edge/next_right_edge for
4631  -- any edge having them still pointing at the edge being removed
4632  -- (eid2 only when modEdge, or both otherwise)
4633  --
4634  -- NOTE:
4635  -- e#freenode is 1 when edge# end node was the common node
4636  -- and -1 otherwise. This gives the sign of possibly found references
4637  -- to its "free" (non connected to other edge) endnode.
4638  -- e2sign is -1 if edge1 direction is opposite to edge2 direction,
4639  -- or 1 otherwise.
4640  --
4641  */
4642 
4643  /* update edges connected to e2's boundary from their end node */
4644  seledge.next_left = e2freenode * eid2;
4645  updedge.next_left = e2freenode * newedge.edge_id * e2sign;
4646  int result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT, &updedge, LWT_COL_EDGE_NEXT_LEFT, NULL, 0);
4647  if (result == -1)
4648  {
4649  _lwt_release_edges(edges, nedges);
4650  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4651  return -1;
4652  }
4653 
4654  /* update edges connected to e2's boundary from their start node */
4655  seledge.next_right = e2freenode * eid2;
4656  updedge.next_right = e2freenode * newedge.edge_id * e2sign;
4657  result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT, &updedge, LWT_COL_EDGE_NEXT_RIGHT, NULL, 0);
4658  if (result == -1)
4659  {
4660  _lwt_release_edges(edges, nedges);
4661  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4662  return -1;
4663  }
4664 
4665  if ( ! modEdge )
4666  {
4667  /* update edges connected to e1's boundary from their end node */
4668  seledge.next_left = e1freenode * eid1;
4669  updedge.next_left = e1freenode * newedge.edge_id;
4670  result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT, &updedge, LWT_COL_EDGE_NEXT_LEFT, NULL, 0);
4671  if (result == -1)
4672  {
4673  _lwt_release_edges(edges, nedges);
4674  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4675  return -1;
4676  }
4677 
4678  /* update edges connected to e1's boundary from their start node */
4679  seledge.next_right = e1freenode * eid1;
4680  updedge.next_right = e1freenode * newedge.edge_id;
4681  result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT, &updedge, LWT_COL_EDGE_NEXT_RIGHT, NULL, 0);
4682  if (result == -1)
4683  {
4684  _lwt_release_edges(edges, nedges);
4685  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4686  return -1;
4687  }
4688  }
4689 
4690  /* delete the edges (only second on modEdge or both) */
4692  if (result == -1)
4693  {
4694  _lwt_release_edges(edges, nedges);
4695  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4696  return -1;
4697  }
4698  if ( ! modEdge ) {
4700  if (result == -1)
4701  {
4702  _lwt_release_edges(edges, nedges);
4703  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4704  return -1;
4705  }
4706  }
4707 
4708  _lwt_release_edges(edges, nedges);
4709 
4710  /* delete the common node */
4711  i = lwt_be_deleteNodesById( topo, &commonnode, 1 );
4712  if (result == -1)
4713  {
4714  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4715  return -1;
4716  }
4717 
4718  /*
4719  --
4720  -- NOT IN THE SPECS:
4721  -- Drop composition rows involving second
4722  -- edge, as the first edge took its space,
4723  -- and all affected TopoGeom have been previously checked
4724  -- for being composed by both edges.
4725  */
4726  if ( ! lwt_be_updateTopoGeomEdgeHeal(topo,
4727  eid1, eid2, newedge.edge_id) )
4728  {
4730  return -1;
4731  }
4732 
4733  return modEdge ? commonnode : newedge.edge_id;
4734 }
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:459
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:497
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: