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 )
98 return Direction::DirectionBoth;
100 else if (
str == mDirectDirectionValue )
102 return Direction::DirectionForward;
104 else if (
str == mReverseDirectionValue )
106 return Direction::DirectionBackward;
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 )
385 QVector< QVariant > prop;
389 prop.push_back( strategy->cost( distance, feature ) );
392 if ( direction == Direction::DirectionForward ||
393 direction == Direction::DirectionBoth )
395 builder->
addEdge( pt1idx, arcPt1, pt2idx, arcPt2, prop );
397 if ( direction == Direction::DirectionBackward ||
398 direction == Direction::DirectionBoth )
400 builder->
addEdge( pt2idx, arcPt2, pt1idx, arcPt1, prop );
405 isFirstPoint =
false;
409 isFirstPoint =
false;
414 feedback->
setProgress( 100.0 *
static_cast< double >( ++step ) / featureCount );
@ MultiLineString
MultiLineString.
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)
This class wraps a request for features to a vector layer (or directly its vector data provider).
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...
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 SIP_HOLDGIL
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
Qgis::WkbType wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
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.
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 SIP_HOLDGIL
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 SIP_HOLDGIL
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...
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) SIP_HOLDGIL
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.
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