PostGIS 3.7.0dev-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 4487 of file lwgeom_topo.c.

4489{
4490 LWT_ELEMID ids[2];
4491 LWT_ELEMID commonnode = -1;
4492 int caseno = 0;
4493 LWT_ISO_EDGE *node_edges;
4494 uint64_t num_node_edges;
4495 LWT_ISO_EDGE *edges;
4496 LWT_ISO_EDGE *e1 = NULL;
4497 LWT_ISO_EDGE *e2 = NULL;
4498 LWT_ISO_EDGE newedge, updedge, seledge;
4499 uint64_t nedges, i;
4500 int e1freenode;
4501 int e2sign, e2freenode;
4502 POINTARRAY *pa;
4503 char buf[256];
4504 char *ptr;
4505 size_t bufleft = 256;
4506
4507 ptr = buf;
4508
4509 /* NOT IN THE SPECS: see if the same edge is given twice.. */
4510 if ( eid1 == eid2 )
4511 {
4512 lwerror("Cannot heal edge %" LWTFMT_ELEMID
4513 " with itself, try with another", eid1);
4514 return -1;
4515 }
4516 ids[0] = eid1;
4517 ids[1] = eid2;
4518 nedges = 2;
4519 edges = lwt_be_getEdgeById(topo, ids, &nedges, LWT_COL_EDGE_ALL);
4520 if ((nedges == UINT64_MAX) || (edges == NULL))
4521 {
4523 return -1;
4524 }
4525 for ( i=0; i<nedges; ++i )
4526 {
4527 if ( edges[i].edge_id == eid1 ) {
4528 if ( e1 ) {
4529 _lwt_release_edges(edges, nedges);
4530 lwerror("Corrupted topology: multiple edges have id %"
4531 LWTFMT_ELEMID, eid1);
4532 return -1;
4533 }
4534 e1 = &(edges[i]);
4535 }
4536 else if ( edges[i].edge_id == eid2 ) {
4537 if ( e2 ) {
4538 _lwt_release_edges(edges, nedges);
4539 lwerror("Corrupted topology: multiple edges have id %"
4540 LWTFMT_ELEMID, eid2);
4541 return -1;
4542 }
4543 e2 = &(edges[i]);
4544 }
4545 }
4546 if ( ! e1 )
4547 {
4548 _lwt_release_edges(edges, nedges);
4549 lwerror(
4550 "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4551 eid1);
4552 return -1;
4553 }
4554 if ( ! e2 )
4555 {
4556 _lwt_release_edges(edges, nedges);
4557 lwerror(
4558 "SQL/MM Spatial exception - non-existent edge %" LWTFMT_ELEMID,
4559 eid2);
4560 return -1;
4561 }
4562
4563 /* NOT IN THE SPECS: See if any of the two edges are closed. */
4564 if ( e1->start_node == e1->end_node )
4565 {
4566 _lwt_release_edges(edges, nedges);
4567 lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4568 LWTFMT_ELEMID, eid1, eid2);
4569 return -1;
4570 }
4571 if ( e2->start_node == e2->end_node )
4572 {
4573 _lwt_release_edges(edges, nedges);
4574 lwerror("Edge %" LWTFMT_ELEMID " is closed, cannot heal to edge %"
4575 LWTFMT_ELEMID, eid2, eid1);
4576 return -1;
4577 }
4578
4579 /* Find common node */
4580
4581 if ( e1->end_node == e2->start_node )
4582 {
4583 commonnode = e1->end_node;
4584 caseno = 1;
4585 }
4586 else if ( e1->end_node == e2->end_node )
4587 {
4588 commonnode = e1->end_node;
4589 caseno = 2;
4590 }
4591 /* Check if any other edge is connected to the common node, if found */
4592 if ( commonnode != -1 )
4593 {
4594 num_node_edges = 1;
4595 node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4596 &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4597 if (num_node_edges == UINT64_MAX)
4598 {
4599 _lwt_release_edges(edges, nedges);
4601 return -1;
4602 }
4603 for (i=0; i<num_node_edges; ++i)
4604 {
4605 int r;
4606 if ( node_edges[i].edge_id == eid1 ) continue;
4607 if ( node_edges[i].edge_id == eid2 ) continue;
4608 commonnode = -1;
4609 /* append to string, for error message */
4610 if ( bufleft > 0 ) {
4611 r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4612 ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4613 if ( r >= (int) bufleft )
4614 {
4615 bufleft = 0;
4616 buf[252] = '.';
4617 buf[253] = '.';
4618 buf[254] = '.';
4619 buf[255] = '\0';
4620 }
4621 else
4622 {
4623 bufleft -= r;
4624 ptr += r;
4625 }
4626 }
4627 }
4628 lwfree(node_edges);
4629 }
4630
4631 if ( commonnode == -1 )
4632 {
4633 if ( e1->start_node == e2->start_node )
4634 {
4635 commonnode = e1->start_node;
4636 caseno = 3;
4637 }
4638 else if ( e1->start_node == e2->end_node )
4639 {
4640 commonnode = e1->start_node;
4641 caseno = 4;
4642 }
4643 /* Check if any other edge is connected to the common node, if found */
4644 if ( commonnode != -1 )
4645 {
4646 num_node_edges = 1;
4647 node_edges = lwt_be_getEdgeByNode( topo, &commonnode,
4648 &num_node_edges, LWT_COL_EDGE_EDGE_ID );
4649 if (num_node_edges == UINT64_MAX)
4650 {
4651 _lwt_release_edges(edges, nedges);
4653 return -1;
4654 }
4655 for (i=0; i<num_node_edges; ++i)
4656 {
4657 int r;
4658 if ( node_edges[i].edge_id == eid1 ) continue;
4659 if ( node_edges[i].edge_id == eid2 ) continue;
4660 commonnode = -1;
4661 /* append to string, for error message */
4662 if ( bufleft > 0 ) {
4663 r = snprintf(ptr, bufleft, "%s%" LWTFMT_ELEMID,
4664 ( ptr==buf ? "" : "," ), node_edges[i].edge_id);
4665 if ( r >= (int) bufleft )
4666 {
4667 bufleft = 0;
4668 buf[252] = '.';
4669 buf[253] = '.';
4670 buf[254] = '.';
4671 buf[255] = '\0';
4672 }
4673 else
4674 {
4675 bufleft -= r;
4676 ptr += r;
4677 }
4678 }
4679 }
4680 if ( num_node_edges ) lwfree(node_edges);
4681 }
4682 }
4683
4684 if ( commonnode == -1 )
4685 {
4686 _lwt_release_edges(edges, nedges);
4687 if ( ptr != buf )
4688 {
4689 lwerror("SQL/MM Spatial exception - other edges connected (%s)",
4690 buf);
4691 }
4692 else
4693 {
4694 lwerror("SQL/MM Spatial exception - non-connected edges");
4695 }
4696 return -1;
4697 }
4698
4699 if ( ! lwt_be_checkTopoGeomRemNode(topo, commonnode,
4700 eid1, eid2 ) )
4701 {
4702 _lwt_release_edges(edges, nedges);
4704 return -1;
4705 }
4706
4707 /* Construct the geometry of the new edge */
4708 switch (caseno)
4709 {
4710 case 1: /* e1.end = e2.start */
4711 pa = ptarray_clone_deep(e1->geom->points);
4712 //pa = ptarray_merge(pa, e2->geom->points);
4713 ptarray_append_ptarray(pa, e2->geom->points, 0);
4714 newedge.start_node = e1->start_node;
4715 newedge.end_node = e2->end_node;
4716 newedge.next_left = e2->next_left;
4717 newedge.next_right = e1->next_right;
4718 e1freenode = 1;
4719 e2freenode = -1;
4720 e2sign = 1;
4721 break;
4722 case 2: /* e1.end = e2.end */
4723 {
4724 POINTARRAY *pa2;
4725 pa2 = ptarray_clone_deep(e2->geom->points);
4727 pa = ptarray_clone_deep(e1->geom->points);
4728 //pa = ptarray_merge(e1->geom->points, pa);
4729 ptarray_append_ptarray(pa, pa2, 0);
4730 ptarray_free(pa2);
4731 newedge.start_node = e1->start_node;
4732 newedge.end_node = e2->start_node;
4733 newedge.next_left = e2->next_right;
4734 newedge.next_right = e1->next_right;
4735 e1freenode = 1;
4736 e2freenode = 1;
4737 e2sign = -1;
4738 break;
4739 }
4740 case 3: /* e1.start = e2.start */
4741 pa = ptarray_clone_deep(e2->geom->points);
4743 //pa = ptarray_merge(pa, e1->geom->points);
4744 ptarray_append_ptarray(pa, e1->geom->points, 0);
4745 newedge.end_node = e1->end_node;
4746 newedge.start_node = e2->end_node;
4747 newedge.next_left = e1->next_left;
4748 newedge.next_right = e2->next_left;
4749 e1freenode = -1;
4750 e2freenode = -1;
4751 e2sign = -1;
4752 break;
4753 case 4: /* e1.start = e2.end */
4754 pa = ptarray_clone_deep(e2->geom->points);
4755 //pa = ptarray_merge(pa, e1->geom->points);
4756 ptarray_append_ptarray(pa, e1->geom->points, 0);
4757 newedge.end_node = e1->end_node;
4758 newedge.start_node = e2->start_node;
4759 newedge.next_left = e1->next_left;
4760 newedge.next_right = e2->next_right;
4761 e1freenode = -1;
4762 e2freenode = 1;
4763 e2sign = 1;
4764 break;
4765 default:
4766 pa = NULL;
4767 e1freenode = 0;
4768 e2freenode = 0;
4769 e2sign = 0;
4770 _lwt_release_edges(edges, nedges);
4771 lwerror("Coding error: caseno=%d should never happen", caseno);
4772 return -1;
4773 break;
4774 }
4775 newedge.geom = lwline_construct(topo->srid, NULL, pa);
4776
4777 if ( modEdge )
4778 {
4779 /* Update data of the first edge */
4780 newedge.edge_id = eid1;
4781 int result = lwt_be_updateEdgesById(topo,
4782 &newedge,
4783 1,
4786 if (result == -1)
4787 {
4788 lwline_free(newedge.geom);
4789 _lwt_release_edges(edges, nedges);
4791 return -1;
4792 }
4793 else if (result != 1)
4794 {
4795 lwline_free(newedge.geom);
4796 if ( edges ) _lwt_release_edges(edges, nedges);
4797 lwerror("Unexpected error: %" PRIu64 " edges updated when expecting 1", i);
4798 return -1;
4799 }
4800 }
4801 else
4802 {
4803 /* Add new edge */
4804 newedge.edge_id = -1;
4805 newedge.face_left = e1->face_left;
4806 newedge.face_right = e1->face_right;
4807 int result = lwt_be_insertEdges(topo, &newedge, 1);
4808 if (result == -1)
4809 {
4810 lwline_free(newedge.geom);
4811 _lwt_release_edges(edges, nedges);
4813 return -1;
4814 }
4815 else if (result == 0)
4816 {
4817 lwline_free(newedge.geom);
4818 _lwt_release_edges(edges, nedges);
4819 lwerror("Insertion of split edge failed (no reason)");
4820 return -1;
4821 }
4822 }
4823 lwline_free(newedge.geom);
4824
4825 /*
4826 -- Update next_left_edge/next_right_edge for
4827 -- any edge having them still pointing at the edge being removed
4828 -- (eid2 only when modEdge, or both otherwise)
4829 --
4830 -- NOTE:
4831 -- e#freenode is 1 when edge# end node was the common node
4832 -- and -1 otherwise. This gives the sign of possibly found references
4833 -- to its "free" (non connected to other edge) endnode.
4834 -- e2sign is -1 if edge1 direction is opposite to edge2 direction,
4835 -- or 1 otherwise.
4836 --
4837 */
4838
4839 /* update edges connected to e2's boundary from their end node */
4840 seledge.next_left = e2freenode * eid2;
4841 updedge.next_left = e2freenode * newedge.edge_id * e2sign;
4842 int result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT, &updedge, LWT_COL_EDGE_NEXT_LEFT, NULL, 0);
4843 if (result == -1)
4844 {
4845 _lwt_release_edges(edges, nedges);
4847 return -1;
4848 }
4849
4850 /* update edges connected to e2's boundary from their start node */
4851 seledge.next_right = e2freenode * eid2;
4852 updedge.next_right = e2freenode * newedge.edge_id * e2sign;
4853 result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT, &updedge, LWT_COL_EDGE_NEXT_RIGHT, NULL, 0);
4854 if (result == -1)
4855 {
4856 _lwt_release_edges(edges, nedges);
4858 return -1;
4859 }
4860
4861 if ( ! modEdge )
4862 {
4863 /* update edges connected to e1's boundary from their end node */
4864 seledge.next_left = e1freenode * eid1;
4865 updedge.next_left = e1freenode * newedge.edge_id;
4866 result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_LEFT, &updedge, LWT_COL_EDGE_NEXT_LEFT, NULL, 0);
4867 if (result == -1)
4868 {
4869 _lwt_release_edges(edges, nedges);
4871 return -1;
4872 }
4873
4874 /* update edges connected to e1's boundary from their start node */
4875 seledge.next_right = e1freenode * eid1;
4876 updedge.next_right = e1freenode * newedge.edge_id;
4877 result = lwt_be_updateEdges(topo, &seledge, LWT_COL_EDGE_NEXT_RIGHT, &updedge, LWT_COL_EDGE_NEXT_RIGHT, NULL, 0);
4878 if (result == -1)
4879 {
4880 _lwt_release_edges(edges, nedges);
4882 return -1;
4883 }
4884 }
4885
4886 /* delete the edges (only second on modEdge or both) */
4888 if (result == -1)
4889 {
4890 _lwt_release_edges(edges, nedges);
4892 return -1;
4893 }
4894 if ( ! modEdge ) {
4896 if (result == -1)
4897 {
4898 _lwt_release_edges(edges, nedges);
4900 return -1;
4901 }
4902 }
4903
4904 _lwt_release_edges(edges, nedges);
4905
4906 /* delete the common node */
4907 result = lwt_be_deleteNodesById( topo, &commonnode, 1 );
4908 if (result == -1)
4909 {
4911 return -1;
4912 }
4913
4914 /*
4915 --
4916 -- NOT IN THE SPECS:
4917 -- Drop composition rows involving second
4918 -- edge, as the first edge took its space,
4919 -- and all affected TopoGeom have been previously checked
4920 -- for being composed by both edges.
4921 */
4923 eid1, eid2, newedge.edge_id) )
4924 {
4926 return -1;
4927 }
4928
4929 return modEdge ? commonnode : newedge.edge_id;
4930}
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: