|
| 1 | +/*************************************************************************** |
| 2 | + testqgsnetworkanalysis.cpp |
| 3 | + -------------------------- |
| 4 | +Date : November 2016 |
| 5 | +Copyright : (C) 2016 by Nyall Dawson |
| 6 | +Email : nyall dot dawson at gmail dot com |
| 7 | + *************************************************************************** |
| 8 | + * * |
| 9 | + * This program is free software; you can redistribute it and/or modify * |
| 10 | + * it under the terms of the GNU General Public License as published by * |
| 11 | + * the Free Software Foundation; either version 2 of the License, or * |
| 12 | + * (at your option) any later version. * |
| 13 | + * * |
| 14 | + ***************************************************************************/ |
| 15 | +#include "qgstest.h" |
| 16 | + |
| 17 | +//header for class being tested |
| 18 | +#include "qgsgeometrysnapper.h" |
| 19 | +#include "qgsgeometry.h" |
| 20 | +#include <qgsapplication.h> |
| 21 | +#include "qgsvectordataprovider.h" |
| 22 | +#include "qgsvectorlayer.h" |
| 23 | +#include "qgsvectorlayerdirector.h" |
| 24 | +#include "qgsnetworkdistancestrategy.h" |
| 25 | +#include "qgsgraphbuilder.h" |
| 26 | +#include "qgsgraph.h" |
| 27 | + |
| 28 | +class TestQgsNetworkAnalysis : public QObject |
| 29 | +{ |
| 30 | + Q_OBJECT |
| 31 | + |
| 32 | + public: |
| 33 | + |
| 34 | + private slots: |
| 35 | + void initTestCase();// will be called before the first testfunction is executed. |
| 36 | + void cleanupTestCase();// will be called after the last testfunction was executed. |
| 37 | + void init() ;// will be called before each testfunction is executed. |
| 38 | + void cleanup() ;// will be called after every testfunction. |
| 39 | + void testGraph(); |
| 40 | + void testBuild(); |
| 41 | + void testBuildTolerance(); |
| 42 | + |
| 43 | + private: |
| 44 | + std::unique_ptr< QgsVectorLayer > buildNetwork(); |
| 45 | + |
| 46 | + |
| 47 | +}; |
| 48 | + |
| 49 | +void TestQgsNetworkAnalysis::initTestCase() |
| 50 | +{ |
| 51 | + // |
| 52 | + // Runs once before any tests are run |
| 53 | + // |
| 54 | + // init QGIS's paths - true means that all path will be inited from prefix |
| 55 | + QgsApplication::init(); |
| 56 | + QgsApplication::initQgis(); |
| 57 | +} |
| 58 | +void TestQgsNetworkAnalysis::cleanupTestCase() |
| 59 | +{ |
| 60 | + QgsApplication::exitQgis(); |
| 61 | +} |
| 62 | +void TestQgsNetworkAnalysis::init() |
| 63 | +{ |
| 64 | + |
| 65 | +} |
| 66 | +void TestQgsNetworkAnalysis::cleanup() |
| 67 | +{ |
| 68 | + |
| 69 | +} |
| 70 | + |
| 71 | +void TestQgsNetworkAnalysis::testGraph() |
| 72 | +{ |
| 73 | + QgsGraph graph; |
| 74 | + QCOMPARE( graph.vertexCount(), 0 ); |
| 75 | + QCOMPARE( graph.edgeCount(), 0 ); |
| 76 | + graph.addVertex( QgsPointXY( 1, 2 ) ); |
| 77 | + QCOMPARE( graph.vertexCount(), 1 ); |
| 78 | + QCOMPARE( graph.vertex( 0 ).point(), QgsPointXY( 1, 2 ) ); |
| 79 | + QVERIFY( graph.vertex( 0 ).inEdges().empty() ); |
| 80 | + QVERIFY( graph.vertex( 0 ).outEdges().empty() ); |
| 81 | + QCOMPARE( graph.findVertex( QgsPointXY( 1, 2 ) ), 0 ); |
| 82 | + graph.addVertex( QgsPointXY( 3, 4 ) ); |
| 83 | + QCOMPARE( graph.vertexCount(), 2 ); |
| 84 | + QCOMPARE( graph.vertex( 1 ).point(), QgsPointXY( 3, 4 ) ); |
| 85 | + QVERIFY( graph.vertex( 1 ).inEdges().empty() ); |
| 86 | + QVERIFY( graph.vertex( 1 ).outEdges().empty() ); |
| 87 | + QCOMPARE( graph.findVertex( QgsPointXY( 1, 2 ) ), 0 ); |
| 88 | + QCOMPARE( graph.findVertex( QgsPointXY( 3, 4 ) ), 1 ); |
| 89 | + QCOMPARE( graph.edgeCount(), 0 ); |
| 90 | + |
| 91 | + graph.addEdge( 1, 0, QVector< QVariant >() << 9 ); |
| 92 | + QCOMPARE( graph.edgeCount(), 1 ); |
| 93 | + QCOMPARE( graph.edge( 0 ).cost( 0 ).toInt(), 9 ); |
| 94 | + QCOMPARE( graph.edge( 0 ).inVertex(), 0 ); |
| 95 | + QCOMPARE( graph.edge( 0 ).outVertex(), 1 ); |
| 96 | + QCOMPARE( graph.vertex( 0 ).inEdges(), QList< int >() << 0 ); |
| 97 | + QCOMPARE( graph.vertex( 0 ).outEdges(), QList< int >() ); |
| 98 | + QCOMPARE( graph.vertex( 1 ).inEdges(), QList< int >() ); |
| 99 | + QCOMPARE( graph.vertex( 1 ).outEdges(), QList< int >() << 0 ); |
| 100 | + |
| 101 | + graph.addVertex( QgsPointXY( 7, 8 ) ); |
| 102 | + QCOMPARE( graph.vertexCount(), 3 ); |
| 103 | + QCOMPARE( graph.vertex( 2 ).point(), QgsPointXY( 7, 8 ) ); |
| 104 | + QVERIFY( graph.vertex( 2 ).inEdges().empty() ); |
| 105 | + QVERIFY( graph.vertex( 2 ).outEdges().empty() ); |
| 106 | + QCOMPARE( graph.edgeCount(), 1 ); |
| 107 | + graph.addEdge( 2, 1, QVector< QVariant >() << 8 ); |
| 108 | + |
| 109 | + QCOMPARE( graph.edge( 1 ).cost( 0 ).toInt(), 8 ); |
| 110 | + QCOMPARE( graph.edge( 1 ).inVertex(), 1 ); |
| 111 | + QCOMPARE( graph.edge( 1 ).outVertex(), 2 ); |
| 112 | + QCOMPARE( graph.vertex( 1 ).inEdges(), QList< int >() << 1 ); |
| 113 | + QCOMPARE( graph.vertex( 1 ).outEdges(), QList< int >() << 0 ); |
| 114 | + QCOMPARE( graph.vertex( 2 ).inEdges(), QList< int >() ); |
| 115 | + QCOMPARE( graph.vertex( 2 ).outEdges(), QList< int >() << 1 ); |
| 116 | +} |
| 117 | + |
| 118 | +std::unique_ptr<QgsVectorLayer> TestQgsNetworkAnalysis::buildNetwork() |
| 119 | +{ |
| 120 | + std::unique_ptr< QgsVectorLayer > l = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "LineString?crs=epsg:4326" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) ); |
| 121 | + |
| 122 | + QgsFeature ff( 0 ); |
| 123 | + QgsGeometry refGeom = QgsGeometry::fromWkt( QStringLiteral( "LineString(0 0, 10 0, 10 10)" ) ); |
| 124 | + ff.setGeometry( refGeom ); |
| 125 | + QgsFeatureList flist; |
| 126 | + flist << ff; |
| 127 | + l->dataProvider()->addFeatures( flist ); |
| 128 | + |
| 129 | + return l; |
| 130 | +} |
| 131 | + |
| 132 | + |
| 133 | +void TestQgsNetworkAnalysis::testBuild() |
| 134 | +{ |
| 135 | + std::unique_ptr<QgsVectorLayer> network = buildNetwork(); |
| 136 | + std::unique_ptr< QgsVectorLayerDirector > director = qgis::make_unique< QgsVectorLayerDirector > ( network.get(), |
| 137 | + -1, QString(), QString(), QString(), QgsVectorLayerDirector::DirectionBoth ); |
| 138 | + std::unique_ptr< QgsNetworkDistanceStrategy > strategy = qgis::make_unique< QgsNetworkDistanceStrategy >(); |
| 139 | + director->addStrategy( strategy.release() ); |
| 140 | + std::unique_ptr< QgsGraphBuilder > builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 ); |
| 141 | + |
| 142 | + QVector<QgsPointXY > snapped; |
| 143 | + director->makeGraph( builder.get(), QVector<QgsPointXY>() << QgsPointXY( 0, 0 ) << QgsPointXY( 10, 10 ), snapped ); |
| 144 | + QCOMPARE( snapped, QVector<QgsPointXY>() << QgsPointXY( 0, 0 ) << QgsPointXY( 10, 10 ) ); |
| 145 | + std::unique_ptr< QgsGraph > graph( builder->graph() ); |
| 146 | + QCOMPARE( graph->vertexCount(), 3 ); |
| 147 | + QCOMPARE( graph->edgeCount(), 4 ); |
| 148 | + QCOMPARE( graph->vertex( 0 ).point(), QgsPointXY( 0, 0 ) ); |
| 149 | + QCOMPARE( graph->vertex( 0 ).inEdges(), QList< int >() << 1 ); |
| 150 | + QCOMPARE( graph->edge( 1 ).inVertex(), 0 ); |
| 151 | + QCOMPARE( graph->edge( 1 ).outVertex(), 1 ); |
| 152 | + QCOMPARE( graph->vertex( 0 ).outEdges(), QList< int >() << 0 ); |
| 153 | + QCOMPARE( graph->edge( 0 ).inVertex(), 1 ); |
| 154 | + QCOMPARE( graph->edge( 0 ).outVertex(), 0 ); |
| 155 | + QCOMPARE( graph->vertex( 1 ).point(), QgsPointXY( 10, 0 ) ); |
| 156 | + QCOMPARE( graph->vertex( 1 ).inEdges(), QList< int >() << 0 << 3 ); |
| 157 | + QCOMPARE( graph->vertex( 1 ).outEdges(), QList< int >() << 1 << 2 ); |
| 158 | + QCOMPARE( graph->edge( 2 ).inVertex(), 2 ); |
| 159 | + QCOMPARE( graph->edge( 2 ).outVertex(), 1 ); |
| 160 | + QCOMPARE( graph->edge( 3 ).inVertex(), 1 ); |
| 161 | + QCOMPARE( graph->edge( 3 ).outVertex(), 2 ); |
| 162 | + QCOMPARE( graph->vertex( 2 ).point(), QgsPointXY( 10, 10 ) ); |
| 163 | + QCOMPARE( graph->vertex( 2 ).inEdges(), QList< int >() << 2 ); |
| 164 | + QCOMPARE( graph->vertex( 2 ).outEdges(), QList< int >() << 3 ); |
| 165 | + |
| 166 | + builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 ); |
| 167 | + director->makeGraph( builder.get(), QVector<QgsPointXY>() << QgsPointXY( 10, 0 ) << QgsPointXY( 10, 10 ), snapped ); |
| 168 | + QCOMPARE( snapped, QVector<QgsPointXY>() << QgsPointXY( 10, 0 ) << QgsPointXY( 10, 10 ) ); |
| 169 | + |
| 170 | + builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 ); |
| 171 | + director->makeGraph( builder.get(), QVector<QgsPointXY>(), snapped ); |
| 172 | + QCOMPARE( snapped, QVector<QgsPointXY>() ); |
| 173 | + |
| 174 | + builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 ); |
| 175 | + director->makeGraph( builder.get(), QVector<QgsPointXY>() << QgsPointXY( 0.2, 0.1 ) << QgsPointXY( 10.1, 9 ), snapped ); |
| 176 | + QCOMPARE( snapped, QVector<QgsPointXY>() << QgsPointXY( 0.2, 0.0 ) << QgsPointXY( 10.0, 9 ) ); |
| 177 | + graph.reset( builder->graph() ); |
| 178 | + QCOMPARE( graph->vertexCount(), 5 ); |
| 179 | + QCOMPARE( graph->edgeCount(), 8 ); |
| 180 | + |
| 181 | +} |
| 182 | + |
| 183 | +void TestQgsNetworkAnalysis::testBuildTolerance() |
| 184 | +{ |
| 185 | + std::unique_ptr<QgsVectorLayer> network = buildNetwork(); |
| 186 | + // has already a linestring LineString(0 0, 10 0, 10 10) |
| 187 | + |
| 188 | + QgsFeature ff( 0 ); |
| 189 | + // 0.1 distance gap |
| 190 | + QgsGeometry refGeom = QgsGeometry::fromWkt( QStringLiteral( "LineString(10.1 10, 20 10 )" ) ); |
| 191 | + ff.setGeometry( refGeom ); |
| 192 | + QgsFeatureList flist; |
| 193 | + flist << ff; |
| 194 | + network->dataProvider()->addFeatures( flist ); |
| 195 | + |
| 196 | + std::unique_ptr< QgsVectorLayerDirector > director = qgis::make_unique< QgsVectorLayerDirector > ( network.get(), |
| 197 | + -1, QString(), QString(), QString(), QgsVectorLayerDirector::DirectionBoth ); |
| 198 | + std::unique_ptr< QgsNetworkDistanceStrategy > strategy = qgis::make_unique< QgsNetworkDistanceStrategy >(); |
| 199 | + director->addStrategy( strategy.release() ); |
| 200 | + std::unique_ptr< QgsGraphBuilder > builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0 ); |
| 201 | + |
| 202 | + QVector<QgsPointXY > snapped; |
| 203 | + director->makeGraph( builder.get(), QVector<QgsPointXY>(), snapped ); |
| 204 | + std::unique_ptr< QgsGraph > graph( builder->graph() ); |
| 205 | + QCOMPARE( graph->vertexCount(), 5 ); |
| 206 | + QCOMPARE( graph->edgeCount(), 6 ); |
| 207 | + QCOMPARE( graph->vertex( 0 ).point(), QgsPointXY( 0, 0 ) ); |
| 208 | + QCOMPARE( graph->vertex( 0 ).inEdges(), QList< int >() << 1 ); |
| 209 | + QCOMPARE( graph->edge( 1 ).inVertex(), 0 ); |
| 210 | + QCOMPARE( graph->edge( 1 ).outVertex(), 1 ); |
| 211 | + QCOMPARE( graph->vertex( 0 ).outEdges(), QList< int >() << 0 ); |
| 212 | + QCOMPARE( graph->edge( 0 ).inVertex(), 1 ); |
| 213 | + QCOMPARE( graph->edge( 0 ).outVertex(), 0 ); |
| 214 | + QCOMPARE( graph->vertex( 1 ).point(), QgsPointXY( 10, 0 ) ); |
| 215 | + QCOMPARE( graph->vertex( 1 ).inEdges(), QList< int >() << 0 << 3 ); |
| 216 | + QCOMPARE( graph->vertex( 1 ).outEdges(), QList< int >() << 1 << 2 ); |
| 217 | + QCOMPARE( graph->edge( 2 ).inVertex(), 2 ); |
| 218 | + QCOMPARE( graph->edge( 2 ).outVertex(), 1 ); |
| 219 | + QCOMPARE( graph->edge( 3 ).inVertex(), 1 ); |
| 220 | + QCOMPARE( graph->edge( 3 ).outVertex(), 2 ); |
| 221 | + QCOMPARE( graph->vertex( 2 ).point(), QgsPointXY( 10, 10 ) ); |
| 222 | + QCOMPARE( graph->vertex( 2 ).inEdges(), QList< int >() << 2 ); |
| 223 | + QCOMPARE( graph->vertex( 2 ).outEdges(), QList< int >() << 3 ); |
| 224 | + QCOMPARE( graph->vertex( 3 ).point(), QgsPointXY( 10.1, 10 ) ); |
| 225 | + QCOMPARE( graph->vertex( 3 ).inEdges(), QList< int >() << 5 ); |
| 226 | + QCOMPARE( graph->vertex( 3 ).outEdges(), QList< int >() << 4 ); |
| 227 | + QCOMPARE( graph->vertex( 4 ).point(), QgsPointXY( 20, 10 ) ); |
| 228 | + QCOMPARE( graph->edge( 4 ).inVertex(), 4 ); |
| 229 | + QCOMPARE( graph->edge( 4 ).outVertex(), 3 ); |
| 230 | + QCOMPARE( graph->edge( 5 ).inVertex(), 3 ); |
| 231 | + QCOMPARE( graph->edge( 5 ).outVertex(), 4 ); |
| 232 | + |
| 233 | +#if 0 // broken |
| 234 | + // with tolerance |
| 235 | + builder = qgis::make_unique< QgsGraphBuilder > ( network->sourceCrs(), true, 0.11 ); |
| 236 | + director->makeGraph( builder.get(), QVector<QgsPointXY>(), snapped ); |
| 237 | + graph.reset( builder->graph() ); |
| 238 | + QCOMPARE( graph->vertexCount(), 5 ); |
| 239 | + QCOMPARE( graph->edgeCount(), 6 ); |
| 240 | + QCOMPARE( graph->vertex( 0 ).point(), QgsPointXY( 0, 0 ) ); |
| 241 | + QCOMPARE( graph->vertex( 0 ).inEdges(), QList< int >() << 1 ); |
| 242 | + QCOMPARE( graph->edge( 1 ).inVertex(), 0 ); |
| 243 | + QCOMPARE( graph->edge( 1 ).outVertex(), 1 ); |
| 244 | + QCOMPARE( graph->vertex( 0 ).outEdges(), QList< int >() << 0 ); |
| 245 | + QCOMPARE( graph->edge( 0 ).inVertex(), 1 ); |
| 246 | + QCOMPARE( graph->edge( 0 ).outVertex(), 0 ); |
| 247 | + QCOMPARE( graph->vertex( 1 ).point(), QgsPointXY( 10, 0 ) ); |
| 248 | + QCOMPARE( graph->vertex( 1 ).inEdges(), QList< int >() << 0 << 3 ); |
| 249 | + QCOMPARE( graph->vertex( 1 ).outEdges(), QList< int >() << 1 << 2 ); |
| 250 | + QCOMPARE( graph->edge( 2 ).inVertex(), 2 ); |
| 251 | + QCOMPARE( graph->edge( 2 ).outVertex(), 1 ); |
| 252 | + QCOMPARE( graph->edge( 3 ).inVertex(), 1 ); |
| 253 | + QCOMPARE( graph->edge( 3 ).outVertex(), 2 ); |
| 254 | + QCOMPARE( graph->vertex( 2 ).point(), QgsPointXY( 10, 10 ) ); |
| 255 | + QCOMPARE( graph->vertex( 2 ).inEdges(), QList< int >() << 2 << 5 ); |
| 256 | + QCOMPARE( graph->vertex( 2 ).outEdges(), QList< int >() << 3 << 4 ); |
| 257 | + QCOMPARE( graph->vertex( 3 ).point(), QgsPointXY( 10.1, 10 ) ); |
| 258 | + QCOMPARE( graph->vertex( 3 ).inEdges(), QList< int >() ); |
| 259 | + QCOMPARE( graph->vertex( 3 ).outEdges(), QList< int >() ); |
| 260 | + QCOMPARE( graph->vertex( 4 ).point(), QgsPointXY( 20, 10 ) ); |
| 261 | + QCOMPARE( graph->edge( 4 ).inVertex(), 4 ); |
| 262 | + QCOMPARE( graph->edge( 4 ).outVertex(), 2 ); |
| 263 | + QCOMPARE( graph->edge( 5 ).inVertex(), 2 ); |
| 264 | + QCOMPARE( graph->edge( 5 ).outVertex(), 4 ); |
| 265 | +#endif |
| 266 | +} |
| 267 | + |
| 268 | + |
| 269 | + |
| 270 | +QGSTEST_MAIN( TestQgsNetworkAnalysis ) |
| 271 | +#include "testqgsnetworkanalysis.moc" |
0 commit comments