32#include <QtAlgorithms>
34#include <spatialindex/SpatialIndex.h>
50 double mLength = std::numeric_limits<double>::max();
58 const QString &directDirectionValue,
59 const QString &reverseDirectionValue,
60 const QString &bothDirectionValue,
63 , mDirectionFieldId( directionFieldId )
64 , mDirectDirectionValue( directDirectionValue )
65 , mReverseDirectionValue( reverseDirectionValue )
66 , mBothDirectionValue( bothDirectionValue )
67 , mDefaultDirection( defaultDirection )
73 return QStringLiteral(
"Vector line" );
80 if ( mDirectionFieldId != -1 )
81 attrs.insert( mDirectionFieldId );
85 attrs.unite( strategy->requiredAttributes() );
87 return qgis::setToList( attrs );
92 if ( mDirectionFieldId < 0 )
93 return mDefaultDirection;
95 QString
str = feature.
attribute( mDirectionFieldId ).toString();
96 if (
str == mBothDirectionValue )
100 else if (
str == mDirectDirectionValue )
104 else if (
str == mReverseDirectionValue )
110 return mDefaultDirection;
115class QgsNetworkVisitor :
public SpatialIndex::IVisitor
118 explicit QgsNetworkVisitor( QVector< int > &pointIndexes )
119 : mPoints( pointIndexes ) {}
121 void visitNode(
const INode &n )
override
124 void visitData(
const IData &d )
override
126 mPoints.append( d.getIdentifier() );
129 void visitData( std::vector<const IData *> &v )
override
133 QVector< int > &mPoints;
141 double fillFactor = 0.7;
142 unsigned long indexCapacity = 10;
143 unsigned long leafCapacity = 10;
144 unsigned long dimension = 2;
145 RTree::RTreeVariant variant = RTree::RV_RSTAR;
148 SpatialIndex::id_type indexId;
149 std::unique_ptr< SpatialIndex::ISpatialIndex > iRTree( RTree::createNewRTree( storageManager, fillFactor, indexCapacity,
150 leafCapacity, dimension, variant, indexId ) );
156 QVector< int > matching;
157 QgsNetworkVisitor visitor( matching );
159 double pt1[2] = { point.
x() - tolerance, point.
y() - tolerance },
160 pt2[2] = { point.
x() + tolerance, point.
y() + tolerance };
161 SpatialIndex::Region searchRegion( pt1, pt2, 2 );
163 index->intersectsWithQuery( searchRegion, visitor );
165 return matching.empty() ? -1 : matching.at( 0 );
169 QVector< QgsPointXY > &snappedPoints,
QgsFeedback *feedback )
const
182 snappedPoints = QVector< QgsPointXY >( additionalPoints.size(),
QgsPointXY( 0.0, 0.0 ) );
184 QVector< TiePointInfo > additionalTiePoints( additionalPoints.size() );
187 QVector< QgsPointXY > graphVertices;
190 std::unique_ptr< SpatialIndex::IStorageManager > iStorage( StorageManager::createNewMemoryStorageManager() );
194 auto findPointWithinTolerance = [&iRTree, tolerance](
const QgsPointXY & point )->
int
198 auto addPointToIndex = [&iRTree](
const QgsPointXY & point,
int index )
200 double coords[] = {point.
x(), point.
y()};
201 iRTree->insertData( 0,
nullptr, SpatialIndex::Point( coords, 2 ), index );
221 bool isFirstPoint =
true;
226 int pt2Idx = findPointWithinTolerance( pt2 ) ;
230 addPointToIndex( pt2, graphVertices.count() );
231 graphVertices.push_back( pt2 );
236 pt2 = graphVertices.at( pt2Idx );
243 for (
const QgsPointXY &additionalPoint : additionalPoints )
247 double thisSegmentClosestDist = std::numeric_limits<double>::max();
250 thisSegmentClosestDist = additionalPoint.sqrDist( pt1 );
256 pt2.
x(), pt2.
y(), snappedPoint, 0 );
259 if ( thisSegmentClosestDist < additionalTiePoints[ i ].mLength )
263 info.
mLength = thisSegmentClosestDist;
266 additionalTiePoints[ i ] = info;
273 isFirstPoint =
false;
277 feedback->
setProgress( 100.0 *
static_cast< double >( ++step ) / featureCount );
281 QHash< QgsFeatureId, QList< int > > tiePointNetworkFeatures;
285 tiePointNetworkFeatures[ info.mNetworkFeatureId ] << i;
290 for (
int i = 0; i < snappedPoints.size(); ++i )
293 const QgsPointXY point = snappedPoints.at( i );
294 int ptIdx = findPointWithinTolerance( point );
298 addPointToIndex( point, graphVertices.count() );
299 graphVertices.push_back( point );
304 snappedPoints[ i ] = graphVertices.at( ptIdx );
308 for (
int i = 0; i < additionalTiePoints.count(); ++i )
310 additionalTiePoints[ i ].mTiedPoint = snappedPoints.at( additionalTiePoints.at( i ).additionalPointId );
319 for (
const QgsPointXY &point : graphVertices )
332 Direction direction = directionForFeature( feature );
345 bool isFirstPoint =
true;
349 int pPt2idx = findPointWithinTolerance( pt2 );
350 Q_ASSERT_X( pPt2idx >= 0,
"QgsVectorLayerDirectory::makeGraph",
"encountered a vertex which was not present in graph" );
351 pt2 = graphVertices.at( pPt2idx );
355 QMap< double, QgsPointXY > pointsOnArc;
356 pointsOnArc[ 0.0 ] = pt1;
357 pointsOnArc[ pt1.
sqrDist( pt2 )] = pt2;
359 const QList< int > tiePointsForCurrentFeature = tiePointNetworkFeatures.value( feature.
id() );
360 for (
int tiePointIdx : tiePointsForCurrentFeature )
362 const TiePointInfo &t = additionalTiePoints.at( tiePointIdx );
373 bool isFirstPoint =
true;
374 for (
auto arcPointIt = pointsOnArc.constBegin(); arcPointIt != pointsOnArc.constEnd(); ++arcPointIt )
376 arcPt2 = arcPointIt.value();
378 pt2idx = findPointWithinTolerance( arcPt2 );
379 Q_ASSERT_X( pt2idx >= 0,
"QgsVectorLayerDirectory::makeGraph",
"encountered a vertex which was not present in graph" );
380 arcPt2 = graphVertices.at( pt2idx );
382 if ( !isFirstPoint && arcPt1 != arcPt2 )
392 QgsDebugError( QStringLiteral(
"An error occurred while calculating length" ) );
395 QVector< QVariant > prop;
399 prop.push_back( strategy->cost( distance, feature ) );
405 builder->
addEdge( pt1idx, arcPt1, pt2idx, arcPt2, prop );
410 builder->
addEdge( pt2idx, arcPt2, pt1idx, arcPt1, prop );
415 isFirstPoint =
false;
419 isFirstPoint =
false;
424 feedback->
setProgress( 100.0 *
static_cast< double >( ++step ) / featureCount );
@ MultiLineString
MultiLineString.
Custom exception class for Coordinate Reference System related exceptions.
double measureLine(const QVector< QgsPointXY > &points) const
Measures the length of a line with multiple segments.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
An interface for objects which provide features via a getFeatures method.
virtual QgsCoordinateReferenceSystem sourceCrs() const =0
Returns the coordinate reference system for features in the source.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const =0
Returns an iterator for the features in the source.
virtual long long featureCount() const =0
Returns the number of features contained in the source, or -1 if the feature count is unknown.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Determine interface for creating a graph.
virtual void addVertex(int id, const QgsPointXY &pt)
Add vertex to the graph.
QgsCoordinateReferenceSystem destinationCrs() const
Returns destinaltion CRS.
QgsDistanceArea * distanceArea()
Returns measurement tool.
virtual void addEdge(int pt1id, const QgsPointXY &pt1, int pt2id, const QgsPointXY &pt2, const QVector< QVariant > &strategies)
Add edge to the graph.
double topologyTolerance() const
Returns topology tolerance.
bool coordinateTransformationEnabled() const
Returns coordinate transformation enabled.
QList< QgsNetworkStrategy * > mStrategies
QgsNetworkStrategy defines strategy used for calculation of the edge cost.
A class to represent a 2D point.
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPointXY &minDistPoint, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Returns the minimum distance between this point and a segment.
QString name() const override
Returns director name.
void makeGraph(QgsGraphBuilderInterface *builder, const QVector< QgsPointXY > &additionalPoints, QVector< QgsPointXY > &snappedPoints, QgsFeedback *feedback=nullptr) const override
Make a graph using QgsGraphBuilder.
Direction
Edge direction Edge can be one-way with direct flow (one can move only from the start point to the en...
@ DirectionForward
One-way direct.
@ DirectionBackward
One-way reversed.
QgsVectorLayerDirector(QgsFeatureSource *source, int directionFieldId, const QString &directDirectionValue, const QString &reverseDirectionValue, const QString &bothDirectionValue, Direction defaultDirection)
Default constructor.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
#define QgsDebugError(str)
std::unique_ptr< SpatialIndex::ISpatialIndex > createVertexSpatialIndex(SpatialIndex::IStorageManager &storageManager)
int findClosestVertex(const QgsPointXY &point, SpatialIndex::ISpatialIndex *index, double tolerance)
TiePointInfo(int additionalPointId, QgsFeatureId featureId, const QgsPointXY &start, const QgsPointXY &end)
QgsFeatureId mNetworkFeatureId