From b337335e9ccc7e075985200a8bc74c12242c5a75 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Sun, 29 Oct 2017 08:21:04 +1000 Subject: [PATCH] Start unit tests for network analysis lib --- .../network/qgsvectorlayerdirector.cpp | 1 - tests/src/analysis/CMakeLists.txt | 2 + tests/src/analysis/testqgsnetworkanalysis.cpp | 271 ++++++++++++++++++ 3 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 tests/src/analysis/testqgsnetworkanalysis.cpp diff --git a/src/analysis/network/qgsvectorlayerdirector.cpp b/src/analysis/network/qgsvectorlayerdirector.cpp index edc7a155656..97e0fbbcb96 100644 --- a/src/analysis/network/qgsvectorlayerdirector.cpp +++ b/src/analysis/network/qgsvectorlayerdirector.cpp @@ -200,7 +200,6 @@ void QgsVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, const if ( pointLengthMap[ i ].mLength > info.mLength ) { - Q_UNUSED( info.mTiedPoint ); info.mFirstPoint = pt1; info.mLastPoint = pt2; diff --git a/tests/src/analysis/CMakeLists.txt b/tests/src/analysis/CMakeLists.txt index 7e782f5e86c..bda7bee4d3c 100644 --- a/tests/src/analysis/CMakeLists.txt +++ b/tests/src/analysis/CMakeLists.txt @@ -17,6 +17,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src/core/raster ${CMAKE_SOURCE_DIR}/src/core/symbology ${CMAKE_SOURCE_DIR}/src/analysis + ${CMAKE_SOURCE_DIR}/src/analysis/network ${CMAKE_SOURCE_DIR}/src/analysis/processing ${CMAKE_SOURCE_DIR}/src/analysis/vector ${CMAKE_SOURCE_DIR}/src/analysis/raster @@ -71,6 +72,7 @@ SET(TESTS testqgszonalstatistics.cpp testqgsrastercalculator.cpp testqgsalignraster.cpp + testqgsnetworkanalysis.cpp ) FOREACH(TESTSRC ${TESTS}) diff --git a/tests/src/analysis/testqgsnetworkanalysis.cpp b/tests/src/analysis/testqgsnetworkanalysis.cpp new file mode 100644 index 00000000000..614e63b2cd0 --- /dev/null +++ b/tests/src/analysis/testqgsnetworkanalysis.cpp @@ -0,0 +1,271 @@ +/*************************************************************************** + testqgsnetworkanalysis.cpp + -------------------------- +Date : November 2016 +Copyright : (C) 2016 by Nyall Dawson +Email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include "qgstest.h" + +//header for class being tested +#include "qgsgeometrysnapper.h" +#include "qgsgeometry.h" +#include +#include "qgsvectordataprovider.h" +#include "qgsvectorlayer.h" +#include "qgsvectorlayerdirector.h" +#include "qgsnetworkdistancestrategy.h" +#include "qgsgraphbuilder.h" +#include "qgsgraph.h" + +class TestQgsNetworkAnalysis : public QObject +{ + Q_OBJECT + + public: + + private slots: + void initTestCase();// will be called before the first testfunction is executed. + void cleanupTestCase();// will be called after the last testfunction was executed. + void init() ;// will be called before each testfunction is executed. + void cleanup() ;// will be called after every testfunction. + void testGraph(); + void testBuild(); + void testBuildTolerance(); + + private: + std::unique_ptr< QgsVectorLayer > buildNetwork(); + + +}; + +void TestQgsNetworkAnalysis::initTestCase() +{ + // + // Runs once before any tests are run + // + // init QGIS's paths - true means that all path will be inited from prefix + QgsApplication::init(); + QgsApplication::initQgis(); +} +void TestQgsNetworkAnalysis::cleanupTestCase() +{ + QgsApplication::exitQgis(); +} +void TestQgsNetworkAnalysis::init() +{ + +} +void TestQgsNetworkAnalysis::cleanup() +{ + +} + +void TestQgsNetworkAnalysis::testGraph() +{ + QgsGraph graph; + QCOMPARE( graph.vertexCount(), 0 ); + QCOMPARE( graph.edgeCount(), 0 ); + graph.addVertex( QgsPointXY( 1, 2 ) ); + QCOMPARE( graph.vertexCount(), 1 ); + QCOMPARE( graph.vertex( 0 ).point(), QgsPointXY( 1, 2 ) ); + QVERIFY( graph.vertex( 0 ).inEdges().empty() ); + QVERIFY( graph.vertex( 0 ).outEdges().empty() ); + QCOMPARE( graph.findVertex( QgsPointXY( 1, 2 ) ), 0 ); + graph.addVertex( QgsPointXY( 3, 4 ) ); + QCOMPARE( graph.vertexCount(), 2 ); + QCOMPARE( graph.vertex( 1 ).point(), QgsPointXY( 3, 4 ) ); + QVERIFY( graph.vertex( 1 ).inEdges().empty() ); + QVERIFY( graph.vertex( 1 ).outEdges().empty() ); + QCOMPARE( graph.findVertex( QgsPointXY( 1, 2 ) ), 0 ); + QCOMPARE( graph.findVertex( QgsPointXY( 3, 4 ) ), 1 ); + QCOMPARE( graph.edgeCount(), 0 ); + + graph.addEdge( 1, 0, QVector< QVariant >() << 9 ); + QCOMPARE( graph.edgeCount(), 1 ); + QCOMPARE( graph.edge( 0 ).cost( 0 ).toInt(), 9 ); + QCOMPARE( graph.edge( 0 ).inVertex(), 0 ); + QCOMPARE( graph.edge( 0 ).outVertex(), 1 ); + QCOMPARE( graph.vertex( 0 ).inEdges(), QList< int >() << 0 ); + QCOMPARE( graph.vertex( 0 ).outEdges(), QList< int >() ); + QCOMPARE( graph.vertex( 1 ).inEdges(), QList< int >() ); + QCOMPARE( graph.vertex( 1 ).outEdges(), QList< int >() << 0 ); + + graph.addVertex( QgsPointXY( 7, 8 ) ); + QCOMPARE( graph.vertexCount(), 3 ); + QCOMPARE( graph.vertex( 2 ).point(), QgsPointXY( 7, 8 ) ); + QVERIFY( graph.vertex( 2 ).inEdges().empty() ); + QVERIFY( graph.vertex( 2 ).outEdges().empty() ); + QCOMPARE( graph.edgeCount(), 1 ); + graph.addEdge( 2, 1, QVector< QVariant >() << 8 ); + + QCOMPARE( graph.edge( 1 ).cost( 0 ).toInt(), 8 ); + QCOMPARE( graph.edge( 1 ).inVertex(), 1 ); + QCOMPARE( graph.edge( 1 ).outVertex(), 2 ); + QCOMPARE( graph.vertex( 1 ).inEdges(), QList< int >() << 1 ); + QCOMPARE( graph.vertex( 1 ).outEdges(), QList< int >() << 0 ); + QCOMPARE( graph.vertex( 2 ).inEdges(), QList< int >() ); + QCOMPARE( graph.vertex( 2 ).outEdges(), QList< int >() << 1 ); +} + +std::unique_ptr TestQgsNetworkAnalysis::buildNetwork() +{ + std::unique_ptr< QgsVectorLayer > l = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "LineString?crs=epsg:4326" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) ); + + QgsFeature ff( 0 ); + QgsGeometry refGeom = QgsGeometry::fromWkt( QStringLiteral( "LineString(0 0, 10 0, 10 10)" ) ); + ff.setGeometry( refGeom ); + QgsFeatureList flist; + flist << ff; + l->dataProvider()->addFeatures( flist ); + + return l; +} + + +void TestQgsNetworkAnalysis::testBuild() +{ + std::unique_ptr network = buildNetwork(); + std::unique_ptr< QgsVectorLayerDirector > director = qgis::make_unique< QgsVectorLayerDirector > ( network.get(), + -1, QString(), QString(), QString(), QgsVectorLayerDirector::DirectionBoth ); + std::unique_ptr< QgsNetworkDistanceStrategy > strategy = qgis::make_unique< QgsNetworkDistanceStrategy >(); + director->addStrategy( strategy.release() ); + std::unique_ptr< QgsGraphBuilder > builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 ); + + QVector snapped; + director->makeGraph( builder.get(), QVector() << QgsPointXY( 0, 0 ) << QgsPointXY( 10, 10 ), snapped ); + QCOMPARE( snapped, QVector() << QgsPointXY( 0, 0 ) << QgsPointXY( 10, 10 ) ); + std::unique_ptr< QgsGraph > graph( builder->graph() ); + QCOMPARE( graph->vertexCount(), 3 ); + QCOMPARE( graph->edgeCount(), 4 ); + 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( 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( 2 ).point(), QgsPointXY( 10, 10 ) ); + QCOMPARE( graph->vertex( 2 ).inEdges(), QList< int >() << 2 ); + QCOMPARE( graph->vertex( 2 ).outEdges(), QList< int >() << 3 ); + + builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 ); + director->makeGraph( builder.get(), QVector() << QgsPointXY( 10, 0 ) << QgsPointXY( 10, 10 ), snapped ); + QCOMPARE( snapped, QVector() << QgsPointXY( 10, 0 ) << QgsPointXY( 10, 10 ) ); + + builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 ); + director->makeGraph( builder.get(), QVector(), snapped ); + QCOMPARE( snapped, QVector() ); + + builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 ); + director->makeGraph( builder.get(), QVector() << QgsPointXY( 0.2, 0.1 ) << QgsPointXY( 10.1, 9 ), snapped ); + QCOMPARE( snapped, QVector() << QgsPointXY( 0.2, 0.0 ) << QgsPointXY( 10.0, 9 ) ); + graph.reset( builder->graph() ); + QCOMPARE( graph->vertexCount(), 5 ); + QCOMPARE( graph->edgeCount(), 8 ); + +} + +void TestQgsNetworkAnalysis::testBuildTolerance() +{ + std::unique_ptr network = buildNetwork(); + // has already a linestring LineString(0 0, 10 0, 10 10) + + QgsFeature ff( 0 ); + // 0.1 distance gap + QgsGeometry refGeom = QgsGeometry::fromWkt( QStringLiteral( "LineString(10.1 10, 20 10 )" ) ); + ff.setGeometry( refGeom ); + QgsFeatureList flist; + flist << ff; + network->dataProvider()->addFeatures( flist ); + + std::unique_ptr< QgsVectorLayerDirector > director = qgis::make_unique< QgsVectorLayerDirector > ( network.get(), + -1, QString(), QString(), QString(), QgsVectorLayerDirector::DirectionBoth ); + std::unique_ptr< QgsNetworkDistanceStrategy > strategy = qgis::make_unique< QgsNetworkDistanceStrategy >(); + director->addStrategy( strategy.release() ); + std::unique_ptr< QgsGraphBuilder > builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 ); + + QVector snapped; + director->makeGraph( builder.get(), QVector(), snapped ); + std::unique_ptr< QgsGraph > graph( 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( 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( 2 ).point(), QgsPointXY( 10, 10 ) ); + QCOMPARE( graph->vertex( 2 ).inEdges(), QList< int >() << 2 ); + QCOMPARE( graph->vertex( 2 ).outEdges(), QList< int >() << 3 ); + QCOMPARE( graph->vertex( 3 ).point(), QgsPointXY( 10.1, 10 ) ); + QCOMPARE( graph->vertex( 3 ).inEdges(), QList< int >() << 5 ); + QCOMPARE( graph->vertex( 3 ).outEdges(), QList< int >() << 4 ); + QCOMPARE( graph->vertex( 4 ).point(), QgsPointXY( 20, 10 ) ); + QCOMPARE( graph->edge( 4 ).inVertex(), 4 ); + QCOMPARE( graph->edge( 4 ).outVertex(), 3 ); + QCOMPARE( graph->edge( 5 ).inVertex(), 3 ); + QCOMPARE( graph->edge( 5 ).outVertex(), 4 ); + +#if 0 // broken + // with tolerance + builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0.11 ); + 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( 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( 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( 3 ).point(), QgsPointXY( 10.1, 10 ) ); + QCOMPARE( graph->vertex( 3 ).inEdges(), QList< int >() ); + QCOMPARE( graph->vertex( 3 ).outEdges(), 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 +} + + + +QGSTEST_MAIN( TestQgsNetworkAnalysis ) +#include "testqgsnetworkanalysis.moc"