Skip to content
Permalink
Browse files

Start unit tests for network analysis lib

  • Loading branch information
nyalldawson committed Oct 28, 2017
1 parent 5ffd721 commit b337335e9ccc7e075985200a8bc74c12242c5a75
@@ -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;

@@ -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})
@@ -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 <qgsapplication.h>
#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<QgsVectorLayer> 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<QgsVectorLayer> 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<QgsPointXY > snapped;
director->makeGraph( builder.get(), QVector<QgsPointXY>() << QgsPointXY( 0, 0 ) << QgsPointXY( 10, 10 ), snapped );
QCOMPARE( snapped, QVector<QgsPointXY>() << 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>() << QgsPointXY( 10, 0 ) << QgsPointXY( 10, 10 ), snapped );
QCOMPARE( snapped, QVector<QgsPointXY>() << QgsPointXY( 10, 0 ) << QgsPointXY( 10, 10 ) );

builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 );
director->makeGraph( builder.get(), QVector<QgsPointXY>(), snapped );
QCOMPARE( snapped, QVector<QgsPointXY>() );

builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 );
director->makeGraph( builder.get(), QVector<QgsPointXY>() << QgsPointXY( 0.2, 0.1 ) << QgsPointXY( 10.1, 9 ), snapped );
QCOMPARE( snapped, QVector<QgsPointXY>() << 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<QgsVectorLayer> 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<QgsPointXY > snapped;
director->makeGraph( builder.get(), QVector<QgsPointXY>(), 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<QgsPointXY>(), 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"

0 comments on commit b337335

Please sign in to comment.
You can’t perform that action at this time.