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

◆ _lwt_SplitAllEdgesToNewNode()

static LWT_ELEMID _lwt_SplitAllEdgesToNewNode ( LWT_TOPOLOGY topo,
LWT_ISO_EDGE edges,
uint64_t  num,
LWPOINT point,
double  tol,
int *  moved 
)
static

Definition at line 6632 of file lwgeom_topo.c.

6633{
6634 uint64_t i, j;
6635 scored_pointer *sorted = lwalloc(sizeof(scored_pointer)*num);
6636 LWT_ISO_EDGE *edges2 = NULL;
6637 LWT_ISO_NODE node;
6638 node.node_id = 0; /* unneeded, but hushes a compiler warning */
6639 LWGEOM *prj; /* incoming point projected to nearest node or edge */
6640 const POINT2D *pt = NULL; /* projected 2d point */
6641 LWGEOM *lwpoint = lwpoint_as_lwgeom(point);
6642
6643 j = 0;
6644 for (i=0; i<num; ++i)
6645 {
6646 double dist;
6647 LWT_ISO_EDGE *e = edges+i;
6648 /* TODO: use square distance */
6649 dist = lwgeom_mindistance2d(lwline_as_lwgeom(edges[i].geom), lwpoint_as_lwgeom(point));
6650 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " distance: %.15g", e->edge_id, dist);
6651 if ( dist >= tol ) continue;
6652 sorted[j].ptr = e;
6653 sorted[j++].score = dist;
6654 }
6655 if ( ! j )
6656 {
6657 lwfree(sorted);
6658 return 0;
6659 }
6660
6661 num = j;
6662 qsort(sorted, num, sizeof(scored_pointer), compare_scored_pointer);
6663 edges2 = lwalloc(sizeof(LWT_ISO_EDGE)*num);
6664 for (j=0, i=0; i<num; ++i)
6665 {
6666 if ( sorted[i].score == sorted[0].score )
6667 {
6668 edges2[j++] = *((LWT_ISO_EDGE*)sorted[i].ptr);
6669 }
6670 else
6671 {
6672 edges2[j++] = *((LWT_ISO_EDGE*)sorted[i].ptr);
6673 //lwline_free(((LWT_ISO_EDGE*)sorted[i].ptr)->geom);
6674 }
6675 }
6676 num = j;
6677 lwfree(sorted);
6678 edges = edges2;
6679
6680 /* project point to closest edge */
6681 prj = lwgeom_closest_point(lwline_as_lwgeom(edges[0].geom), lwpoint);
6682 if ( moved ) *moved = lwgeom_same(prj, lwpoint) ? 0 : 1;
6683 if ( lwgeom_has_z(lwpoint) )
6684 {{
6685 /*
6686 -- This is a workaround for ClosestPoint lack of Z support:
6687 -- http://trac.osgeo.org/postgis/ticket/2033
6688 */
6689 LWGEOM *tmp;
6690 double z;
6691 POINT4D p4d;
6692 LWPOINT *prjpt;
6693 /* add Z to "prj" */
6694 tmp = lwgeom_force_3dz(prj, 0);
6695 prjpt = lwgeom_as_lwpoint(tmp);
6696 getPoint4d_p(point->point, 0, &p4d);
6697 z = p4d.z;
6698 getPoint4d_p(prjpt->point, 0, &p4d);
6699 p4d.z = z;
6700 ptarray_set_point4d(prjpt->point, 0, &p4d);
6701 lwgeom_free(prj);
6702 prj = tmp;
6703 }}
6704
6705 LWDEBUGG(1, prj, "Projected point");
6706 node.geom = lwgeom_as_lwpoint(prj);
6707 node.containing_face = -1; /* means not-isolated */
6708
6709 for (i=0; i<num; ++i)
6710 {
6711 /* The point is on or near one or more edges,
6712 * project it to closest edge and then split all
6713 * edges to it
6714 */
6715
6716 LWT_ISO_EDGE *e = &(edges[i]);
6717 LWGEOM *g = lwline_as_lwgeom(e->geom);
6718 int contains;
6719 LWT_ELEMID edge_id = e->edge_id;
6720
6721 if ( i )
6722 {{
6723 int ret = _lwt_SnapEdgeToExistingNode( topo, &node, e, tol );
6724 if ( ret != 0 ) {
6725 lwerror("Something went wrong with _lwt_SnapEdgeToExistingNode");
6726 return -1;
6727 }
6728 continue;
6729 }}
6730
6731 LWDEBUGF(1, "Splitting closest edge %" LWTFMT_ELEMID, edge_id);
6732
6733 pt = getPoint2d_cp(lwgeom_as_lwpoint(prj)->point, 0);
6735 if ( ! contains )
6736 {{
6737 LWGEOM *snapedge;
6738 LWLINE *snapline;
6739 POINT4D p1, p2;
6740
6741 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID
6742 " does not contain projected point to it",
6743 edge_id);
6744
6745#if 0
6746 /* In order to reduce the robustness issues, we'll pick
6747 * an edge that contains the projected point, if possible */
6748 if ( i+1 < num )
6749 {
6750 LWDEBUG(1, "But there's another to check");
6751 //lwgeom_free(prj);
6752 continue;
6753 }
6754#endif
6755
6756 snapedge = _lwt_toposnap(g, prj, tol);
6757 snapline = lwgeom_as_lwline(snapedge);
6758
6759 LWDEBUGF(1, "Edge snapped with tolerance %g", tol);
6760
6761 /* TODO: check if snapping did anything ? */
6762#if POSTGIS_DEBUG_LEVEL > 0
6763 {
6764 size_t sz;
6765 char *wkt1 = lwgeom_to_wkt(g, WKT_EXTENDED, 15, &sz);
6766 char *wkt2 = lwgeom_to_wkt(snapedge, WKT_EXTENDED, 15, &sz);
6767 LWDEBUGF(1, "Edge %s snapped became %s", wkt1, wkt2);
6768 lwfree(wkt1);
6769 lwfree(wkt2);
6770 }
6771#endif
6772
6773
6774 /*
6775 -- Snapping currently snaps the first point below tolerance
6776 -- so may possibly move first point. See ticket #1631
6777 */
6778 getPoint4d_p(e->geom->points, 0, &p1);
6779 getPoint4d_p(snapline->points, 0, &p2);
6780 LWDEBUGF(1, "Edge first point is %g %g, "
6781 "snapline first point is %g %g",
6782 p1.x, p1.y, p2.x, p2.y);
6783 if ( p1.x != p2.x || p1.y != p2.y )
6784 {
6785 LWDEBUG(1, "Snapping moved first point, re-adding it");
6786 if ( LW_SUCCESS != ptarray_insert_point(snapline->points, &p1, 0) )
6787 {
6788 lwgeom_free(prj);
6789 lwgeom_free(snapedge);
6790 lwerror("GEOS exception on Contains: %s", lwgeom_geos_errmsg);
6791 return -1;
6792 }
6793#if POSTGIS_DEBUG_LEVEL > 0
6794 {
6795 size_t sz;
6796 char *wkt1 = lwgeom_to_wkt(g, WKT_EXTENDED, 15, &sz);
6797 LWDEBUGF(1, "Tweaked snapline became %s", wkt1);
6798 lwfree(wkt1);
6799 }
6800#endif
6801 }
6802#if POSTGIS_DEBUG_LEVEL > 0
6803 else {
6804 LWDEBUG(1, "Snapping did not move first point");
6805 }
6806#endif
6807
6808 if ( -1 == lwt_ChangeEdgeGeom( topo, edge_id, snapline ) )
6809 {
6810 /* TODO: should have invoked lwerror already, leaking memory */
6811 lwgeom_free(prj);
6812 lwgeom_free(snapedge);
6813 lwerror("lwt_ChangeEdgeGeom failed");
6814 return -1;
6815 }
6816 lwgeom_free(snapedge);
6817 }}
6818#if POSTGIS_DEBUG_LEVEL > 0
6819 else
6820 {{
6821 size_t sz;
6822 char *wkt1 = lwgeom_to_wkt(g, WKT_EXTENDED, 15, &sz);
6823 char *wkt2 = lwgeom_to_wkt(prj, WKT_EXTENDED, 15, &sz);
6824 LWDEBUGF(1, "Edge %s contains projected point %s", wkt1, wkt2);
6825 lwfree(wkt1);
6826 lwfree(wkt2);
6827 }}
6828#endif
6829
6830 /* TODO: pass 1 as last argument (skipChecks) ? */
6831 node.node_id = lwt_ModEdgeSplit( topo, edge_id, node.geom, 0 );
6832 if ( -1 == node.node_id )
6833 {
6834 /* TODO: should have invoked lwerror already, leaking memory */
6835 lwgeom_free(prj);
6836 lwerror("lwt_ModEdgeSplit failed");
6837 return -1;
6838 }
6839
6840 /*
6841 * TODO: decimate the two new edges with the given tolerance ?
6842 *
6843 * the edge identifiers to decimate would be: edge_id and "id"
6844 * The problem here is that decimation of existing edges
6845 * may introduce intersections or topological inconsistencies,
6846 * for example:
6847 *
6848 * - A node may end up falling on the other side of the edge
6849 * - The decimated edge might intersect another existing edge
6850 *
6851 */
6852
6853 }
6854
6855 lwgeom_free(prj);
6856
6857 if ( edges2 ) lwfree(edges2);
6858 return node.node_id;
6859}
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:372
char lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
geom1 same as geom2 iff
Definition lwgeom.c:619
LWGEOM * lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures.c:55
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1246
#define WKT_EXTENDED
Definition liblwgeom.h:2221
#define LW_SUCCESS
Definition liblwgeom.h:97
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom, double zval)
Definition lwgeom.c:827
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition lwout_wkt.c:708
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition lwgeom.c:962
void * lwalloc(size_t size)
Definition lwutil.c:227
int ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, uint32_t where)
Insert a point into an existing POINTARRAY.
Definition ptarray.c:85
void lwfree(void *mem)
Definition lwutil.c:248
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:367
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing min distance calculation.
Definition measures.c:212
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition lwgeom_api.c:125
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition lwgeom.c:207
void ptarray_set_point4d(POINTARRAY *pa, uint32_t n, const POINT4D *p4d)
Definition lwgeom_api.c:369
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
Definition ptarray.c:1031
#define LW_BOUNDARY
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWTFMT_ELEMID
Datum contains(PG_FUNCTION_ARGS)
#define LWDEBUG(level, msg)
Definition lwgeom_log.h:101
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
#define LWDEBUGG(level, geom, msg)
Definition lwgeom_log.h:111
static LWGEOM * _lwt_toposnap(LWGEOM *src, LWGEOM *tgt, double tol)
static int _lwt_SnapEdgeToExistingNode(LWT_TOPOLOGY *topo, LWT_ISO_NODE *node, LWT_ISO_EDGE *edge, double tol)
LWT_ELEMID lwt_ModEdgeSplit(LWT_TOPOLOGY *topo, LWT_ELEMID edge, LWPOINT *pt, int skipISOChecks)
Split an edge by a node, modifying the original edge and adding a new one.
static int compare_scored_pointer(const void *si1, const void *si2)
int lwt_ChangeEdgeGeom(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, LWLINE *geom)
Changes the shape of an edge without affecting the topology structure.
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition lwinline.h:127
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:97
POINTARRAY * points
Definition liblwgeom.h:483
POINTARRAY * point
Definition liblwgeom.h:471
LWT_ELEMID edge_id
LWT_ELEMID node_id
LWT_ELEMID containing_face
LWPOINT * geom
double x
Definition liblwgeom.h:414
double z
Definition liblwgeom.h:414
double y
Definition liblwgeom.h:414

References _lwt_SnapEdgeToExistingNode(), _lwt_toposnap(), compare_scored_pointer(), LWT_ISO_NODE::containing_face, contains(), LWT_ISO_EDGE::edge_id, LWT_ISO_NODE::geom, LWT_ISO_EDGE::geom, getPoint2d_cp(), getPoint4d_p(), LW_BOUNDARY, LW_SUCCESS, lwalloc(), LWDEBUG, LWDEBUGF, LWDEBUGG, lwerror(), lwfree(), lwgeom_as_lwline(), lwgeom_as_lwpoint(), lwgeom_closest_point(), lwgeom_force_3dz(), lwgeom_free(), lwgeom_geos_errmsg, lwgeom_has_z(), lwgeom_mindistance2d(), lwgeom_same(), lwgeom_to_wkt(), lwline_as_lwgeom(), lwpoint_as_lwgeom(), lwt_ChangeEdgeGeom(), lwt_ModEdgeSplit(), LWTFMT_ELEMID, LWT_ISO_NODE::node_id, LWPOINT::point, LWLINE::points, ptarray_contains_point_partial(), ptarray_insert_point(), ptarray_set_point4d(), scored_pointer_t::ptr, scored_pointer_t::score, WKT_EXTENDED, POINT4D::x, POINT4D::y, and POINT4D::z.

Referenced by _lwt_AddPoint().

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