PostGIS  2.2.8dev-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 4300 of file lwgeom_topo.c.

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

Referenced by lwt_ModEdgeHeal(), and lwt_NewEdgeHeal().

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