PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ _lwt_SnapEdgeToExistingNode()

static int _lwt_SnapEdgeToExistingNode ( LWT_TOPOLOGY topo,
LWT_ISO_NODE node,
LWT_ISO_EDGE edge,
double  tol 
)
static

Definition at line 5290 of file lwgeom_topo.c.

5296 {
5297  LWGEOM *prj = lwpoint_as_lwgeom(node->geom);
5298  const POINT2D *pt = getPoint2d_cp(lwgeom_as_lwpoint(prj)->point, 0);
5299 
5300  LWDEBUGF(1, "Experimental handling of within-tolerance edge %" LWTFMT_ELEMID, edge->edge_id);
5301  LWGEOM *snapE = lwgeom_snap(lwline_as_lwgeom(edge->geom), prj, tol);
5302 
5303  /* TODO: check if an endpoint moved */
5304 
5305  LWGEOM *splitE = lwgeom_split(snapE, prj);
5306  LWDEBUGG(1, splitE, "Split edge");
5307 
5308  LWCOLLECTION *splitC = lwgeom_as_lwcollection(splitE);
5309  if ( splitC->ngeoms != 2 )
5310  {
5311  lwerror("Split of edge resulted in %d components", splitC->ngeoms);
5312  return -1;
5313  }
5314 
5315  LWT_NODE_EDGES *firstNodeEdges = lwt_nodeEdges_loadFromDB(topo, edge->start_node, LWT_COL_EDGE_ALL );
5316  if ( ! firstNodeEdges ) {
5317  lwerror("No edges found in DB to be incident to split edge's first node");
5318  return -1;
5319  }
5320  LWT_NODE_EDGES *lastNodeEdges = lwt_nodeEdges_loadFromDB(topo, edge->end_node, LWT_COL_EDGE_ALL );
5321  if ( ! lastNodeEdges ) {
5322  lwerror("No edges found in DB to be incident to split edge's last node");
5323  return -1;
5324  }
5325  LWT_NODE_EDGES *splitNodeEdges = lwt_nodeEdges_loadFromDB(topo, node->node_id, LWT_COL_EDGE_ALL);
5326  if ( ! splitNodeEdges ) {
5327  lwerror("No edges found in DB to be incident to split node");
5328  return -1;
5329  }
5330 
5331  /* Update split edge reference as it was possibly changed by previous call */
5332  for ( uint64_t t=0; t<firstNodeEdges->numEdges; t++ )
5333  {
5334  if ( firstNodeEdges->edges[t].edge_id == edge->edge_id )
5335  {
5336  edge = &(firstNodeEdges->edges[t]);
5337  break;
5338  }
5339  }
5340 
5341  LWDEBUGF(1, "Split edge %"
5342  LWTFMT_ELEMID " start condition: next_right:%"
5343  LWTFMT_ELEMID ", next_left:%"
5344  LWTFMT_ELEMID ", face_right:%"
5345  LWTFMT_ELEMID ", face_left:%"
5346  LWTFMT_ELEMID ", start_node:%"
5347  LWTFMT_ELEMID ", end_node:%"
5348  LWTFMT_ELEMID,
5349  edge->edge_id,
5350  edge->next_right,
5351  edge->next_left,
5352  edge->face_right,
5353  edge->face_left,
5354  edge->start_node,
5355  edge->end_node
5356  );
5357 
5358  int ret;
5359 
5360  uint64_t n;
5361  LWT_ELEMID replacedBy[2];
5362  LWT_ISO_EDGE *existingEdges[2];
5363  //int replacedByForward[2];
5364  edgeend splitNodeEdgeEnds[2];
5365  for ( n=0; n<2; ++n)
5366  {
5367  int forward;
5368  /* TODO: directly get full existing edge rather than just id * */
5369  LWT_ELEMID existingEdgeId = _lwt_GetEqualEdge( topo, lwgeom_as_lwline(splitC->geoms[n]), &forward );
5370  if ( existingEdgeId == -1 )
5371  {
5372  /* probably too late, due to internal lwerror */
5373  return -1;
5374  }
5375  existingEdges[n] = NULL;
5376  if ( existingEdgeId == 0 )
5377  {
5378  LWDEBUGF(1, "Split component %llu is a new edge, computing edgeEndInfo", n);
5379  {
5380  // Compute nextCW and nextCCW of the split edge now
5381  // incident to the split point
5382 
5383  POINT2D op; /* other point */
5384  if ( n == 1 ) {
5386  lwgeom_as_lwline(splitC->geoms[1])->points, //const POINTARRAY* pa,
5387  pt, //POINT2D *ref,
5388  0, // int from,
5389  1, // int dir,
5390  &op // POINT2D *op
5391  );
5392  if (!ret)
5393  {
5394  lwerror("No distinct vertices found on second part of split edge");
5395  return -1; /* lwerror should have been raised */
5396  }
5397  } else {
5398  const POINTARRAY *pa = lwgeom_as_lwline(splitC->geoms[0])->points;
5400  pa, //const POINTARRAY* pa,
5401  pt, //POINT2D *ref,
5402  pa->npoints-1, // int from,
5403  -1, // int dir,
5404  &op // POINT2D *op
5405  );
5406  if (!ret)
5407  {
5408  lwerror("No distinct vertices found on first part of split edge");
5409  return -1; /* lwerror should have been raised */
5410  }
5411  }
5412  if ( ! azimuth_pt_pt(pt, &op, &(splitNodeEdgeEnds[n].myaz)) ) {
5413  lwerror("error computing azimuth of split endpoint [%.15g %.15g,%.15g %.15g]",
5414  op.x, op.y,
5415  pt->x, pt->y
5416  );
5417  return -1;
5418  }
5419  LWDEBUGF(1, "Azimuth of split component %llu edgeend [%.15g %.15g,%.15g %.15g] is %.15g",
5420  n, op.x, op.y, pt->x, pt->y, splitNodeEdgeEnds[n].myaz);
5421  ret = _lwt_FindAdjacentEdges( topo, node->node_id, &(splitNodeEdgeEnds[n]), NULL, -1 );
5422  if ( ! ret ) {
5423  lwerror("Unexpected backend return: _lwt_FindAdjacentEdges(%"
5424  LWTFMT_ELEMID ") found no edges when we previously split edge %"
5425  LWTFMT_ELEMID "d on it",
5426  node->node_id, edge->edge_id);
5427  return -1;
5428  }
5429  LWDEBUGF(1, "Component %llu of split edge %" LWTFMT_ELEMID
5430  " next CW is %" LWTFMT_ELEMID ", next CCW is %" LWTFMT_ELEMID,
5431  n, edge->edge_id, splitNodeEdgeEnds[n].nextCW, splitNodeEdgeEnds[n].nextCCW);
5432  }
5433  }
5434  else
5435  {
5436  LWDEBUGF(1, "Split component %llu matches existing edge %" LWTFMT_ELEMID
5437  " (%s)", n, existingEdgeId, forward ? "forward" : "backward" );
5438  /* Get existing edge */
5439  for ( uint64_t t=0; t<splitNodeEdges->numEdges; t++ )
5440  {
5441  if ( splitNodeEdges->edges[t].edge_id == existingEdgeId )
5442  {
5443  existingEdges[n] = &(splitNodeEdges->edges[t]);
5444  break;
5445  }
5446  }
5447  if (existingEdges[n] == NULL)
5448  {
5449  lwerror("could not find edge %" LWTFMT_ELEMID " in database, but _lwt_GetEqualEdges said it was there", existingEdgeId );
5450  return -1;
5451  }
5452  }
5453 
5454  replacedBy[n] = existingEdgeId;
5455  }
5456 
5457 
5458  LWT_ISO_EDGE updatedEdge;
5459  int updateFlags;
5460  LWT_ISO_EDGE selEdge;
5461 
5462  if ( ( replacedBy[0] != 0 && replacedBy[1] == 0 ) ||
5463  ( replacedBy[1] != 0 && replacedBy[0] == 0 ) )
5464  {
5465  /* One side of the snapped edge collapsed to an existing edge */
5466 
5467  LWT_ISO_EDGE *existingEdge;
5468  edgeend *splitNodeEdgeEndInfo;
5469  LWLINE *newSplitEdgeLine;
5470  int splitNodeNewEdgeOutgoing; // The new split edge goes out of the split node
5471 
5472  if ( replacedBy[1] == 0 )
5473  /* First part of edge is the existing edge */
5474  {
5475  existingEdge = existingEdges[0];
5476  newSplitEdgeLine = lwgeom_as_lwline(splitC->geoms[1]);
5477  splitNodeEdgeEndInfo = &(splitNodeEdgeEnds[1]);
5478  splitNodeNewEdgeOutgoing = 1;
5479  }
5480  else
5481  /* Second part of edge is the existing edge */
5482  {
5483  existingEdge = existingEdges[1];
5484  newSplitEdgeLine = lwgeom_as_lwline(splitC->geoms[0]);
5485  splitNodeEdgeEndInfo = &(splitNodeEdgeEnds[0]);
5486  splitNodeNewEdgeOutgoing = 0;
5487  }
5488 
5489  _lwt_SnapEdge_checkMotion( topo, splitC, edge, existingEdge, splitNodeEdges );
5490 
5491  LWDEBUGF(1, "Existing edge %"
5492  LWTFMT_ELEMID " (post-modEdgeSplit) next_right:%"
5493  LWTFMT_ELEMID ", next_left:%"
5494  LWTFMT_ELEMID ", face_right:%"
5495  LWTFMT_ELEMID ", face_left:%"
5496  LWTFMT_ELEMID,
5497  existingEdge->edge_id,
5498  existingEdge->next_right,
5499  existingEdge->next_left,
5500  existingEdge->face_right,
5501  existingEdge->face_left
5502  );
5503 
5504  /*****
5505  *
5506  * Update edge linking
5507  *
5508  */
5509 
5510  /*
5511  * Update next CW / CCW edges on split node
5512  * (fix linking on split node)
5513  */
5514 
5515  /* Update next CCW edge */
5516  {
5517  LWT_ELEMID nextEdge, sideFace;
5518  if ( splitNodeNewEdgeOutgoing ) {
5519  nextEdge = edge->edge_id;
5520  sideFace = edge->face_left;
5521  } else {
5522  nextEdge = -edge->edge_id;
5523  sideFace = edge->face_right;
5524  }
5525 
5526  LWDEBUGF(1, "Setting nextEdge/sideFace of CCW edge %" LWTFMT_ELEMID
5527  " to %" LWTFMT_ELEMID "/%" LWTFMT_ELEMID,
5528  splitNodeEdgeEndInfo->nextCCW,
5529  nextEdge, sideFace
5530  );
5531 
5532  if ( splitNodeEdgeEndInfo->nextCCW > 0 )
5533  {
5534  selEdge.edge_id = splitNodeEdgeEndInfo->nextCCW;
5535  updatedEdge.next_right = nextEdge;
5536  updatedEdge.face_right = sideFace;
5537  updateFlags = LWT_COL_EDGE_NEXT_RIGHT|
5539  LWDEBUGF(1, "Will update next_right/face_right of outgoing CCW edge %" LWTFMT_ELEMID
5540  " to %" LWTFMT_ELEMID "/%" LWTFMT_ELEMID,
5541  selEdge.edge_id,
5542  nextEdge, sideFace
5543  );
5544  }
5545  else
5546  {
5547  selEdge.edge_id = -splitNodeEdgeEndInfo->nextCCW;
5548  updatedEdge.next_left = nextEdge;
5549  updatedEdge.face_left = sideFace;
5550  updateFlags = LWT_COL_EDGE_NEXT_LEFT|
5552  LWDEBUGF(1, "Will update next_left/face_left of incoming CCW edge %" LWTFMT_ELEMID
5553  " to %" LWTFMT_ELEMID "/%" LWTFMT_ELEMID,
5554  selEdge.edge_id,
5555  nextEdge, sideFace
5556  );
5557  }
5558 
5559  ret = lwt_be_updateEdges(topo,
5560  &selEdge, LWT_COL_EDGE_EDGE_ID,
5561  &updatedEdge, updateFlags,
5562  NULL, 0);
5563  if ( ret == -1 ) {
5564  PGTOPO_BE_ERROR();
5565  return -1;
5566  } else if ( ret == 0 ) {
5567  lwerror("Edge %" LWTFMT_ELEMID " disappeared during operations", selEdge.edge_id);
5568  return -1;
5569  } else if ( ret > 1 ) {
5570  lwerror("More than a single edge found with id %"
5571  LWTFMT_ELEMID " ! (corrupted topology?)", selEdge.edge_id);
5572  return -1;
5573  }
5574  }
5575 
5576  /* Update next CW edge on split node */
5577  {
5578  LWT_ELEMID sideFace;
5579  if ( splitNodeNewEdgeOutgoing ) {
5580  sideFace = edge->face_right;
5581  } else {
5582  sideFace = edge->face_left;
5583  }
5584 
5585  LWDEBUGF(1, "Setting sideFace of CW edge %" LWTFMT_ELEMID
5586  " to %" LWTFMT_ELEMID,
5587  splitNodeEdgeEndInfo->nextCW, sideFace
5588  );
5589 
5590  if ( splitNodeEdgeEndInfo->nextCW > 0 )
5591  {
5592  selEdge.edge_id = splitNodeEdgeEndInfo->nextCW;
5593  updatedEdge.face_left = sideFace;
5594  updateFlags = LWT_COL_EDGE_FACE_LEFT;
5595  LWDEBUGF(1, "Updating left_face of edge %" LWTFMT_ELEMID
5596  ", outgoing next CW of new split edge on split node",
5597  selEdge.edge_id);
5598  }
5599  else
5600  {
5601  selEdge.edge_id = -splitNodeEdgeEndInfo->nextCW;
5602  updatedEdge.face_right = sideFace;
5603  updateFlags = LWT_COL_EDGE_FACE_RIGHT;
5604  LWDEBUGF(1, "Updating right_face of edge %" LWTFMT_ELEMID
5605  ", incoming next CW of new split edge on split node",
5606  selEdge.edge_id);
5607  }
5608 
5609  ret = lwt_be_updateEdges(topo,
5610  &selEdge, LWT_COL_EDGE_EDGE_ID,
5611  &updatedEdge, updateFlags,
5612  NULL, 0);
5613  if ( ret == -1 ) {
5614  PGTOPO_BE_ERROR();
5615  return -1;
5616  } else if ( ret == 0 ) {
5617  lwerror("Edge %" LWTFMT_ELEMID " disappeared during operations", selEdge.edge_id);
5618  return -1;
5619  } else if ( ret > 1 ) {
5620  lwerror("More than a single edge found with edge_id %"
5621  LWTFMT_ELEMID " ! (corrupted topology?)", selEdge.edge_id);
5622  return -1;
5623  }
5624  }
5625 
5626  /*
5627  * Update links to now-disappeared edgeend
5628  * on the node originally in common with
5629  * the existing node
5630  */
5631 
5632  LWT_ISO_EDGE *nextCCWEdge = NULL;
5633  int nextCCWEdgeIsIncoming = 0;
5634  int collapsedEdgeIsIncoming;
5635 
5636  LWT_ELEMID commonNodeID;
5637 
5638  LWT_NODE_EDGES *commonNodeEdges;
5639  if ( replacedBy[0] ) {
5640  commonNodeEdges = firstNodeEdges;
5641  commonNodeID = edge->start_node;
5642  collapsedEdgeIsIncoming = 0;
5643  } else {
5644  commonNodeEdges = lastNodeEdges;
5645  commonNodeID = edge->end_node;
5646  collapsedEdgeIsIncoming = 1;
5647  }
5648 
5649 
5650  // Update next CCW edge
5651  {
5652  LWT_ELEMID signedCollapsedEdgeID = collapsedEdgeIsIncoming ? -edge->edge_id: edge->edge_id;
5653 
5654  LWDEBUGF(1, "Looking for next CCW edge of split edge %"
5655  LWTFMT_ELEMID " on common node %" LWTFMT_ELEMID
5656  " having %llu attached edges",
5657  edge->edge_id,
5658  commonNodeID, commonNodeEdges->numEdges
5659  );
5660 
5661  /* Find next CCW edge */
5662  for ( uint64_t t=0; t<commonNodeEdges->numEdges; t++ )
5663  {
5664  LWT_ISO_EDGE *et = &(commonNodeEdges->edges[t]);
5665 
5666  LWDEBUGF(1, "common node edge %"
5667  LWTFMT_ELEMID " has next_left:%" LWTFMT_ELEMID
5668  " next_right:%" LWTFMT_ELEMID,
5669  et->edge_id,
5670  et->next_left,
5671  et->next_right
5672  );
5673 
5674  if ( et->start_node == commonNodeID )
5675  {
5676  if ( et->next_right == signedCollapsedEdgeID )
5677  {
5678  nextCCWEdge = et;
5679  nextCCWEdgeIsIncoming = 0;
5680  break;
5681  }
5682  }
5683  else if ( et->end_node == commonNodeID )
5684  {
5685  if ( et->next_left == signedCollapsedEdgeID )
5686  {
5687  nextCCWEdge = et;
5688  nextCCWEdgeIsIncoming = 1;
5689  break;
5690  }
5691  }
5692  }
5693  if ( ! nextCCWEdge )
5694  {
5695  lwerror("Could not find nextCCW edge on common node %" LWTFMT_ELEMID,
5696  commonNodeID
5697  );
5698  return -1;
5699  }
5700 
5701  LWDEBUGF(1, "Next CCW edge of split edge %"
5702  LWTFMT_ELEMID " on common node %" LWTFMT_ELEMID
5703  " is (%s) %" LWTFMT_ELEMID,
5704  edge->edge_id,
5705  commonNodeID,
5706  nextCCWEdgeIsIncoming ? "incoming" : "outgoing",
5707  nextCCWEdge->edge_id
5708  );
5709 
5710  if ( nextCCWEdge->edge_id == existingEdge->edge_id )
5711  {
5712  LWDEBUG(1, "Next CCW edge is existing/collapse edge, will not update here");
5713  }
5714  else
5715  {
5716  /*
5717  * TODO: the nextCCW is only of interest IFF the collapse
5718  * happened clockwise!
5719  *
5720  * just update to the split edge id (positive or negative
5721  * depending on whether it was outgoing or incoming in the
5722  * common node)
5723  */
5724  LWT_ELEMID newNextEdge = existingEdge->start_node == commonNodeID ?
5725  existingEdge->edge_id :
5726  -existingEdge->edge_id;
5727 
5728  selEdge.edge_id = nextCCWEdge->edge_id;
5729  if ( nextCCWEdgeIsIncoming ) {
5730  updatedEdge.next_left = newNextEdge;
5731  updateFlags = LWT_COL_EDGE_NEXT_LEFT;
5732  LWDEBUGF(1, "Updating next_left of incoming next CCW edge %"
5734  " to %" LWTFMT_ELEMID,
5735  selEdge.edge_id,
5736  newNextEdge
5737  );
5738  } else {
5739  updatedEdge.next_right = newNextEdge;
5740  updateFlags = LWT_COL_EDGE_NEXT_RIGHT;
5741  LWDEBUGF(1, "Updating next_right of outgoing next CCW edge %"
5743  " to %" LWTFMT_ELEMID,
5744  selEdge.edge_id,
5745  newNextEdge
5746  );
5747  }
5748  ret = lwt_be_updateEdges(topo,
5749  &selEdge, LWT_COL_EDGE_EDGE_ID,
5750  &updatedEdge, updateFlags,
5751  NULL, 0);
5752  if ( ret == -1 ) {
5753  PGTOPO_BE_ERROR();
5754  return -1;
5755  } else if ( ret == 0 ) {
5756  lwerror("Edge %" LWTFMT_ELEMID " disappeared during operations", selEdge.edge_id);
5757  return -1;
5758  } else if ( ret > 1 ) {
5759  lwerror("More than a single edge found with next_left %"
5760  LWTFMT_ELEMID " ! (corrupted topology?)", selEdge.next_left);
5761  return -1;
5762  }
5763  }
5764  }
5765 
5766  /*****
5767  *
5768  * Update the existing edge our split edge collapsed to
5769  *
5770  */
5771 
5772  selEdge.edge_id = existingEdge->edge_id;
5773  updateFlags = 0;
5774  if ( existingEdge->next_left == edge->edge_id )
5775  {
5776  updatedEdge.next_left = edge->next_right;
5777  updateFlags |= LWT_COL_EDGE_NEXT_LEFT;
5778  LWDEBUGF(1, "Will update next_left of existing edge %"
5779  LWTFMT_ELEMID " to %" LWTFMT_ELEMID,
5780  selEdge.edge_id,
5781  updatedEdge.next_left
5782  );
5783  }
5784  if ( existingEdge->next_right == edge->edge_id )
5785  {
5786  updatedEdge.next_right = edge->next_right;
5787  updateFlags |= LWT_COL_EDGE_NEXT_RIGHT;
5788  LWDEBUGF(1, "Will update next_right of existing edge %"
5789  LWTFMT_ELEMID " to %" LWTFMT_ELEMID,
5790  selEdge.edge_id,
5791  updatedEdge.next_right
5792  );
5793  }
5794  if ( existingEdge->next_left == -edge->edge_id )
5795  {
5796  updatedEdge.next_left = edge->next_left;
5797  updateFlags |= LWT_COL_EDGE_NEXT_LEFT;
5798  LWDEBUGF(1, "Will update next_left of existing edge %"
5799  LWTFMT_ELEMID " to %" LWTFMT_ELEMID,
5800  selEdge.edge_id,
5801  updatedEdge.next_left
5802  );
5803  }
5804  if ( existingEdge->next_right == -edge->edge_id )
5805  {
5806  updatedEdge.next_right = edge->next_left;
5807  updateFlags |= LWT_COL_EDGE_NEXT_RIGHT;
5808  LWDEBUGF(1, "Will update next_right of existing edge %"
5809  LWTFMT_ELEMID " to %" LWTFMT_ELEMID,
5810  selEdge.edge_id,
5811  updatedEdge.next_right
5812  );
5813  }
5814  if ( updateFlags )
5815  {
5816  ret = lwt_be_updateEdges(topo,
5817  &selEdge, LWT_COL_EDGE_EDGE_ID,
5818  &updatedEdge, updateFlags,
5819  NULL, 0);
5820  if ( ret == -1 ) {
5821  PGTOPO_BE_ERROR();
5822  return -1;
5823  } else if ( ret == 0 ) {
5824  lwerror("Edge being split (%" LWTFMT_ELEMID ") disappeared during operations?", selEdge.edge_id);
5825  return -1;
5826  } else if ( ret > 1 ) {
5827  lwerror("More than a single edge found with id %"
5828  LWTFMT_ELEMID " !", selEdge.edge_id);
5829  return -1;
5830  }
5831  }
5832 
5833  /*****
5834  *
5835  * Update the split edge
5836  *
5837  */
5838 
5839  selEdge.edge_id = edge->edge_id;
5840  updatedEdge.geom = newSplitEdgeLine;
5841  updateFlags = LWT_COL_EDGE_GEOM;
5842  if ( splitNodeNewEdgeOutgoing ) {
5843  updatedEdge.start_node = node->node_id;
5844  updatedEdge.next_right = splitNodeEdgeEndInfo->nextCW;
5845  updateFlags |= LWT_COL_EDGE_START_NODE;
5846  updateFlags |= LWT_COL_EDGE_NEXT_RIGHT;
5847  LWDEBUGF(1, "Updating split edge %" LWTFMT_ELEMID
5848  " start node to %" LWTFMT_ELEMID
5849  " and next_right to %" LWTFMT_ELEMID,
5850  selEdge.edge_id,
5851  updatedEdge.start_node,
5852  updatedEdge.next_right
5853  );
5854  } else {
5855  updatedEdge.end_node = node->node_id;
5856  updatedEdge.next_left = splitNodeEdgeEndInfo->nextCW;
5857  updateFlags |= LWT_COL_EDGE_END_NODE;
5858  updateFlags |= LWT_COL_EDGE_NEXT_LEFT;
5859  LWDEBUGF(1, "Updating split edge %" LWTFMT_ELEMID
5860  " end node to %" LWTFMT_ELEMID
5861  " and next_left to %" LWTFMT_ELEMID
5862  ,
5863  selEdge.edge_id,
5864  updatedEdge.end_node
5865  , updatedEdge.next_left
5866  );
5867  }
5868 
5869  ret = lwt_be_updateEdges(topo,
5870  &selEdge, LWT_COL_EDGE_EDGE_ID,
5871  &updatedEdge, updateFlags,
5872  NULL, 0);
5873  if ( ret == -1 ) {
5874  PGTOPO_BE_ERROR();
5875  return -1;
5876  } else if ( ret == 0 ) {
5877  lwerror("Edge being split (%" LWTFMT_ELEMID ") disappeared during operations?", selEdge.edge_id);
5878  return -1;
5879  } else if ( ret > 1 ) {
5880  lwerror("More than a single edge found with id %"
5881  LWTFMT_ELEMID " !", selEdge.edge_id);
5882  return -1;
5883  }
5884 
5885  /************
5886  *
5887  * Update split-edge collapsed side face MBR, if needed
5888  *
5889  */
5890 
5891  if ( edge->face_left != edge->face_right )
5892  {
5893  /* TODO: update a single face ? */
5894  LWT_ISO_FACE updface;
5895  updface.face_id = edge->face_right;
5896  if ( updface.face_id != 0 )
5897  {
5898  /* We only need to update the MBR if the shrunk face is
5899  * not the universe face */
5900  LWGEOM *fg = lwt_GetFaceGeometry(topo, updface.face_id);
5901  if ( ! fg )
5902  {
5903  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, updface.face_id);
5904  return -1;
5905  }
5906  updface.mbr = (GBOX *)lwgeom_get_bbox(fg);
5907  if ( updface.mbr )
5908  {
5909  int ret = lwt_be_updateFacesById( topo, &updface, 1 );
5910  if ( ret == -1 )
5911  {
5912  PGTOPO_BE_ERROR();
5913  return -1;
5914  }
5915  lwgeom_free(fg);
5916  }
5917  else
5918  {
5919  lwerror("Programmatic error ? Geometry of face %" LWTFMT_ELEMID " is empty!", updface.face_id);
5920  }
5921  }
5922  updface.face_id = edge->face_left;
5923  if ( updface.face_id != 0 )
5924  {
5925  /* We only need to update the MBR if the shrunk face is
5926  * not the universe face */
5927  LWGEOM *fg = lwt_GetFaceGeometry(topo, updface.face_id);
5928  if ( ! fg )
5929  {
5930  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, updface.face_id);
5931  return -1;
5932  }
5933  updface.mbr = (GBOX *)lwgeom_get_bbox(fg);
5934  if ( updface.mbr )
5935  {
5936  int ret = lwt_be_updateFacesById( topo, &updface, 1 );
5937  if ( ret == -1 )
5938  {
5939  PGTOPO_BE_ERROR();
5940  return -1;
5941  }
5942  lwgeom_free(fg);
5943  }
5944  else
5945  {
5946  lwerror("Programmatic error ? Geometry of face %" LWTFMT_ELEMID " is empty!", updface.face_id);
5947  }
5948  }
5949  }
5950 
5951  /************
5952  *
5953  * Update TopoGeometries composition
5954  *
5955  */
5956 
5957  LWDEBUGF(1, "Updating lineal TopoGeometry composition to add edge %" LWTFMT_ELEMID
5958  " to features composed by edge %" LWTFMT_ELEMID,
5959  existingEdge->edge_id, edge->edge_id
5960  );
5961  ret = lwt_be_updateTopoGeomEdgeSplit(topo, edge->edge_id, existingEdge->edge_id, -1);
5962  if ( ! ret ) {
5963  PGTOPO_BE_ERROR();
5964  return -1;
5965  }
5966 
5967  return 0;
5968  }
5969  else if ( replacedBy[0] == 0 && replacedBy[1] == 0 )
5970  {
5971 
5972  /* Neither sides of the snapped edge collapsed to an existing edge */
5973 
5974  /* New edge is the outgoing one, by design */
5975  LWT_ISO_EDGE newEdge;
5976  newEdge.edge_id = lwt_be_getNextEdgeId( topo );
5977  if ( newEdge.edge_id == -1 ) {
5978  PGTOPO_BE_ERROR();
5979  return -1;
5980  }
5981  newEdge.geom = lwgeom_as_lwline(splitC->geoms[1]);
5982  newEdge.end_node = edge->end_node;
5983  newEdge.start_node = node->node_id;
5984  newEdge.next_right = -updatedEdge.edge_id; // to be assigned later, if needed
5985  if ( edge->next_left == -edge->edge_id ) {
5986  newEdge.next_left = -newEdge.edge_id;
5987  } else {
5988  newEdge.next_left = edge->next_left; // unchanged
5989  }
5990  newEdge.face_left = edge->face_left; // to be changed later
5991  newEdge.face_right = edge->face_right; // to be changed later
5992 
5993  /* Updated edge is the incoming one, by design */
5994  updatedEdge.edge_id = edge->edge_id;
5995  updatedEdge.geom = lwgeom_as_lwline(splitC->geoms[0]);
5996  updatedEdge.end_node = node->node_id;
5997  updatedEdge.next_left = newEdge.edge_id; // to be re-assigned later, if needed
5998 
5999 
6000  LWT_EDGEEND_STAR *nodeStar = lwt_edgeEndStar_init( node->node_id );
6001  for ( uint64_t t=0; t<splitNodeEdges->numEdges; t++ )
6002  {
6003  lwt_edgeEndStar_addEdge( nodeStar, &(splitNodeEdges->edges[t]) );
6004  }
6005  lwt_edgeEndStar_addEdge( nodeStar, &updatedEdge );
6006  lwt_edgeEndStar_addEdge( nodeStar, &newEdge );
6007 
6008  _lwt_SnapEdge_checkMotion( topo, splitC, edge, NULL, splitNodeEdges );
6009 
6010  /* There cannot be anything in the middle of the two components,
6011  * so both sides will give the same nextCCW and same nextCW */
6012 
6013  lwt_EdgeEndStar_debugPrint( nodeStar );
6014 
6015  const LWT_EDGEEND *ee0 = lwt_edgeEndStar_getNextCW( nodeStar, &updatedEdge, 0); // incoming
6016  LWDEBUGF(1, "* NextCW of incoming snap-edge component is %s %" LWTFMT_ELEMID,
6017  ee0->outgoing ? "outgoing" : "incoming", ee0->edge->edge_id);
6018  if ( ee0->outgoing ) {
6019  updatedEdge.next_left = ee0->edge->edge_id;
6020  } else {
6021  updatedEdge.next_left = -ee0->edge->edge_id;
6022  }
6023  int splitFaceOnLeft = 1;
6024  if ( ee0->edge->edge_id == newEdge.edge_id )
6025  {
6026  splitFaceOnLeft = 0;
6027  }
6028 
6029  const LWT_EDGEEND *ee1 = lwt_edgeEndStar_getNextCW( nodeStar, &newEdge, 1); // outgoing
6030  LWDEBUGF(1, "* NextCW of outgoing snap-edge component is %s %" LWTFMT_ELEMID,
6031  ee1->outgoing ? "outgoing" : "incoming", ee1->edge->edge_id);
6032  if ( ee1->outgoing ) {
6033  newEdge.next_right = ee1->edge->edge_id;
6034  } else {
6035  newEdge.next_right = -ee1->edge->edge_id;
6036  }
6037 
6038  int ret = lwt_be_insertEdges(topo, &newEdge, 1);
6039  if (ret != 1)
6040  {
6041  PGTOPO_BE_ERROR();
6042  return -1;
6043  }
6044 
6045  /* Updating the first portion of the edge */
6046  selEdge.edge_id = edge->edge_id;
6047  ret = lwt_be_updateEdges(topo,
6048  &selEdge, LWT_COL_EDGE_EDGE_ID,
6050  NULL, 0);
6051  if ( ret == -1 ) {
6052  PGTOPO_BE_ERROR();
6053  return -1;
6054  } else if ( ret == 0 ) {
6055  lwerror("Edge being split (%" LWTFMT_ELEMID ") disappeared during operations?", selEdge.edge_id);
6056  return -1;
6057  } else if ( ret > 1 ) {
6058  lwerror("More than a single edge found with id %"
6059  LWTFMT_ELEMID " !", selEdge.edge_id);
6060  return -1;
6061  }
6062 
6063  /* Update CCW edges if needed */
6064  ee0 = lwt_edgeEndStar_getNextCCW( nodeStar, &updatedEdge, 0); // incoming
6065  LWDEBUGF(1, "* NextCCW of incoming snap-edge component is %s %" LWTFMT_ELEMID,
6066  ee0->outgoing ? "outgoing" : "incoming", ee0->edge->edge_id);
6067  if ( ee0->edge->edge_id != newEdge.edge_id )
6068  {
6069  selEdge.edge_id = ee0->edge->edge_id;
6070  if ( ee0->outgoing ) {
6071  updatedEdge.next_right = -edge->edge_id;
6072  updateFlags = LWT_COL_EDGE_NEXT_RIGHT;
6073  } else {
6074  updatedEdge.next_left = -edge->edge_id;
6075  updateFlags = LWT_COL_EDGE_NEXT_LEFT;
6076  }
6077 
6078  LWDEBUGF(1, "Updating edge %" LWTFMT_ELEMID ", %s nextCCW of incoming snap-edge",
6079  selEdge.edge_id, ee0->outgoing ? "outgoing" : "incoming");
6080  ret = lwt_be_updateEdges(topo,
6081  &selEdge, LWT_COL_EDGE_EDGE_ID,
6082  &updatedEdge, updateFlags,
6083  NULL, 0);
6084  if ( ret == -1 ) {
6085  PGTOPO_BE_ERROR();
6086  return -1;
6087  } else if ( ret == 0 ) {
6088  lwerror("Edge being split (%" LWTFMT_ELEMID ") disappeared during operations?", selEdge.edge_id);
6089  return -1;
6090  } else if ( ret > 1 ) {
6091  lwerror("More than a single edge found with id %"
6092  LWTFMT_ELEMID " !", selEdge.edge_id);
6093  return -1;
6094  }
6095  }
6096 
6097  /* Update CCW edge of outgoing portion if needed */
6098  ee1 = lwt_edgeEndStar_getNextCCW( nodeStar, &newEdge, 1); // outgoing
6099  LWDEBUGF(1, "* NextCCW of outgoing snap-edge component is %s %" LWTFMT_ELEMID,
6100  ee1->outgoing ? "outgoing" : "incoming", ee1->edge->edge_id);
6101  if ( ee1->edge->edge_id != edge->edge_id )
6102  {
6103  selEdge.edge_id = ee1->edge->edge_id;
6104  if ( ee1->outgoing ) {
6105  updatedEdge.next_right = newEdge.edge_id;
6106  updateFlags = LWT_COL_EDGE_NEXT_RIGHT;
6107  } else {
6108  updatedEdge.next_left = newEdge.edge_id;
6109  updateFlags = LWT_COL_EDGE_NEXT_LEFT;
6110  }
6111 
6112  LWDEBUGF(1, "Updating edge %" LWTFMT_ELEMID ", %s nextCCW of outgoing snap-edge",
6113  selEdge.edge_id, ee1->outgoing ? "outgoing" : "incoming");
6114  ret = lwt_be_updateEdges(topo,
6115  &selEdge, LWT_COL_EDGE_EDGE_ID,
6116  &updatedEdge, updateFlags,
6117  NULL, 0);
6118  if ( ret == -1 ) {
6119  PGTOPO_BE_ERROR();
6120  return -1;
6121  } else if ( ret == 0 ) {
6122  lwerror("Edge being split (%" LWTFMT_ELEMID ") disappeared during operations?", selEdge.edge_id);
6123  return -1;
6124  } else if ( ret > 1 ) {
6125  lwerror("More than a single edge found with id %"
6126  LWTFMT_ELEMID " !", selEdge.edge_id);
6127  return -1;
6128  }
6129  }
6130 
6131  /* If any edge was connected to the end node of the split edge, we
6132  * need to update its link to us */
6133  updateFlags = 0;
6134  for ( uint64_t t=0; t<lastNodeEdges->numEdges; t++ )
6135  {
6136  const LWT_ISO_EDGE *in = &(lastNodeEdges->edges[t]);
6137  if ( in->next_right == -edge->edge_id )
6138  {
6139  if ( in->edge_id != edge->edge_id ) {
6140  selEdge.edge_id = in->edge_id;
6141  updatedEdge.next_right = -newEdge.edge_id;
6142  updateFlags = LWT_COL_EDGE_NEXT_RIGHT;
6143  }
6144  break;
6145  }
6146  if ( in->next_left == -edge->edge_id )
6147  {
6148  if ( in->edge_id != edge->edge_id ) {
6149  selEdge.edge_id = in->edge_id;
6150  updatedEdge.next_left = -newEdge.edge_id;
6151  updateFlags = LWT_COL_EDGE_NEXT_LEFT;
6152  }
6153  break;
6154  }
6155  }
6156  if ( updateFlags != 0 )
6157  {
6158  LWDEBUGF(1, "Updating edge %" LWTFMT_ELEMID ", %s nextCCW of outgoing snap-edge",
6159  selEdge.edge_id,
6160  updateFlags & LWT_COL_EDGE_NEXT_LEFT ? "incoming" : "outgoing");
6161  ret = lwt_be_updateEdges(topo,
6162  &selEdge, LWT_COL_EDGE_EDGE_ID,
6163  &updatedEdge, updateFlags,
6164  NULL, 0);
6165  if ( ret == -1 ) {
6166  PGTOPO_BE_ERROR();
6167  return -1;
6168  } else if ( ret == 0 ) {
6169  lwerror("Edge being split (%" LWTFMT_ELEMID ") disappeared during operations?", selEdge.edge_id);
6170  return -1;
6171  } else if ( ret > 1 ) {
6172  lwerror("More than a single edge found with id %"
6173  LWTFMT_ELEMID " !", selEdge.edge_id);
6174  return -1;
6175  }
6176  }
6177 
6178  /* Handle face split */
6179  LWT_ELEMID newFaceId1 = 0;
6180  LWT_ELEMID newFaceId2 = 0;
6181  LWT_ELEMID oldFaceId;
6182  if ( splitFaceOnLeft ) {
6183 
6184  oldFaceId = edge->face_left;
6185 
6186  LWDEBUGF(1, "Adding face split for left side of new edge %" LWTFMT_ELEMID, newEdge.edge_id);
6187  newFaceId1 = _lwt_AddFaceSplit( topo, newEdge.edge_id, oldFaceId, 0 );
6188  LWDEBUGF(1, "_lwt_AddFaceSplit(%" LWTFMT_ELEMID ") returned %" LWTFMT_ELEMID,
6189  newEdge.edge_id, newFaceId1);
6190 
6191  // TODO: retain oldFaceID rather than creating a new one, if a
6192  // new one was already created for the new edge ring !
6193  LWDEBUGF(1, "Adding face split for left side of updated edge %" LWTFMT_ELEMID, edge->edge_id);
6194  newFaceId2 = _lwt_AddFaceSplit( topo, edge->edge_id, oldFaceId, 0 );
6195  LWDEBUGF(1, "_lwt_AddFaceSplit(%" LWTFMT_ELEMID ") returned %" LWTFMT_ELEMID,
6196  edge->edge_id, newFaceId2);
6197 
6198 
6199  } else {
6200 
6201  oldFaceId = edge->face_right;
6202 
6203  LWDEBUGF(1, "Adding face split for right side of new edge %" LWTFMT_ELEMID, newEdge.edge_id);
6204  newFaceId1 = _lwt_AddFaceSplit( topo, -newEdge.edge_id, oldFaceId, 0 );
6205  LWDEBUGF(1, "_lwt_AddFaceSplit(%" LWTFMT_ELEMID ") returned %" LWTFMT_ELEMID,
6206  -newEdge.edge_id, newFaceId1);
6207 
6208  // TODO: retain oldFaceID rather than creating a new one, if a
6209  // new one was already created on the new edge ring !
6210  LWDEBUGF(1, "Adding face split for right side of updated edge %" LWTFMT_ELEMID, edge->edge_id);
6211  newFaceId2 = _lwt_AddFaceSplit( topo, -edge->edge_id, oldFaceId, 0 );
6212  LWDEBUGF(1, "_lwt_AddFaceSplit(%" LWTFMT_ELEMID ") returned %" LWTFMT_ELEMID,
6213  -edge->edge_id, newFaceId2);
6214 
6215  }
6216 
6217  /************
6218  *
6219  * Update TopoGeometries composition
6220  *
6221  */
6222 
6223  ret = lwt_be_updateTopoGeomEdgeSplit(topo, edge->edge_id, newEdge.edge_id, -1);
6224  if ( ! ret ) {
6225  PGTOPO_BE_ERROR();
6226  return -1;
6227  }
6228 
6229  LWDEBUGF(1, "New faces %" LWTFMT_ELEMID " and %" LWTFMT_ELEMID
6230  "split from from old face %" LWTFMT_ELEMID,
6231  newFaceId1, newFaceId2, oldFaceId);
6232  if ( newFaceId1 || newFaceId2 )
6233  {
6235  topo, oldFaceId,
6236  newFaceId1 ? newFaceId1 : oldFaceId,
6237  newFaceId2 ? newFaceId2 : oldFaceId
6238  );
6239  if ( ! ret ) {
6240  PGTOPO_BE_ERROR();
6241  return -1;
6242  }
6243 
6244  if ( newFaceId1 && newFaceId2 )
6245  {
6246  LWDEBUGF(1, "Deleting fully replaced face %" LWTFMT_ELEMID, oldFaceId);
6247  int nids = 1;
6248  ret = lwt_be_deleteFacesById(topo, &oldFaceId, nids);
6249  if ( ret == -1 ) {
6250  PGTOPO_BE_ERROR();
6251  return -1;
6252  }
6253  }
6254  }
6255 
6256  return 0;
6257  }
6258  else if ( replacedBy[0] != 0 && replacedBy[1] != 0 )
6259  {
6260  // Edge was replaced with two existing edges
6261 
6262  // Sanity check
6263  if ( edge->face_right == edge->face_left )
6264  {
6265  lwerror("Unexpectedly, dangling edge %" LWTFMT_ELEMID " was replaced by "
6266  "edges %" LWTFMT_ELEMID " and %" LWTFMT_ELEMID
6267  " when snap to node %" LWTFMT_ELEMID,
6268  edge->edge_id, replacedBy[0], replacedBy[1], node->node_id);
6269  return -1;
6270  }
6271 
6272  LWT_ELEMID collapsedFace = 0;
6273  LWT_ELEMID replacingFace = 0;
6274 
6275  if ( FP_ABS(edge->next_right) == replacedBy[0] ) {
6276  /* Face on the right of the removed edge disappeared */
6277  // We need to update nextCW on first node and nextCCW on last node
6278  collapsedFace = edge->face_right;
6279  replacingFace = edge->face_left;
6280  } else {
6281  /* Face on the left of the removed edge disappeared */
6282  // We need to update nextCCW on first node and nextCW on last node
6283  collapsedFace = edge->face_left;
6284  replacingFace = edge->face_right;
6285  }
6286 
6287  //const LWT_ISO_EDGE *sp_nextCCW = 0;
6288  //const LWT_ISO_EDGE *ep_nextCCW = 0;
6289 
6290  // Update CCW edge on first node
6291  updateFlags = 0;
6292  for ( uint64_t t=0; t<firstNodeEdges->numEdges; t++ )
6293  {
6294  const LWT_ISO_EDGE *in = &(firstNodeEdges->edges[t]);
6295  if ( in->edge_id == edge->edge_id ) continue;
6296  if ( in->next_right == edge->edge_id )
6297  {
6298  selEdge.edge_id = in->edge_id;
6299  updatedEdge.next_right = edge->next_right;
6300  updateFlags = LWT_COL_EDGE_NEXT_RIGHT;
6301  if ( in->face_right == collapsedFace ) {
6302  updatedEdge.face_right = replacingFace;
6303  updateFlags |= LWT_COL_EDGE_FACE_RIGHT;
6304  }
6305  //sp_nextCCW = in;
6306  break;
6307  }
6308  if ( in->next_left == edge->edge_id )
6309  {
6310  selEdge.edge_id = in->edge_id;
6311  updatedEdge.next_left = edge->next_right;
6312  updateFlags = LWT_COL_EDGE_NEXT_LEFT;
6313  if ( in->face_left == collapsedFace ) {
6314  updatedEdge.face_left = replacingFace;
6315  updateFlags |= LWT_COL_EDGE_FACE_LEFT;
6316  }
6317  //sp_nextCCW = in;
6318  break;
6319  }
6320  }
6321  if ( updateFlags != 0 )
6322  {
6323  LWDEBUGF(1, "Updating edge %" LWTFMT_ELEMID ", %s nextCCW of outgoing snap-edge",
6324  selEdge.edge_id,
6325  updateFlags & LWT_COL_EDGE_NEXT_LEFT ? "incoming" : "outgoing");
6326  ret = lwt_be_updateEdges(topo,
6327  &selEdge, LWT_COL_EDGE_EDGE_ID,
6328  &updatedEdge, updateFlags,
6329  NULL, 0);
6330  if ( ret == -1 ) {
6331  PGTOPO_BE_ERROR();
6332  return -1;
6333  } else if ( ret == 0 ) {
6334  lwerror("Edge being split (%" LWTFMT_ELEMID ") disappeared during operations?", selEdge.edge_id);
6335  return -1;
6336  } else if ( ret > 1 ) {
6337  lwerror("More than a single edge found with id %"
6338  LWTFMT_ELEMID " !", selEdge.edge_id);
6339  return -1;
6340  }
6341  }
6342 
6343  // Update CCW edge on last node
6344  updateFlags = 0;
6345  for ( uint64_t t=0; t<lastNodeEdges->numEdges; t++ )
6346  {
6347  const LWT_ISO_EDGE *in = &(lastNodeEdges->edges[t]);
6348  if ( in->edge_id == edge->edge_id ) continue;
6349  if ( in->next_right == -edge->edge_id )
6350  {
6351  selEdge.edge_id = in->edge_id;
6352  updatedEdge.next_right = edge->next_left;
6353  updateFlags = LWT_COL_EDGE_NEXT_RIGHT;
6354  if ( in->face_right == collapsedFace ) {
6355  updatedEdge.face_right = replacingFace;
6356  updateFlags |= LWT_COL_EDGE_FACE_RIGHT;
6357  }
6358  break;
6359  }
6360  if ( in->next_left == -edge->edge_id )
6361  {
6362  selEdge.edge_id = in->edge_id;
6363  updatedEdge.next_left = edge->next_left;
6364  updateFlags = LWT_COL_EDGE_NEXT_LEFT;
6365  if ( in->face_left == collapsedFace ) {
6366  updatedEdge.face_left = replacingFace;
6367  updateFlags |= LWT_COL_EDGE_FACE_LEFT;
6368  }
6369  break;
6370  }
6371  }
6372  if ( updateFlags != 0 )
6373  {
6374  LWDEBUGF(1, "Updating edge %" LWTFMT_ELEMID ", %s nextCCW of incoming snap-edge",
6375  selEdge.edge_id,
6376  updateFlags & LWT_COL_EDGE_NEXT_LEFT ? "incoming" : "outgoing");
6377  ret = lwt_be_updateEdges(topo,
6378  &selEdge, LWT_COL_EDGE_EDGE_ID,
6379  &updatedEdge, updateFlags,
6380  NULL, 0);
6381  if ( ret == -1 ) {
6382  PGTOPO_BE_ERROR();
6383  return -1;
6384  } else if ( ret == 0 ) {
6385  lwerror("Edge being split (%" LWTFMT_ELEMID ") disappeared during operations?", selEdge.edge_id);
6386  return -1;
6387  } else if ( ret > 1 ) {
6388  lwerror("More than a single edge found with id %"
6389  LWTFMT_ELEMID " !", selEdge.edge_id);
6390  return -1;
6391  }
6392  }
6393 
6394  if ( collapsedFace == edge->face_right )
6395  {
6396  // We need to update side face of nextCW on first node and nextCCW on last node
6397  // nextCCW on last node was done already, supposedly so we need to do nextCW
6398  // on first
6399  if ( edge->next_right < 0 ) {
6400  selEdge.edge_id = -edge->next_right;
6401  updatedEdge.face_right = replacingFace;
6402  updateFlags = LWT_COL_EDGE_FACE_RIGHT;
6403  } else {
6404  selEdge.edge_id = edge->next_right;
6405  updatedEdge.face_left = replacingFace;
6406  updateFlags = LWT_COL_EDGE_FACE_LEFT;
6407  }
6408  LWDEBUGF(1, "Updating %s face of edge %" LWTFMT_ELEMID ", %s nextCW of outgoing snap-edge",
6409  updateFlags & LWT_COL_EDGE_FACE_LEFT ? "left" : "right",
6410  selEdge.edge_id,
6411  updateFlags & LWT_COL_EDGE_FACE_RIGHT ? "incoming" : "outgoing");
6412  ret = lwt_be_updateEdges(topo,
6413  &selEdge, LWT_COL_EDGE_EDGE_ID,
6414  &updatedEdge, updateFlags,
6415  NULL, 0);
6416  if ( ret == -1 ) {
6417  PGTOPO_BE_ERROR();
6418  return -1;
6419  } else if ( ret == 0 ) {
6420  lwerror("Edge being split (%" LWTFMT_ELEMID ") disappeared during operations?", selEdge.edge_id);
6421  return -1;
6422  } else if ( ret > 1 ) {
6423  lwerror("More than a single edge found with id %"
6424  LWTFMT_ELEMID " !", selEdge.edge_id);
6425  return -1;
6426  }
6427  }
6428  else
6429  {
6430  // We need to update side face of nextCCW on first node and nextCW on last node
6431  // nextCCW on first node was done already, supposedly so we need to do nextCW
6432  // on last
6433  if ( edge->next_left < 0 ) {
6434  selEdge.edge_id = -edge->next_left;
6435  updatedEdge.face_right = replacingFace;
6436  updateFlags = LWT_COL_EDGE_FACE_RIGHT;
6437  } else {
6438  selEdge.edge_id = edge->next_left;
6439  updatedEdge.face_left = replacingFace;
6440  updateFlags = LWT_COL_EDGE_FACE_LEFT;
6441  }
6442  LWDEBUGF(1, "Updating %s face of edge %" LWTFMT_ELEMID ", %s nextCW of incoming snap-edge",
6443  updateFlags & LWT_COL_EDGE_FACE_LEFT ? "left" : "right",
6444  selEdge.edge_id,
6445  updateFlags & LWT_COL_EDGE_FACE_RIGHT ? "incoming" : "outgoing");
6446  ret = lwt_be_updateEdges(topo,
6447  &selEdge, LWT_COL_EDGE_EDGE_ID,
6448  &updatedEdge, updateFlags,
6449  NULL, 0);
6450  if ( ret == -1 ) {
6451  PGTOPO_BE_ERROR();
6452  return -1;
6453  } else if ( ret == 0 ) {
6454  lwerror("Edge being split (%" LWTFMT_ELEMID ") disappeared during operations?", selEdge.edge_id);
6455  return -1;
6456  } else if ( ret > 1 ) {
6457  lwerror("More than a single edge found with id %"
6458  LWTFMT_ELEMID " !", selEdge.edge_id);
6459  return -1;
6460  }
6461  }
6462 
6463  /* Delete the old edge */
6464  selEdge.edge_id = edge->edge_id;
6465  LWDEBUGF(1, "Deleting edge %" LWTFMT_ELEMID, selEdge.edge_id);
6466  ret = lwt_be_deleteEdges(topo, &selEdge, LWT_COL_EDGE_EDGE_ID);
6467  if ( ret == -1 ) {
6468  PGTOPO_BE_ERROR();
6469  return -1;
6470  }
6471 
6472  /* Delete collapsed face */
6473  LWDEBUGF(1, "Deleting collapsed face %" LWTFMT_ELEMID, collapsedFace);
6474  int nids = 1;
6475  ret = lwt_be_deleteFacesById(topo, &collapsedFace, nids);
6476  if ( ret == -1 ) {
6477  PGTOPO_BE_ERROR();
6478  return -1;
6479  }
6480 
6481  /* Delete the collapsed face from composition of TopoGeometries */
6482  if ( ! lwt_be_updateTopoGeomFaceHeal( topo, collapsedFace, -1, -1) )
6483  {
6484  PGTOPO_BE_ERROR();
6485  return -1;
6486  }
6487 
6488  return 0;
6489  }
6490 
6491  //LWDEBUGF(1, "Not handling within-tolerance edge %" LWTFMT_ELEMID, edge->edge_id);
6492  lwerror("Don't know how to deal with edge %" LWTFMT_ELEMID
6493  " replaced by edges %" LWTFMT_ELEMID
6494  " and %" LWTFMT_ELEMID, edge->edge_id, replacedBy[0], replacedBy[1]);
6495 
6496  return -1;
6497 }
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:179
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
int azimuth_pt_pt(const POINT2D *p1, const POINT2D *p2, double *ret)
Compute the azimuth of segment AB in radians.
Definition: measures.c:2509
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1218
LWGEOM * lwgeom_split(const LWGEOM *lwgeom_in, const LWGEOM *blade_in)
LWGEOM * lwgeom_snap(const LWGEOM *geom1, const LWGEOM *geom2, double tolerance)
Snap vertices and segments of a geometry to another using a given tolerance.
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:344
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition: lwgeom.c:743
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:233
#define FP_ABS(a)
#define LWT_COL_EDGE_FACE_RIGHT
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_EDGE_START_NODE
#define LWT_COL_EDGE_FACE_LEFT
#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
#define PGTOPO_BE_ERROR()
#define LWTFMT_ELEMID
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:101
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
#define LWDEBUGG(level, geom, msg)
Definition: lwgeom_log.h:111
static uint64_t lwt_be_updateFacesById(LWT_TOPOLOGY *topo, const LWT_ISO_FACE *faces, uint64_t numfaces)
Definition: lwgeom_topo.c:286
static int lwt_be_deleteFacesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t numelems)
Definition: lwgeom_topo.c:197
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
Definition: lwgeom_topo.c:2841
static int _lwt_SnapEdge_checkMotion(LWT_TOPOLOGY *topo, const LWCOLLECTION *splitC, const LWT_ISO_EDGE *edge, LWT_ISO_EDGE *existingEdge, const LWT_NODE_EDGES *splitNodeEdges)
Check the motion of a snapped edge, invoke lwerror if the movement hits any other edge or node.
Definition: lwgeom_topo.c:5205
LWT_ELEMID lwt_be_getNextEdgeId(LWT_TOPOLOGY *topo)
Definition: lwgeom_topo.c:209
static int lwt_be_updateTopoGeomFaceSplit(LWT_TOPOLOGY *topo, LWT_ELEMID split_face, LWT_ELEMID new_face1, LWT_ELEMID new_face2)
Definition: lwgeom_topo.c:324
static int lwt_be_updateTopoGeomFaceHeal(LWT_TOPOLOGY *topo, LWT_ELEMID face1, LWT_ELEMID face2, LWT_ELEMID newface)
Definition: lwgeom_topo.c:357
int lwt_be_updateTopoGeomEdgeSplit(LWT_TOPOLOGY *topo, LWT_ELEMID split_edge, LWT_ELEMID new_edge1, LWT_ELEMID new_edge2)
Definition: lwgeom_topo.c:318
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:262
static LWT_ELEMID _lwt_GetEqualEdge(LWT_TOPOLOGY *topo, LWLINE *edge, int *forward)
Definition: lwgeom_topo.c:5091
int lwt_be_deleteEdges(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *sel_edge, int sel_fields)
Definition: lwgeom_topo.c:310
static LWT_ELEMID _lwt_AddFaceSplit(LWT_TOPOLOGY *topo, LWT_ELEMID sedge, LWT_ELEMID face, int mbr_only)
Definition: lwgeom_topo.c:1893
int lwt_be_insertEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, uint64_t numelems)
Definition: lwgeom_topo.c:256
static int _lwt_FirstDistinctVertex2D(const POINTARRAY *pa, const POINT2D *ref, int from, int dir, POINT2D *op)
Definition: lwgeom_topo.c:1428
static int _lwt_FindAdjacentEdges(LWT_TOPOLOGY *topo, LWT_ELEMID node, edgeend *data, edgeend *other, LWT_ELEMID myedge_id)
Definition: lwgeom_topo.c:1524
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwinline.h:97
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwinline.h:127
const LWT_EDGEEND * lwt_edgeEndStar_getNextCW(LWT_EDGEEND_STAR *star, LWT_ISO_EDGE *edge, int outgoing)
LWT_EDGEEND_STAR * lwt_edgeEndStar_init(LWT_ELEMID nodeID)
const LWT_EDGEEND * lwt_edgeEndStar_getNextCCW(LWT_EDGEEND_STAR *star, LWT_ISO_EDGE *edge, int outgoing)
void lwt_EdgeEndStar_debugPrint(const LWT_EDGEEND_STAR *star)
void lwt_edgeEndStar_addEdge(LWT_EDGEEND_STAR *star, const LWT_ISO_EDGE *edge)
LWT_NODE_EDGES * lwt_nodeEdges_loadFromDB(LWT_TOPOLOGY *topo, LWT_ELEMID node_id, int fields)
uint32_t ngeoms
Definition: liblwgeom.h:580
LWGEOM ** geoms
Definition: liblwgeom.h:575
POINTARRAY * points
Definition: liblwgeom.h:483
const LWT_ISO_EDGE * edge
Definition: lwt_edgeend.h:33
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
LWT_ELEMID face_id
LWT_ELEMID node_id
LWPOINT * geom
LWT_ISO_EDGE * edges
double y
Definition: liblwgeom.h:390
double x
Definition: liblwgeom.h:390
uint32_t npoints
Definition: liblwgeom.h:427
LWT_ELEMID nextCCW
Definition: lwgeom_topo.c:1411
LWT_ELEMID nextCW
Definition: lwgeom_topo.c:1407

References _lwt_AddFaceSplit(), _lwt_FindAdjacentEdges(), _lwt_FirstDistinctVertex2D(), _lwt_GetEqualEdge(), _lwt_SnapEdge_checkMotion(), azimuth_pt_pt(), LWT_EDGEEND_t::edge, LWT_ISO_EDGE::edge_id, LWT_NODE_EDGES_t::edges, LWT_ISO_EDGE::end_node, LWT_ISO_FACE::face_id, LWT_ISO_EDGE::face_left, LWT_ISO_EDGE::face_right, FP_ABS, LWT_ISO_NODE::geom, LWT_ISO_EDGE::geom, LWCOLLECTION::geoms, getPoint2d_cp(), LWDEBUG, LWDEBUGF, LWDEBUGG, lwerror(), lwgeom_as_lwcollection(), lwgeom_as_lwline(), lwgeom_as_lwpoint(), lwgeom_free(), lwgeom_get_bbox(), lwgeom_snap(), lwgeom_split(), lwline_as_lwgeom(), lwpoint_as_lwgeom(), lwt_be_deleteEdges(), lwt_be_deleteFacesById(), lwt_be_getNextEdgeId(), lwt_be_insertEdges(), lwt_be_updateEdges(), lwt_be_updateFacesById(), lwt_be_updateTopoGeomEdgeSplit(), lwt_be_updateTopoGeomFaceHeal(), lwt_be_updateTopoGeomFaceSplit(), LWT_COL_EDGE_ALL, LWT_COL_EDGE_EDGE_ID, LWT_COL_EDGE_END_NODE, LWT_COL_EDGE_FACE_LEFT, LWT_COL_EDGE_FACE_RIGHT, LWT_COL_EDGE_GEOM, LWT_COL_EDGE_NEXT_LEFT, LWT_COL_EDGE_NEXT_RIGHT, LWT_COL_EDGE_START_NODE, lwt_edgeEndStar_addEdge(), lwt_EdgeEndStar_debugPrint(), lwt_edgeEndStar_getNextCCW(), lwt_edgeEndStar_getNextCW(), lwt_edgeEndStar_init(), lwt_GetFaceGeometry(), lwt_nodeEdges_loadFromDB(), LWTFMT_ELEMID, LWT_ISO_FACE::mbr, edgeend_t::myaz, LWT_ISO_EDGE::next_left, LWT_ISO_EDGE::next_right, edgeend_t::nextCCW, edgeend_t::nextCW, LWCOLLECTION::ngeoms, LWT_ISO_NODE::node_id, POINTARRAY::npoints, LWT_NODE_EDGES_t::numEdges, LWT_EDGEEND_t::outgoing, PGTOPO_BE_ERROR, LWLINE::points, LWT_ISO_EDGE::start_node, POINT2D::x, and POINT2D::y.

Referenced by _lwt_SplitAllEdgesToNewNode().

Here is the call graph for this function:
Here is the caller graph for this function: