23#include <spatialindex/SpatialIndex.h>
35#include <QtAlgorithms>
37#include "moc_qgsvectorlayerdirector.cpp"
39using namespace Qt::StringLiterals;
55 double mLength = std::numeric_limits<double>::max();
63 , mDirectionFieldId( directionFieldId )
64 , mDirectDirectionValue( directDirectionValue )
65 , mReverseDirectionValue( reverseDirectionValue )
66 , mBothDirectionValue( bothDirectionValue )
67 , mDefaultDirection( defaultDirection )
73 return u
"Vector line"_s;
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
126 void visitData(
const IData &d )
override
128 mPoints.append( d.getIdentifier() );
131 void visitData( std::vector<const IData *> &v )
override
137 QVector<int> &mPoints;
145 double fillFactor = 0.7;
146 unsigned long indexCapacity = 10;
147 unsigned long leafCapacity = 10;
148 unsigned long dimension = 2;
149 RTree::RTreeVariant variant = RTree::RV_RSTAR;
152 SpatialIndex::id_type indexId;
153 std::unique_ptr<SpatialIndex::ISpatialIndex> iRTree( RTree::createNewRTree( storageManager, fillFactor, indexCapacity, leafCapacity, dimension, variant, indexId ) );
159 QVector<int> matching;
160 QgsNetworkVisitor visitor( matching );
162 double pt1[2] = { point.
x() - tolerance, point.
y() - tolerance },
163 pt2[2] = { point.
x() + tolerance, point.
y() + tolerance };
164 SpatialIndex::Region searchRegion( pt1, pt2, 2 );
166 index->intersectsWithQuery( searchRegion, visitor );
168 return matching.empty() ? -1 : matching.at( 0 );
173 long featureCount = mSource->featureCount() * 2;
184 snappedPoints = QVector<QgsPointXY>( additionalPoints.size(),
QgsPointXY( 0.0, 0.0 ) );
186 QVector<TiePointInfo> additionalTiePoints( additionalPoints.size() );
189 QVector<QgsPointXY> graphVertices;
192 std::unique_ptr<SpatialIndex::IStorageManager> iStorage( StorageManager::createNewMemoryStorageManager() );
196 auto findPointWithinTolerance = [&iRTree, tolerance](
const QgsPointXY &point ) ->
int {
199 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 )
246 double thisSegmentClosestDist = std::numeric_limits<double>::max();
249 thisSegmentClosestDist = additionalPoint.sqrDist( pt1 );
254 thisSegmentClosestDist = additionalPoint.sqrDistToSegment( pt1.
x(), pt1.
y(), pt2.
x(), pt2.
y(), snappedPoint, 0 );
257 if ( thisSegmentClosestDist < additionalTiePoints[i].mLength )
261 info.
mLength = thisSegmentClosestDist;
264 additionalTiePoints[i] = info;
271 isFirstPoint =
false;
275 feedback->
setProgress( 100.0 *
static_cast<double>( ++step ) / featureCount );
279 QHash<QgsFeatureId, QList<int>> tiePointNetworkFeatures;
283 tiePointNetworkFeatures[info.mNetworkFeatureId] << i;
288 for (
int i = 0; i < snappedPoints.size(); ++i )
291 const QgsPointXY point = snappedPoints.at( i );
292 int ptIdx = findPointWithinTolerance( point );
296 addPointToIndex( point, graphVertices.count() );
297 graphVertices.push_back( point );
302 snappedPoints[i] = graphVertices.at( ptIdx );
306 for (
int i = 0; i < additionalTiePoints.count(); ++i )
308 additionalTiePoints[i].mTiedPoint = snappedPoints.at( additionalTiePoints.at( i ).additionalPointId );
317 for (
const QgsPointXY &point : graphVertices )
324 fit = mSource->getFeatures(
QgsFeatureRequest().setSubsetOfAttributes( requiredAttributes() ) );
330 Direction direction = directionForFeature( feature );
343 bool isFirstPoint =
true;
347 int pPt2idx = findPointWithinTolerance( pt2 );
348 Q_ASSERT_X( pPt2idx >= 0,
"QgsVectorLayerDirectory::makeGraph",
"encountered a vertex which was not present in graph" );
349 pt2 = graphVertices.at( pPt2idx );
353 QMap<double, QgsPointXY> pointsOnArc;
354 pointsOnArc[0.0] = pt1;
355 pointsOnArc[pt1.
sqrDist( pt2 )] = pt2;
357 const QList<int> tiePointsForCurrentFeature = tiePointNetworkFeatures.value( feature.
id() );
358 for (
int tiePointIdx : tiePointsForCurrentFeature )
360 const TiePointInfo &t = additionalTiePoints.at( tiePointIdx );
371 bool isFirstPoint =
true;
372 for (
auto arcPointIt = pointsOnArc.constBegin(); arcPointIt != pointsOnArc.constEnd(); ++arcPointIt )
374 arcPt2 = arcPointIt.value();
376 pt2idx = findPointWithinTolerance( arcPt2 );
377 Q_ASSERT_X( pt2idx >= 0,
"QgsVectorLayerDirectory::makeGraph",
"encountered a vertex which was not present in graph" );
378 arcPt2 = graphVertices.at( pt2idx );
380 if ( !isFirstPoint && arcPt1 != arcPt2 )
390 QgsDebugError( u
"An error occurred while calculating length"_s );
393 QVector<QVariant> prop;
397 prop.push_back( strategy->cost( distance, feature ) );
402 builder->
addEdge( pt1idx, arcPt1, pt2idx, arcPt2, prop );
406 builder->
addEdge( pt2idx, arcPt2, pt1idx, arcPt1, prop );
411 isFirstPoint =
false;
415 isFirstPoint =
false;
420 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.
Wraps a request for features to a vector layer (or directly its vector data provider).
An interface for objects which provide features via a getFeatures method.
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.).
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
Defines strategy used for calculation of the edge cost in networks.
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
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