PostGIS  2.5.7dev-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 4186 of file lwgeom_topo.c.

4188 {
4189  LWT_ELEMID ids[2];
4190  LWT_ELEMID commonnode = -1;
4191  int caseno = 0;
4192  LWT_ISO_EDGE *node_edges;
4193  int num_node_edges;
4194  LWT_ISO_EDGE *edges;
4195  LWT_ISO_EDGE *e1 = NULL;
4196  LWT_ISO_EDGE *e2 = NULL;
4197  LWT_ISO_EDGE newedge, updedge, seledge;
4198  int nedges, i;
4199  int e1freenode;
4200  int e2sign, e2freenode;
4201  POINTARRAY *pa;
4202  char buf[256];
4203  char *ptr;
4204  size_t bufleft = 256;
4205 
4206  ptr = buf;
4207 
4208  /* NOT IN THE SPECS: see if the same edge is given twice.. */
4209  if ( eid1 == eid2 )
4210  {
4211  lwerror("Cannot heal edge %" LWTFMT_ELEMID
4212  " with itself, try with another", eid1);
4213  return -1;
4214  }
4215  ids[0] = eid1;
4216  ids[1] = eid2;
4217  nedges = 2;
4218  edges = lwt_be_getEdgeById(topo, ids, &nedges, LWT_COL_EDGE_ALL);
4219  if ((nedges == -1) || (edges == NULL))
4220  {
4221  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4222  return -1;
4223  }
4224  for ( i=0; i<nedges; ++i )
4225  {
4226  if ( edges[i].edge_id == eid1 ) {
4227  if ( e1 ) {
4228  _lwt_release_edges(edges, nedges);
4229  lwerror("Corrupted topology: multiple edges have id %"
4230  LWTFMT_ELEMID, eid1);
4231  return -1;
4232  }
4233  e1 = &(edges[i]);
4234  }
4235  else if ( edges[i].edge_id == eid2 ) {
4236  if ( e2 ) {
4237  _lwt_release_edges(edges, nedges);
4238  lwerror("Corrupted topology: multiple edges have id %"
4239  LWTFMT_ELEMID, eid2);
4240  return -1;
4241  }
4242  e2 = &(edges[i]);
4243  }
4244  }
4245  if ( ! e1 )
4246  {
4247  _lwt_release_edges(edges, nedges);
4248  lwerror(
4249  "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4250  eid1);
4251  return -1;
4252  }
4253  if ( ! e2 )
4254  {
4255  _lwt_release_edges(edges, nedges);
4256  lwerror(
4257  "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4258  eid2);
4259  return -1;
4260  }
4261 
4262  /* NOT IN THE SPECS: See if any of the two edges are closed. */
4263  if ( e1->start_node == e1->end_node )
4264  {
4265  _lwt_release_edges(edges, nedges);
4266  lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4267  LWTFMT_ELEMID, eid1, eid2);
4268  return -1;
4269  }
4270  if ( e2->start_node == e2->end_node )
4271  {
4272  _lwt_release_edges(edges, nedges);
4273  lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4274  LWTFMT_ELEMID, eid2, eid1);
4275  return -1;
4276  }
4277 
4278  /* Find common node */
4279 
4280  if ( e1->end_node == e2->start_node )
4281  {
4282  commonnode = e1->end_node;
4283  caseno = 1;
4284  }
4285  else if ( e1->end_node == e2->end_node )
4286  {
4287  commonnode = e1->end_node;
4288  caseno = 2;
4289  }
4290  /* Check if any other edge is connected to the common node, if found */
4291  if ( commonnode != -1 )
4292  {
4293  num_node_edges = 1;
4294  node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4295  &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4296  if ( num_node_edges == -1 ) {
4297  _lwt_release_edges(edges, nedges);
4298  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4299  return -1;
4300  }
4301  for (i=0; i<num_node_edges; ++i)
4302  {
4303  int r;
4304  if ( node_edges[i].edge_id == eid1 ) continue;
4305  if ( node_edges[i].edge_id == eid2 ) continue;
4306  commonnode = -1;
4307  /* append to string, for error message */
4308  if ( bufleft > 0 ) {
4309  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4310  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4311  if ( r >= (int) bufleft )
4312  {
4313  bufleft = 0;
4314  buf[252] = '.';
4315  buf[253] = '.';
4316  buf[254] = '.';
4317  buf[255] = '\0';
4318  }
4319  else
4320  {
4321  bufleft -= r;
4322  ptr += r;
4323  }
4324  }
4325  }
4326  lwfree(node_edges);
4327  }
4328 
4329  if ( commonnode == -1 )
4330  {
4331  if ( e1->start_node == e2->start_node )
4332  {
4333  commonnode = e1->start_node;
4334  caseno = 3;
4335  }
4336  else if ( e1->start_node == e2->end_node )
4337  {
4338  commonnode = e1->start_node;
4339  caseno = 4;
4340  }
4341  /* Check if any other edge is connected to the common node, if found */
4342  if ( commonnode != -1 )
4343  {
4344  num_node_edges = 1;
4345  node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4346  &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4347  if ( num_node_edges == -1 ) {
4348  _lwt_release_edges(edges, nedges);
4349  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4350  return -1;
4351  }
4352  for (i=0; i<num_node_edges; ++i)
4353  {
4354  int r;
4355  if ( node_edges[i].edge_id == eid1 ) continue;
4356  if ( node_edges[i].edge_id == eid2 ) continue;
4357  commonnode = -1;
4358  /* append to string, for error message */
4359  if ( bufleft > 0 ) {
4360  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4361  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4362  if ( r >= (int) bufleft )
4363  {
4364  bufleft = 0;
4365  buf[252] = '.';
4366  buf[253] = '.';
4367  buf[254] = '.';
4368  buf[255] = '\0';
4369  }
4370  else
4371  {
4372  bufleft -= r;
4373  ptr += r;
4374  }
4375  }
4376  }
4377  if ( num_node_edges ) lwfree(node_edges);
4378  }
4379  }
4380 
4381  if ( commonnode == -1 )
4382  {
4383  _lwt_release_edges(edges, nedges);
4384  if ( ptr != buf )
4385  {
4386  lwerror("SQL/MM Spatial exception - other edges connected (%s)",
4387  buf);
4388  }
4389  else
4390  {
4391  lwerror("SQL/MM Spatial exception - non-connected edges");
4392  }
4393  return -1;
4394  }
4395 
4396  if ( ! lwt_be_checkTopoGeomRemNode(topo, commonnode,
4397  eid1, eid2 ) )
4398  {
4399  _lwt_release_edges(edges, nedges);
4401  return -1;
4402  }
4403 
4404  /* Construct the geometry of the new edge */
4405  switch (caseno)
4406  {
4407  case 1: /* e1.end = e2.start */
4408  pa = ptarray_clone_deep(e1->geom->points);
4409  //pa = ptarray_merge(pa, e2->geom->points);
4410  ptarray_append_ptarray(pa, e2->geom->points, 0);
4411  newedge.start_node = e1->start_node;
4412  newedge.end_node = e2->end_node;
4413  newedge.next_left = e2->next_left;
4414  newedge.next_right = e1->next_right;
4415  e1freenode = 1;
4416  e2freenode = -1;
4417  e2sign = 1;
4418  break;
4419  case 2: /* e1.end = e2.end */
4420  {
4421  POINTARRAY *pa2;
4422  pa2 = ptarray_clone_deep(e2->geom->points);
4424  pa = ptarray_clone_deep(e1->geom->points);
4425  //pa = ptarray_merge(e1->geom->points, pa);
4426  ptarray_append_ptarray(pa, pa2, 0);
4427  ptarray_free(pa2);
4428  newedge.start_node = e1->start_node;
4429  newedge.end_node = e2->start_node;
4430  newedge.next_left = e2->next_right;
4431  newedge.next_right = e1->next_right;
4432  e1freenode = 1;
4433  e2freenode = 1;
4434  e2sign = -1;
4435  break;
4436  }
4437  case 3: /* e1.start = e2.start */
4438  pa = ptarray_clone_deep(e2->geom->points);
4440  //pa = ptarray_merge(pa, e1->geom->points);
4441  ptarray_append_ptarray(pa, e1->geom->points, 0);
4442  newedge.end_node = e1->end_node;
4443  newedge.start_node = e2->end_node;
4444  newedge.next_left = e1->next_left;
4445  newedge.next_right = e2->next_left;
4446  e1freenode = -1;
4447  e2freenode = -1;
4448  e2sign = -1;
4449  break;
4450  case 4: /* e1.start = e2.end */
4451  pa = ptarray_clone_deep(e2->geom->points);
4452  //pa = ptarray_merge(pa, e1->geom->points);
4453  ptarray_append_ptarray(pa, e1->geom->points, 0);
4454  newedge.end_node = e1->end_node;
4455  newedge.start_node = e2->start_node;
4456  newedge.next_left = e1->next_left;
4457  newedge.next_right = e2->next_right;
4458  e1freenode = -1;
4459  e2freenode = 1;
4460  e2sign = 1;
4461  break;
4462  default:
4463  pa = NULL;
4464  e1freenode = 0;
4465  e2freenode = 0;
4466  e2sign = 0;
4467  _lwt_release_edges(edges, nedges);
4468  lwerror("Coding error: caseno=%d should never happen", caseno);
4469  break;
4470  }
4471  newedge.geom = lwline_construct(topo->srid, NULL, pa);
4472 
4473  if ( modEdge )
4474  {
4475  /* Update data of the first edge */
4476  newedge.edge_id = eid1;
4477  i = lwt_be_updateEdgesById(topo, &newedge, 1,
4483  if ( i == -1 )
4484  {
4485  lwline_free(newedge.geom);
4486  _lwt_release_edges(edges, nedges);
4487  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4488  return -1;
4489  }
4490  else if ( i != 1 )
4491  {
4492  lwline_free(newedge.geom);
4493  if ( edges ) _lwt_release_edges(edges, nedges);
4494  lwerror("Unexpected error: %d edges updated when expecting 1", i);
4495  return -1;
4496  }
4497  }
4498  else
4499  {
4500  /* Add new edge */
4501  newedge.edge_id = -1;
4502  newedge.face_left = e1->face_left;
4503  newedge.face_right = e1->face_right;
4504  i = lwt_be_insertEdges(topo, &newedge, 1);
4505  if ( i == -1 ) {
4506  lwline_free(newedge.geom);
4507  _lwt_release_edges(edges, nedges);
4508  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4509  return -1;
4510  } else if ( i == 0 ) {
4511  lwline_free(newedge.geom);
4512  _lwt_release_edges(edges, nedges);
4513  lwerror("Insertion of split edge failed (no reason)");
4514  return -1;
4515  }
4516  }
4517  lwline_free(newedge.geom);
4518 
4519  /*
4520  -- Update next_left_edge/next_right_edge for
4521  -- any edge having them still pointing at the edge being removed
4522  -- (eid2 only when modEdge, or both otherwise)
4523  --
4524  -- NOTE:
4525  -- e#freenode is 1 when edge# end node was the common node
4526  -- and -1 otherwise. This gives the sign of possibly found references
4527  -- to its "free" (non connected to other edge) endnode.
4528  -- e2sign is -1 if edge1 direction is opposite to edge2 direction,
4529  -- or 1 otherwise.
4530  --
4531  */
4532 
4533  /* update edges connected to e2's boundary from their end node */
4534  seledge.next_left = e2freenode * eid2;
4535  updedge.next_left = e2freenode * newedge.edge_id * e2sign;
4536  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT,
4537  &updedge, LWT_COL_EDGE_NEXT_LEFT,
4538  NULL, 0);
4539  if ( i == -1 )
4540  {
4541  _lwt_release_edges(edges, nedges);
4542  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4543  return -1;
4544  }
4545 
4546  /* update edges connected to e2's boundary from their start node */
4547  seledge.next_right = e2freenode * eid2;
4548  updedge.next_right = e2freenode * newedge.edge_id * e2sign;
4549  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT,
4550  &updedge, LWT_COL_EDGE_NEXT_RIGHT,
4551  NULL, 0);
4552  if ( i == -1 )
4553  {
4554  _lwt_release_edges(edges, nedges);
4555  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4556  return -1;
4557  }
4558 
4559  if ( ! modEdge )
4560  {
4561  /* update edges connected to e1's boundary from their end node */
4562  seledge.next_left = e1freenode * eid1;
4563  updedge.next_left = e1freenode * newedge.edge_id;
4564  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT,
4565  &updedge, LWT_COL_EDGE_NEXT_LEFT,
4566  NULL, 0);
4567  if ( i == -1 )
4568  {
4569  _lwt_release_edges(edges, nedges);
4570  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4571  return -1;
4572  }
4573 
4574  /* update edges connected to e1's boundary from their start node */
4575  seledge.next_right = e1freenode * eid1;
4576  updedge.next_right = e1freenode * newedge.edge_id;
4577  i = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT,
4578  &updedge, LWT_COL_EDGE_NEXT_RIGHT,
4579  NULL, 0);
4580  if ( i == -1 )
4581  {
4582  _lwt_release_edges(edges, nedges);
4583  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4584  return -1;
4585  }
4586  }
4587 
4588  /* delete the edges (only second on modEdge or both) */
4590  if ( i == -1 )
4591  {
4592  _lwt_release_edges(edges, nedges);
4593  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4594  return -1;
4595  }
4596  if ( ! modEdge ) {
4598  if ( i == -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 
4606  _lwt_release_edges(edges, nedges);
4607 
4608  /* delete the common node */
4609  i = lwt_be_deleteNodesById( topo, &commonnode, 1 );
4610  if ( i == -1 )
4611  {
4612  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4613  return -1;
4614  }
4615 
4616  /*
4617  --
4618  -- NOT IN THE SPECS:
4619  -- Drop composition rows involving second
4620  -- edge, as the first edge took its space,
4621  -- and all affected TopoGeom have been previously checked
4622  -- for being composed by both edges.
4623  */
4624  if ( ! lwt_be_updateTopoGeomEdgeHeal(topo,
4625  eid1, eid2, newedge.edge_id) )
4626  {
4628  return -1;
4629  }
4630 
4631  return modEdge ? commonnode : newedge.edge_id;
4632 }
char * r
Definition: cu_in_wkt.c:24
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
POINTARRAY * ptarray_clone_deep(const POINTARRAY *ptarray)
Deep clone a pointarray (also clones serialized pointlist)
Definition: ptarray.c:628
void lwfree(void *mem)
Definition: lwutil.c:244
void ptarray_free(POINTARRAY *pa)
Definition: ptarray.c:328
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
void lwline_free(LWLINE *line)
Definition: lwline.c:76
void ptarray_reverse_in_place(POINTARRAY *pa)
Definition: ptarray.c:341
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:120
LWT_ISO_EDGE * lwt_be_getEdgeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:225
static int lwt_be_updateTopoGeomEdgeHeal(LWT_TOPOLOGY *topo, LWT_ELEMID edge1, LWT_ELEMID edge2, LWT_ELEMID newedge)
Definition: lwgeom_topo.c:372
static int lwt_be_deleteNodesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int numelems)
Definition: lwgeom_topo.c:213
static int lwt_be_checkTopoGeomRemNode(LWT_TOPOLOGY *topo, LWT_ELEMID node_id, LWT_ELEMID eid1, LWT_ELEMID eid2)
Definition: lwgeom_topo.c:357
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
int lwt_be_deleteEdges(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *sel_edge, int sel_fields)
Definition: lwgeom_topo.c:322
static LWT_ISO_EDGE * lwt_be_getEdgeByNode(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:239
int lwt_be_insertEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, int numelems)
Definition: lwgeom_topo.c:268
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:44
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:457
static int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
Definition: lwgeom_topo.c:306
POINTARRAY * points
Definition: liblwgeom.h:425
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, 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: