PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ _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 6515 of file lwgeom_topo.c.

6516 {
6517  uint64_t i, j;
6518  scored_pointer *sorted = lwalloc(sizeof(scored_pointer)*num);
6519  LWT_ISO_EDGE *edges2 = NULL;
6520  LWT_ISO_NODE node;
6521  node.node_id = 0; /* unneeded, but hushes a compiler warning */
6522  LWGEOM *prj; /* incoming point projected to nearest node or edge */
6523  const POINT2D *pt = NULL; /* projected 2d point */
6524  LWGEOM *lwpoint = lwpoint_as_lwgeom(point);
6525 
6526  j = 0;
6527  for (i=0; i<num; ++i)
6528  {
6529  double dist;
6530  LWT_ISO_EDGE *e = edges+i;
6531  /* TODO: use square distance */
6532  dist = lwgeom_mindistance2d(lwline_as_lwgeom(edges[i].geom), lwpoint_as_lwgeom(point));
6533  LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " distance: %.15g", e->edge_id, dist);
6534  if ( dist >= tol ) continue;
6535  sorted[j].ptr = e;
6536  sorted[j++].score = dist;
6537  }
6538  if ( ! j )
6539  {
6540  lwfree(sorted);
6541  return 0;
6542  }
6543 
6544  num = j;
6545  qsort(sorted, num, sizeof(scored_pointer), compare_scored_pointer);
6546  edges2 = lwalloc(sizeof(LWT_ISO_EDGE)*num);
6547  for (j=0, i=0; i<num; ++i)
6548  {
6549  if ( sorted[i].score == sorted[0].score )
6550  {
6551  edges2[j++] = *((LWT_ISO_EDGE*)sorted[i].ptr);
6552  }
6553  else
6554  {
6555  edges2[j++] = *((LWT_ISO_EDGE*)sorted[i].ptr);
6556  //lwline_free(((LWT_ISO_EDGE*)sorted[i].ptr)->geom);
6557  }
6558  }
6559  num = j;
6560  lwfree(sorted);
6561  edges = edges2;
6562 
6563  /* project point to closest edge */
6564  prj = lwgeom_closest_point(lwline_as_lwgeom(edges[0].geom), lwpoint);
6565  if ( moved ) *moved = lwgeom_same(prj, lwpoint) ? 0 : 1;
6566  if ( lwgeom_has_z(lwpoint) )
6567  {{
6568  /*
6569  -- This is a workaround for ClosestPoint lack of Z support:
6570  -- http://trac.osgeo.org/postgis/ticket/2033
6571  */
6572  LWGEOM *tmp;
6573  double z;
6574  POINT4D p4d;
6575  LWPOINT *prjpt;
6576  /* add Z to "prj" */
6577  tmp = lwgeom_force_3dz(prj, 0);
6578  prjpt = lwgeom_as_lwpoint(tmp);
6579  getPoint4d_p(point->point, 0, &p4d);
6580  z = p4d.z;
6581  getPoint4d_p(prjpt->point, 0, &p4d);
6582  p4d.z = z;
6583  ptarray_set_point4d(prjpt->point, 0, &p4d);
6584  lwgeom_free(prj);
6585  prj = tmp;
6586  }}
6587 
6588  LWDEBUGG(1, prj, "Projected point");
6589  node.geom = lwgeom_as_lwpoint(prj);
6590  node.containing_face = -1; /* means not-isolated */
6591 
6592  for (i=0; i<num; ++i)
6593  {
6594  /* The point is on or near one or more edges,
6595  * project it to closest edge and then split all
6596  * edges to it
6597  */
6598 
6599  LWT_ISO_EDGE *e = &(edges[i]);
6600  LWGEOM *g = lwline_as_lwgeom(e->geom);
6601  int contains;
6602  LWT_ELEMID edge_id = e->edge_id;
6603 
6604  if ( i )
6605  {{
6606  int ret = _lwt_SnapEdgeToExistingNode( topo, &node, e, tol );
6607  if ( ret != 0 ) {
6608  lwerror("Something went wrong with _lwt_SnapEdgeToExistingNode");
6609  return -1;
6610  }
6611  continue;
6612  }}
6613 
6614  LWDEBUGF(1, "Splitting closest edge %" LWTFMT_ELEMID, edge_id);
6615 
6616  pt = getPoint2d_cp(lwgeom_as_lwpoint(prj)->point, 0);
6618  if ( ! contains )
6619  {{
6620  LWGEOM *snapedge;
6621  LWLINE *snapline;
6622  POINT4D p1, p2;
6623 
6624  LWDEBUGF(1, "Edge %" LWTFMT_ELEMID
6625  " does not contain projected point to it",
6626  edge_id);
6627 
6628 #if 0
6629  /* In order to reduce the robustness issues, we'll pick
6630  * an edge that contains the projected point, if possible */
6631  if ( i+1 < num )
6632  {
6633  LWDEBUG(1, "But there's another to check");
6634  //lwgeom_free(prj);
6635  continue;
6636  }
6637 #endif
6638 
6639  snapedge = _lwt_toposnap(g, prj, tol);
6640  snapline = lwgeom_as_lwline(snapedge);
6641 
6642  LWDEBUGF(1, "Edge snapped with tolerance %g", tol);
6643 
6644  /* TODO: check if snapping did anything ? */
6645 #if POSTGIS_DEBUG_LEVEL > 0
6646  {
6647  size_t sz;
6648  char *wkt1 = lwgeom_to_wkt(g, WKT_EXTENDED, 15, &sz);
6649  char *wkt2 = lwgeom_to_wkt(snapedge, WKT_EXTENDED, 15, &sz);
6650  LWDEBUGF(1, "Edge %s snapped became %s", wkt1, wkt2);
6651  lwfree(wkt1);
6652  lwfree(wkt2);
6653  }
6654 #endif
6655 
6656 
6657  /*
6658  -- Snapping currently snaps the first point below tolerance
6659  -- so may possibly move first point. See ticket #1631
6660  */
6661  getPoint4d_p(e->geom->points, 0, &p1);
6662  getPoint4d_p(snapline->points, 0, &p2);
6663  LWDEBUGF(1, "Edge first point is %g %g, "
6664  "snapline first point is %g %g",
6665  p1.x, p1.y, p2.x, p2.y);
6666  if ( p1.x != p2.x || p1.y != p2.y )
6667  {
6668  LWDEBUG(1, "Snapping moved first point, re-adding it");
6669  if ( LW_SUCCESS != ptarray_insert_point(snapline->points, &p1, 0) )
6670  {
6671  lwgeom_free(prj);
6672  lwgeom_free(snapedge);
6673  lwerror("GEOS exception on Contains: %s", lwgeom_geos_errmsg);
6674  return -1;
6675  }
6676 #if POSTGIS_DEBUG_LEVEL > 0
6677  {
6678  size_t sz;
6679  char *wkt1 = lwgeom_to_wkt(g, WKT_EXTENDED, 15, &sz);
6680  LWDEBUGF(1, "Tweaked snapline became %s", wkt1);
6681  lwfree(wkt1);
6682  }
6683 #endif
6684  }
6685 #if POSTGIS_DEBUG_LEVEL > 0
6686  else {
6687  LWDEBUG(1, "Snapping did not move first point");
6688  }
6689 #endif
6690 
6691  if ( -1 == lwt_ChangeEdgeGeom( topo, edge_id, snapline ) )
6692  {
6693  /* TODO: should have invoked lwerror already, leaking memory */
6694  lwgeom_free(prj);
6695  lwgeom_free(snapedge);
6696  lwerror("lwt_ChangeEdgeGeom failed");
6697  return -1;
6698  }
6699  lwgeom_free(snapedge);
6700  }}
6701 #if POSTGIS_DEBUG_LEVEL > 0
6702  else
6703  {{
6704  size_t sz;
6705  char *wkt1 = lwgeom_to_wkt(g, WKT_EXTENDED, 15, &sz);
6706  char *wkt2 = lwgeom_to_wkt(prj, WKT_EXTENDED, 15, &sz);
6707  LWDEBUGF(1, "Edge %s contains projected point %s", wkt1, wkt2);
6708  lwfree(wkt1);
6709  lwfree(wkt2);
6710  }}
6711 #endif
6712 
6713  /* TODO: pass 1 as last argument (skipChecks) ? */
6714  node.node_id = lwt_ModEdgeSplit( topo, edge_id, node.geom, 0 );
6715  if ( -1 == node.node_id )
6716  {
6717  /* TODO: should have invoked lwerror already, leaking memory */
6718  lwgeom_free(prj);
6719  lwerror("lwt_ModEdgeSplit failed");
6720  return -1;
6721  }
6722 
6723  /*
6724  * TODO: decimate the two new edges with the given tolerance ?
6725  *
6726  * the edge identifiers to decimate would be: edge_id and "id"
6727  * The problem here is that decimation of existing edges
6728  * may introduce intersections or topological inconsistencies,
6729  * for example:
6730  *
6731  * - A node may end up falling on the other side of the edge
6732  * - The decimated edge might intersect another existing edge
6733  *
6734  */
6735 
6736  }
6737 
6738  lwgeom_free(prj);
6739 
6740  if ( edges2 ) lwfree(edges2);
6741  return node.node_id;
6742 }
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:179
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
char lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
geom1 same as geom2 iff
Definition: lwgeom.c:591
LWGEOM * lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures.c:55
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1218
#define WKT_EXTENDED
Definition: liblwgeom.h:2218
#define LW_SUCCESS
Definition: liblwgeom.h:97
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom, double zval)
Definition: lwgeom.c:799
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:934
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 * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:344
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing min distance calculation.
Definition: measures.c:200
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:125
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:708
void * lwalloc(size_t size)
Definition: lwutil.c:227
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:763
#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 int _lwt_SnapEdgeToExistingNode(LWT_TOPOLOGY *topo, LWT_ISO_NODE *node, LWT_ISO_EDGE *edge, double tol)
Definition: lwgeom_topo.c:5290
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.
Definition: lwgeom_topo.c:1052
static int compare_scored_pointer(const void *si1, const void *si2)
Definition: lwgeom_topo.c:5071
static LWGEOM * _lwt_toposnap(LWGEOM *src, LWGEOM *tgt, double tol)
Definition: lwgeom_topo.c:423
int lwt_ChangeEdgeGeom(LWT_TOPOLOGY *topo, LWT_ELEMID edge_id, LWLINE *geom)
Changes the shape of an edge without affecting the topology structure.
Definition: lwgeom_topo.c:3260
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
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwinline.h:127
POINTARRAY * points
Definition: liblwgeom.h:483
POINTARRAY * point
Definition: liblwgeom.h:471
LWLINE * geom
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: