PostGIS  3.1.6dev-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 4255 of file lwgeom_topo.c.

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