23#include <spatialindex/SpatialIndex.h>
35#include <QtAlgorithms>
37#include "moc_qgsvectorlayerdirector.cpp"
53 double mLength = std::numeric_limits<double>::max();
61 , mDirectionFieldId( directionFieldId )
62 , mDirectDirectionValue( directDirectionValue )
63 , mReverseDirectionValue( reverseDirectionValue )
64 , mBothDirectionValue( bothDirectionValue )
65 , mDefaultDirection( defaultDirection )
71 return QStringLiteral(
"Vector line" );
78 if ( mDirectionFieldId != -1 )
79 attrs.insert( mDirectionFieldId );
83 attrs.unite( strategy->requiredAttributes() );
85 return qgis::setToList( attrs );
90 if ( mDirectionFieldId < 0 )
91 return mDefaultDirection;
93 QString str = feature.
attribute( mDirectionFieldId ).toString();
94 if ( str == mBothDirectionValue )
98 else if ( str == mDirectDirectionValue )
102 else if ( str == mReverseDirectionValue )
108 return mDefaultDirection;
113class QgsNetworkVisitor :
public SpatialIndex::IVisitor
116 explicit QgsNetworkVisitor( QVector<int> &pointIndexes )
117 : mPoints( pointIndexes ) {}
119 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
135 QVector<int> &mPoints;
143 double fillFactor = 0.7;
144 unsigned long indexCapacity = 10;
145 unsigned long leafCapacity = 10;
146 unsigned long dimension = 2;
147 RTree::RTreeVariant variant = RTree::RV_RSTAR;
150 SpatialIndex::id_type indexId;
151 std::unique_ptr<SpatialIndex::ISpatialIndex> iRTree( RTree::createNewRTree( storageManager, fillFactor, indexCapacity, leafCapacity, dimension, variant, indexId ) );
157 QVector<int> matching;
158 QgsNetworkVisitor visitor( matching );
160 double pt1[2] = { point.
x() - tolerance, point.
y() - tolerance },
161 pt2[2] = { point.
x() + tolerance, point.
y() + tolerance };
162 SpatialIndex::Region searchRegion( pt1, pt2, 2 );
164 index->intersectsWithQuery( searchRegion, visitor );
166 return matching.empty() ? -1 : matching.at( 0 );
171 long featureCount = mSource->featureCount() * 2;
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 {
197 auto addPointToIndex = [&iRTree](
const QgsPointXY &point,
int index ) {
198 double coords[] = { point.
x(), point.
y() };
199 iRTree->insertData( 0,
nullptr, SpatialIndex::Point( coords, 2 ), index );
219 bool isFirstPoint =
true;
224 int pt2Idx = findPointWithinTolerance( pt2 );
228 addPointToIndex( pt2, graphVertices.count() );
229 graphVertices.push_back( pt2 );
234 pt2 = graphVertices.at( pt2Idx );
241 for (
const QgsPointXY &additionalPoint : additionalPoints )
244 double thisSegmentClosestDist = std::numeric_limits<double>::max();
247 thisSegmentClosestDist = additionalPoint.sqrDist( pt1 );
252 thisSegmentClosestDist = additionalPoint.sqrDistToSegment( pt1.
x(), pt1.
y(), pt2.
x(), pt2.
y(), snappedPoint, 0 );
255 if ( thisSegmentClosestDist < additionalTiePoints[i].mLength )
259 info.
mLength = thisSegmentClosestDist;
262 additionalTiePoints[i] = info;
269 isFirstPoint =
false;
273 feedback->
setProgress( 100.0 *
static_cast<double>( ++step ) / featureCount );
277 QHash<QgsFeatureId, QList<int>> tiePointNetworkFeatures;
281 tiePointNetworkFeatures[info.mNetworkFeatureId] << i;
286 for (
int i = 0; i < snappedPoints.size(); ++i )
289 const QgsPointXY point = snappedPoints.at( i );
290 int ptIdx = findPointWithinTolerance( point );
294 addPointToIndex( point, graphVertices.count() );
295 graphVertices.push_back( point );
300 snappedPoints[i] = graphVertices.at( ptIdx );
304 for (
int i = 0; i < additionalTiePoints.count(); ++i )
306 additionalTiePoints[i].mTiedPoint = snappedPoints.at( additionalTiePoints.at( i ).additionalPointId );
315 for (
const QgsPointXY &point : graphVertices )
322 fit = mSource->getFeatures(
QgsFeatureRequest().setSubsetOfAttributes( requiredAttributes() ) );
328 Direction direction = directionForFeature( feature );
341 bool isFirstPoint =
true;
345 int pPt2idx = findPointWithinTolerance( pt2 );
346 Q_ASSERT_X( pPt2idx >= 0,
"QgsVectorLayerDirectory::makeGraph",
"encountered a vertex which was not present in graph" );
347 pt2 = graphVertices.at( pPt2idx );
351 QMap<double, QgsPointXY> pointsOnArc;
352 pointsOnArc[0.0] = pt1;
353 pointsOnArc[pt1.
sqrDist( pt2 )] = pt2;
355 const QList<int> tiePointsForCurrentFeature = tiePointNetworkFeatures.value( feature.
id() );
356 for (
int tiePointIdx : tiePointsForCurrentFeature )
358 const TiePointInfo &t = additionalTiePoints.at( tiePointIdx );
369 bool isFirstPoint =
true;
370 for (
auto arcPointIt = pointsOnArc.constBegin(); arcPointIt != pointsOnArc.constEnd(); ++arcPointIt )
372 arcPt2 = arcPointIt.value();
374 pt2idx = findPointWithinTolerance( arcPt2 );
375 Q_ASSERT_X( pt2idx >= 0,
"QgsVectorLayerDirectory::makeGraph",
"encountered a vertex which was not present in graph" );
376 arcPt2 = graphVertices.at( pt2idx );
378 if ( !isFirstPoint && arcPt1 != arcPt2 )
388 QgsDebugError( QStringLiteral(
"An error occurred while calculating length" ) );
391 QVector<QVariant> prop;
395 prop.push_back( strategy->cost( distance, feature ) );
400 builder->
addEdge( pt1idx, arcPt1, pt2idx, arcPt2, prop );
404 builder->
addEdge( pt2idx, arcPt2, pt1idx, arcPt1, prop );
409 isFirstPoint =
false;
413 isFirstPoint =
false;
418 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