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 qgis::setToList( attrs );
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
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;
267 additionalTiePoints[ i ] = info;
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 )
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 );