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 );