PostGIS  2.5.7dev-r@@SVN_REVISION@@

◆ _lwt_RemEdge()

static LWT_ELEMID _lwt_RemEdge ( LWT_TOPOLOGY topo,
LWT_ELEMID  edge_id,
int  modFace 
)
static

Definition at line 3796 of file lwgeom_topo.c.

3797 {
3798  int i, nedges, nfaces, fields;
3799  LWT_ISO_EDGE *edge = NULL;
3800  LWT_ISO_EDGE *upd_edge = NULL;
3801  LWT_ISO_EDGE upd_edge_left[2];
3802  int nedge_left = 0;
3803  LWT_ISO_EDGE upd_edge_right[2];
3804  int nedge_right = 0;
3805  LWT_ISO_NODE upd_node[2];
3806  int nnode = 0;
3807  LWT_ISO_FACE *faces = NULL;
3808  LWT_ISO_FACE newface;
3809  LWT_ELEMID node_ids[2];
3810  LWT_ELEMID face_ids[2];
3811  int fnode_edges = 0; /* number of edges on the first node (excluded
3812  * the one being removed ) */
3813  int lnode_edges = 0; /* number of edges on the last node (excluded
3814  * the one being removed ) */
3815 
3816  newface.face_id = 0;
3817 
3818  i = 1;
3819  edge = lwt_be_getEdgeById(topo, &edge_id, &i, LWT_COL_EDGE_ALL);
3820  if ( ! edge )
3821  {
3822  LWDEBUGF(1, "lwt_be_getEdgeById returned NULL and set i=%d", i);
3823  if ( i == -1 )
3824  {
3825  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3826  return -1;
3827  }
3828  else if ( i == 0 )
3829  {
3830  lwerror("SQL/MM Spatial exception - non-existent edge %"
3831  LWTFMT_ELEMID, edge_id);
3832  return -1;
3833  }
3834  else
3835  {
3836  lwerror("Backend coding error: getEdgeById callback returned NULL "
3837  "but numelements output parameter has value %d "
3838  "(expected 0 or 1)", i);
3839  return -1;
3840  }
3841  }
3842 
3843  if ( ! lwt_be_checkTopoGeomRemEdge(topo, edge_id,
3844  edge->face_left, edge->face_right) )
3845  {
3847  return -1;
3848  }
3849 
3850  LWDEBUG(1, "Updating next_{right,left}_face of ring edges...");
3851 
3852  /* Update edge linking */
3853 
3854  nedges = 0;
3855  node_ids[nedges++] = edge->start_node;
3856  if ( edge->end_node != edge->start_node )
3857  {
3858  node_ids[nedges++] = edge->end_node;
3859  }
3863  upd_edge = lwt_be_getEdgeByNode( topo, &(node_ids[0]), &nedges, fields );
3864  if ( nedges == -1 ) {
3865  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3866  return -1;
3867  }
3868  nedge_left = nedge_right = 0;
3869  for ( i=0; i<nedges; ++i )
3870  {
3871  LWT_ISO_EDGE *e = &(upd_edge[i]);
3872  if ( e->edge_id == edge_id ) continue;
3873  if ( e->start_node == edge->start_node || e->end_node == edge->start_node )
3874  {
3875  ++fnode_edges;
3876  }
3877  if ( e->start_node == edge->end_node || e->end_node == edge->end_node )
3878  {
3879  ++lnode_edges;
3880  }
3881  if ( e->next_left == -edge_id )
3882  {
3883  upd_edge_left[nedge_left].edge_id = e->edge_id;
3884  upd_edge_left[nedge_left++].next_left =
3885  edge->next_left != edge_id ? edge->next_left : edge->next_right;
3886  }
3887  else if ( e->next_left == edge_id )
3888  {
3889  upd_edge_left[nedge_left].edge_id = e->edge_id;
3890  upd_edge_left[nedge_left++].next_left =
3891  edge->next_right != -edge_id ? edge->next_right : edge->next_left;
3892  }
3893 
3894  if ( e->next_right == -edge_id )
3895  {
3896  upd_edge_right[nedge_right].edge_id = e->edge_id;
3897  upd_edge_right[nedge_right++].next_right =
3898  edge->next_left != edge_id ? edge->next_left : edge->next_right;
3899  }
3900  else if ( e->next_right == edge_id )
3901  {
3902  upd_edge_right[nedge_right].edge_id = e->edge_id;
3903  upd_edge_right[nedge_right++].next_right =
3904  edge->next_right != -edge_id ? edge->next_right : edge->next_left;
3905  }
3906  }
3907 
3908  if ( nedge_left )
3909  {
3910  LWDEBUGF(1, "updating %d 'next_left' edges", nedge_left);
3911  /* update edges in upd_edge_left set next_left */
3912  i = lwt_be_updateEdgesById(topo, &(upd_edge_left[0]), nedge_left,
3914  if ( i == -1 )
3915  {
3916  _lwt_release_edges(edge, 1);
3917  lwfree(upd_edge);
3918  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3919  return -1;
3920  }
3921  }
3922  if ( nedge_right )
3923  {
3924  LWDEBUGF(1, "updating %d 'next_right' edges", nedge_right);
3925  /* update edges in upd_edge_right set next_right */
3926  i = lwt_be_updateEdgesById(topo, &(upd_edge_right[0]), nedge_right,
3928  if ( i == -1 )
3929  {
3930  _lwt_release_edges(edge, 1);
3931  lwfree(upd_edge);
3932  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3933  return -1;
3934  }
3935  }
3936  LWDEBUGF(1, "releasing %d updateable edges in %p", nedges, upd_edge);
3937  lwfree(upd_edge);
3938 
3939  /* Id of face that will take up all the space previously
3940  * taken by left and right faces of the edge */
3941  LWT_ELEMID floodface;
3942 
3943  /* Find floodface, and update its mbr if != 0 */
3944  if ( edge->face_left == edge->face_right )
3945  {
3946  floodface = edge->face_right;
3947  }
3948  else
3949  {
3950  /* Two faces healed */
3951  if ( edge->face_left == 0 || edge->face_right == 0 )
3952  {
3953  floodface = 0;
3954  LWDEBUG(1, "floodface is universe");
3955  }
3956  else
3957  {
3958  /* we choose right face as the face that will remain
3959  * to be symmetric with ST_AddEdgeModFace */
3960  floodface = edge->face_right;
3961  LWDEBUGF(1, "floodface is %" LWTFMT_ELEMID, floodface);
3962  /* update mbr of floodface as union of mbr of both faces */
3963  face_ids[0] = edge->face_left;
3964  face_ids[1] = edge->face_right;
3965  nfaces = 2;
3966  fields = LWT_COL_FACE_ALL;
3967  faces = lwt_be_getFaceById(topo, face_ids, &nfaces, fields);
3968  if ( nfaces == -1 ) {
3969  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3970  return -1;
3971  }
3972  GBOX *box1=NULL;
3973  GBOX *box2=NULL;
3974  for ( i=0; i<nfaces; ++i )
3975  {
3976  if ( faces[i].face_id == edge->face_left )
3977  {
3978  if ( ! box1 ) box1 = faces[i].mbr;
3979  else
3980  {
3981  i = edge->face_left;
3982  _lwt_release_edges(edge, 1);
3983  _lwt_release_faces(faces, nfaces);
3984  lwerror("corrupted topology: more than 1 face have face_id=%"
3985  LWTFMT_ELEMID, i);
3986  return -1;
3987  }
3988  }
3989  else if ( faces[i].face_id == edge->face_right )
3990  {
3991  if ( ! box2 ) box2 = faces[i].mbr;
3992  else
3993  {
3994  i = edge->face_right;
3995  _lwt_release_edges(edge, 1);
3996  _lwt_release_faces(faces, nfaces);
3997  lwerror("corrupted topology: more than 1 face have face_id=%"
3998  LWTFMT_ELEMID, i);
3999  return -1;
4000  }
4001  }
4002  else
4003  {
4004  i = faces[i].face_id;
4005  _lwt_release_edges(edge, 1);
4006  _lwt_release_faces(faces, nfaces);
4007  lwerror("Backend coding error: getFaceById returned face "
4008  "with non-requested id %" LWTFMT_ELEMID, i);
4009  return -1;
4010  }
4011  }
4012  if ( ! box1 ) {
4013  i = edge->face_left;
4014  _lwt_release_edges(edge, 1);
4015  _lwt_release_faces(faces, nfaces);
4016  lwerror("corrupted topology: no face have face_id=%"
4017  LWTFMT_ELEMID " (left face for edge %"
4018  LWTFMT_ELEMID ")", i, edge_id);
4019  return -1;
4020  }
4021  if ( ! box2 ) {
4022  i = edge->face_right;
4023  _lwt_release_edges(edge, 1);
4024  _lwt_release_faces(faces, nfaces);
4025  lwerror("corrupted topology: no face have face_id=%"
4026  LWTFMT_ELEMID " (right face for edge %"
4027  LWTFMT_ELEMID ")", i, edge_id);
4028  return -1;
4029  }
4030  gbox_merge(box2, box1); /* box1 is now the union of the two */
4031  newface.mbr = box1;
4032  if ( modFace )
4033  {
4034  newface.face_id = floodface;
4035  i = lwt_be_updateFacesById( topo, &newface, 1 );
4036  _lwt_release_faces(faces, 2);
4037  if ( i == -1 )
4038  {
4039  _lwt_release_edges(edge, 1);
4040  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4041  return -1;
4042  }
4043  if ( i != 1 )
4044  {
4045  _lwt_release_edges(edge, 1);
4046  lwerror("Unexpected error: %d faces updated when expecting 1", i);
4047  return -1;
4048  }
4049  }
4050  else
4051  {
4052  /* New face replaces the old two faces */
4053  newface.face_id = -1;
4054  i = lwt_be_insertFaces( topo, &newface, 1 );
4055  _lwt_release_faces(faces, 2);
4056  if ( i == -1 )
4057  {
4058  _lwt_release_edges(edge, 1);
4059  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4060  return -1;
4061  }
4062  if ( i != 1 )
4063  {
4064  _lwt_release_edges(edge, 1);
4065  lwerror("Unexpected error: %d faces inserted when expecting 1", i);
4066  return -1;
4067  }
4068  floodface = newface.face_id;
4069  }
4070  }
4071 
4072  /* Update face references for edges and nodes still referencing
4073  * the removed face(s) */
4074 
4075  if ( edge->face_left != floodface )
4076  {
4077  if ( -1 == _lwt_UpdateEdgeFaceRef(topo, edge->face_left, floodface) )
4078  {
4079  _lwt_release_edges(edge, 1);
4080  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4081  return -1;
4082  }
4083  if ( -1 == _lwt_UpdateNodeFaceRef(topo, edge->face_left, floodface) )
4084  {
4085  _lwt_release_edges(edge, 1);
4086  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4087  return -1;
4088  }
4089  }
4090 
4091  if ( edge->face_right != floodface )
4092  {
4093  if ( -1 == _lwt_UpdateEdgeFaceRef(topo, edge->face_right, floodface) )
4094  {
4095  _lwt_release_edges(edge, 1);
4096  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4097  return -1;
4098  }
4099  if ( -1 == _lwt_UpdateNodeFaceRef(topo, edge->face_right, floodface) )
4100  {
4101  _lwt_release_edges(edge, 1);
4102  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4103  return -1;
4104  }
4105  }
4106 
4107  /* Update topogeoms on heal */
4108  if ( ! lwt_be_updateTopoGeomFaceHeal(topo,
4109  edge->face_right, edge->face_left,
4110  floodface) )
4111  {
4112  _lwt_release_edges(edge, 1);
4114  return -1;
4115  }
4116  } /* two faces healed */
4117 
4118  /* Delete the edge */
4119  i = lwt_be_deleteEdges(topo, edge, LWT_COL_EDGE_EDGE_ID);
4120  if ( i == -1 ) {
4121  _lwt_release_edges(edge, 1);
4122  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4123  return -1;
4124  }
4125 
4126  /* If any of the edge nodes remained isolated, set
4127  * containing_face = floodface
4128  */
4129  if ( ! fnode_edges )
4130  {
4131  upd_node[nnode].node_id = edge->start_node;
4132  upd_node[nnode].containing_face = floodface;
4133  ++nnode;
4134  }
4135  if ( edge->end_node != edge->start_node && ! lnode_edges )
4136  {
4137  upd_node[nnode].node_id = edge->end_node;
4138  upd_node[nnode].containing_face = floodface;
4139  ++nnode;
4140  }
4141  if ( nnode )
4142  {
4143  i = lwt_be_updateNodesById(topo, upd_node, nnode,
4145  if ( i == -1 ) {
4146  _lwt_release_edges(edge, 1);
4147  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4148  return -1;
4149  }
4150  }
4151 
4152  if ( edge->face_left != edge->face_right )
4153  /* or there'd be no face to remove */
4154  {
4155  LWT_ELEMID ids[2];
4156  int nids = 0;
4157  if ( edge->face_right != floodface )
4158  ids[nids++] = edge->face_right;
4159  if ( edge->face_left != floodface )
4160  ids[nids++] = edge->face_left;
4161  i = lwt_be_deleteFacesById(topo, ids, nids);
4162  if ( i == -1 ) {
4163  _lwt_release_edges(edge, 1);
4164  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4165  return -1;
4166  }
4167  }
4168 
4169  _lwt_release_edges(edge, 1);
4170  return modFace ? floodface : newface.face_id;
4171 }
int gbox_merge(const GBOX *new_box, GBOX *merge_box)
Update the merged GBOX to be large enough to include itself and the new box.
Definition: g_box.c:264
void lwfree(void *mem)
Definition: lwutil.c:244
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_FACE_ALL
#define LWT_COL_EDGE_START_NODE
#define LWT_COL_EDGE_NEXT_RIGHT
#define LWT_COL_NODE_CONTAINING_FACE
#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 LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
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:120
LWT_ISO_EDGE * lwt_be_getEdgeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:225
static int lwt_be_checkTopoGeomRemEdge(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, LWT_ELEMID face_left, LWT_ELEMID face_right)
Definition: lwgeom_topo.c:350
static int _lwt_UpdateEdgeFaceRef(LWT_TOPOLOGY *topo, LWT_ELEMID of, LWT_ELEMID nf)
Definition: lwgeom_topo.c:3738
static int lwt_be_updateFacesById(LWT_TOPOLOGY *topo, const LWT_ISO_FACE *faces, int numfaces)
Definition: lwgeom_topo.c:298
static int lwt_be_updateNodesById(LWT_TOPOLOGY *topo, const LWT_ISO_NODE *nodes, int numnodes, int upd_fields)
Definition: lwgeom_topo.c:314
static int lwt_be_updateTopoGeomFaceHeal(LWT_TOPOLOGY *topo, LWT_ELEMID face1, LWT_ELEMID face2, LWT_ELEMID newface)
Definition: lwgeom_topo.c:364
static LWT_ISO_FACE * lwt_be_getFaceById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:232
static int lwt_be_insertFaces(LWT_TOPOLOGY *topo, LWT_ISO_FACE *face, int numelems)
Definition: lwgeom_topo.c:201
int lwt_be_deleteEdges(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *sel_edge, int sel_fields)
Definition: lwgeom_topo.c:322
static int _lwt_UpdateNodeFaceRef(LWT_TOPOLOGY *topo, LWT_ELEMID of, LWT_ELEMID nf)
Definition: lwgeom_topo.c:3771
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:447
static LWT_ISO_EDGE * lwt_be_getEdgeByNode(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:239
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:44
static int lwt_be_deleteFacesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int numelems)
Definition: lwgeom_topo.c:207
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:457
static int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
Definition: lwgeom_topo.c:306
LWT_ELEMID face_right
LWT_ELEMID next_right
LWT_ELEMID end_node
LWT_ELEMID face_left
LWT_ELEMID next_left
LWT_ELEMID edge_id
LWT_ELEMID start_node
LWT_ELEMID face_id
LWT_ELEMID node_id
LWT_ELEMID containing_face
const LWT_BE_IFACE * be_iface

References _lwt_release_edges(), _lwt_release_faces(), _lwt_UpdateEdgeFaceRef(), _lwt_UpdateNodeFaceRef(), LWT_TOPOLOGY_T::be_iface, LWT_ISO_NODE::containing_face, LWT_ISO_EDGE::edge_id, LWT_ISO_EDGE::end_node, LWT_ISO_FACE::face_id, LWT_ISO_EDGE::face_left, LWT_ISO_EDGE::face_right, gbox_merge(), LWDEBUG, LWDEBUGF, lwerror(), lwfree(), lwt_be_checkTopoGeomRemEdge(), lwt_be_deleteEdges(), lwt_be_deleteFacesById(), lwt_be_getEdgeById(), lwt_be_getEdgeByNode(), lwt_be_getFaceById(), lwt_be_insertFaces(), lwt_be_lastErrorMessage(), lwt_be_updateEdgesById(), lwt_be_updateFacesById(), lwt_be_updateNodesById(), lwt_be_updateTopoGeomFaceHeal(), LWT_COL_EDGE_ALL, LWT_COL_EDGE_EDGE_ID, LWT_COL_EDGE_END_NODE, LWT_COL_EDGE_NEXT_LEFT, LWT_COL_EDGE_NEXT_RIGHT, LWT_COL_EDGE_START_NODE, LWT_COL_FACE_ALL, LWT_COL_NODE_CONTAINING_FACE, LWTFMT_ELEMID, LWT_ISO_FACE::mbr, LWT_ISO_EDGE::next_left, LWT_ISO_EDGE::next_right, LWT_ISO_NODE::node_id, and LWT_ISO_EDGE::start_node.

Referenced by lwt_RemEdgeModFace(), and lwt_RemEdgeNewFace().

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