33 #include <QtAlgorithms> 35 #include "SpatialIndex.h" 43 : additionalPointId( additionalPointId )
44 , mNetworkFeatureId( featureId )
45 , mFirstPoint( start )
49 int additionalPointId = -1;
51 double mLength = DBL_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 = DBL_MAX;
251 thisSegmentClosestDist = additionalPoint.
sqrDist( pt1 );
257 pt2.
x(), pt2.
y(), snappedPoint );
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;
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 );
Wrapper for iterator of features from vector data provider or vector layer.
QgsNetworkStrategy defines strategy used for calculation of the edge cost. For example it can take in...
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)
virtual void addEdge(int pt1id, const QgsPointXY &pt1, int pt2id, const QgsPointXY &pt2, const QVector< QVariant > &strategies)
Add edge to the graph.
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.
QgsMultiPolylineXY asMultiPolyline() const
Returns contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
Base class for feedback objects to be used for cancelation 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)...
QgsVectorLayerDirector(QgsFeatureSource *source, int directionFieldId, const QString &directDirectionValue, const QString &reverseDirectionValue, const QString &bothDirectionValue, const Direction defaultDirection)
Default constructor.
QgsGeometry geometry() const
Returns the geometry associated with this feature.
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.
virtual void addVertex(int id, const QgsPointXY &pt)
Add vertex to the graph.
QList< QgsNetworkStrategy * > mStrategies
double topologyTolerance()
Returns topology tolerance.
QgsPolylineXY asPolyline() const
Returns contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list...
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.