PostGIS  3.0.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 4203 of file lwgeom_topo.c.

4205 {
4206  LWT_ELEMID ids[2];
4207  LWT_ELEMID commonnode = -1;
4208  int caseno = 0;
4209  LWT_ISO_EDGE *node_edges;
4210  uint64_t num_node_edges;
4211  LWT_ISO_EDGE *edges;
4212  LWT_ISO_EDGE *e1 = NULL;
4213  LWT_ISO_EDGE *e2 = NULL;
4214  LWT_ISO_EDGE newedge, updedge, seledge;
4215  uint64_t nedges, i;
4216  int e1freenode;
4217  int e2sign, e2freenode;
4218  POINTARRAY *pa;
4219  char buf[256];
4220  char *ptr;
4221  size_t bufleft = 256;
4222 
4223  ptr = buf;
4224 
4225  /* NOT IN THE SPECS: see if the same edge is given twice.. */
4226  if ( eid1 == eid2 )
4227  {
4228  lwerror("Cannot heal edge %" LWTFMT_ELEMID
4229  " with itself, try with another", eid1);
4230  return -1;
4231  }
4232  ids[0] = eid1;
4233  ids[1] = eid2;
4234  nedges = 2;
4235  edges = lwt_be_getEdgeById(topo, ids, &nedges, LWT_COL_EDGE_ALL);
4236  if ((nedges == UINT64_MAX) || (edges == NULL))
4237  {
4238  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4239  return -1;
4240  }
4241  for ( i=0; i<nedges; ++i )
4242  {
4243  if ( edges[i].edge_id == eid1 ) {
4244  if ( e1 ) {
4245  _lwt_release_edges(edges, nedges);
4246  lwerror("Corrupted topology: multiple edges have id %"
4247  LWTFMT_ELEMID, eid1);
4248  return -1;
4249  }
4250  e1 = &(edges[i]);
4251  }
4252  else if ( edges[i].edge_id == eid2 ) {
4253  if ( e2 ) {
4254  _lwt_release_edges(edges, nedges);
4255  lwerror("Corrupted topology: multiple edges have id %"
4256  LWTFMT_ELEMID, eid2);
4257  return -1;
4258  }
4259  e2 = &(edges[i]);
4260  }
4261  }
4262  if ( ! e1 )
4263  {
4264  _lwt_release_edges(edges, nedges);
4265  lwerror(
4266  "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4267  eid1);
4268  return -1;
4269  }
4270  if ( ! e2 )
4271  {
4272  _lwt_release_edges(edges, nedges);
4273  lwerror(
4274  "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4275  eid2);
4276  return -1;
4277  }
4278 
4279  /* NOT IN THE SPECS: See if any of the two edges are closed. */
4280  if ( e1->start_node == e1->end_node )
4281  {
4282  _lwt_release_edges(edges, nedges);
4283  lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4284  LWTFMT_ELEMID, eid1, eid2);
4285  return -1;
4286  }
4287  if ( e2->start_node == e2->end_node )
4288  {
4289  _lwt_release_edges(edges, nedges);
4290  lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4291  LWTFMT_ELEMID, eid2, eid1);
4292  return -1;
4293  }
4294 
4295  /* Find common node */
4296 
4297  if ( e1->end_node == e2->start_node )
4298  {
4299  commonnode = e1->end_node;
4300  caseno = 1;
4301  }
4302  else if ( e1->end_node == e2->end_node )
4303  {
4304  commonnode = e1->end_node;
4305  caseno = 2;
4306  }
4307  /* Check if any other edge is connected to the common node, if found */
4308  if ( commonnode != -1 )
4309  {
4310  num_node_edges = 1;
4311  node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4312  &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4313  if (num_node_edges == UINT64_MAX)
4314  {
4315  _lwt_release_edges(edges, nedges);
4316  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4317  return -1;
4318  }
4319  for (i=0; i<num_node_edges; ++i)
4320  {
4321  int r;
4322  if ( node_edges[i].edge_id == eid1 ) continue;
4323  if ( node_edges[i].edge_id == eid2 ) continue;
4324  commonnode = -1;
4325  /* append to string, for error message */
4326  if ( bufleft > 0 ) {
4327  r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4328  ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4329  if ( r >= (int) bufleft )
4330  {
4331  bufleft = 0;
4332  buf[252] = '.';
4333  buf[253] = '.';
4334  buf[254] = '.';
4335  buf[255] = '\0';
4336  }
4337  else
4338  {
4339  bufleft -= r;
4340  ptr += r;
4341  }
4342  }
4343  }
4344  lwfree(node_edges);
4345  }
4346 
4347  if ( commonnode == -1 )
4348  {
4349  if ( e1->start_node == e2->start_node )
4350  {
4351  commonnode = e1->start_node;
4352  caseno = 3;
4353  }
4354  else if ( e1->start_node == e2->end_node )
4355  {
4356  commonnode = e1->start_node;
4357  caseno = 4;
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  if ( num_node_edges ) lwfree(node_edges);
4397  }
4398  }
4399 
4400  if ( commonnode == -1 )
4401  {
4402  _lwt_release_edges(edges, nedges);
4403  if ( ptr != buf )
4404  {
4405  lwerror("SQL/MM Spatial exception - other edges connected (%s)",
4406  buf);
4407  }
4408  else
4409  {
4410  lwerror("SQL/MM Spatial exception - non-connected edges");
4411  }
4412  return -1;
4413  }
4414 
4415  if ( ! lwt_be_checkTopoGeomRemNode(topo, commonnode,
4416  eid1, eid2 ) )
4417  {
4418  _lwt_release_edges(edges, nedges);
4420  return -1;
4421  }
4422 
4423  /* Construct the geometry of the new edge */
4424  switch (caseno)
4425  {
4426  case 1: /* e1.end = e2.start */
4427  pa = ptarray_clone_deep(e1->geom->points);
4428  //pa = ptarray_merge(pa, e2->geom->points);
4429  ptarray_append_ptarray(pa, e2->geom->points, 0);
4430  newedge.start_node = e1->start_node;
4431  newedge.end_node = e2->end_node;
4432  newedge.next_left = e2->next_left;
4433  newedge.next_right = e1->next_right;
4434  e1freenode = 1;
4435  e2freenode = -1;
4436  e2sign = 1;
4437  break;
4438  case 2: /* e1.end = e2.end */
4439  {
4440  POINTARRAY *pa2;
4441  pa2 = ptarray_clone_deep(e2->geom->points);
4443  pa = ptarray_clone_deep(e1->geom->points);
4444  //pa = ptarray_merge(e1->geom->points, pa);
4445  ptarray_append_ptarray(pa, pa2, 0);
4446  ptarray_free(pa2);
4447  newedge.start_node = e1->start_node;
4448  newedge.end_node = e2->start_node;
4449  newedge.next_left = e2->next_right;
4450  newedge.next_right = e1->next_right;
4451  e1freenode = 1;
4452  e2freenode = 1;
4453  e2sign = -1;
4454  break;
4455  }
4456  case 3: /* e1.start = e2.start */
4457  pa = ptarray_clone_deep(e2->geom->points);
4459  //pa = ptarray_merge(pa, e1->geom->points);
4460  ptarray_append_ptarray(pa, e1->geom->points, 0);
4461  newedge.end_node = e1->end_node;
4462  newedge.start_node = e2->end_node;
4463  newedge.next_left = e1->next_left;
4464  newedge.next_right = e2->next_left;
4465  e1freenode = -1;
4466  e2freenode = -1;
4467  e2sign = -1;
4468  break;
4469  case 4: /* e1.start = e2.end */
4470  pa = ptarray_clone_deep(e2->geom->points);
4471  //pa = ptarray_merge(pa, e1->geom->points);
4472  ptarray_append_ptarray(pa, e1->geom->points, 0);
4473  newedge.end_node = e1->end_node;
4474  newedge.start_node = e2->start_node;
4475  newedge.next_left = e1->next_left;
4476  newedge.next_right = e2->next_right;
4477  e1freenode = -1;
4478  e2freenode = 1;
4479  e2sign = 1;
4480  break;
4481  default:
4482  pa = NULL;
4483  e1freenode = 0;
4484  e2freenode = 0;
4485  e2sign = 0;
4486  _lwt_release_edges(edges, nedges);
4487  lwerror("Coding error: caseno=%d should never happen", caseno);
4488  break;
4489  }
4490  newedge.geom = lwline_construct(topo->srid, NULL, pa);
4491 
4492  if ( modEdge )
4493  {
4494  /* Update data of the first edge */
4495  newedge.edge_id = eid1;
4496  int result = lwt_be_updateEdgesById(topo,
4497  &newedge,
4498  1,
4501  if (result == -1)
4502  {
4503  lwline_free(newedge.geom);
4504  _lwt_release_edges(edges, nedges);
4505  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4506  return -1;
4507  }
4508  else if (result != 1)
4509  {
4510  lwline_free(newedge.geom);
4511  if ( edges ) _lwt_release_edges(edges, nedges);
4512  lwerror("Unexpected error: %d edges updated when expecting 1", i);
4513  return -1;
4514  }
4515  }
4516  else
4517  {
4518  /* Add new edge */
4519  newedge.edge_id = -1;
4520  newedge.face_left = e1->face_left;
4521  newedge.face_right = e1->face_right;
4522  int result = lwt_be_insertEdges(topo, &newedge, 1);
4523  if (result == -1)
4524  {
4525  lwline_free(newedge.geom);
4526  _lwt_release_edges(edges, nedges);
4527  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4528  return -1;
4529  }
4530  else if (result == 0)
4531  {
4532  lwline_free(newedge.geom);
4533  _lwt_release_edges(edges, nedges);
4534  lwerror("Insertion of split edge failed (no reason)");
4535  return -1;
4536  }
4537  }
4538  lwline_free(newedge.geom);
4539 
4540  /*
4541  -- Update next_left_edge/next_right_edge for
4542  -- any edge having them still pointing at the edge being removed
4543  -- (eid2 only when modEdge, or both otherwise)
4544  --
4545  -- NOTE:
4546  -- e#freenode is 1 when edge# end node was the common node
4547  -- and -1 otherwise. This gives the sign of possibly found references
4548  -- to its "free" (non connected to other edge) endnode.
4549  -- e2sign is -1 if edge1 direction is opposite to edge2 direction,
4550  -- or 1 otherwise.
4551  --
4552  */
4553 
4554  /* update edges connected to e2's boundary from their end node */
4555  seledge.next_left = e2freenode * eid2;
4556  updedge.next_left = e2freenode * newedge.edge_id * e2sign;
4557  int result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT, &updedge, LWT_COL_EDGE_NEXT_LEFT, NULL, 0);
4558  if (result == -1)
4559  {
4560  _lwt_release_edges(edges, nedges);
4561  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4562  return -1;
4563  }
4564 
4565  /* update edges connected to e2's boundary from their start node */
4566  seledge.next_right = e2freenode * eid2;
4567  updedge.next_right = e2freenode * newedge.edge_id * e2sign;
4568  result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT, &updedge, LWT_COL_EDGE_NEXT_RIGHT, NULL, 0);
4569  if (result == -1)
4570  {
4571  _lwt_release_edges(edges, nedges);
4572  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4573  return -1;
4574  }
4575 
4576  if ( ! modEdge )
4577  {
4578  /* update edges connected to e1's boundary from their end node */
4579  seledge.next_left = e1freenode * eid1;
4580  updedge.next_left = e1freenode * newedge.edge_id;
4581  result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT, &updedge, LWT_COL_EDGE_NEXT_LEFT, NULL, 0);
4582  if (result == -1)
4583  {
4584  _lwt_release_edges(edges, nedges);
4585  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4586  return -1;
4587  }
4588 
4589  /* update edges connected to e1's boundary from their start node */
4590  seledge.next_right = e1freenode * eid1;
4591  updedge.next_right = e1freenode * newedge.edge_id;
4592  result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT, &updedge, LWT_COL_EDGE_NEXT_RIGHT, NULL, 0);
4593  if (result == -1)
4594  {
4595  _lwt_release_edges(edges, nedges);
4596  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4597  return -1;
4598  }
4599  }
4600 
4601  /* delete the edges (only second on modEdge or both) */
4602  result = lwt_be_deleteEdges(topo, e2, LWT_COL_EDGE_EDGE_ID);
4603  if (result == -1)
4604  {
4605  _lwt_release_edges(edges, nedges);
4606  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4607  return -1;
4608  }
4609  if ( ! modEdge ) {
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 
4619  _lwt_release_edges(edges, nedges);
4620 
4621  /* delete the common node */
4622  i = lwt_be_deleteNodesById( topo, &commonnode, 1 );
4623  if (result == -1)
4624  {
4625  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4626  return -1;
4627  }
4628 
4629  /*
4630  --
4631  -- NOT IN THE SPECS:
4632  -- Drop composition rows involving second
4633  -- edge, as the first edge took its space,
4634  -- and all affected TopoGeom have been previously checked
4635  -- for being composed by both edges.
4636  */
4637  if ( ! lwt_be_updateTopoGeomEdgeHeal(topo,
4638  eid1, eid2, newedge.edge_id) )
4639  {
4641  return -1;
4642  }
4643 
4644  return modEdge ? commonnode : newedge.edge_id;
4645 }
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: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:469
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: