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 4201 of file lwgeom_topo.c.

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