QGIS API Documentation  2.14.5-Essen
qgstracer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstracer.cpp
3  --------------------------------------
4  Date : January 2016
5  Copyright : (C) 2016 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgstracer.h"
17 
18 #include "qgsgeometry.h"
19 #include "qgsgeometryutils.h"
20 #include "qgsgeos.h"
21 #include "qgslogger.h"
22 #include "qgsvectorlayer.h"
23 
24 #include <queue>
25 #include <vector>
26 
27 typedef std::pair<int, double> DijkstraQueueItem; // first = vertex index, second = distance
28 
29 // utility comparator for queue items based on distance
30 struct comp
31 {
33  {
34  return a.second > b.second;
35  }
36 };
37 
38 
39 // TODO: move to geometry utils
40 double distance2D( const QgsPolyline& coords )
41 {
42  int np = coords.count();
43  if ( np == 0 )
44  return 0;
45 
46  double x0 = coords[0].x(), y0 = coords[0].y();
47  double x1, y1;
48  double dist = 0;
49  for ( int i = 1; i < np; ++i )
50  {
51  x1 = coords[i].x();
52  y1 = coords[i].y();
53  dist += sqrt(( x1 - x0 ) * ( x1 - x0 ) + ( y1 - y0 ) * ( y1 - y0 ) );
54  x0 = x1;
55  y0 = y1;
56  }
57  return dist;
58 }
59 
60 
61 // TODO: move to geometry utils
62 double closestSegment( const QgsPolyline& pl, const QgsPoint& pt, int& vertexAfter, double epsilon )
63 {
64  double sqrDist = std::numeric_limits<double>::max();
65  const QgsPoint* pldata = pl.constData();
66  int plcount = pl.count();
67  double prevX = pldata[0].x(), prevY = pldata[0].y();
68  double segmentPtX, segmentPtY;
69  for ( int i = 1; i < plcount; ++i )
70  {
71  double currentX = pldata[i].x();
72  double currentY = pldata[i].y();
73  double testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY, segmentPtX, segmentPtY, epsilon );
74  if ( testDist < sqrDist )
75  {
76  sqrDist = testDist;
77  vertexAfter = i;
78  }
79  prevX = currentX;
80  prevY = currentY;
81  }
82  return sqrDist;
83 }
84 
86 
89 {
90  struct E // bidirectional edge
91  {
93  int v1, v2;
96 
97  int otherVertex( int v0 ) const { return v1 == v0 ? v2 : v1; }
98  double weight() const { return distance2D( coords ); }
99  };
100 
101  struct V
102  {
107  };
108 
113 
118 };
119 
120 
122 {
124  g->joinedVertices = 0;
126 
127  Q_FOREACH ( const QgsPolyline& line, edges )
128  {
129  QgsPoint p1( line[0] );
130  QgsPoint p2( line[line.count() - 1] );
131 
132  int v1 = -1, v2 = -1;
133  // get or add vertex 1
134  if ( point2vertex.contains( p1 ) )
135  v1 = point2vertex.value( p1 );
136  else
137  {
138  v1 = g->v.count();
140  v.pt = p1;
141  g->v.append( v );
142  point2vertex[p1] = v1;
143  }
144 
145  // get or add vertex 2
146  if ( point2vertex.contains( p2 ) )
147  v2 = point2vertex.value( p2 );
148  else
149  {
150  v2 = g->v.count();
152  v.pt = p2;
153  g->v.append( v );
154  point2vertex[p2] = v2;
155  }
156 
157  // add edge
159  e.v1 = v1;
160  e.v2 = v2;
161  e.coords = line;
162  g->e.append( e );
163 
164  // link edge to vertices
165  int eIdx = g->e.count() - 1;
166  g->v[v1].edges << eIdx;
167  g->v[v2].edges << eIdx;
168  }
169 
170  return g;
171 }
172 
173 
174 QVector<QgsPoint> shortestPath( const QgsTracerGraph& g, int v1, int v2 )
175 {
176  if ( v1 == -1 || v2 == -1 )
177  return QVector<QgsPoint>(); // invalid input
178 
179  // priority queue to drive Dijkstra:
180  // first of the pair is vertex index, second is distance
181  std::priority_queue< DijkstraQueueItem, std::vector< DijkstraQueueItem >, comp > Q;
182 
183  // shortest distances to each vertex
185  D[v1] = 0;
186 
187  // whether vertices have been already processed
188  QVector<bool> F( g.v.count() );
189 
190  // using which edge there is shortest path to each vertex
191  QVector<int> S( g.v.count(), -1 );
192 
193  int u = -1;
194  Q.push( DijkstraQueueItem( v1, 0 ) );
195 
196  while ( !Q.empty() )
197  {
198  u = Q.top().first; // new vertex to visit
199  Q.pop();
200 
201  if ( u == v2 )
202  break; // we can stop now, there won't be a shorter path
203 
204  if ( F[u] )
205  continue; // ignore previously added path which is actually longer
206 
207  const QgsTracerGraph::V& vu = g.v[u];
208  const int* vuEdges = vu.edges.constData();
209  int count = vu.edges.count();
210  for ( int i = 0; i < count; ++i )
211  {
212  const QgsTracerGraph::E& edge = g.e[ vuEdges[i] ];
213  int v = edge.otherVertex( u );
214  double w = edge.weight();
215  if ( !F[v] && D[u] + w < D[v] )
216  {
217  // found a shorter way to the vertex
218  D[v] = D[u] + w;
219  S[v] = vuEdges[i];
220  Q.push( DijkstraQueueItem( v, D[v] ) );
221  }
222  }
223  F[u] = 1; // mark the vertex as processed (we know the fastest path to it)
224  }
225 
226  if ( u != v2 ) // there's no path to the end vertex
227  return QVector<QgsPoint>();
228 
229  //qDebug("dist %f", D[u]);
230 
231  QVector<QgsPoint> points;
232  QList<int> path;
233  while ( S[u] != -1 )
234  {
235  path << S[u];
236  const QgsTracerGraph::E& e = g.e[S[u]];
237  QVector<QgsPoint> edgePoints = e.coords;
238  if ( edgePoints[0] != g.v[u].pt )
239  std::reverse( edgePoints.begin(), edgePoints.end() );
240  if ( !points.isEmpty() )
241  points.remove( points.count() - 1 ); // chop last one (will be used from next edge)
242  points << edgePoints;
243  u = e.otherVertex( u );
244  }
245 
246  std::reverse( path.begin(), path.end() );
247  //Q_FOREACH (int x, path)
248  // qDebug("e: %d", x);
249 
250  std::reverse( points.begin(), points.end() );
251  return points;
252 }
253 
254 
255 int point2vertex( const QgsTracerGraph& g, const QgsPoint& pt, double epsilon = 1e-6 )
256 {
257  // TODO: use spatial index
258 
259  for ( int i = 0; i < g.v.count(); ++i )
260  {
261  const QgsTracerGraph::V& v = g.v.at( i );
262  if ( v.pt == pt || ( fabs( v.pt.x() - pt.x() ) < epsilon && fabs( v.pt.y() - pt.y() ) < epsilon ) )
263  return i;
264  }
265 
266  return -1;
267 }
268 
269 
270 int point2edge( const QgsTracerGraph& g, const QgsPoint& pt, int& lineVertexAfter, double epsilon = 1e-6 )
271 {
272  int vertexAfter;
273 
274  for ( int i = 0; i < g.e.count(); ++i )
275  {
276  if ( g.inactiveEdges.contains( i ) )
277  continue; // ignore temporarily disabled edges
278 
279  const QgsTracerGraph::E& e = g.e.at( i );
280  double dist = closestSegment( e.coords, pt, vertexAfter, epsilon );
281  if ( dist == 0 )
282  {
283  lineVertexAfter = vertexAfter;
284  return i;
285  }
286  }
287  return -1;
288 }
289 
290 
291 void splitLinestring( const QgsPolyline& points, const QgsPoint& pt, int lineVertexAfter, QgsPolyline& pts1, QgsPolyline& pts2 )
292 {
293  int count1 = lineVertexAfter;
294  int count2 = points.count() - lineVertexAfter;
295 
296  for ( int i = 0; i < count1; ++i )
297  pts1 << points[i];
298  if ( points[lineVertexAfter-1] != pt )
299  pts1 << pt; // repeat if not split exactly at that point
300 
301  if ( pt != points[lineVertexAfter] )
302  pts2 << pt; // repeat if not split exactly at that point
303  for ( int i = 0; i < count2; ++i )
304  pts2 << points[i + lineVertexAfter];
305 }
306 
307 
309 {
310  // find edge where the point is
311  int lineVertexAfter;
312  int eIdx = point2edge( g, pt, lineVertexAfter );
313 
314  //qDebug("e: %d", eIdx);
315 
316  if ( eIdx == -1 )
317  return -1;
318 
319  const QgsTracerGraph::E& e = g.e[eIdx];
320  QgsTracerGraph::V& v1 = g.v[e.v1];
321  QgsTracerGraph::V& v2 = g.v[e.v2];
322 
323  QgsPolyline out1, out2;
324  splitLinestring( e.coords, pt, lineVertexAfter, out1, out2 );
325 
326  int vIdx = g.v.count();
327  int e1Idx = g.e.count();
328  int e2Idx = e1Idx + 1;
329 
330  // prepare new vertex and edges
331 
333  v.pt = pt;
334  v.edges << e1Idx << e2Idx;
335 
337  e1.v1 = e.v1;
338  e1.v2 = vIdx;
339  e1.coords = out1;
340 
342  e2.v1 = vIdx;
343  e2.v2 = e.v2;
344  e2.coords = out2;
345 
346  // update edge connectivity of existing vertices
347  v1.edges.replace( v1.edges.indexOf( eIdx ), e1Idx );
348  v2.edges.replace( v2.edges.indexOf( eIdx ), e2Idx );
349  g.inactiveEdges << eIdx;
350 
351  // add new vertex and edges to the graph
352  g.v.append( v );
353  g.e.append( e1 );
354  g.e.append( e2 );
355  g.joinedVertices++;
356 
357  return vIdx;
358 }
359 
360 
362 {
363  // try to use existing vertex in the graph
364  int v = point2vertex( g, pt );
365  if ( v != -1 )
366  return v;
367 
368  // try to add the vertex to an edge (may fail if point is not on edge)
369  return joinVertexToGraph( g, pt );
370 }
371 
372 
374 {
375  // remove extra vertices and edges
376  g.v.resize( g.v.count() - g.joinedVertices );
377  g.e.resize( g.e.count() - g.joinedVertices * 2 );
378  g.joinedVertices = 0;
379 
380  // fix vertices of deactivated edges
381  Q_FOREACH ( int eIdx, g.inactiveEdges )
382  {
383  if ( eIdx >= g.e.count() )
384  continue;
385  const QgsTracerGraph::E& e = g.e[eIdx];
386  QgsTracerGraph::V& v1 = g.v[e.v1];
387  for ( int i = 0; i < v1.edges.count(); ++i )
388  {
389  if ( v1.edges[i] >= g.e.count() )
390  v1.edges.remove( i-- );
391  }
392  v1.edges << eIdx;
393 
394  QgsTracerGraph::V& v2 = g.v[e.v2];
395  for ( int i = 0; i < v2.edges.count(); ++i )
396  {
397  if ( v2.edges[i] >= g.e.count() )
398  v2.edges.remove( i-- );
399  }
400  v2.edges << eIdx;
401  }
402 
403  g.inactiveEdges.clear();
404 }
405 
406 
408 {
409  switch ( QgsWKBTypes::flatType( g->geometry()->wkbType() ) )
410  {
412  mpl << g->asPolyline();
413  break;
414 
416  Q_FOREACH ( const QgsPolyline& ring, g->asPolygon() )
417  mpl << ring;
418  break;
419 
421  Q_FOREACH ( const QgsPolyline& linestring, g->asMultiPolyline() )
422  mpl << linestring;
423  break;
424 
426  Q_FOREACH ( const QgsPolygon& polygon, g->asMultiPolygon() )
427  Q_FOREACH ( const QgsPolyline& ring, polygon )
428  mpl << ring;
429  break;
430 
431  default:
432  break; // unknown type - do nothing
433  }
434 }
435 
436 // -------------
437 
438 
440  : mGraph( 0 )
441  , mReprojectionEnabled( false )
442  , mMaxFeatureCount( 0 )
443  , mHasTopologyProblem( false )
444 {
445 }
446 
447 
448 bool QgsTracer::initGraph()
449 {
450  if ( mGraph )
451  return true; // already initialized
452 
453  mHasTopologyProblem = false;
454 
455  QgsFeature f;
456  QgsMultiPolyline mpl;
457 
458  // extract linestrings
459 
460  // TODO: use QgsPointLocator as a source for the linework
461 
462  QTime t1, t2, t2a, t3;
463 
464  t1.start();
465  int featuresCounted = 0;
466  Q_FOREACH ( QgsVectorLayer* vl, mLayers )
467  {
468  QgsCoordinateTransform ct( vl->crs(), mCRS );
469 
470  QgsFeatureRequest request;
472  if ( !mExtent.isEmpty() )
473  request.setFilterRect( mReprojectionEnabled ? ct.transformBoundingBox( mExtent, QgsCoordinateTransform::ReverseTransform ) : mExtent );
474 
475  QgsFeatureIterator fi = vl->getFeatures( request );
476  while ( fi.nextFeature( f ) )
477  {
478  if ( !f.constGeometry() )
479  continue;
480 
481  if ( mReprojectionEnabled && !ct.isShortCircuited() )
482  {
483  try
484  {
485  f.geometry()->transform( ct );
486  }
487  catch ( QgsCsException& )
488  {
489  continue; // ignore if the transform failed
490  }
491  }
492 
493  extractLinework( f.constGeometry(), mpl );
494 
495  ++featuresCounted;
496  if ( mMaxFeatureCount != 0 && featuresCounted >= mMaxFeatureCount )
497  return false;
498  }
499  }
500  int timeExtract = t1.elapsed();
501 
502  // resolve intersections
503 
504  t2.start();
505 
506  int timeNodingCall = 0;
507 
508 #if 0
509  // without noding - if data are known to be noded beforehand
510 #else
512 
513  try
514  {
515  t2a.start();
516  // GEOSNode_r may throw an exception
517  GEOSGeometry* allNoded = GEOSNode_r( QgsGeometry::getGEOSHandler(), allGeom->asGeos() );
518  timeNodingCall = t2a.elapsed();
519 
520  QgsGeometry* noded = new QgsGeometry;
521  noded->fromGeos( allNoded );
522  delete allGeom;
523 
524  mpl = noded->asMultiPolyline();
525 
526  delete noded;
527  }
528  catch ( GEOSException &e )
529  {
530  // no big deal... we will just not have nicely noded linework, potentially
531  // missing some intersections
532 
533  mHasTopologyProblem = true;
534 
535  QgsDebugMsg( "Tracer Noding Exception: " + e.what() );
536  }
537 #endif
538 
539  int timeNoding = t2.elapsed();
540 
541  t3.start();
542 
543  mGraph = makeGraph( mpl );
544 
545  int timeMake = t3.elapsed();
546 
547  Q_UNUSED( timeExtract );
548  Q_UNUSED( timeNoding );
549  Q_UNUSED( timeNodingCall );
550  Q_UNUSED( timeMake );
551  QgsDebugMsg( QString( "tracer extract %1 ms, noding %2 ms (call %3 ms), make %4 ms" )
552  .arg( timeExtract ).arg( timeNoding ).arg( timeNodingCall ).arg( timeMake ) );
553  return true;
554 }
555 
557 {
558  invalidateGraph();
559 }
560 
562 {
563  if ( mLayers == layers )
564  return;
565 
566  Q_FOREACH ( QgsVectorLayer* layer, mLayers )
567  {
568  disconnect( layer, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( onFeatureAdded( QgsFeatureId ) ) );
569  disconnect( layer, SIGNAL( featureDeleted( QgsFeatureId ) ), this, SLOT( onFeatureDeleted( QgsFeatureId ) ) );
570  disconnect( layer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ), this, SLOT( onGeometryChanged( QgsFeatureId, QgsGeometry& ) ) );
571  disconnect( layer, SIGNAL( destroyed( QObject* ) ), this, SLOT( onLayerDestroyed( QObject* ) ) );
572  }
573 
574  mLayers = layers;
575 
576  Q_FOREACH ( QgsVectorLayer* layer, mLayers )
577  {
578  connect( layer, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( onFeatureAdded( QgsFeatureId ) ) );
579  connect( layer, SIGNAL( featureDeleted( QgsFeatureId ) ), this, SLOT( onFeatureDeleted( QgsFeatureId ) ) );
580  connect( layer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ), this, SLOT( onGeometryChanged( QgsFeatureId, QgsGeometry& ) ) );
581  connect( layer, SIGNAL( destroyed( QObject* ) ), this, SLOT( onLayerDestroyed( QObject* ) ) );
582  }
583 
584  invalidateGraph();
585 }
586 
588 {
589  if ( mReprojectionEnabled == enabled )
590  return;
591 
592  mReprojectionEnabled = enabled;
593  invalidateGraph();
594 }
595 
597 {
598  if ( mCRS == crs )
599  return;
600 
601  mCRS = crs;
602  invalidateGraph();
603 }
604 
606 {
607  if ( mExtent == extent )
608  return;
609 
610  mExtent = extent;
611  invalidateGraph();
612 }
613 
615 {
616  if ( mGraph )
617  return true;
618 
619  // configuration from derived class?
620  configure();
621 
622  return initGraph();
623 }
624 
625 
627 {
628  delete mGraph;
629  mGraph = 0;
630 }
631 
632 void QgsTracer::onFeatureAdded( QgsFeatureId fid )
633 {
634  Q_UNUSED( fid );
635  invalidateGraph();
636 }
637 
638 void QgsTracer::onFeatureDeleted( QgsFeatureId fid )
639 {
640  Q_UNUSED( fid );
641  invalidateGraph();
642 }
643 
644 void QgsTracer::onGeometryChanged( QgsFeatureId fid, QgsGeometry& geom )
645 {
646  Q_UNUSED( fid );
647  Q_UNUSED( geom );
648  invalidateGraph();
649 }
650 
651 void QgsTracer::onLayerDestroyed( QObject* obj )
652 {
653  // remove the layer before it is completely invalid (static_cast should be the safest cast)
654  mLayers.removeAll( static_cast<QgsVectorLayer*>( obj ) );
655  invalidateGraph();
656 }
657 
659 {
660  init(); // does nothing if the graph exists already
661  if ( !mGraph )
662  {
663  if ( error ) *error = ErrTooManyFeatures;
664  return QVector<QgsPoint>();
665  }
666 
667  QTime t;
668  t.start();
669  int v1 = pointInGraph( *mGraph, p1 );
670  int v2 = pointInGraph( *mGraph, p2 );
671  int tPrep = t.elapsed();
672 
673  if ( v1 == -1 )
674  {
675  if ( error ) *error = ErrPoint1;
676  return QVector<QgsPoint>();
677  }
678  if ( v2 == -1 )
679  {
680  if ( error ) *error = ErrPoint2;
681  return QVector<QgsPoint>();
682  }
683 
684  QTime t2;
685  t2.start();
686  QgsPolyline points = shortestPath( *mGraph, v1, v2 );
687  int tPath = t2.elapsed();
688 
689  Q_UNUSED( tPrep );
690  Q_UNUSED( tPath );
691  QgsDebugMsg( QString( "path timing: prep %1 ms, path %2 ms" ).arg( tPrep ).arg( tPath ) );
692 
693  resetGraph( *mGraph );
694 
695  if ( error )
696  *error = points.isEmpty() ? ErrNoPath : ErrNone;
697 
698  return points;
699 }
700 
702 {
703  init(); // does nothing if the graph exists already
704  if ( !mGraph )
705  return false;
706 
707  if ( point2vertex( *mGraph, pt ) != -1 )
708  return true;
709 
710  int lineVertexAfter;
711  int e = point2edge( *mGraph, pt, lineVertexAfter );
712  return e != -1;
713 }
QVector< E > e
Edges of the graph.
Definition: qgstracer.cpp:112
Wrapper for iterator of features from vector data provider or vector layer.
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
bool isEmpty() const
test if rectangle is empty.
QVector< QgsPoint > shortestPath(const QgsTracerGraph &g, int v1, int v2)
Definition: qgstracer.cpp:174
iterator begin()
int joinedVertices
Temporarily added vertices (for each there are two extra edges)
Definition: qgstracer.cpp:117
virtual void configure()
Allows derived classes to setup the settings just before the tracer is initialized.
Definition: qgstracer.h:106
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
int indexOf(const T &value, int from) const
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
QgsMultiPolyline asMultiPolyline() const
Return contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
int pointInGraph(QgsTracerGraph &g, const QgsPoint &pt)
Definition: qgstracer.cpp:361
QgsPolygon asPolygon() const
Return contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list...
double weight() const
Definition: qgstracer.cpp:98
void setExtent(const QgsRectangle &extent)
Set extent to which graph&#39;s features will be limited (empty extent means no limit) ...
Definition: qgstracer.cpp:605
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
int point2vertex(const QgsTracerGraph &g, const QgsPoint &pt, double epsilon=1e-6)
Definition: qgstracer.cpp:255
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
QgsTracerGraph * makeGraph(const QVector< QgsPolyline > &edges)
Definition: qgstracer.cpp:121
T & first()
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
double closestSegment(const QgsPolyline &pl, const QgsPoint &pt, int &vertexAfter, double epsilon)
Definition: qgstracer.cpp:62
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
double x() const
Get the x value of the point.
Definition: qgspoint.h:128
std::pair< int, double > DijkstraQueueItem
Definition: qgstracer.cpp:27
QgsMultiPolygon asMultiPolygon() const
Return contents of the geometry as a multi polygon if wkbType is WKBMultiPolygon, otherwise an empty ...
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
int elapsed() const
QSet< int > inactiveEdges
Temporarily removed edges.
Definition: qgstracer.cpp:115
Max feature count threshold was reached while reading features.
Definition: qgstracer.h:88
void setLayers(const QList< QgsVectorLayer * > &layers)
Set layers used for tracing.
Definition: qgstracer.cpp:561
int removeAll(const T &value)
void remove(int i)
PathError
Possible errors that may happen when calling findShortestPath()
Definition: qgstracer.h:85
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
void fromGeos(GEOSGeometry *geos)
Set the geometry, feeding in a geometry in GEOS format.
void splitLinestring(const QgsPolyline &points, const QgsPoint &pt, int lineVertexAfter, QgsPolyline &pts1, QgsPolyline &pts2)
Definition: qgstracer.cpp:291
const T * constData() const
Simple graph structure for shortest path search.
Definition: qgstracer.cpp:88
QList< QgsVectorLayer * > layers() const
Get layers used for tracing.
Definition: qgstracer.h:46
const GEOSGeometry * asGeos(double precision=0) const
Returns a geos geometry.
A class to represent a point.
Definition: qgspoint.h:65
iterator end()
const T value(const Key &key) const
void resetGraph(QgsTracerGraph &g)
Definition: qgstracer.cpp:373
QgsGeometry * geometry()
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:76
bool contains(const T &value) const
static QgsGeometry * fromMultiPolyline(const QgsMultiPolyline &multiline)
Creates a new geometry from a QgsMultiPolyline object.
End point cannot be joined to the graph.
Definition: qgstracer.h:90
QgsPolyline asPolyline() const
Return contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list...
QVector< V > v
Vertices of the graph.
Definition: qgstracer.cpp:110
void setCrsTransformEnabled(bool enabled)
Set whether to do reprojection to destination CRS.
Definition: qgstracer.cpp:587
QVector< int > edges
indices of adjacent edges (used in Dijkstra algorithm)
Definition: qgstracer.cpp:106
static GEOSContextHandle_t getGEOSHandler()
Return GEOS context handle.
bool isEmpty() const
QgsPoint pt
location of the vertex
Definition: qgstracer.cpp:104
void invalidateGraph()
Destroy the existing graph structure if any (de-initialize)
Definition: qgstracer.cpp:626
Class for storing a coordinate reference system (CRS)
int count(const T &value) const
bool isPointSnapped(const QgsPoint &pt)
Find out whether the point is snapped to a vertex or edge (i.e. it can be used for tracing start/stop...
Definition: qgstracer.cpp:701
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
Class for doing transforms between two map coordinate systems.
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
qint64 QgsFeatureId
Definition: qgsfeature.h:31
No error.
Definition: qgstracer.h:87
void replace(int i, const T &value)
QgsRectangle extent() const
Get extent to which graph&#39;s features will be limited (empty extent means no limit) ...
Definition: qgstracer.h:61
double y() const
Get the y value of the point.
Definition: qgspoint.h:136
const QgsCoordinateReferenceSystem & crs() const
Returns layer&#39;s spatial reference system.
QVector< QgsPoint > coords
coordinates of the edge (including endpoints)
Definition: qgstracer.cpp:95
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon)
Returns the squared distance between a point and a line.
bool init()
Build the internal data structures.
Definition: qgstracer.cpp:614
void start()
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:366
bool contains(const Key &key) const
Custom exception class for Coordinate Reference System related exceptions.
double distance2D(const QgsPolyline &coords)
Definition: qgstracer.cpp:40
bool nextFeature(QgsFeature &f)
void clear()
bool operator()(DijkstraQueueItem a, DijkstraQueueItem b)
Definition: qgstracer.cpp:32
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int otherVertex(int v0) const
Definition: qgstracer.cpp:97
Represents a vector layer which manages a vector based data sets.
bool empty() const
iterator end()
void extractLinework(const QgsGeometry *g, QgsMultiPolyline &mpl)
Definition: qgstracer.cpp:407
int point2edge(const QgsTracerGraph &g, const QgsPoint &pt, int &lineVertexAfter, double epsilon=1e-6)
Definition: qgstracer.cpp:270
iterator begin()
void destroyed(QObject *obj)
QVector< QgsPoint > findShortestPath(const QgsPoint &p1, const QgsPoint &p2, PathError *error=nullptr)
Given two points, find the shortest path and return points on the way.
Definition: qgstracer.cpp:658
QgsFeatureRequest & setFilterRect(const QgsRectangle &rect)
Set rectangle from which features will be taken.
Points are not connected in the graph.
Definition: qgstracer.h:91
Start point cannot be joined to the graph.
Definition: qgstracer.h:89
int v1
vertices that the edge connects
Definition: qgstracer.cpp:93
int joinVertexToGraph(QgsTracerGraph &g, const QgsPoint &pt)
Definition: qgstracer.cpp:308
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Set CRS used for tracing.
Definition: qgstracer.cpp:596