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 };
135 const auto constEdges = edges;
141 int v1 = -1, v2 = -1;
143 if ( point2vertex.contains( p1 ) )
144 v1 = point2vertex.value( p1 );
151 point2vertex[p1] = v1;
155 if ( point2vertex.contains( p2 ) )
156 v2 = point2vertex.value( p2 );
163 point2vertex[p2] = v2;
174 int eIdx = g->
e.count() - 1;
175 g->
v[v1].edges << eIdx;
176 g->
v[v2].edges << eIdx;
185 if ( v1 == -1 || v2 == -1 )
186 return QVector<QgsPointXY>();
190 std::priority_queue< DijkstraQueueItem, std::vector< DijkstraQueueItem >,
comp > Q;
193 QVector<double> D( g.
v.count(), std::numeric_limits<double>::max() );
197 QVector<bool> F( g.
v.count() );
200 QVector<int> S( g.
v.count(), -1 );
217 const int *vuEdges = vu.
edges.constData();
218 int count = vu.
edges.count();
219 for (
int i = 0; i < count; ++i )
224 if ( !F[v] && D[u] + w < D[v] )
236 return QVector<QgsPointXY>();
240 QVector<QgsPointXY> points;
246 QVector<QgsPointXY> edgePoints = e.
coords;
247 if ( edgePoints[0] != g.
v[u].pt )
248 std::reverse( edgePoints.begin(), edgePoints.end() );
249 if ( !points.isEmpty() )
250 points.remove( points.count() - 1 );
251 points << edgePoints;
255 std::reverse( path.begin(), path.end() );
259 std::reverse( points.begin(), points.end() );
268 for (
int i = 0; i < g.
v.count(); ++i )
271 if ( v.
pt == pt || ( std::fabs( v.
pt.
x() - pt.
x() ) < epsilon && std::fabs( v.
pt.
y() - pt.
y() ) < epsilon ) )
283 for (
int i = 0; i < g.
e.count(); ++i )
292 lineVertexAfter = vertexAfter;
302 int count1 = lineVertexAfter;
303 int count2 = points.count() - lineVertexAfter;
305 for (
int i = 0; i < count1; ++i )
307 if ( points[lineVertexAfter - 1] != pt )
310 if ( pt != points[lineVertexAfter] )
312 for (
int i = 0; i < count2; ++i )
313 pts2 << points[i + lineVertexAfter];
321 int eIdx =
point2edge( g, pt, lineVertexAfter );
335 int vIdx = g.
v.count();
336 int e1Idx = g.
e.count();
337 int e2Idx = e1Idx + 1;
343 v.
edges << e1Idx << e2Idx;
356 v1.
edges.replace( v1.
edges.indexOf( eIdx ), e1Idx );
357 v2.
edges.replace( v2.
edges.indexOf( eIdx ), e2Idx );
392 if ( eIdx >= g.
e.count() )
396 for (
int i = 0; i < v1.
edges.count(); ++i )
398 if ( v1.
edges[i] >= g.
e.count() )
399 v1.
edges.remove( i-- );
404 for (
int i = 0; i < v2.
edges.count(); ++i )
406 if ( v2.
edges[i] >= g.
e.count() )
407 v2.
edges.remove( i-- );
424 if ( !segmentizedGeomV2 )
473 bool QgsTracer::initGraph()
478 mHasTopologyProblem =
false;
487 QTime t1, t2, t2a, t3;
490 int featuresCounted = 0;
491 bool enableInvisibleFeature =
QgsSettings().
value( QStringLiteral(
"/qgis/digitizing/snap_invisible_feature" ),
false ).toBool();
496 std::unique_ptr< QgsFeatureRenderer > renderer;
497 std::unique_ptr<QgsRenderContext> ctx;
499 if ( !enableInvisibleFeature && mRenderContext && vl->renderer() )
501 renderer.reset( vl->renderer()->clone() );
506 renderer->startRender( *ctx.get(), vl->fields() );
516 if ( !mExtent.isEmpty() )
527 ctx->expressionContext().setFeature( f );
528 if ( !renderer->willRenderFeature( f, *ctx.get() ) )
537 if ( mMaxFeatureCount != 0 && featuresCounted >= mMaxFeatureCount )
543 renderer->stopRender( *ctx.get() );
546 int timeExtract = t1.elapsed();
552 int timeNodingCall = 0;
565 timeNodingCall = t2a.elapsed();
571 catch ( GEOSException &e )
576 mHasTopologyProblem =
true;
578 QgsDebugMsg( QStringLiteral(
"Tracer Noding Exception: %1" ).arg( e.what() ) );
582 int timeNoding = t2.elapsed();
588 int timeMake = t3.elapsed();
590 Q_UNUSED( timeExtract )
591 Q_UNUSED( timeNoding )
592 Q_UNUSED( timeNodingCall )
594 QgsDebugMsg( QStringLiteral(
"tracer extract %1 ms, noding %2 ms (call %3 ms), make %4 ms" )
595 .arg( timeExtract ).arg( timeNoding ).arg( timeNodingCall ).arg( timeMake ) );
607 if ( mLayers == layers )
618 disconnect( layer, &QObject::destroyed,
this, &QgsTracer::onLayerDestroyed );
631 connect( layer, &QObject::destroyed,
this, &QgsTracer::onLayerDestroyed );
640 mTransformContext = context;
652 if ( mExtent == extent )
666 quadSegments = mOffsetSegments;
667 joinStyle = mOffsetJoinStyle;
668 miterLimit = mOffsetMiterLimit;
673 mOffsetSegments = quadSegments;
674 mOffsetJoinStyle = joinStyle;
675 mOffsetMiterLimit = miterLimit;
692 mGraph.reset(
nullptr );
714 void QgsTracer::onAttributeValueChanged(
QgsFeatureId fid,
int idx,
const QVariant &value )
722 void QgsTracer::onDataChanged( )
727 void QgsTracer::onStyleChanged( )
732 void QgsTracer::onLayerDestroyed( QObject *obj )
735 mLayers.removeAll( static_cast<QgsVectorLayer *>( obj ) );
744 if ( error ) *error = ErrTooManyFeatures;
745 return QVector<QgsPointXY>();
752 int tPrep = t.elapsed();
756 if ( error ) *error = ErrPoint1;
757 return QVector<QgsPointXY>();
761 if ( error ) *error = ErrPoint2;
762 return QVector<QgsPointXY>();
768 int tPath = t2.elapsed();
772 QgsDebugMsg( QStringLiteral(
"path timing: prep %1 ms, path %2 ms" ).arg( tPrep ).arg( tPath ) );
776 if ( !points.isEmpty() && mOffset != 0 )
778 QVector<QgsPointXY> pointsInput( points );
781 std::unique_ptr<QgsAbstractGeometry> linestringOffset( linestringEngine->offsetCurve( mOffset, mOffsetSegments, mOffsetJoinStyle, mOffsetMiterLimit ) );
782 if (
QgsLineString *ls2 = qgsgeometry_cast<QgsLineString *>( linestringOffset.get() ) )
785 for (
int i = 0; i < ls2->numPoints(); ++i )
789 if ( points.count() >= 2 )
791 QgsPointXY res1 = points.first(), res2 = points.last();
792 double diffNormal = res1.
distance( p1 ) + res2.distance( p2 );
793 double diffReversed = res1.
distance( p2 ) + res2.distance( p1 );
794 if ( diffReversed < diffNormal )
795 std::reverse( points.begin(), points.end() );
801 *error = points.isEmpty() ? ErrNoPath : ErrNone;
816 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)
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)
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