33 #include <QtAlgorithms> 35 #include <spatialindex/SpatialIndex.h> 43 : additionalPointId( additionalPointId )
44 , mNetworkFeatureId( featureId )
45 , mFirstPoint( start )
49 int additionalPointId = -1;
51 double mLength = std::numeric_limits<double>::max();
59 const QString &directDirectionValue,
60 const QString &reverseDirectionValue,
61 const QString &bothDirectionValue,
64 , mDirectionFieldId( directionFieldId )
65 , mDirectDirectionValue( directDirectionValue )
66 , mReverseDirectionValue( reverseDirectionValue )
67 , mBothDirectionValue( bothDirectionValue )
68 , mDefaultDirection( defaultDirection )
74 return QStringLiteral(
"Vector line" );
81 if ( mDirectionFieldId != -1 )
82 attrs.insert( mDirectionFieldId );
86 attrs.unite( strategy->requiredAttributes() );
88 return attrs.toList();
93 if ( mDirectionFieldId < 0 )
94 return mDefaultDirection;
96 QString str = feature.
attribute( mDirectionFieldId ).toString();
97 if ( str == mBothDirectionValue )
99 return Direction::DirectionBoth;
101 else if ( str == mDirectDirectionValue )
103 return Direction::DirectionForward;
105 else if ( str == mReverseDirectionValue )
107 return Direction::DirectionBackward;
111 return mDefaultDirection;
116 class QgsNetworkVisitor :
public SpatialIndex::IVisitor
119 explicit QgsNetworkVisitor( QVector< int > &pointIndexes )
120 : mPoints( pointIndexes ) {}
122 void visitNode(
const INode &n )
override 125 void visitData(
const IData &d )
override 127 mPoints.append( d.getIdentifier() );
130 void visitData( std::vector<const IData *> &v )
override 134 QVector< int > &mPoints;
142 double fillFactor = 0.7;
143 unsigned long indexCapacity = 10;
144 unsigned long leafCapacity = 10;
145 unsigned long dimension = 2;
146 RTree::RTreeVariant variant = RTree::RV_RSTAR;
149 SpatialIndex::id_type indexId;
150 std::unique_ptr< SpatialIndex::ISpatialIndex > iRTree( RTree::createNewRTree( storageManager, fillFactor, indexCapacity,
151 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 );
170 QVector< QgsPointXY > &snappedPoints,
QgsFeedback *feedback )
const 172 long featureCount = mSource->featureCount() * 2;
183 snappedPoints = QVector< QgsPointXY >( additionalPoints.size(),
QgsPointXY( 0.0, 0.0 ) );
185 QVector< TiePointInfo > additionalTiePoints( additionalPoints.size() );
188 QVector< QgsPointXY > graphVertices;
191 std::unique_ptr< SpatialIndex::IStorageManager > iStorage( StorageManager::createNewMemoryStorageManager() );
195 auto findPointWithinTolerance = [&iRTree, tolerance](
const QgsPointXY & point )->
int 199 auto addPointToIndex = [&iRTree](
const QgsPointXY & point,
int index )
201 double coords[] = {point.
x(), point.
y()};
202 iRTree->insertData( 0,
nullptr, SpatialIndex::Point( coords, 2 ), index );
222 bool isFirstPoint =
true;
227 int pt2Idx = findPointWithinTolerance( pt2 ) ;
231 addPointToIndex( pt2, graphVertices.count() );
232 graphVertices.push_back( pt2 );
237 pt2 = graphVertices.at( pt2Idx );
244 for (
const QgsPointXY &additionalPoint : additionalPoints )
248 double thisSegmentClosestDist = std::numeric_limits<double>::max();
251 thisSegmentClosestDist = additionalPoint.sqrDist( pt1 );
257 pt2.
x(), pt2.
y(), snappedPoint, 0 );
260 if ( thisSegmentClosestDist < additionalTiePoints[ i ].mLength )
264 info.
mLength = thisSegmentClosestDist;
265 info.mTiedPoint = snappedPoint;
267 additionalTiePoints[ i ] = info;
268 snappedPoints[ i ] = info.mTiedPoint;
274 isFirstPoint =
false;
278 feedback->
setProgress( 100.0 * static_cast< double >( ++step ) / featureCount );
282 QHash< QgsFeatureId, QList< int > > tiePointNetworkFeatures;
286 tiePointNetworkFeatures[ info.mNetworkFeatureId ] << i;
291 for (
int i = 0; i < snappedPoints.size(); ++i )
294 const QgsPointXY point = snappedPoints.at( i );
295 int ptIdx = findPointWithinTolerance( point );
299 addPointToIndex( point, graphVertices.count() );
300 graphVertices.push_back( point );
305 snappedPoints[ i ] = graphVertices.at( ptIdx );
309 for (
int i = 0; i < additionalTiePoints.count(); ++i )
311 additionalTiePoints[ i ].mTiedPoint = snappedPoints.at( additionalTiePoints.at( i ).additionalPointId );
320 for (
const QgsPointXY &point : graphVertices )
327 fit = mSource->getFeatures(
QgsFeatureRequest().setSubsetOfAttributes( requiredAttributes() ) );
333 Direction direction = directionForFeature( feature );
346 bool isFirstPoint =
true;
350 int pPt2idx = findPointWithinTolerance( pt2 );
351 Q_ASSERT_X( pPt2idx >= 0,
"QgsVectorLayerDirectory::makeGraph",
"encountered a vertex which was not present in graph" );
352 pt2 = graphVertices.at( pPt2idx );
356 QMap< double, QgsPointXY > pointsOnArc;
357 pointsOnArc[ 0.0 ] = pt1;
358 pointsOnArc[ pt1.
sqrDist( pt2 )] = pt2;
360 const QList< int > tiePointsForCurrentFeature = tiePointNetworkFeatures.value( feature.
id() );
361 for (
int tiePointIdx : tiePointsForCurrentFeature )
363 const TiePointInfo &t = additionalTiePoints.at( tiePointIdx );
374 bool isFirstPoint =
true;
375 for (
auto arcPointIt = pointsOnArc.constBegin(); arcPointIt != pointsOnArc.constEnd(); ++arcPointIt )
377 arcPt2 = arcPointIt.value();
379 pt2idx = findPointWithinTolerance( arcPt2 );
380 Q_ASSERT_X( pt2idx >= 0,
"QgsVectorLayerDirectory::makeGraph",
"encountered a vertex which was not present in graph" );
381 arcPt2 = graphVertices.at( pt2idx );
383 if ( !isFirstPoint && arcPt1 != arcPt2 )
386 QVector< QVariant > prop;
390 prop.push_back( strategy->cost( distance, feature ) );
393 if ( direction == Direction::DirectionForward ||
394 direction == Direction::DirectionBoth )
396 builder->
addEdge( pt1idx, arcPt1, pt2idx, arcPt2, prop );
398 if ( direction == Direction::DirectionBackward ||
399 direction == Direction::DirectionBoth )
401 builder->
addEdge( pt2idx, arcPt2, pt1idx, arcPt1, prop );
406 isFirstPoint =
false;
410 isFirstPoint =
false;
415 feedback->
setProgress( 100.0 * static_cast< double >( ++step ) / featureCount );
Wrapper for iterator of features from vector data provider or vector layer.
QgsNetworkStrategy defines strategy used for calculation of the edge cost.
QgsVectorLayerDirector(QgsFeatureSource *source, int directionFieldId, const QString &directDirectionValue, const QString &reverseDirectionValue, const QString &bothDirectionValue, Direction defaultDirection)
Default constructor.
Direction
Edge direction Edge can be one-way with direct flow (one can move only from the start point to the en...
int findClosestVertex(const QgsPointXY &point, SpatialIndex::ISpatialIndex *index, double tolerance)
void makeGraph(QgsGraphBuilderInterface *builder, const QVector< QgsPointXY > &additionalPoints, QVector< QgsPointXY > &snappedPoints, QgsFeedback *feedback=nullptr) const override
Make a graph using QgsGraphBuilder.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
bool coordinateTransformationEnabled()
Returns coordinate transformation enabled.
A class to represent a 2D point.
void setProgress(double progress)
Sets the current progress for the feedback object.
Determine interface for creating a graph.
TiePointInfo(int additionalPointId, QgsFeatureId featureId, const QgsPointXY &start, const QgsPointXY &end)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
virtual void addVertex(int id, const QgsPointXY &pt)
Add vertex to the graph.
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
Base class for feedback objects to be used for cancellation of something running in a worker thread...
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPointXY &minDistPoint, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Returns the minimum distance between this point and a segment.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
virtual void addEdge(int pt1id, const QgsPointXY &pt1, int pt2id, const QgsPointXY &pt2, const QVector< QVariant > &strategies)
Add edge to the graph.
std::unique_ptr< SpatialIndex::ISpatialIndex > createVertexSpatialIndex(SpatialIndex::IStorageManager &storageManager)
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
bool isCanceled() const
Tells whether the operation has been canceled already.
An interface for objects which provide features via a getFeatures method.
QList< QgsNetworkStrategy * > mStrategies
double topologyTolerance()
Returns topology tolerance.
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
QList< int > QgsAttributeList
bool nextFeature(QgsFeature &f)
QgsCoordinateReferenceSystem destinationCrs() const
Returns destinaltion CRS.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
static Type flatType(Type type)
Returns the flat type for a WKB type.
QgsDistanceArea * distanceArea()
Returns measurement tool.
double measureLine(const QVector< QgsPointXY > &points) const
Measures the length of a line with multiple segments.
QString name() const override
Returns director name.