40 return a.second > b.second;
48 int np = coords.count();
52 double x0 = coords[0].x(), y0 = coords[0].y();
55 for (
int i = 1; i < np; ++i )
59 dist += std::sqrt( ( x1 - x0 ) * ( x1 - x0 ) + ( y1 - y0 ) * ( y1 - y0 ) );
70 double sqrDist = std::numeric_limits<double>::max();
72 int plcount = pl.count();
73 double prevX = pldata[0].
x(), prevY = pldata[0].
y();
74 double segmentPtX, segmentPtY;
75 for (
int i = 1; i < plcount; ++i )
77 double currentX = pldata[i].
x();
78 double currentY = pldata[i].
y();
80 if ( testDist < sqrDist )
125 int joinedVertices{ 0 };
140 int v1 = -1, v2 = -1;
142 if ( point2vertex.contains( p1 ) )
143 v1 = point2vertex.value( p1 );
150 point2vertex[p1] = v1;
154 if ( point2vertex.contains( p2 ) )
155 v2 = point2vertex.value( p2 );
162 point2vertex[p2] = v2;
173 int eIdx = g->
e.count() - 1;
174 g->
v[v1].edges << eIdx;
175 g->
v[v2].edges << eIdx;
184 if ( v1 == -1 || v2 == -1 )
185 return QVector<QgsPointXY>();
189 std::priority_queue< DijkstraQueueItem, std::vector< DijkstraQueueItem >,
comp > Q;
192 QVector<double> D( g.
v.count(), std::numeric_limits<double>::max() );
196 QVector<bool> F( g.
v.count() );
199 QVector<int> S( g.
v.count(), -1 );
216 const int *vuEdges = vu.
edges.constData();
217 int count = vu.
edges.count();
218 for (
int i = 0; i < count; ++i )
223 if ( !F[v] && D[u] + w < D[v] )
235 return QVector<QgsPointXY>();
239 QVector<QgsPointXY> points;
245 QVector<QgsPointXY> edgePoints = e.
coords;
246 if ( edgePoints[0] != g.
v[u].pt )
247 std::reverse( edgePoints.begin(), edgePoints.end() );
248 if ( !points.isEmpty() )
249 points.remove( points.count() - 1 );
250 points << edgePoints;
254 std::reverse( path.begin(), path.end() );
258 std::reverse( points.begin(), points.end() );
267 for (
int i = 0; i < g.
v.count(); ++i )
270 if ( v.
pt == pt || ( std::fabs( v.
pt.
x() - pt.
x() ) < epsilon && std::fabs( v.
pt.
y() - pt.
y() ) < epsilon ) )
282 for (
int i = 0; i < g.
e.count(); ++i )
291 lineVertexAfter = vertexAfter;
301 int count1 = lineVertexAfter;
302 int count2 = points.count() - lineVertexAfter;
304 for (
int i = 0; i < count1; ++i )
306 if ( points[lineVertexAfter - 1] != pt )
309 if ( pt != points[lineVertexAfter] )
311 for (
int i = 0; i < count2; ++i )
312 pts2 << points[i + lineVertexAfter];
320 int eIdx =
point2edge( g, pt, lineVertexAfter );
334 int vIdx = g.
v.count();
335 int e1Idx = g.
e.count();
336 int e2Idx = e1Idx + 1;
342 v.
edges << e1Idx << e2Idx;
355 v1.
edges.replace( v1.
edges.indexOf( eIdx ), e1Idx );
356 v2.
edges.replace( v2.
edges.indexOf( eIdx ), e2Idx );
391 if ( eIdx >= g.
e.count() )
395 for (
int i = 0; i < v1.
edges.count(); ++i )
397 if ( v1.
edges[i] >= g.
e.count() )
398 v1.
edges.remove( i-- );
403 for (
int i = 0; i < v2.
edges.count(); ++i )
405 if ( v2.
edges[i] >= g.
e.count() )
406 v2.
edges.remove( i-- );
423 if ( !segmentizedGeomV2 )
461 bool QgsTracer::initGraph()
466 mHasTopologyProblem =
false;
475 QTime t1, t2, t2a, t3;
478 int featuresCounted = 0;
479 bool enableInvisibleFeature =
QgsSettings().
value( QStringLiteral(
"/qgis/digitizing/snap_invisible_feature" ),
false ).toBool();
484 std::unique_ptr< QgsFeatureRenderer > renderer;
485 std::unique_ptr<QgsRenderContext> ctx;
487 if ( !enableInvisibleFeature && mRenderContext && vl->renderer() )
489 renderer.reset( vl->renderer()->clone() );
494 renderer->startRender( *ctx.get(), vl->fields() );
504 if ( !mExtent.isEmpty() )
515 ctx->expressionContext().setFeature( f );
516 if ( !renderer->willRenderFeature( f, *ctx.get() ) )
525 if ( mMaxFeatureCount != 0 && featuresCounted >= mMaxFeatureCount )
531 renderer->stopRender( *ctx.get() );
534 int timeExtract = t1.elapsed();
540 int timeNodingCall = 0;
553 timeNodingCall = t2a.elapsed();
559 catch ( GEOSException &e )
564 mHasTopologyProblem =
true;
566 QgsDebugMsg( QStringLiteral(
"Tracer Noding Exception: %1" ).arg( e.what() ) );
570 int timeNoding = t2.elapsed();
576 int timeMake = t3.elapsed();
578 Q_UNUSED( timeExtract );
579 Q_UNUSED( timeNoding );
580 Q_UNUSED( timeNodingCall );
581 Q_UNUSED( timeMake );
582 QgsDebugMsg( QStringLiteral(
"tracer extract %1 ms, noding %2 ms (call %3 ms), make %4 ms" )
583 .arg( timeExtract ).arg( timeNoding ).arg( timeNodingCall ).arg( timeMake ) );
595 if ( mLayers == layers )
606 disconnect( layer, &QObject::destroyed,
this, &QgsTracer::onLayerDestroyed );
619 connect( layer, &QObject::destroyed,
this, &QgsTracer::onLayerDestroyed );
628 mTransformContext = context;
640 if ( mExtent == extent )
654 quadSegments = mOffsetSegments;
655 joinStyle = mOffsetJoinStyle;
656 miterLimit = mOffsetMiterLimit;
661 mOffsetSegments = quadSegments;
662 mOffsetJoinStyle = joinStyle;
663 mOffsetMiterLimit = miterLimit;
680 mGraph.reset(
nullptr );
702 void QgsTracer::onAttributeValueChanged(
QgsFeatureId fid,
int idx,
const QVariant &value )
710 void QgsTracer::onDataChanged( )
715 void QgsTracer::onStyleChanged( )
720 void QgsTracer::onLayerDestroyed( QObject *obj )
723 mLayers.removeAll( static_cast<QgsVectorLayer *>( obj ) );
732 if ( error ) *error = ErrTooManyFeatures;
733 return QVector<QgsPointXY>();
740 int tPrep = t.elapsed();
744 if ( error ) *error = ErrPoint1;
745 return QVector<QgsPointXY>();
749 if ( error ) *error = ErrPoint2;
750 return QVector<QgsPointXY>();
756 int tPath = t2.elapsed();
760 QgsDebugMsg( QStringLiteral(
"path timing: prep %1 ms, path %2 ms" ).arg( tPrep ).arg( tPath ) );
764 if ( !points.isEmpty() && mOffset != 0 )
766 QVector<QgsPointXY> pointsInput( points );
769 std::unique_ptr<QgsAbstractGeometry> linestringOffset( linestringEngine->offsetCurve( mOffset, mOffsetSegments, mOffsetJoinStyle, mOffsetMiterLimit ) );
770 if (
QgsLineString *ls2 = qgsgeometry_cast<QgsLineString *>( linestringOffset.get() ) )
773 for (
int i = 0; i < ls2->numPoints(); ++i )
777 if ( points.count() >= 2 )
779 QgsPointXY res1 = points.first(), res2 = points.last();
780 double diffNormal = res1.
distance( p1 ) + res2.distance( p2 );
781 double diffReversed = res1.
distance( p2 ) + res2.distance( p1 );
782 if ( diffReversed < diffNormal )
783 std::reverse( points.begin(), points.end() );
789 *error = points.isEmpty() ? ErrNoPath : ErrNone;
804 int e =
point2edge( *mGraph, pt, lineVertexAfter );
QVector< E > e
Edges of the graph.
QgsFeatureRequest & setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the destination crs for feature's geometries.
Wrapper for iterator of features from vector data provider or vector layer.
A rectangle specified with double values.
int pointInGraph(QgsTracerGraph &g, const QgsPointXY &pt)
QVector< QgsPointXY > coords
coordinates of the edge (including endpoints)
This class is a composition of two QSettings instances:
int point2vertex(const QgsTracerGraph &g, const QgsPointXY &pt, double epsilon=1e-6)
void setRenderContext(const QgsRenderContext *renderContext)
Sets the renderContext used for tracing only on visible features.
int joinedVertices
Temporarily added vertices (for each there are two extra edges)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Features may be filtered, i.e. some features may not be rendered (categorized, rule based ...
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
A class to represent a 2D point.
QgsExpressionContext * expressionContext()
Returns the expression context used to evaluate filter expressions.
static QgsGeometry fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Creates a new geometry from a QgsMultiPolylineXY object.
void setExtent(const QgsRectangle &extent)
Sets extent to which graph's features will be limited (empty extent means no limit) ...
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsTracerGraph * makeGraph(const QVector< QgsPolylineXY > &edges)
A geometry is the spatial representation of a feature.
void splitLinestring(const QgsPolylineXY &points, const QgsPointXY &pt, int lineVertexAfter, QgsPolylineXY &pts1, QgsPolylineXY &pts2)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
const QgsCoordinateReferenceSystem & crs
bool hasGeometry() const
Returns true if the feature has an associated geometry.
int joinVertexToGraph(QgsTracerGraph &g, const QgsPointXY &pt)
void featureDeleted(QgsFeatureId fid)
Emitted when a feature has been deleted.
std::pair< int, double > DijkstraQueueItem
void styleChanged()
Signal emitted whenever a change affects the layer's style.
static GEOSContextHandle_t getGEOSHandler()
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
void setOffsetParameters(int quadSegments, int joinStyle, double miterLimit)
Set extra parameters for offset curve algorithm (used when offset is non-zero)
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets the crs and transform context used for tracing.
QSet< int > inactiveEdges
Temporarily removed edges.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
QgsPolygonXY asPolygon() const
Returns the contents of the geometry as a polygon.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
PathError
Possible errors that may happen when calling findShortestPath()
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
void setOffset(double offset)
Set offset in map units that should be applied to the traced paths returned from findShortestPath().
int point2edge(const QgsTracerGraph &g, const QgsPointXY &pt, int &lineVertexAfter, double epsilon=1e-6)
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geometry)
Is emitted whenever a geometry change is done in the edit buffer.
QVector< QgsPointXY > shortestPath(const QgsTracerGraph &g, int v1, int v2)
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Is emitted whenever an attribute value change is done in the edit buffer.
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer.
Simple graph structure for shortest path search.
Abstract base class for all geometries.
Contains information about the context in which a coordinate transform is executed.
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
void resetGraph(QgsTracerGraph &g)
double closestSegment(const QgsPolylineXY &pl, const QgsPointXY &pt, int &vertexAfter, double epsilon)
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
double distance2D(const QgsPolylineXY &coords)
QgsTracer()
Constructor for QgsTracer.
QVector< V > v
Vertices of the graph.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Contains information about the context of a rendering operation.
QVector< int > edges
indices of adjacent edges (used in Dijkstra algorithm)
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0)
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
void invalidateGraph()
Destroy the existing graph structure if any (de-initialize)
void extractLinework(const QgsGeometry &g, QgsMultiPolylineXY &mpl)
Line string geometry type, with support for z-dimension and m-values.
QgsPointXY pt
location of the vertex
This class represents a coordinate reference system (CRS).
QVector< QgsPointXY > findShortestPath(const QgsPointXY &p1, const QgsPointXY &p2, PathError *error=nullptr)
Given two points, find the shortest path and return points on the way.
void dataChanged()
Data of layer changed.
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.
void offsetParameters(int &quadSegments, int &joinStyle, double &miterLimit)
Gets extra parameters for offset curve algorithm (used when offset is non-zero)
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
bool isPointSnapped(const QgsPointXY &pt)
Find out whether the point is snapped to a vertex or edge (i.e. it can be used for tracing start/stop...
static QgsGeometry geometryFromGeos(GEOSGeometry *geos)
Creates a new QgsGeometry object, feeding in a geometry in GEOS format.
int otherVertex(int v0) const
bool operator()(DijkstraQueueItem a, DijkstraQueueItem b)
Represents a vector layer which manages a vector based data sets.
static Type flatType(Type type)
Returns the flat type for a WKB type.
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
QgsMultiPolygonXY asMultiPolygon() const
Returns the contents of the geometry as a multi-polygon.
void setLayers(const QList< QgsVectorLayer *> &layers)
Sets layers used for tracing.
int v1
vertices that the edge connects