PostGIS  2.4.9dev-r@@SVN_REVISION@@

◆ _lwt_RemEdge()

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

Definition at line 3940 of file lwgeom_topo.c.

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().

3941 {
3942  int i, nedges, nfaces, fields;
3943  LWT_ISO_EDGE *edge = NULL;
3944  LWT_ISO_EDGE *upd_edge = NULL;
3945  LWT_ISO_EDGE upd_edge_left[2];
3946  int nedge_left = 0;
3947  LWT_ISO_EDGE upd_edge_right[2];
3948  int nedge_right = 0;
3949  LWT_ISO_NODE upd_node[2];
3950  int nnode = 0;
3951  LWT_ISO_FACE *faces = NULL;
3952  LWT_ISO_FACE newface;
3953  LWT_ELEMID node_ids[2];
3954  LWT_ELEMID face_ids[2];
3955  int fnode_edges = 0; /* number of edges on the first node (excluded
3956  * the one being removed ) */
3957  int lnode_edges = 0; /* number of edges on the last node (excluded
3958  * the one being removed ) */
3959 
3960  newface.face_id = 0;
3961 
3962  i = 1;
3963  edge = lwt_be_getEdgeById(topo, &edge_id, &i, LWT_COL_EDGE_ALL);
3964  if ( ! edge )
3965  {
3966  LWDEBUGF(1, "lwt_be_getEdgeById returned NULL and set i=%d", i);
3967  if ( i == -1 )
3968  {
3969  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3970  return -1;
3971  }
3972  else if ( i == 0 )
3973  {
3974  lwerror("SQL/MM Spatial exception - non-existent edge %"
3975  LWTFMT_ELEMID, edge_id);
3976  return -1;
3977  }
3978  else
3979  {
3980  lwerror("Backend coding error: getEdgeById callback returned NULL "
3981  "but numelements output parameter has value %d "
3982  "(expected 0 or 1)", i);
3983  return -1;
3984  }
3985  }
3986 
3987  if ( ! lwt_be_checkTopoGeomRemEdge(topo, edge_id,
3988  edge->face_left, edge->face_right) )
3989  {
3991  return -1;
3992  }
3993 
3994  LWDEBUG(1, "Updating next_{right,left}_face of ring edges...");
3995 
3996  /* Update edge linking */
3997 
3998  nedges = 0;
3999  node_ids[nedges++] = edge->start_node;
4000  if ( edge->end_node != edge->start_node )
4001  {
4002  node_ids[nedges++] = edge->end_node;
4003  }
4007  upd_edge = lwt_be_getEdgeByNode( topo, &(node_ids[0]), &nedges, fields );
4008  if ( nedges == -1 ) {
4009  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4010  return -1;
4011  }
4012  nedge_left = nedge_right = 0;
4013  for ( i=0; i<nedges; ++i )
4014  {
4015  LWT_ISO_EDGE *e = &(upd_edge[i]);
4016  if ( e->edge_id == edge_id ) continue;
4017  if ( e->start_node == edge->start_node || e->end_node == edge->start_node )
4018  {
4019  ++fnode_edges;
4020  }
4021  if ( e->start_node == edge->end_node || e->end_node == edge->end_node )
4022  {
4023  ++lnode_edges;
4024  }
4025  if ( e->next_left == -edge_id )
4026  {
4027  upd_edge_left[nedge_left].edge_id = e->edge_id;
4028  upd_edge_left[nedge_left++].next_left =
4029  edge->next_left != edge_id ? edge->next_left : edge->next_right;
4030  }
4031  else if ( e->next_left == edge_id )
4032  {
4033  upd_edge_left[nedge_left].edge_id = e->edge_id;
4034  upd_edge_left[nedge_left++].next_left =
4035  edge->next_right != -edge_id ? edge->next_right : edge->next_left;
4036  }
4037 
4038  if ( e->next_right == -edge_id )
4039  {
4040  upd_edge_right[nedge_right].edge_id = e->edge_id;
4041  upd_edge_right[nedge_right++].next_right =
4042  edge->next_left != edge_id ? edge->next_left : edge->next_right;
4043  }
4044  else if ( e->next_right == edge_id )
4045  {
4046  upd_edge_right[nedge_right].edge_id = e->edge_id;
4047  upd_edge_right[nedge_right++].next_right =
4048  edge->next_right != -edge_id ? edge->next_right : edge->next_left;
4049  }
4050  }
4051 
4052  if ( nedge_left )
4053  {
4054  LWDEBUGF(1, "updating %d 'next_left' edges", nedge_left);
4055  /* update edges in upd_edge_left set next_left */
4056  i = lwt_be_updateEdgesById(topo, &(upd_edge_left[0]), nedge_left,
4058  if ( i == -1 )
4059  {
4060  _lwt_release_edges(edge, 1);
4061  lwfree(upd_edge);
4062  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4063  return -1;
4064  }
4065  }
4066  if ( nedge_right )
4067  {
4068  LWDEBUGF(1, "updating %d 'next_right' edges", nedge_right);
4069  /* update edges in upd_edge_right set next_right */
4070  i = lwt_be_updateEdgesById(topo, &(upd_edge_right[0]), nedge_right,
4072  if ( i == -1 )
4073  {
4074  _lwt_release_edges(edge, 1);
4075  lwfree(upd_edge);
4076  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4077  return -1;
4078  }
4079  }
4080  LWDEBUGF(1, "releasing %d updateable edges in %p", nedges, upd_edge);
4081  lwfree(upd_edge);
4082 
4083  /* Id of face that will take up all the space previously
4084  * taken by left and right faces of the edge */
4085  LWT_ELEMID floodface;
4086 
4087  /* Find floodface, and update its mbr if != 0 */
4088  if ( edge->face_left == edge->face_right )
4089  {
4090  floodface = edge->face_right;
4091  }
4092  else
4093  {
4094  /* Two faces healed */
4095  if ( edge->face_left == 0 || edge->face_right == 0 )
4096  {
4097  floodface = 0;
4098  LWDEBUG(1, "floodface is universe");
4099  }
4100  else
4101  {
4102  /* we choose right face as the face that will remain
4103  * to be symmetric with ST_AddEdgeModFace */
4104  floodface = edge->face_right;
4105  LWDEBUGF(1, "floodface is %" LWTFMT_ELEMID, floodface);
4106  /* update mbr of floodface as union of mbr of both faces */
4107  face_ids[0] = edge->face_left;
4108  face_ids[1] = edge->face_right;
4109  nfaces = 2;
4110  fields = LWT_COL_FACE_ALL;
4111  faces = lwt_be_getFaceById(topo, face_ids, &nfaces, fields);
4112  if ( nfaces == -1 ) {
4113  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4114  return -1;
4115  }
4116  GBOX *box1=NULL;
4117  GBOX *box2=NULL;
4118  for ( i=0; i<nfaces; ++i )
4119  {
4120  if ( faces[i].face_id == edge->face_left )
4121  {
4122  if ( ! box1 ) box1 = faces[i].mbr;
4123  else
4124  {
4125  i = edge->face_left;
4126  _lwt_release_edges(edge, 1);
4127  _lwt_release_faces(faces, nfaces);
4128  lwerror("corrupted topology: more than 1 face have face_id=%"
4129  LWTFMT_ELEMID, i);
4130  return -1;
4131  }
4132  }
4133  else if ( faces[i].face_id == edge->face_right )
4134  {
4135  if ( ! box2 ) box2 = faces[i].mbr;
4136  else
4137  {
4138  i = edge->face_right;
4139  _lwt_release_edges(edge, 1);
4140  _lwt_release_faces(faces, nfaces);
4141  lwerror("corrupted topology: more than 1 face have face_id=%"
4142  LWTFMT_ELEMID, i);
4143  return -1;
4144  }
4145  }
4146  else
4147  {
4148  i = faces[i].face_id;
4149  _lwt_release_edges(edge, 1);
4150  _lwt_release_faces(faces, nfaces);
4151  lwerror("Backend coding error: getFaceById returned face "
4152  "with non-requested id %" LWTFMT_ELEMID, i);
4153  return -1;
4154  }
4155  }
4156  if ( ! box1 ) {
4157  i = edge->face_left;
4158  _lwt_release_edges(edge, 1);
4159  _lwt_release_faces(faces, nfaces);
4160  lwerror("corrupted topology: no face have face_id=%"
4161  LWTFMT_ELEMID " (left face for edge %"
4162  LWTFMT_ELEMID ")", i, edge_id);
4163  return -1;
4164  }
4165  if ( ! box2 ) {
4166  i = edge->face_right;
4167  _lwt_release_edges(edge, 1);
4168  _lwt_release_faces(faces, nfaces);
4169  lwerror("corrupted topology: no face have face_id=%"
4170  LWTFMT_ELEMID " (right face for edge %"
4171  LWTFMT_ELEMID ")", i, edge_id);
4172  return -1;
4173  }
4174  gbox_merge(box2, box1); /* box1 is now the union of the two */
4175  newface.mbr = box1;
4176  if ( modFace )
4177  {
4178  newface.face_id = floodface;
4179  i = lwt_be_updateFacesById( topo, &newface, 1 );
4180  _lwt_release_faces(faces, 2);
4181  if ( i == -1 )
4182  {
4183  _lwt_release_edges(edge, 1);
4184  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4185  return -1;
4186  }
4187  if ( i != 1 )
4188  {
4189  _lwt_release_edges(edge, 1);
4190  lwerror("Unexpected error: %d faces updated when expecting 1", i);
4191  return -1;
4192  }
4193  }
4194  else
4195  {
4196  /* New face replaces the old two faces */
4197  newface.face_id = -1;
4198  i = lwt_be_insertFaces( topo, &newface, 1 );
4199  _lwt_release_faces(faces, 2);
4200  if ( i == -1 )
4201  {
4202  _lwt_release_edges(edge, 1);
4203  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4204  return -1;
4205  }
4206  if ( i != 1 )
4207  {
4208  _lwt_release_edges(edge, 1);
4209  lwerror("Unexpected error: %d faces inserted when expecting 1", i);
4210  return -1;
4211  }
4212  floodface = newface.face_id;
4213  }
4214  }
4215 
4216  /* Update face references for edges and nodes still referencing
4217  * the removed face(s) */
4218 
4219  if ( edge->face_left != floodface )
4220  {
4221  if ( -1 == _lwt_UpdateEdgeFaceRef(topo, edge->face_left, floodface) )
4222  {
4223  _lwt_release_edges(edge, 1);
4224  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4225  return -1;
4226  }
4227  if ( -1 == _lwt_UpdateNodeFaceRef(topo, edge->face_left, floodface) )
4228  {
4229  _lwt_release_edges(edge, 1);
4230  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4231  return -1;
4232  }
4233  }
4234 
4235  if ( edge->face_right != floodface )
4236  {
4237  if ( -1 == _lwt_UpdateEdgeFaceRef(topo, edge->face_right, floodface) )
4238  {
4239  _lwt_release_edges(edge, 1);
4240  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4241  return -1;
4242  }
4243  if ( -1 == _lwt_UpdateNodeFaceRef(topo, edge->face_right, floodface) )
4244  {
4245  _lwt_release_edges(edge, 1);
4246  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4247  return -1;
4248  }
4249  }
4250 
4251  /* Update topogeoms on heal */
4252  if ( ! lwt_be_updateTopoGeomFaceHeal(topo,
4253  edge->face_right, edge->face_left,
4254  floodface) )
4255  {
4256  _lwt_release_edges(edge, 1);
4258  return -1;
4259  }
4260  } /* two faces healed */
4261 
4262  /* Delete the edge */
4263  i = lwt_be_deleteEdges(topo, edge, LWT_COL_EDGE_EDGE_ID);
4264  if ( i == -1 ) {
4265  _lwt_release_edges(edge, 1);
4266  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4267  return -1;
4268  }
4269 
4270  /* If any of the edge nodes remained isolated, set
4271  * containing_face = floodface
4272  */
4273  if ( ! fnode_edges )
4274  {
4275  upd_node[nnode].node_id = edge->start_node;
4276  upd_node[nnode].containing_face = floodface;
4277  ++nnode;
4278  }
4279  if ( edge->end_node != edge->start_node && ! lnode_edges )
4280  {
4281  upd_node[nnode].node_id = edge->end_node;
4282  upd_node[nnode].containing_face = floodface;
4283  ++nnode;
4284  }
4285  if ( nnode )
4286  {
4287  i = lwt_be_updateNodesById(topo, upd_node, nnode,
4289  if ( i == -1 ) {
4290  _lwt_release_edges(edge, 1);
4291  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4292  return -1;
4293  }
4294  }
4295 
4296  if ( edge->face_left != edge->face_right )
4297  /* or there'd be no face to remove */
4298  {
4299  LWT_ELEMID ids[2];
4300  int nids = 0;
4301  if ( edge->face_right != floodface )
4302  ids[nids++] = edge->face_right;
4303  if ( edge->face_left != floodface )
4304  ids[nids++] = edge->face_left;
4305  i = lwt_be_deleteFacesById(topo, ids, nids);
4306  if ( i == -1 ) {
4307  _lwt_release_edges(edge, 1);
4308  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
4309  return -1;
4310  }
4311  }
4312 
4313  _lwt_release_edges(edge, 1);
4314  return modFace ? floodface : newface.face_id;
4315 }
static LWT_ISO_FACE * lwt_be_getFaceById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:232
LWT_ELEMID face_left
#define LWT_COL_NODE_CONTAINING_FACE
static int lwt_be_insertFaces(LWT_TOPOLOGY *topo, LWT_ISO_FACE *face, int numelems)
Definition: lwgeom_topo.c:201
LWT_ELEMID containing_face
static int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
Definition: lwgeom_topo.c:306
void lwfree(void *mem)
Definition: lwutil.c:244
static int _lwt_UpdateNodeFaceRef(LWT_TOPOLOGY *topo, LWT_ELEMID of, LWT_ELEMID nf)
Definition: lwgeom_topo.c:3915
int lwt_be_deleteEdges(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *sel_edge, int sel_fields)
Definition: lwgeom_topo.c:322
#define LWT_COL_EDGE_START_NODE
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
LWT_ISO_EDGE * lwt_be_getEdgeById(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:225
LWT_ELEMID next_left
int 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:269
static int lwt_be_updateFacesById(LWT_TOPOLOGY *topo, const LWT_ISO_FACE *faces, int numfaces)
Definition: lwgeom_topo.c:298
const LWT_BE_IFACE * be_iface
#define LWT_COL_EDGE_END_NODE
LWT_ELEMID face_id
static int lwt_be_updateTopoGeomFaceHeal(LWT_TOPOLOGY *topo, LWT_ELEMID face1, LWT_ELEMID face2, LWT_ELEMID newface)
Definition: lwgeom_topo.c:364
LWT_ELEMID face_right
#define LWT_COL_EDGE_ALL
LWT_ELEMID node_id
LWT_ELEMID edge_id
static int lwt_be_deleteFacesById(const LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int numelems)
Definition: lwgeom_topo.c:207
static int lwt_be_updateNodesById(LWT_TOPOLOGY *topo, const LWT_ISO_NODE *nodes, int numnodes, int upd_fields)
Definition: lwgeom_topo.c:314
#define LWT_COL_EDGE_EDGE_ID
Edge fields.
#define LWT_COL_FACE_ALL
#define LWT_COL_EDGE_NEXT_LEFT
static int _lwt_UpdateEdgeFaceRef(LWT_TOPOLOGY *topo, LWT_ELEMID of, LWT_ELEMID nf)
Definition: lwgeom_topo.c:3882
#define LWT_COL_EDGE_NEXT_RIGHT
LWT_ELEMID start_node
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:467
LWT_ELEMID next_right
LWT_INT64 LWT_ELEMID
Identifier of topology element.
static LWT_ISO_EDGE * lwt_be_getEdgeByNode(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, int *numelems, int fields)
Definition: lwgeom_topo.c:239
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:457
LWT_ELEMID end_node
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:120
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
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
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:44
Here is the call graph for this function:
Here is the caller graph for this function: