Fix QgsGraphAnalyzer::dijkstra traverses through edges backwards

This means that it flips the direction of the graph edge, breaking
route restrictions.

Refs #17325
This commit is contained in:
Nyall Dawson 2017-10-30 12:51:27 +10:00
parent 57edec668e
commit 8d32bf729e
7 changed files with 286 additions and 86 deletions

View File

@ -250,7 +250,7 @@ class ShortestPathLayerToPoint(QgisAlgorithm):
idxStart = graph.findVertex(snappedPoints[i])
tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
if tree[idxEnd] == -1:
msg = self.tr('There is no route from start point ({}) to end point ({}).'.format(points[i].toString(), endPoint.toString()))
@ -266,9 +266,9 @@ class ShortestPathLayerToPoint(QgisAlgorithm):
cost = 0.0
current = idxEnd
while current != idxStart:
cost += graph.edge(tree[current]).cost(0)
route.append(graph.vertex(graph.edge(tree[current]).fromVertex()).point())
current = graph.edge(tree[current]).toVertex()
cost += costs[current]
current = graph.edge(tree[current]).fromVertex()
route.append(graph.vertex(current).point())
route.append(snappedPoints[i])
route.reverse()

View File

@ -241,8 +241,7 @@ class ShortestPathPointToLayer(QgisAlgorithm):
graph = builder.graph()
idxStart = graph.findVertex(snappedPoints[0])
tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
route = []
tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
nPoints = len(snappedPoints)
total = 100.0 / nPoints if nPoints else 1
@ -266,9 +265,9 @@ class ShortestPathPointToLayer(QgisAlgorithm):
cost = 0.0
current = idxEnd
while current != idxStart:
cost += graph.edge(tree[current]).cost(0)
route.append(graph.vertex(graph.edge(tree[current]).fromVertex()).point())
current = graph.edge(tree[current]).toVertex()
cost += costs[current]
current = graph.edge(tree[current]).fromVertex()
route.append(graph.vertex(current).point())
route.append(snappedPoints[0])
route.reverse()

View File

@ -217,7 +217,7 @@ class ShortestPathPointToPoint(QgisAlgorithm):
idxStart = graph.findVertex(snappedPoints[0])
idxEnd = graph.findVertex(snappedPoints[1])
tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
tree, costs = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0)
if tree[idxEnd] == -1:
raise QgsProcessingException(
self.tr('There is no route from start point to end point.'))
@ -226,9 +226,9 @@ class ShortestPathPointToPoint(QgisAlgorithm):
cost = 0.0
current = idxEnd
while current != idxStart:
cost += graph.edge(tree[current]).cost(0)
route.append(graph.vertex(graph.edge(tree[current]).fromVertex()).point())
current = graph.edge(tree[current]).toVertex()
cost += costs[current]
current = graph.edge(tree[current]).fromVertex()
route.append(graph.vertex(current).point())
route.append(snappedPoints[0])
route.reverse()

View File

@ -59,21 +59,20 @@ void QgsGraphAnalyzer::dijkstra( const QgsGraph *source, int startPointIdx, int
not_begin.erase( it );
// edge index list
QgsGraphEdgeIds l = source->vertex( curVertex ).incomingEdges();
QgsGraphEdgeIds::iterator arcIt;
for ( arcIt = l.begin(); arcIt != l.end(); ++arcIt )
const QgsGraphEdgeIds &outgoingEdges = source->vertex( curVertex ).outgoingEdges();
for ( int edgeId : outgoingEdges )
{
const QgsGraphEdge arc = source->edge( *arcIt );
const QgsGraphEdge &arc = source->edge( edgeId );
double cost = arc.cost( criterionNum ).toDouble() + curCost;
if ( cost < ( *result )[ arc.fromVertex()] )
if ( cost < ( *result )[ arc.toVertex()] )
{
( *result )[ arc.fromVertex()] = cost;
( *result )[ arc.toVertex()] = cost;
if ( resultTree )
{
( *resultTree )[ arc.fromVertex()] = *arcIt;
( *resultTree )[ arc.toVertex()] = edgeId;
}
not_begin.insert( cost, arc.fromVertex() );
not_begin.insert( cost, arc.toVertex() );
}
}
}

View File

@ -42,7 +42,7 @@ void QgsGraphBuilder::addVertex( int, const QgsPointXY &pt )
void QgsGraphBuilder::addEdge( int pt1id, const QgsPointXY &, int pt2id, const QgsPointXY &, const QVector< QVariant > &prop )
{
mGraph->addEdge( pt2id, pt1id, prop );
mGraph->addEdge( pt1id, pt2id, prop );
}
QgsGraph *QgsGraphBuilder::graph()

View File

@ -39,12 +39,14 @@ using namespace SpatialIndex;
struct TiePointInfo
{
TiePointInfo() = default;
TiePointInfo( QgsFeatureId featureId, const QgsPointXY &start, const QgsPointXY &end )
: mNetworkFeatureId( featureId )
TiePointInfo( int additionalPointId, QgsFeatureId featureId, const QgsPointXY &start, const QgsPointXY &end )
: additionalPointId( additionalPointId )
, mNetworkFeatureId( featureId )
, mFirstPoint( start )
, mLastPoint( end )
{}
int additionalPointId = -1;
QgsPointXY mTiedPoint;
double mLength = DBL_MAX;
QgsFeatureId mNetworkFeatureId = -1;
@ -255,7 +257,7 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const
if ( thisSegmentClosestDist < additionalTiePoints[ i ].mLength )
{
// found a closer segment for this additional point
TiePointInfo info( feature.id(), pt1, pt2 );
TiePointInfo info( i, feature.id(), pt1, pt2 );
info.mLength = thisSegmentClosestDist;
info.mTiedPoint = snappedPoint;
@ -300,8 +302,11 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const
snappedPoints[ i ] = graphVertices.at( ptIdx );
}
}
// also need to update tie points - they need to be matched for snapped points
for ( int i = 0; i < additionalTiePoints.count(); ++i )
{
additionalTiePoints[ i ].mTiedPoint = snappedPoints.at( additionalTiePoints.at( i ).additionalPointId );
}
// begin graph construction
@ -361,9 +366,9 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const
int pt1idx = -1;
int pt2idx = -1;
bool isFirstPoint = true;
for ( const QgsPointXY &arcPoint : qgis::as_const( pointsOnArc ) )
for ( auto arcPointIt = pointsOnArc.constBegin(); arcPointIt != pointsOnArc.constEnd(); ++arcPointIt )
{
pt2 = arcPoint;
pt2 = arcPointIt.value();
pt2idx = findPointWithinTolerance( pt2 );
Q_ASSERT_X( pt2idx >= 0, "QgsVectorLayerDirectory::makeGraph", "encountered a vertex which was not present in graph" );
@ -372,10 +377,9 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const
{
double distance = builder->distanceArea()->measureLine( pt1, pt2 );
QVector< QVariant > prop;
QList< QgsNetworkStrategy * >::const_iterator it;
for ( it = mStrategies.begin(); it != mStrategies.end(); ++it )
for ( QgsNetworkStrategy *strategy : mStrategies )
{
prop.push_back( ( *it )->cost( distance, feature ) );
prop.push_back( strategy->cost( distance, feature ) );
}
if ( direction == Direction::DirectionForward ||

View File

@ -24,6 +24,7 @@ Email : nyall dot dawson at gmail dot com
#include "qgsnetworkdistancestrategy.h"
#include "qgsgraphbuilder.h"
#include "qgsgraph.h"
#include "qgsgraphanalyzer.h"
class TestQgsNetworkAnalysis : public QObject
{
@ -39,6 +40,7 @@ class TestQgsNetworkAnalysis : public QObject
void testGraph();
void testBuild();
void testBuildTolerance();
void dijkkjkjkskkjsktra();
private:
std::unique_ptr< QgsVectorLayer > buildNetwork();
@ -46,6 +48,18 @@ class TestQgsNetworkAnalysis : public QObject
};
class TestNetworkStrategy : public QgsNetworkStrategy
{
QSet< int > requiredAttributes() const override
{
return QSet< int >() << 0;
}
QVariant cost( double, const QgsFeature &f ) const override
{
return f.attribute( 0 );
}
};
void TestQgsNetworkAnalysis::initTestCase()
{
//
@ -117,11 +131,12 @@ void TestQgsNetworkAnalysis::testGraph()
std::unique_ptr<QgsVectorLayer> TestQgsNetworkAnalysis::buildNetwork()
{
std::unique_ptr< QgsVectorLayer > l = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "LineString?crs=epsg:4326" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
std::unique_ptr< QgsVectorLayer > l = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "LineString?crs=epsg:4326&field=cost:int" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
QgsFeature ff( 0 );
QgsGeometry refGeom = QgsGeometry::fromWkt( QStringLiteral( "LineString(0 0, 10 0, 10 10)" ) );
ff.setGeometry( refGeom );
ff.setAttributes( QgsAttributes() << 1 );
QgsFeatureList flist;
flist << ff;
l->dataProvider()->addFeatures( flist );
@ -146,22 +161,22 @@ void TestQgsNetworkAnalysis::testBuild()
QCOMPARE( graph->vertexCount(), 3 );
QCOMPARE( graph->edgeCount(), 4 );
QCOMPARE( graph->vertex( 0 ).point(), QgsPointXY( 0, 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( 0 ).outgoingEdges(), QList< int >() << 0 );
QCOMPARE( graph->edge( 0 ).fromVertex(), 0 );
QCOMPARE( graph->edge( 0 ).toVertex(), 1 );
QCOMPARE( graph->vertex( 0 ).incomingEdges(), QList< int >() << 1 );
QCOMPARE( graph->edge( 1 ).fromVertex(), 1 );
QCOMPARE( graph->edge( 1 ).toVertex(), 0 );
QCOMPARE( graph->vertex( 1 ).point(), QgsPointXY( 10, 0 ) );
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( 1 ).outgoingEdges(), QList< int >() << 1 << 2 );
QCOMPARE( graph->vertex( 1 ).incomingEdges(), QList< int >() << 0 << 3 );
QCOMPARE( graph->edge( 3 ).fromVertex(), 2 );
QCOMPARE( graph->edge( 3 ).toVertex(), 1 );
QCOMPARE( graph->edge( 2 ).fromVertex(), 1 );
QCOMPARE( graph->edge( 2 ).toVertex(), 2 );
QCOMPARE( graph->vertex( 2 ).point(), QgsPointXY( 10, 10 ) );
QCOMPARE( graph->vertex( 2 ).outgoingEdges(), QList< int >() << 2 );
QCOMPARE( graph->vertex( 2 ).incomingEdges(), QList< int >() << 3 );
QCOMPARE( graph->vertex( 2 ).outgoingEdges(), QList< int >() << 3 );
QCOMPARE( graph->vertex( 2 ).incomingEdges(), QList< int >() << 2 );
builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 );
director->makeGraph( builder.get(), QVector<QgsPointXY>() << QgsPointXY( 10, 0 ) << QgsPointXY( 10, 10 ), snapped );
@ -205,30 +220,30 @@ void TestQgsNetworkAnalysis::testBuildTolerance()
QCOMPARE( graph->vertexCount(), 5 );
QCOMPARE( graph->edgeCount(), 6 );
QCOMPARE( graph->vertex( 0 ).point(), QgsPointXY( 0, 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( 0 ).outgoingEdges(), QList< int >() << 0 );
QCOMPARE( graph->edge( 0 ).fromVertex(), 0 );
QCOMPARE( graph->edge( 0 ).toVertex(), 1 );
QCOMPARE( graph->vertex( 0 ).incomingEdges(), QList< int >() << 1 );
QCOMPARE( graph->edge( 1 ).fromVertex(), 1 );
QCOMPARE( graph->edge( 1 ).toVertex(), 0 );
QCOMPARE( graph->vertex( 1 ).point(), QgsPointXY( 10, 0 ) );
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( 1 ).outgoingEdges(), QList< int >() << 1 << 2 );
QCOMPARE( graph->vertex( 1 ).incomingEdges(), QList< int >() << 0 << 3 );
QCOMPARE( graph->edge( 3 ).fromVertex(), 2 );
QCOMPARE( graph->edge( 3 ).toVertex(), 1 );
QCOMPARE( graph->edge( 2 ).fromVertex(), 1 );
QCOMPARE( graph->edge( 2 ).toVertex(), 2 );
QCOMPARE( graph->vertex( 2 ).point(), QgsPointXY( 10, 10 ) );
QCOMPARE( graph->vertex( 2 ).outgoingEdges(), QList< int >() << 2 );
QCOMPARE( graph->vertex( 2 ).incomingEdges(), QList< int >() << 3 );
QCOMPARE( graph->vertex( 2 ).outgoingEdges(), QList< int >() << 3 );
QCOMPARE( graph->vertex( 2 ).incomingEdges(), QList< int >() << 2 );
QCOMPARE( graph->vertex( 3 ).point(), QgsPointXY( 10.1, 10 ) );
QCOMPARE( graph->vertex( 3 ).outgoingEdges(), QList< int >() << 5 );
QCOMPARE( graph->vertex( 3 ).incomingEdges(), QList< int >() << 4 );
QCOMPARE( graph->vertex( 3 ).outgoingEdges(), QList< int >() << 4 );
QCOMPARE( graph->vertex( 3 ).incomingEdges(), QList< int >() << 5 );
QCOMPARE( graph->vertex( 4 ).point(), QgsPointXY( 20, 10 ) );
QCOMPARE( graph->edge( 4 ).fromVertex(), 4 );
QCOMPARE( graph->edge( 4 ).toVertex(), 3 );
QCOMPARE( graph->edge( 5 ).fromVertex(), 3 );
QCOMPARE( graph->edge( 5 ).toVertex(), 4 );
QCOMPARE( graph->edge( 5 ).fromVertex(), 4 );
QCOMPARE( graph->edge( 5 ).toVertex(), 3 );
QCOMPARE( graph->edge( 4 ).fromVertex(), 3 );
QCOMPARE( graph->edge( 4 ).toVertex(), 4 );
// with tolerance
double tolerance = 0.11;
@ -239,29 +254,212 @@ void TestQgsNetworkAnalysis::testBuildTolerance()
QCOMPARE( graph->vertexCount(), 4 );
QCOMPARE( graph->edgeCount(), 6 );
QCOMPARE( graph->vertex( 0 ).point(), QgsPointXY( 0, 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( 0 ).outgoingEdges(), QList< int >() << 0 );
QCOMPARE( graph->edge( 0 ).fromVertex(), 0 );
QCOMPARE( graph->edge( 0 ).toVertex(), 1 );
QCOMPARE( graph->vertex( 0 ).incomingEdges(), QList< int >() << 1 );
QCOMPARE( graph->edge( 1 ).fromVertex(), 1 );
QCOMPARE( graph->edge( 1 ).toVertex(), 0 );
QCOMPARE( graph->vertex( 1 ).point(), QgsPointXY( 10, 0 ) );
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( 1 ).outgoingEdges(), QList< int >() << 1 << 2 );
QCOMPARE( graph->vertex( 1 ).incomingEdges(), QList< int >() << 0 << 3 );
QCOMPARE( graph->edge( 3 ).fromVertex(), 2 );
QCOMPARE( graph->edge( 3 ).toVertex(), 1 );
QCOMPARE( graph->edge( 2 ).fromVertex(), 1 );
QCOMPARE( graph->edge( 2 ).toVertex(), 2 );
QCOMPARE( graph->vertex( 2 ).point(), QgsPointXY( 10, 10 ) );
QCOMPARE( graph->vertex( 2 ).outgoingEdges(), QList< int >() << 2 << 5 );
QCOMPARE( graph->vertex( 2 ).incomingEdges(), QList< int >() << 3 << 4 );
QCOMPARE( graph->vertex( 2 ).outgoingEdges(), QList< int >() << 3 << 4 );
QCOMPARE( graph->vertex( 2 ).incomingEdges(), QList< int >() << 2 << 5 );
QCOMPARE( graph->vertex( 3 ).point(), QgsPointXY( 20, 10 ) );
QCOMPARE( graph->vertex( 3 ).outgoingEdges(), QList< int >() << 4 );
QCOMPARE( graph->vertex( 3 ).incomingEdges(), QList< int >() << 5 );
QCOMPARE( graph->edge( 4 ).fromVertex(), 3 );
QCOMPARE( graph->edge( 4 ).toVertex(), 2 );
QCOMPARE( graph->edge( 5 ).fromVertex(), 2 );
QCOMPARE( graph->edge( 5 ).toVertex(), 3 );
QCOMPARE( graph->vertex( 3 ).outgoingEdges(), QList< int >() << 5 );
QCOMPARE( graph->vertex( 3 ).incomingEdges(), QList< int >() << 4 );
QCOMPARE( graph->edge( 5 ).fromVertex(), 3 );
QCOMPARE( graph->edge( 5 ).toVertex(), 2 );
QCOMPARE( graph->edge( 4 ).fromVertex(), 2 );
QCOMPARE( graph->edge( 4 ).toVertex(), 3 );
}
void TestQgsNetworkAnalysis::dijkkjkjkskkjsktra()
{
std::unique_ptr<QgsVectorLayer> network = buildNetwork();
// has already a linestring LineString(0 0, 10 0, 10 10)
// add some more lines to network
QgsFeature ff( 0 );
QgsFeatureList flist;
ff.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineString(10 10, 20 10 )" ) ) );
ff.setAttributes( QgsAttributes() << 2 );
flist << ff;
ff.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineString(10 20, 10 10 )" ) ) );
ff.setAttributes( QgsAttributes() << 3 );
flist << ff;
ff.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineString(20 -10, 20 10 )" ) ) );
ff.setAttributes( QgsAttributes() << 4 );
flist << ff;
network->dataProvider()->addFeatures( flist );
/*
Out network is:
Numbers in brackets are cost for segment
20 o
|
v (3)
| (2)
10 o---->----o
| |
(1) ^ ^
(1) | |
0 o---->-----. |(4)
|
^
|
-10 o
0 10 20
*/
// build graph
std::unique_ptr< QgsVectorLayerDirector > director = qgis::make_unique< QgsVectorLayerDirector > ( network.get(),
-1, QString(), QString(), QString(), QgsVectorLayerDirector::DirectionBoth );
std::unique_ptr< QgsNetworkStrategy > strategy = qgis::make_unique< TestNetworkStrategy >();
director->addStrategy( strategy.release() );
std::unique_ptr< QgsGraphBuilder > builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 );
QVector<QgsPointXY > snapped;
director->makeGraph( builder.get(), QVector<QgsPointXY>(), snapped );
std::unique_ptr< QgsGraph > graph( builder->graph() );
int startVertexIdx = graph->findVertex( QgsPointXY( 20, -10 ) );
QVERIFY( startVertexIdx != -1 );
// both directions
QVector<int> resultTree;
QVector<double> resultCost;
QgsGraphAnalyzer::dijkstra( graph.get(), startVertexIdx, 0, &resultTree, &resultCost );
int point_0_0_idx = graph->findVertex( QgsPointXY( 0, 0 ) );
QVERIFY( point_0_0_idx != -1 );
int point_10_0_idx = graph->findVertex( QgsPointXY( 10, 0 ) );
QVERIFY( point_10_0_idx != -1 );
int point_10_10_idx = graph->findVertex( QgsPointXY( 10, 10 ) );
QVERIFY( point_10_10_idx != -1 );
int point_10_20_idx = graph->findVertex( QgsPointXY( 10, 20 ) );
QVERIFY( point_10_20_idx != -1 );
int point_20_10_idx = graph->findVertex( QgsPointXY( 20, 10 ) );
QVERIFY( point_20_10_idx != -1 );
QCOMPARE( resultTree.at( startVertexIdx ), -1 );
QCOMPARE( resultCost.at( startVertexIdx ), 0.0 );
QVERIFY( resultTree.at( point_20_10_idx ) != -1 );
QCOMPARE( resultCost.at( point_20_10_idx ), 4.0 );
QCOMPARE( graph->edge( resultTree.at( point_20_10_idx ) ).fromVertex(), startVertexIdx );
QCOMPARE( graph->edge( resultTree.at( point_20_10_idx ) ).toVertex(), point_20_10_idx );
QVERIFY( resultTree.at( point_10_10_idx ) != -1 );
QCOMPARE( resultCost.at( point_10_10_idx ), 6.0 );
QCOMPARE( graph->edge( resultTree.at( point_10_10_idx ) ).fromVertex(), point_20_10_idx );
QCOMPARE( graph->edge( resultTree.at( point_10_10_idx ) ).toVertex(), point_10_10_idx );
QVERIFY( resultTree.at( point_10_20_idx ) != -1 );
QCOMPARE( resultCost.at( point_10_20_idx ), 9.0 );
QCOMPARE( graph->edge( resultTree.at( point_10_20_idx ) ).fromVertex(), point_10_10_idx );
QCOMPARE( graph->edge( resultTree.at( point_10_20_idx ) ).toVertex(), point_10_20_idx );
QVERIFY( resultTree.at( point_10_0_idx ) != -1 );
QCOMPARE( resultCost.at( point_10_0_idx ), 7.0 );
QCOMPARE( graph->edge( resultTree.at( point_10_0_idx ) ).fromVertex(), point_10_10_idx );
QCOMPARE( graph->edge( resultTree.at( point_10_0_idx ) ).toVertex(), point_10_0_idx );
QVERIFY( resultTree.at( point_0_0_idx ) != -1 );
QCOMPARE( resultCost.at( point_0_0_idx ), 8.0 );
QCOMPARE( graph->edge( resultTree.at( point_0_0_idx ) ).fromVertex(), point_10_0_idx );
QCOMPARE( graph->edge( resultTree.at( point_0_0_idx ) ).toVertex(), point_0_0_idx );
// forward direction
director = qgis::make_unique< QgsVectorLayerDirector > ( network.get(),
-1, QString(), QString(), QString(), QgsVectorLayerDirector::DirectionForward );
strategy = qgis::make_unique< TestNetworkStrategy >();
director->addStrategy( strategy.release() );
builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 );
director->makeGraph( builder.get(), QVector<QgsPointXY>(), snapped );
graph.reset( builder->graph() );
startVertexIdx = graph->findVertex( QgsPointXY( 0, 0 ) );
QVERIFY( startVertexIdx != -1 );
resultTree.clear();
resultCost.clear();
QgsGraphAnalyzer::dijkstra( graph.get(), startVertexIdx, 0, &resultTree, &resultCost );
point_0_0_idx = graph->findVertex( QgsPointXY( 0, 0 ) );
QVERIFY( point_0_0_idx != -1 );
point_10_0_idx = graph->findVertex( QgsPointXY( 10, 0 ) );
QVERIFY( point_10_0_idx != -1 );
point_10_10_idx = graph->findVertex( QgsPointXY( 10, 10 ) );
QVERIFY( point_10_10_idx != -1 );
point_10_20_idx = graph->findVertex( QgsPointXY( 10, 20 ) );
QVERIFY( point_10_20_idx != -1 );
point_20_10_idx = graph->findVertex( QgsPointXY( 20, 10 ) );
QVERIFY( point_20_10_idx != -1 );
int point_20_n10_idx = graph->findVertex( QgsPointXY( 20, -10 ) );
QVERIFY( point_20_n10_idx != -1 );
QCOMPARE( resultTree.at( startVertexIdx ), -1 );
QCOMPARE( resultCost.at( startVertexIdx ), 0.0 );
QVERIFY( resultTree.at( point_10_0_idx ) != -1 );
QCOMPARE( resultCost.at( point_10_0_idx ), 1.0 );
QCOMPARE( graph->edge( resultTree.at( point_10_0_idx ) ).fromVertex(), startVertexIdx );
QCOMPARE( graph->edge( resultTree.at( point_10_0_idx ) ).toVertex(), point_10_0_idx );
QVERIFY( resultTree.at( point_10_10_idx ) != -1 );
QCOMPARE( resultCost.at( point_10_10_idx ), 2.0 );
QCOMPARE( graph->edge( resultTree.at( point_10_10_idx ) ).fromVertex(), point_10_0_idx );
QCOMPARE( graph->edge( resultTree.at( point_10_10_idx ) ).toVertex(), point_10_10_idx );
QCOMPARE( resultTree.at( point_10_20_idx ), -1 ); // unreachable
QVERIFY( resultTree.at( point_20_10_idx ) != -1 );
QCOMPARE( resultCost.at( point_20_10_idx ), 4.0 );
QCOMPARE( graph->edge( resultTree.at( point_20_10_idx ) ).fromVertex(), point_10_10_idx );
QCOMPARE( graph->edge( resultTree.at( point_20_10_idx ) ).toVertex(), point_20_10_idx );
QCOMPARE( resultTree.at( point_20_n10_idx ), -1 ); // unreachable
// backward direction
director = qgis::make_unique< QgsVectorLayerDirector > ( network.get(),
-1, QString(), QString(), QString(), QgsVectorLayerDirector::DirectionBackward );
strategy = qgis::make_unique< TestNetworkStrategy >();
director->addStrategy( strategy.release() );
builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 );
director->makeGraph( builder.get(), QVector<QgsPointXY>(), snapped );
graph.reset( builder->graph() );
startVertexIdx = graph->findVertex( QgsPointXY( 10, 10 ) );
QVERIFY( startVertexIdx != -1 );
resultTree.clear();
resultCost.clear();
QgsGraphAnalyzer::dijkstra( graph.get(), startVertexIdx, 0, &resultTree, &resultCost );
point_0_0_idx = graph->findVertex( QgsPointXY( 0, 0 ) );
QVERIFY( point_0_0_idx != -1 );
point_10_0_idx = graph->findVertex( QgsPointXY( 10, 0 ) );
QVERIFY( point_10_0_idx != -1 );
point_10_10_idx = graph->findVertex( QgsPointXY( 10, 10 ) );
QVERIFY( point_10_10_idx != -1 );
point_10_20_idx = graph->findVertex( QgsPointXY( 10, 20 ) );
QVERIFY( point_10_20_idx != -1 );
point_20_10_idx = graph->findVertex( QgsPointXY( 20, 10 ) );
QVERIFY( point_20_10_idx != -1 );
point_20_n10_idx = graph->findVertex( QgsPointXY( 20, -10 ) );
QVERIFY( point_20_n10_idx != -1 );
QCOMPARE( resultTree.at( startVertexIdx ), -1 );
QCOMPARE( resultCost.at( startVertexIdx ), 0.0 );
QCOMPARE( resultTree.at( point_20_10_idx ), -1 );
QCOMPARE( resultTree.at( point_20_n10_idx ), -1 );
QVERIFY( resultTree.at( point_10_20_idx ) != -1 );
QCOMPARE( resultCost.at( point_10_20_idx ), 3.0 );
QCOMPARE( graph->edge( resultTree.at( point_10_20_idx ) ).fromVertex(), startVertexIdx );
QCOMPARE( graph->edge( resultTree.at( point_10_20_idx ) ).toVertex(), point_10_20_idx );
QVERIFY( resultTree.at( point_10_0_idx ) != -1 );
QCOMPARE( resultCost.at( point_10_0_idx ), 1.0 );
QCOMPARE( graph->edge( resultTree.at( point_10_0_idx ) ).fromVertex(), startVertexIdx );
QCOMPARE( graph->edge( resultTree.at( point_10_0_idx ) ).toVertex(), point_10_0_idx );
QVERIFY( resultTree.at( point_0_0_idx ) != -1 );
QCOMPARE( resultCost.at( point_0_0_idx ), 2.0 );
QCOMPARE( graph->edge( resultTree.at( point_0_0_idx ) ).fromVertex(), point_10_0_idx );
QCOMPARE( graph->edge( resultTree.at( point_0_0_idx ) ).toVertex(), point_0_0_idx );
}