PostGIS 3.6.2dev-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 4370 of file lwgeom_topo.c.

4372{
4373 LWT_ELEMID ids[2];
4374 LWT_ELEMID commonnode = -1;
4375 int caseno = 0;
4376 LWT_ISO_EDGE *node_edges;
4377 uint64_t num_node_edges;
4378 LWT_ISO_EDGE *edges;
4379 LWT_ISO_EDGE *e1 = NULL;
4380 LWT_ISO_EDGE *e2 = NULL;
4381 LWT_ISO_EDGE newedge, updedge, seledge;
4382 uint64_t nedges, i;
4383 int e1freenode;
4384 int e2sign, e2freenode;
4385 POINTARRAY *pa;
4386 char buf[256];
4387 char *ptr;
4388 size_t bufleft = 256;
4389
4390 ptr = buf;
4391
4392 /* NOT IN THE SPECS: see if the same edge is given twice.. */
4393 if ( eid1 == eid2 )
4394 {
4395 lwerror("Cannot heal edge %" LWTFMT_ELEMID
4396 " with itself, try with another", eid1);
4397 return -1;
4398 }
4399 ids[0] = eid1;
4400 ids[1] = eid2;
4401 nedges = 2;
4402 edges = lwt_be_getEdgeById(topo, ids, &nedges, LWT_COL_EDGE_ALL);
4403 if ((nedges == UINT64_MAX) || (edges == NULL))
4404 {
4406 return -1;
4407 }
4408 for ( i=0; i<nedges; ++i )
4409 {
4410 if ( edges[i].edge_id == eid1 ) {
4411 if ( e1 ) {
4412 _lwt_release_edges(edges, nedges);
4413 lwerror("Corrupted topology: multiple edges have id %"
4414 LWTFMT_ELEMID, eid1);
4415 return -1;
4416 }
4417 e1 = &(edges[i]);
4418 }
4419 else if ( edges[i].edge_id == eid2 ) {
4420 if ( e2 ) {
4421 _lwt_release_edges(edges, nedges);
4422 lwerror("Corrupted topology: multiple edges have id %"
4423 LWTFMT_ELEMID, eid2);
4424 return -1;
4425 }
4426 e2 = &(edges[i]);
4427 }
4428 }
4429 if ( ! e1 )
4430 {
4431 _lwt_release_edges(edges, nedges);
4432 lwerror(
4433 "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4434 eid1);
4435 return -1;
4436 }
4437 if ( ! e2 )
4438 {
4439 _lwt_release_edges(edges, nedges);
4440 lwerror(
4441 "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4442 eid2);
4443 return -1;
4444 }
4445
4446 /* NOT IN THE SPECS: See if any of the two edges are closed. */
4447 if ( e1->start_node == e1->end_node )
4448 {
4449 _lwt_release_edges(edges, nedges);
4450 lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4451 LWTFMT_ELEMID, eid1, eid2);
4452 return -1;
4453 }
4454 if ( e2->start_node == e2->end_node )
4455 {
4456 _lwt_release_edges(edges, nedges);
4457 lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4458 LWTFMT_ELEMID, eid2, eid1);
4459 return -1;
4460 }
4461
4462 /* Find common node */
4463
4464 if ( e1->end_node == e2->start_node )
4465 {
4466 commonnode = e1->end_node;
4467 caseno = 1;
4468 }
4469 else if ( e1->end_node == e2->end_node )
4470 {
4471 commonnode = e1->end_node;
4472 caseno = 2;
4473 }
4474 /* Check if any other edge is connected to the common node, if found */
4475 if ( commonnode != -1 )
4476 {
4477 num_node_edges = 1;
4478 node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4479 &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4480 if (num_node_edges == UINT64_MAX)
4481 {
4482 _lwt_release_edges(edges, nedges);
4484 return -1;
4485 }
4486 for (i=0; i<num_node_edges; ++i)
4487 {
4488 int r;
4489 if ( node_edges[i].edge_id == eid1 ) continue;
4490 if ( node_edges[i].edge_id == eid2 ) continue;
4491 commonnode = -1;
4492 /* append to string, for error message */
4493 if ( bufleft > 0 ) {
4494 r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4495 ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4496 if ( r >= (int) bufleft )
4497 {
4498 bufleft = 0;
4499 buf[252] = '.';
4500 buf[253] = '.';
4501 buf[254] = '.';
4502 buf[255] = '\0';
4503 }
4504 else
4505 {
4506 bufleft -= r;
4507 ptr += r;
4508 }
4509 }
4510 }
4511 lwfree(node_edges);
4512 }
4513
4514 if ( commonnode == -1 )
4515 {
4516 if ( e1->start_node == e2->start_node )
4517 {
4518 commonnode = e1->start_node;
4519 caseno = 3;
4520 }
4521 else if ( e1->start_node == e2->end_node )
4522 {
4523 commonnode = e1->start_node;
4524 caseno = 4;
4525 }
4526 /* Check if any other edge is connected to the common node, if found */
4527 if ( commonnode != -1 )
4528 {
4529 num_node_edges = 1;
4530 node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4531 &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4532 if (num_node_edges == UINT64_MAX)
4533 {
4534 _lwt_release_edges(edges, nedges);
4536 return -1;
4537 }
4538 for (i=0; i<num_node_edges; ++i)
4539 {
4540 int r;
4541 if ( node_edges[i].edge_id == eid1 ) continue;
4542 if ( node_edges[i].edge_id == eid2 ) continue;
4543 commonnode = -1;
4544 /* append to string, for error message */
4545 if ( bufleft > 0 ) {
4546 r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4547 ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4548 if ( r >= (int) bufleft )
4549 {
4550 bufleft = 0;
4551 buf[252] = '.';
4552 buf[253] = '.';
4553 buf[254] = '.';
4554 buf[255] = '\0';
4555 }
4556 else
4557 {
4558 bufleft -= r;
4559 ptr += r;
4560 }
4561 }
4562 }
4563 if ( num_node_edges ) lwfree(node_edges);
4564 }
4565 }
4566
4567 if ( commonnode == -1 )
4568 {
4569 _lwt_release_edges(edges, nedges);
4570 if ( ptr != buf )
4571 {
4572 lwerror("SQL/MM Spatial exception - other edges connected (%s)",
4573 buf);
4574 }
4575 else
4576 {
4577 lwerror("SQL/MM Spatial exception - non-connected edges");
4578 }
4579 return -1;
4580 }
4581
4582 if ( ! lwt_be_checkTopoGeomRemNode(topo, commonnode,
4583 eid1, eid2 ) )
4584 {
4585 _lwt_release_edges(edges, nedges);
4587 return -1;
4588 }
4589
4590 /* Construct the geometry of the new edge */
4591 switch (caseno)
4592 {
4593 case 1: /* e1.end = e2.start */
4594 pa = ptarray_clone_deep(e1->geom->points);
4595 //pa = ptarray_merge(pa, e2->geom->points);
4596 ptarray_append_ptarray(pa, e2->geom->points, 0);
4597 newedge.start_node = e1->start_node;
4598 newedge.end_node = e2->end_node;
4599 newedge.next_left = e2->next_left;
4600 newedge.next_right = e1->next_right;
4601 e1freenode = 1;
4602 e2freenode = -1;
4603 e2sign = 1;
4604 break;
4605 case 2: /* e1.end = e2.end */
4606 {
4607 POINTARRAY *pa2;
4608 pa2 = ptarray_clone_deep(e2->geom->points);
4610 pa = ptarray_clone_deep(e1->geom->points);
4611 //pa = ptarray_merge(e1->geom->points, pa);
4612 ptarray_append_ptarray(pa, pa2, 0);
4613 ptarray_free(pa2);
4614 newedge.start_node = e1->start_node;
4615 newedge.end_node = e2->start_node;
4616 newedge.next_left = e2->next_right;
4617 newedge.next_right = e1->next_right;
4618 e1freenode = 1;
4619 e2freenode = 1;
4620 e2sign = -1;
4621 break;
4622 }
4623 case 3: /* e1.start = e2.start */
4624 pa = ptarray_clone_deep(e2->geom->points);
4626 //pa = ptarray_merge(pa, e1->geom->points);
4627 ptarray_append_ptarray(pa, e1->geom->points, 0);
4628 newedge.end_node = e1->end_node;
4629 newedge.start_node = e2->end_node;
4630 newedge.next_left = e1->next_left;
4631 newedge.next_right = e2->next_left;
4632 e1freenode = -1;
4633 e2freenode = -1;
4634 e2sign = -1;
4635 break;
4636 case 4: /* e1.start = e2.end */
4637 pa = ptarray_clone_deep(e2->geom->points);
4638 //pa = ptarray_merge(pa, e1->geom->points);
4639 ptarray_append_ptarray(pa, e1->geom->points, 0);
4640 newedge.end_node = e1->end_node;
4641 newedge.start_node = e2->start_node;
4642 newedge.next_left = e1->next_left;
4643 newedge.next_right = e2->next_right;
4644 e1freenode = -1;
4645 e2freenode = 1;
4646 e2sign = 1;
4647 break;
4648 default:
4649 pa = NULL;
4650 e1freenode = 0;
4651 e2freenode = 0;
4652 e2sign = 0;
4653 _lwt_release_edges(edges, nedges);
4654 lwerror("Coding error: caseno=%d should never happen", caseno);
4655 return -1;
4656 break;
4657 }
4658 newedge.geom = lwline_construct(topo->srid, NULL, pa);
4659
4660 if ( modEdge )
4661 {
4662 /* Update data of the first edge */
4663 newedge.edge_id = eid1;
4664 int result = lwt_be_updateEdgesById(topo,
4665 &newedge,
4666 1,
4669 if (result == -1)
4670 {
4671 lwline_free(newedge.geom);
4672 _lwt_release_edges(edges, nedges);
4674 return -1;
4675 }
4676 else if (result != 1)
4677 {
4678 lwline_free(newedge.geom);
4679 if ( edges ) _lwt_release_edges(edges, nedges);
4680 lwerror("Unexpected error: %" PRIu64 " edges updated when expecting 1", i);
4681 return -1;
4682 }
4683 }
4684 else
4685 {
4686 /* Add new edge */
4687 newedge.edge_id = -1;
4688 newedge.face_left = e1->face_left;
4689 newedge.face_right = e1->face_right;
4690 int result = lwt_be_insertEdges(topo, &newedge, 1);
4691 if (result == -1)
4692 {
4693 lwline_free(newedge.geom);
4694 _lwt_release_edges(edges, nedges);
4696 return -1;
4697 }
4698 else if (result == 0)
4699 {
4700 lwline_free(newedge.geom);
4701 _lwt_release_edges(edges, nedges);
4702 lwerror("Insertion of split edge failed (no reason)");
4703 return -1;
4704 }
4705 }
4706 lwline_free(newedge.geom);
4707
4708 /*
4709 -- Update next_left_edge/next_right_edge for
4710 -- any edge having them still pointing at the edge being removed
4711 -- (eid2 only when modEdge, or both otherwise)
4712 --
4713 -- NOTE:
4714 -- e#freenode is 1 when edge# end node was the common node
4715 -- and -1 otherwise. This gives the sign of possibly found references
4716 -- to its "free" (non connected to other edge) endnode.
4717 -- e2sign is -1 if edge1 direction is opposite to edge2 direction,
4718 -- or 1 otherwise.
4719 --
4720 */
4721
4722 /* update edges connected to e2's boundary from their end node */
4723 seledge.next_left = e2freenode * eid2;
4724 updedge.next_left = e2freenode * newedge.edge_id * e2sign;
4725 int result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT, &updedge, LWT_COL_EDGE_NEXT_LEFT, NULL, 0);
4726 if (result == -1)
4727 {
4728 _lwt_release_edges(edges, nedges);
4730 return -1;
4731 }
4732
4733 /* update edges connected to e2's boundary from their start node */
4734 seledge.next_right = e2freenode * eid2;
4735 updedge.next_right = e2freenode * newedge.edge_id * e2sign;
4736 result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT, &updedge, LWT_COL_EDGE_NEXT_RIGHT, NULL, 0);
4737 if (result == -1)
4738 {
4739 _lwt_release_edges(edges, nedges);
4741 return -1;
4742 }
4743
4744 if ( ! modEdge )
4745 {
4746 /* update edges connected to e1's boundary from their end node */
4747 seledge.next_left = e1freenode * eid1;
4748 updedge.next_left = e1freenode * newedge.edge_id;
4749 result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT, &updedge, LWT_COL_EDGE_NEXT_LEFT, NULL, 0);
4750 if (result == -1)
4751 {
4752 _lwt_release_edges(edges, nedges);
4754 return -1;
4755 }
4756
4757 /* update edges connected to e1's boundary from their start node */
4758 seledge.next_right = e1freenode * eid1;
4759 updedge.next_right = e1freenode * newedge.edge_id;
4760 result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT, &updedge, LWT_COL_EDGE_NEXT_RIGHT, NULL, 0);
4761 if (result == -1)
4762 {
4763 _lwt_release_edges(edges, nedges);
4765 return -1;
4766 }
4767 }
4768
4769 /* delete the edges (only second on modEdge or both) */
4771 if (result == -1)
4772 {
4773 _lwt_release_edges(edges, nedges);
4775 return -1;
4776 }
4777 if ( ! modEdge ) {
4779 if (result == -1)
4780 {
4781 _lwt_release_edges(edges, nedges);
4783 return -1;
4784 }
4785 }
4786
4787 _lwt_release_edges(edges, nedges);
4788
4789 /* delete the common node */
4790 result = lwt_be_deleteNodesById( topo, &commonnode, 1 );
4791 if (result == -1)
4792 {
4794 return -1;
4795 }
4796
4797 /*
4798 --
4799 -- NOT IN THE SPECS:
4800 -- Drop composition rows involving second
4801 -- edge, as the first edge took its space,
4802 -- and all affected TopoGeom have been previously checked
4803 -- for being composed by both edges.
4804 */
4806 eid1, eid2, newedge.edge_id) )
4807 {
4809 return -1;
4810 }
4811
4812 return modEdge ? commonnode : newedge.edge_id;
4813}
char * r
Definition cu_in_wkt.c:24
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
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:248
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:643
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
#define PGTOPO_BE_ERROR()
#define LWTFMT_ELEMID
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
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)
void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
int lwt_be_updateEdgesById(LWT_TOPOLOGY *topo, const LWT_ISO_EDGE *edges, int numedges, int upd_fields)
int lwt_be_insertEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, uint64_t numelems)
LWT_ISO_EDGE * lwt_be_getEdgeByNode(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
POINTARRAY * points
Definition liblwgeom.h:483
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, PGTOPO_BE_ERROR, LWLINE::points, ptarray_append_ptarray(), ptarray_clone_deep(), ptarray_free(), ptarray_reverse_in_place(), r, result, 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: