PostGIS  2.5.1dev-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 4166 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_in_place(), r, LWT_TOPOLOGY_T::srid, and LWT_ISO_EDGE::start_node.

Referenced by lwt_ModEdgeHeal(), and lwt_NewEdgeHeal().

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