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(
static_cast<int>( 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 );
226 bool isFirstPoint =
true;
231 int pt2Idx = findPointWithinTolerance( pt2 );
235 addPointToIndex( pt2,
static_cast<int>( graphVertices.count() ) );
236 graphVertices.push_back( pt2 );
241 pt2 = graphVertices.at( pt2Idx );
248 for (
const QgsPointXY &additionalPoint : additionalPoints )
251 double thisSegmentClosestDist = std::numeric_limits<double>::max();
254 thisSegmentClosestDist = additionalPoint.sqrDist( pt1 );
259 thisSegmentClosestDist = additionalPoint.sqrDistToSegment( pt1.
x(), pt1.
y(), pt2.
x(), pt2.
y(), snappedPoint, 0 );
262 if ( thisSegmentClosestDist < additionalTiePoints[i].mLength )
266 info.
mLength = thisSegmentClosestDist;
269 additionalTiePoints[i] = info;
276 isFirstPoint =
false;
280 feedback->
setProgress( 100.0 *
static_cast<double>( ++step ) /
static_cast<double>( featureCount ) );
284 QHash<QgsFeatureId, QList<int>> tiePointNetworkFeatures;
288 tiePointNetworkFeatures[info.mNetworkFeatureId] << i;
293 for (
int i = 0; i < snappedPoints.size(); ++i )
296 const QgsPointXY point = snappedPoints.at( i );
297 int ptIdx = findPointWithinTolerance( point );
301 addPointToIndex( point,
static_cast<int>( graphVertices.count() ) );
302 graphVertices.push_back( point );
307 snappedPoints[i] = graphVertices.at( ptIdx );
311 for (
int i = 0; i < additionalTiePoints.count(); ++i )
313 additionalTiePoints[i].mTiedPoint = snappedPoints.at( additionalTiePoints.at( i ).additionalPointId );
321 for (
const QgsPointXY &point : graphVertices )
328 fit = mSource->getFeatures(
QgsFeatureRequest().setSubsetOfAttributes( requiredAttributes() ) );
334 Direction direction = directionForFeature( feature );
352 bool isFirstPoint =
true;
356 int pPt2idx = findPointWithinTolerance( pt2 );
357 Q_ASSERT_X( pPt2idx >= 0,
"QgsVectorLayerDirector::makeGraph",
"encountered a vertex which was not present in graph" );
358 pt2 = graphVertices.at( pPt2idx );
362 QMap<double, QgsPointXY> pointsOnArc;
363 pointsOnArc[0.0] = pt1;
364 pointsOnArc[pt1.
sqrDist( pt2 )] = pt2;
366 const QList<int> tiePointsForCurrentFeature = tiePointNetworkFeatures.value( feature.
id() );
367 for (
int tiePointIdx : tiePointsForCurrentFeature )
369 const TiePointInfo &t = additionalTiePoints.at( tiePointIdx );
380 bool isFirstPoint =
true;
381 for (
auto arcPointIt = pointsOnArc.constBegin(); arcPointIt != pointsOnArc.constEnd(); ++arcPointIt )
383 arcPt2 = arcPointIt.value();
385 pt2idx = findPointWithinTolerance( arcPt2 );
386 Q_ASSERT_X( pt2idx >= 0,
"QgsVectorLayerDirector::makeGraph",
"encountered a vertex which was not present in graph" );
387 arcPt2 = graphVertices.at( pt2idx );
389 if ( !isFirstPoint && arcPt1 != arcPt2 )
399 QgsDebugError( u
"An error occurred while calculating length"_s );
402 QVector<QVariant> prop;
406 prop.push_back( strategy->cost( distance, feature ) );
411 builder->
addEdge( pt1idx, arcPt1, pt2idx, arcPt2, prop );
415 builder->
addEdge( pt2idx, arcPt2, pt1idx, arcPt1, prop );
420 isFirstPoint =
false;
424 isFirstPoint =
false;
429 feedback->
setProgress( 100.0 *
static_cast<double>( ++step ) /
static_cast<double>( featureCount ) );
WkbType
The WKB type describes the number of dimensions a geometry has.
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::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
static Q_INVOKABLE bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi 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