PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ _lwt_HealEdges()

static LWT_ELEMID _lwt_HealEdges ( LWT_TOPOLOGY topo,
LWT_ELEMID  eid1,
LWT_ELEMID  eid2,
int  modEdge 
)
static

Definition at line 4203 of file lwgeom_topo.c.

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