From ae8dc1cfb34db157b5c90eea8258ad4fa350e0d7 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Sun, 29 Oct 2017 09:29:11 +1000 Subject: [PATCH] Optimise and simplify tie point calculation --- .../network/qgsvectorlayerdirector.cpp | 68 +++++++------------ tests/src/analysis/testqgsnetworkanalysis.cpp | 50 +++++++------- 2 files changed, 53 insertions(+), 65 deletions(-) diff --git a/src/analysis/network/qgsvectorlayerdirector.cpp b/src/analysis/network/qgsvectorlayerdirector.cpp index 8ff7e339de5..b6dd0934d11 100644 --- a/src/analysis/network/qgsvectorlayerdirector.cpp +++ b/src/analysis/network/qgsvectorlayerdirector.cpp @@ -89,20 +89,20 @@ template RandIter my_bin struct TiePointInfo { + TiePointInfo() = default; + TiePointInfo( QgsFeatureId featureId, const QgsPointXY &start, const QgsPointXY &end ) + : mNetworkFeatureId( featureId ) + , mFirstPoint( start ) + , mLastPoint( end ) + {} + QgsPointXY mTiedPoint; - double mLength; + double mLength = DBL_MAX; + QgsFeatureId mNetworkFeatureId = -1; QgsPointXY mFirstPoint; QgsPointXY mLastPoint; }; -bool TiePointInfoCompare( const TiePointInfo &a, const TiePointInfo &b ) -{ - if ( a.mFirstPoint == b.mFirstPoint ) - return a.mLastPoint.x() == b.mLastPoint.x() ? a.mLastPoint.y() < b.mLastPoint.y() : a.mLastPoint.x() < b.mLastPoint.x(); - - return a.mFirstPoint.x() == b.mFirstPoint.x() ? a.mFirstPoint.y() < b.mFirstPoint.y() : a.mFirstPoint.x() < b.mFirstPoint.x(); -} - QgsVectorLayerDirector::QgsVectorLayerDirector( QgsFeatureSource *source, int directionFieldId, const QString &directDirectionValue, @@ -157,11 +157,7 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const snappedPoints = QVector< QgsPointXY >( additionalPoints.size(), QgsPointXY( 0.0, 0.0 ) ); - TiePointInfo tmpInfo; - tmpInfo.mLength = std::numeric_limits::infinity(); - - QVector< TiePointInfo > pointLengthMap( additionalPoints.size(), tmpInfo ); - QVector< TiePointInfo >::iterator pointLengthIt; + QVector< TiePointInfo > additionalTiePoints( additionalPoints.size() ); //Graph's points; QVector< QgsPointXY > points; @@ -199,7 +195,7 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const int i = 0; for ( i = 0; i != additionalPoints.size(); ++i ) { - TiePointInfo info; + TiePointInfo info( feature.id(), pt1, pt2 ); if ( pt1 == pt2 ) { info.mLength = additionalPoints[ i ].sqrDist( pt1 ); @@ -211,12 +207,9 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const pt2.x(), pt2.y(), info.mTiedPoint ); } - if ( pointLengthMap[ i ].mLength > info.mLength ) + if ( additionalTiePoints[ i ].mLength > info.mLength ) { - info.mFirstPoint = pt1; - info.mLastPoint = pt2; - - pointLengthMap[ i ] = info; + additionalTiePoints[ i ] = info; snappedPoints[ i ] = info.mTiedPoint; } } @@ -231,10 +224,15 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const } } - // end: tie points to graph + QHash< QgsFeatureId, QList< int > > tiePointNetworkFeatures; + int i = 0; + for ( TiePointInfo &info : additionalTiePoints ) + { + tiePointNetworkFeatures[ info.mNetworkFeatureId ] << i; + i++; + } // add tied point to graph - int i = 0; for ( i = 0; i < snappedPoints.size(); ++i ) { if ( snappedPoints[ i ] != QgsPointXY( 0.0, 0.0 ) ) @@ -255,8 +253,6 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const for ( i = 0; i < snappedPoints.size() ; ++i ) snappedPoints[ i ] = *( my_binary_search( points.begin(), points.end(), snappedPoints[ i ], pointCompare ) ); - std::sort( pointLengthMap.begin(), pointLengthMap.end(), TiePointInfoCompare ); - // begin graph construction fit = mSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( requiredAttributes() ) ); while ( fit.nextFeature( feature ) ) @@ -307,27 +303,15 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const pointsOnArc[ 0.0 ] = pt1; pointsOnArc[ pt1.sqrDist( pt2 )] = pt2; - TiePointInfo t; - t.mFirstPoint = pt1; - t.mLastPoint = pt2; - t.mLength = 0.0; - pointLengthIt = my_binary_search( pointLengthMap.begin(), pointLengthMap.end(), t, TiePointInfoCompare ); - - if ( pointLengthIt != pointLengthMap.end() ) + const QList< int > tiePointsForCurrentFeature = tiePointNetworkFeatures.value( feature.id() ); + if ( !tiePointsForCurrentFeature.empty() ) { - QVector< TiePointInfo >::iterator it; - for ( it = pointLengthIt; it - pointLengthMap.begin() >= 0; --it ) + for ( int tiePointIdx : tiePointsForCurrentFeature ) { - if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 ) + const TiePointInfo &t = additionalTiePoints.at( tiePointIdx ); + if ( t.mFirstPoint == pt1 && t.mLastPoint == pt2 ) { - pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint; - } - } - for ( it = pointLengthIt + 1; it != pointLengthMap.end(); ++it ) - { - if ( it->mFirstPoint == pt1 && it->mLastPoint == pt2 ) - { - pointsOnArc[ pt1.sqrDist( it->mTiedPoint )] = it->mTiedPoint; + pointsOnArc[ pt1.sqrDist( t.mTiedPoint )] = t.mTiedPoint; } } } diff --git a/tests/src/analysis/testqgsnetworkanalysis.cpp b/tests/src/analysis/testqgsnetworkanalysis.cpp index 3b8695d26d7..766303123a0 100644 --- a/tests/src/analysis/testqgsnetworkanalysis.cpp +++ b/tests/src/analysis/testqgsnetworkanalysis.cpp @@ -230,39 +230,43 @@ void TestQgsNetworkAnalysis::testBuildTolerance() QCOMPARE( graph->edge( 5 ).fromVertex(), 3 ); QCOMPARE( graph->edge( 5 ).toVertex(), 4 ); -#if 0 // broken // with tolerance - builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0.11 ); +#if 0 //BROKEN, but should be sufficient + double tolerance = 0.11; +#else + double tolerance = 6; +#endif + + builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, tolerance ); director->makeGraph( builder.get(), QVector(), snapped ); graph.reset( builder->graph() ); QCOMPARE( graph->vertexCount(), 5 ); QCOMPARE( graph->edgeCount(), 6 ); QCOMPARE( graph->vertex( 0 ).point(), QgsPointXY( 0, 0 ) ); - QCOMPARE( graph->vertex( 0 ).inEdges(), QList< int >() << 1 ); - QCOMPARE( graph->edge( 1 ).inVertex(), 0 ); - QCOMPARE( graph->edge( 1 ).outVertex(), 1 ); - QCOMPARE( graph->vertex( 0 ).outEdges(), QList< int >() << 0 ); - QCOMPARE( graph->edge( 0 ).inVertex(), 1 ); - QCOMPARE( graph->edge( 0 ).outVertex(), 0 ); + QCOMPARE( graph->vertex( 0 ).outgoingEdges(), QList< int >() << 1 ); + QCOMPARE( graph->edge( 1 ).fromVertex(), 0 ); + QCOMPARE( graph->edge( 1 ).toVertex(), 1 ); + QCOMPARE( graph->vertex( 0 ).incomingEdges(), QList< int >() << 0 ); + QCOMPARE( graph->edge( 0 ).fromVertex(), 1 ); + QCOMPARE( graph->edge( 0 ).toVertex(), 0 ); QCOMPARE( graph->vertex( 1 ).point(), QgsPointXY( 10, 0 ) ); - QCOMPARE( graph->vertex( 1 ).inEdges(), QList< int >() << 0 << 3 ); - QCOMPARE( graph->vertex( 1 ).outEdges(), QList< int >() << 1 << 2 ); - QCOMPARE( graph->edge( 2 ).inVertex(), 2 ); - QCOMPARE( graph->edge( 2 ).outVertex(), 1 ); - QCOMPARE( graph->edge( 3 ).inVertex(), 1 ); - QCOMPARE( graph->edge( 3 ).outVertex(), 2 ); + QCOMPARE( graph->vertex( 1 ).outgoingEdges(), QList< int >() << 0 << 3 ); + QCOMPARE( graph->vertex( 1 ).incomingEdges(), QList< int >() << 1 << 2 ); + QCOMPARE( graph->edge( 2 ).fromVertex(), 2 ); + QCOMPARE( graph->edge( 2 ).toVertex(), 1 ); + QCOMPARE( graph->edge( 3 ).fromVertex(), 1 ); + QCOMPARE( graph->edge( 3 ).toVertex(), 2 ); QCOMPARE( graph->vertex( 2 ).point(), QgsPointXY( 10, 10 ) ); - QCOMPARE( graph->vertex( 2 ).inEdges(), QList< int >() << 2 << 5 ); - QCOMPARE( graph->vertex( 2 ).outEdges(), QList< int >() << 3 << 4 ); + QCOMPARE( graph->vertex( 2 ).outgoingEdges(), QList< int >() << 2 << 5 ); + QCOMPARE( graph->vertex( 2 ).incomingEdges(), QList< int >() << 3 << 4 ); QCOMPARE( graph->vertex( 3 ).point(), QgsPointXY( 10.1, 10 ) ); - QCOMPARE( graph->vertex( 3 ).inEdges(), QList< int >() ); - QCOMPARE( graph->vertex( 3 ).outEdges(), QList< int >() ); + QCOMPARE( graph->vertex( 3 ).outgoingEdges(), QList< int >() ); + QCOMPARE( graph->vertex( 3 ).incomingEdges(), QList< int >() ); QCOMPARE( graph->vertex( 4 ).point(), QgsPointXY( 20, 10 ) ); - QCOMPARE( graph->edge( 4 ).inVertex(), 4 ); - QCOMPARE( graph->edge( 4 ).outVertex(), 2 ); - QCOMPARE( graph->edge( 5 ).inVertex(), 2 ); - QCOMPARE( graph->edge( 5 ).outVertex(), 4 ); -#endif + QCOMPARE( graph->edge( 4 ).fromVertex(), 4 ); + QCOMPARE( graph->edge( 4 ).toVertex(), 2 ); + QCOMPARE( graph->edge( 5 ).fromVertex(), 2 ); + QCOMPARE( graph->edge( 5 ).toVertex(), 4 ); }