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();
62 QgsFeatureSource *source,
int directionFieldId,
const QString &directDirectionValue,
const QString &reverseDirectionValue,
const QString &bothDirectionValue,
const Direction defaultDirection
65 , mDirectionFieldId( directionFieldId )
66 , mDirectDirectionValue( directDirectionValue )
67 , mReverseDirectionValue( reverseDirectionValue )
68 , mBothDirectionValue( bothDirectionValue )
69 , mDefaultDirection( defaultDirection )
74 return u
"Vector line"_s;
81 if ( mDirectionFieldId != -1 )
82 attrs.insert( mDirectionFieldId );
86 attrs.unite( strategy->requiredAttributes() );
88 return qgis::setToList( attrs );
93 if ( mDirectionFieldId < 0 )
94 return mDefaultDirection;
96 QString str = feature.
attribute( mDirectionFieldId ).toString();
97 if ( str == mBothDirectionValue )
101 else if ( str == mDirectDirectionValue )
105 else if ( str == mReverseDirectionValue )
111 return mDefaultDirection;
116class QgsNetworkVisitor :
public SpatialIndex::IVisitor
119 explicit QgsNetworkVisitor( QVector<int> &pointIndexes )
120 : mPoints( pointIndexes )
123 void visitNode(
const INode &n )
override { Q_UNUSED( n ) }
125 void visitData(
const IData &d )
override { mPoints.append(
static_cast<int>( d.getIdentifier() ) ); }
127 void visitData( std::vector<const IData *> &v )
override { Q_UNUSED( v ) }
130 QVector<int> &mPoints;
138 double fillFactor = 0.7;
139 unsigned long indexCapacity = 10;
140 unsigned long leafCapacity = 10;
141 unsigned long dimension = 2;
142 RTree::RTreeVariant variant = RTree::RV_RSTAR;
145 SpatialIndex::id_type indexId;
146 std::unique_ptr<SpatialIndex::ISpatialIndex> iRTree( RTree::createNewRTree( storageManager, fillFactor, indexCapacity, leafCapacity, dimension, variant, indexId ) );
152 QVector<int> matching;
153 QgsNetworkVisitor visitor( matching );
155 double pt1[2] = { point.
x() - tolerance, point.
y() - tolerance }, pt2[2] = { point.
x() + tolerance, point.
y() + tolerance };
156 SpatialIndex::Region searchRegion( pt1, pt2, 2 );
158 index->intersectsWithQuery( searchRegion, visitor );
160 return matching.empty() ? -1 : matching.at( 0 );
165 long featureCount = mSource->featureCount() * 2;
176 snappedPoints = QVector<QgsPointXY>( additionalPoints.size(),
QgsPointXY( 0.0, 0.0 ) );
178 QVector<TiePointInfo> additionalTiePoints( additionalPoints.size() );
181 QVector<QgsPointXY> graphVertices;
184 std::unique_ptr<SpatialIndex::IStorageManager> iStorage( StorageManager::createNewMemoryStorageManager() );
188 auto findPointWithinTolerance = [&iRTree, tolerance](
const QgsPointXY &point ) ->
int {
return findClosestVertex( point, iRTree.get(), tolerance ); };
189 auto addPointToIndex = [&iRTree](
const QgsPointXY &point,
int index ) {
190 double coords[] = { point.
x(), point.
y() };
191 iRTree->insertData( 0,
nullptr, SpatialIndex::Point( coords, 2 ), index );
216 bool isFirstPoint =
true;
221 int pt2Idx = findPointWithinTolerance( pt2 );
225 addPointToIndex( pt2,
static_cast<int>( graphVertices.count() ) );
226 graphVertices.push_back( pt2 );
231 pt2 = graphVertices.at( pt2Idx );
238 for (
const QgsPointXY &additionalPoint : additionalPoints )
241 double thisSegmentClosestDist = std::numeric_limits<double>::max();
244 thisSegmentClosestDist = additionalPoint.sqrDist( pt1 );
249 thisSegmentClosestDist = additionalPoint.sqrDistToSegment( pt1.
x(), pt1.
y(), pt2.
x(), pt2.
y(), snappedPoint, 0 );
252 if ( thisSegmentClosestDist < additionalTiePoints[i].mLength )
256 info.
mLength = thisSegmentClosestDist;
259 additionalTiePoints[i] = info;
266 isFirstPoint =
false;
270 feedback->
setProgress( 100.0 *
static_cast<double>( ++step ) /
static_cast<double>( featureCount ) );
274 QHash<QgsFeatureId, QList<int>> tiePointNetworkFeatures;
278 tiePointNetworkFeatures[info.mNetworkFeatureId] << i;
283 for (
int i = 0; i < snappedPoints.size(); ++i )
286 const QgsPointXY point = snappedPoints.at( i );
287 int ptIdx = findPointWithinTolerance( point );
291 addPointToIndex( point,
static_cast<int>( graphVertices.count() ) );
292 graphVertices.push_back( point );
297 snappedPoints[i] = graphVertices.at( ptIdx );
301 for (
int i = 0; i < additionalTiePoints.count(); ++i )
303 additionalTiePoints[i].mTiedPoint = snappedPoints.at( additionalTiePoints.at( i ).additionalPointId );
311 for (
const QgsPointXY &point : graphVertices )
318 mVertexSources.resize( graphVertices.size() );
320 fit = mSource->getFeatures(
QgsFeatureRequest().setSubsetOfAttributes( requiredAttributes() ) );
327 Direction direction = directionForFeature( feature );
347 bool isFirstPoint =
true;
351 int pPt2idx = findPointWithinTolerance( pt2 );
352 Q_ASSERT_X( pPt2idx >= 0,
"QgsVectorLayerDirector::makeGraph",
"encountered a vertex which was not present in graph" );
353 pt2 = graphVertices.at( pPt2idx );
355 std::vector<VertexSourceInfo> &sourceList = mVertexSources[pPt2idx];
357 if ( std::find( sourceList.begin(), sourceList.end(), info ) == sourceList.end() )
359 sourceList.push_back( info );
364 QMap<double, QgsPointXY> pointsOnArc;
365 pointsOnArc[0.0] = pt1;
366 pointsOnArc[pt1.
sqrDist( pt2 )] = pt2;
368 const QList<int> tiePointsForCurrentFeature = tiePointNetworkFeatures.value( feature.
id() );
369 for (
int tiePointIdx : tiePointsForCurrentFeature )
371 const TiePointInfo &t = additionalTiePoints.at( tiePointIdx );
382 bool isFirstPoint =
true;
383 for (
auto arcPointIt = pointsOnArc.constBegin(); arcPointIt != pointsOnArc.constEnd(); ++arcPointIt )
385 arcPt2 = arcPointIt.value();
387 pt2idx = findPointWithinTolerance( arcPt2 );
388 Q_ASSERT_X( pt2idx >= 0,
"QgsVectorLayerDirector::makeGraph",
"encountered a vertex which was not present in graph" );
389 arcPt2 = graphVertices.at( pt2idx );
391 if ( !isFirstPoint && arcPt1 != arcPt2 )
401 QgsDebugError( u
"An error occurred while calculating length"_s );
404 QVector<QVariant> prop;
408 prop.push_back( strategy->cost( distance, feature ) );
413 builder->
addEdge( pt1idx, arcPt1, pt2idx, arcPt2, prop );
417 builder->
addEdge( pt2idx, arcPt2, pt1idx, arcPt1, prop );
422 isFirstPoint =
false;
426 isFirstPoint =
false;
431 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.
QgsCoordinateReferenceSystem destinationCrs() const
Returns destinaltion CRS.
virtual int addVertex(int id, const QgsPointXY &pt)
Add vertex to the graph.
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)
Represents information about a graph node's source vertex.
TiePointInfo(int additionalPointId, QgsFeatureId featureId, const QgsPointXY &start, const QgsPointXY &end)
QgsFeatureId mNetworkFeatureId