PostGIS  2.5.1dev-r@@SVN_REVISION@@

◆ _lwt_AddLine()

static LWT_ELEMID* _lwt_AddLine ( LWT_TOPOLOGY topo,
LWLINE line,
double  tol,
int *  nedges,
int  handleFaceSplit 
)
static

Definition at line 5489 of file lwgeom_topo.c.

References _lwt_AddLineEdge(), _LWT_MINTOLERANCE, _lwt_release_edges(), _lwt_release_nodes(), _lwt_split_by_nodes(), _lwt_toposnap(), LWT_TOPOLOGY_T::be_iface, COLLECTIONTYPE, gbox_expand(), LWT_ISO_NODE::geom, LWT_ISO_EDGE::geom, LWCOLLECTION::geoms, LW_ON_INTERRUPT, lwalloc(), lwcollection_as_lwgeom(), lwcollection_construct(), lwcollection_release(), LWDEBUG, LWDEBUGF, LWDEBUGG, lwerror(), lwfree(), lwgeom_as_lwcollection(), lwgeom_as_lwline(), lwgeom_difference(), lwgeom_free(), lwgeom_get_bbox(), lwgeom_intersection(), lwgeom_linemerge(), lwgeom_mindistance2d(), lwgeom_node(), lwgeom_to_wkt(), lwgeom_unaryunion(), lwgeom_union(), lwline_as_lwgeom(), lwline_remove_repeated_points(), lwpoint_as_lwgeom(), lwrealloc(), lwt_be_getEdgeWithinBox2D(), lwt_be_getNodeWithinBox2D(), lwt_be_lastErrorMessage(), LWT_COL_EDGE_ALL, LWT_COL_NODE_ALL, LWTFMT_ELEMID, MULTIPOINTTYPE, LWCOLLECTION::ngeoms, POINTARRAY::npoints, LWLINE::points, LWT_TOPOLOGY_T::srid, LWGEOM::srid, WKT_EXTENDED, GBOX::xmax, GBOX::xmin, GBOX::ymax, and GBOX::ymin.

Referenced by lwt_AddLine(), and lwt_AddLineNoFace().

5491 {
5492  LWGEOM *geomsbuf[1];
5493  LWGEOM **geoms;
5494  int ngeoms;
5495  LWGEOM *noded, *tmp;
5496  LWCOLLECTION *col;
5497  LWT_ELEMID *ids;
5498  LWT_ISO_EDGE *edges;
5499  LWT_ISO_NODE *nodes;
5500  int num, numedges=0, numnodes=0;
5501  int i;
5502  GBOX qbox;
5503 
5504  *nedges = -1; /* error condition, by default */
5505 
5506  /* Get tolerance, if 0 was given */
5507  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)line );
5508  LWDEBUGF(1, "Working tolerance:%.15g", tol);
5509  LWDEBUGF(1, "Input line has srid=%d", line->srid);
5510 
5511  /* Remove consecutive vertices below given tolerance upfront */
5512  if ( tol )
5513  {{
5515  tmp = lwline_as_lwgeom(clean); /* NOTE: might collapse to non-simple */
5516  LWDEBUGG(1, tmp, "Repeated-point removed");
5517  }} else tmp=(LWGEOM*)line;
5518 
5519  /* 1. Self-node */
5520  noded = lwgeom_node((LWGEOM*)tmp);
5521  if ( tmp != (LWGEOM*)line ) lwgeom_free(tmp);
5522  if ( ! noded ) return NULL; /* should have called lwerror already */
5523  LWDEBUGG(1, noded, "Noded");
5524 
5525  qbox = *lwgeom_get_bbox( lwline_as_lwgeom(line) );
5526  LWDEBUGF(1, "Line BOX is %.15g %.15g, %.15g %.15g", qbox.xmin, qbox.ymin,
5527  qbox.xmax, qbox.ymax);
5528  gbox_expand(&qbox, tol);
5529  LWDEBUGF(1, "BOX expanded by %g is %.15g %.15g, %.15g %.15g",
5530  tol, qbox.xmin, qbox.ymin, qbox.xmax, qbox.ymax);
5531 
5532  LWGEOM **nearby = 0;
5533  int nearbyindex=0;
5534  int nearbycount = 0;
5535 
5536  /* 2. Node to edges falling within tol distance */
5537  edges = lwt_be_getEdgeWithinBox2D( topo, &qbox, &numedges, LWT_COL_EDGE_ALL, 0 );
5538  if ( numedges == -1 )
5539  {
5540  lwgeom_free(noded);
5541  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
5542  return NULL;
5543  }
5544  LWDEBUGF(1, "Line has %d points, its bbox intersects %d edges bboxes",
5545  line->points->npoints, numedges);
5546  if ( numedges )
5547  {{
5548  /* collect those whose distance from us is < tol */
5549  nearbycount += numedges;
5550  nearby = lwalloc(nearbycount * sizeof(LWGEOM *));
5551  for (i=0; i<numedges; ++i)
5552  {
5553  LW_ON_INTERRUPT(return NULL);
5554  LWT_ISO_EDGE *e = &(edges[i]);
5555  LWGEOM *g = lwline_as_lwgeom(e->geom);
5556  LWDEBUGF(2, "Computing distance from edge %d having %d points", i, e->geom->points->npoints);
5557  double dist = lwgeom_mindistance2d(g, noded);
5558  /* must be closer than tolerated, unless distance is zero */
5559  if ( dist && dist >= tol ) continue;
5560  nearby[nearbyindex++] = g;
5561  }
5562  LWDEBUGF(2, "Found %d lines closer than tolerance (%g)", nearbyindex, tol);
5563  if ( nearbyindex )
5564  {{
5565  LWCOLLECTION *col;
5566  LWGEOM *iedges; /* just an alias for col */
5567  LWGEOM *snapped;
5568  LWGEOM *set1, *set2;
5569 
5570  LWDEBUGF(1, "Line intersects %d edges", nearbyindex);
5571 
5573  NULL, nearbyindex, nearby);
5574  iedges = lwcollection_as_lwgeom(col);
5575  LWDEBUGG(1, iedges, "Collected edges");
5576  LWDEBUGF(1, "Snapping noded, with srid=%d "
5577  "to interesecting edges, with srid=%d",
5578  noded->srid, iedges->srid);
5579  snapped = _lwt_toposnap(noded, iedges, tol);
5580  lwgeom_free(noded);
5581  LWDEBUGG(1, snapped, "Snapped");
5582  LWDEBUGF(1, "Diffing snapped, with srid=%d "
5583  "and interesecting edges, with srid=%d",
5584  snapped->srid, iedges->srid);
5585  noded = lwgeom_difference(snapped, iedges);
5586  LWDEBUGG(1, noded, "Differenced");
5587  LWDEBUGF(1, "Intersecting snapped, with srid=%d "
5588  "and interesecting edges, with srid=%d",
5589  snapped->srid, iedges->srid);
5590  set1 = lwgeom_intersection(snapped, iedges);
5591  LWDEBUGG(1, set1, "Intersected");
5592  lwgeom_free(snapped);
5593  LWDEBUGF(1, "Linemerging set1, with srid=%d", set1->srid);
5594  set2 = lwgeom_linemerge(set1);
5595  LWDEBUGG(1, set2, "Linemerged");
5596  LWDEBUGG(1, noded, "Noded");
5597  lwgeom_free(set1);
5598  LWDEBUGF(1, "Unioning noded, with srid=%d "
5599  "and set2, with srid=%d", noded->srid, set2->srid);
5600  set1 = lwgeom_union(noded, set2);
5601  lwgeom_free(set2);
5602  lwgeom_free(noded);
5603  noded = set1;
5604  LWDEBUGG(1, set1, "Unioned");
5605 
5606  /* will not release the geoms array */
5607  lwcollection_release(col);
5608  }}
5609  }}
5610 
5611  /* 2.1. Node with existing nodes within tol
5612  * TODO: check if we should be only considering _isolated_ nodes! */
5613  nodes = lwt_be_getNodeWithinBox2D( topo, &qbox, &numnodes, LWT_COL_NODE_ALL, 0 );
5614  if ( numnodes == -1 )
5615  {
5616  lwgeom_free(noded);
5617  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
5618  return NULL;
5619  }
5620  LWDEBUGF(1, "Line bbox intersects %d nodes bboxes", numnodes);
5621  int nearbyedgecount = nearbyindex;
5622  if ( numnodes )
5623  {{
5624  /* collect those whose distance from us is < tol */
5625  nearbycount = nearbyindex + numnodes;
5626  nearby = nearby ?
5627  lwrealloc(nearby, nearbycount * sizeof(LWGEOM *))
5628  :
5629  lwalloc(nearbycount * sizeof(LWGEOM *))
5630  ;
5631  int nn = 0;
5632  for (i=0; i<numnodes; ++i)
5633  {
5634  LWT_ISO_NODE *n = &(nodes[i]);
5635  LWGEOM *g = lwpoint_as_lwgeom(n->geom);
5636  double dist = lwgeom_mindistance2d(g, noded);
5637  /* must be closer than tolerated, unless distance is zero */
5638  if ( dist && dist >= tol ) continue;
5639  nearby[nearbyindex++] = g;
5640  ++nn;
5641  }
5642  }}
5643 
5644  LWDEBUGF(1, "Number of nearby elements is %d", nearbyindex);
5645 
5646  if ( numnodes )
5647  {{
5648  LWCOLLECTION *col;
5649  LWGEOM *elems;
5650 
5652  NULL, nearbyindex, nearby);
5653  elems = lwcollection_as_lwgeom(col);
5654 
5655  LWDEBUGG(1, elems, "Collected nearby elements");
5656 
5657  tmp = _lwt_toposnap(noded, elems, tol);
5658  lwgeom_free(noded);
5659  noded = tmp;
5660  LWDEBUGG(1, noded, "Elements-snapped");
5661 
5662  /* will not release the geoms array */
5663  lwcollection_release(col);
5664 
5665  if ( numnodes )
5666  {{
5668  NULL, nearbyindex-nearbyedgecount,
5669  nearby + nearbyedgecount);
5670  LWGEOM *inodes = lwcollection_as_lwgeom(col);
5671  tmp = _lwt_split_by_nodes(noded, inodes);
5672  lwgeom_free(noded);
5673  noded = tmp;
5674  LWDEBUGG(1, noded, "Node-split");
5675  /* will not release the geoms array */
5676  lwcollection_release(col);
5677  }}
5678 
5679  /*
5680  -- re-node to account for ST_Snap introduced self-intersections
5681  -- See http://trac.osgeo.org/postgis/ticket/1714
5682  -- TODO: consider running UnaryUnion once after all noding
5683  */
5684  tmp = lwgeom_unaryunion(noded);
5685  lwgeom_free(noded);
5686  noded = tmp;
5687  LWDEBUGG(1, noded, "Unary-unioned");
5688 
5689  }}
5690 
5691  LWDEBUG(1, "Freeing up nearby elements");
5692 
5693  if ( nearby ) lwfree(nearby);
5694  if ( nodes ) _lwt_release_nodes(nodes, numnodes);
5695  if ( edges ) _lwt_release_edges(edges, numedges);
5696 
5697  LWDEBUGG(1, noded, "Finally-noded");
5698 
5699  /* 3. For each (now-noded) segment, insert an edge */
5700  col = lwgeom_as_lwcollection(noded);
5701  if ( col )
5702  {
5703  LWDEBUG(1, "Noded line was a collection");
5704  geoms = col->geoms;
5705  ngeoms = col->ngeoms;
5706  }
5707  else
5708  {
5709  LWDEBUG(1, "Noded line was a single geom");
5710  geomsbuf[0] = noded;
5711  geoms = geomsbuf;
5712  ngeoms = 1;
5713  }
5714 
5715  LWDEBUGF(1, "Line was split into %d edges", ngeoms);
5716 
5717  /* TODO: refactor to first add all nodes (re-snapping edges if
5718  * needed) and then check all edges for existing already
5719  * ( so to save a DB scan for each edge to be added )
5720  */
5721  ids = lwalloc(sizeof(LWT_ELEMID)*ngeoms);
5722  num = 0;
5723  for ( i=0; i<ngeoms; ++i )
5724  {
5725  LWT_ELEMID id;
5726  LWGEOM *g = geoms[i];
5727  g->srid = noded->srid;
5728 
5729 #if POSTGIS_DEBUG_LEVEL > 0
5730  {
5731  size_t sz;
5732  char *wkt1 = lwgeom_to_wkt(g, WKT_EXTENDED, 15, &sz);
5733  LWDEBUGF(1, "Component %d of split line is: %s", i, wkt1);
5734  lwfree(wkt1);
5735  }
5736 #endif
5737 
5738  id = _lwt_AddLineEdge( topo, lwgeom_as_lwline(g), tol, handleFaceSplit );
5739  LWDEBUGF(1, "_lwt_AddLineEdge returned %" LWTFMT_ELEMID, id);
5740  if ( id < 0 )
5741  {
5742  lwgeom_free(noded);
5743  lwfree(ids);
5744  return NULL;
5745  }
5746  if ( ! id )
5747  {
5748  LWDEBUGF(1, "Component %d of split line collapsed", i);
5749  continue;
5750  }
5751 
5752  LWDEBUGF(1, "Component %d of split line is edge %" LWTFMT_ELEMID,
5753  i, id);
5754  ids[num++] = id; /* TODO: skip duplicates */
5755  }
5756 
5757  LWDEBUGG(1, noded, "Noded before free");
5758  lwgeom_free(noded);
5759 
5760  /* TODO: XXX remove duplicated ids if not done before */
5761 
5762  *nedges = num;
5763  return ids;
5764 }
static void _lwt_release_nodes(LWT_ISO_NODE *nodes, int num_nodes)
Definition: lwgeom_topo.c:467
LWCOLLECTION * lwcollection_construct(uint8_t type, int srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:43
LWPOINT * geom
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:676
void lwfree(void *mem)
Definition: lwutil.c:244
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
Definition: g_box.c:104
double xmax
Definition: liblwgeom.h:295
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1144
#define MULTIPOINTTYPE
Definition: liblwgeom.h:87
LWLINE * geom
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define LW_ON_INTERRUPT(x)
int32_t srid
Definition: liblwgeom.h:423
uint32_t ngeoms
Definition: liblwgeom.h:509
#define _LWT_MINTOLERANCE(topo, geom)
Definition: lwgeom_topo.c:4857
int32_t srid
Definition: liblwgeom.h:401
double ymin
Definition: liblwgeom.h:296
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:330
double xmin
Definition: liblwgeom.h:294
LWGEOM * lwgeom_node(const LWGEOM *lwgeom_in)
const LWT_BE_IFACE * be_iface
LWGEOM ** geoms
Definition: liblwgeom.h:511
LWGEOM * lwgeom_intersection(const LWGEOM *geom1, const LWGEOM *geom2)
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition: lwgeom.c:734
LWGEOM * lwgeom_difference(const LWGEOM *geom1, const LWGEOM *geom2)
#define LWT_COL_EDGE_ALL
double ymax
Definition: liblwgeom.h:297
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:170
#define LWDEBUGG(level, geom, msg)
Definition: lwgeom_log.h:93
void lwcollection_release(LWCOLLECTION *lwcollection)
Definition: lwcollection.c:36
LWGEOM * lwline_remove_repeated_points(const LWLINE *in, double tolerance)
Definition: lwline.c:448
#define WKT_EXTENDED
Definition: liblwgeom.h:2076
static LWT_ELEMID _lwt_AddLineEdge(LWT_TOPOLOGY *topo, LWLINE *edge, double tol, int handleFaceSplit)
Definition: lwgeom_topo.c:5283
#define LWT_COL_NODE_ALL
LWGEOM * lwgeom_unaryunion(const LWGEOM *geom1)
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:224
static LWGEOM * _lwt_split_by_nodes(const LWGEOM *g, const LWGEOM *nodes)
Definition: lwgeom_topo.c:5467
void * lwrealloc(void *mem, size_t size)
Definition: lwutil.c:237
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:457
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing min distance calculation.
Definition: measures.c:202
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:335
LWT_INT64 LWT_ELEMID
Identifier of topology element.
LWGEOM * lwgeom_union(const LWGEOM *geom1, const LWGEOM *geom2)
void * lwalloc(size_t size)
Definition: lwutil.c:229
static LWGEOM * _lwt_toposnap(LWGEOM *src, LWGEOM *tgt, double tol)
Definition: lwgeom_topo.c:420
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
static LWT_ISO_EDGE * lwt_be_getEdgeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, int *numelems, int fields, int limit)
Definition: lwgeom_topo.c:179
uint32_t e
Definition: geobuf.h:57
static LWT_ISO_NODE * lwt_be_getNodeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, int *numelems, int fields, int limit)
Definition: lwgeom_topo.c:171
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:120
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
#define COLLECTIONTYPE
Definition: liblwgeom.h:90
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:44
LWGEOM * lwgeom_linemerge(const LWGEOM *geom1)
POINTARRAY * points
Definition: liblwgeom.h:424
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:300
uint32_t npoints
Definition: liblwgeom.h:373
Here is the call graph for this function:
Here is the caller graph for this function: