PostGIS  3.4.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 4231 of file lwgeom_topo.c.

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