1 /***************************************************************************
2 testqgsmeasuretool.cpp
3 ----------------------
4 Date : 2016-02-14
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 #include "qgisapp.h"
17 #include "qgsapplication.h"
18 #include "qgsvectorlayer.h"
19 #include "qgsfeature.h"
20 #include "qgsgeometry.h"
21 #include "qgsvectordataprovider.h"
22 #include "qgsmeasuretool.h"
23 #include "qgsmeasuredialog.h"
24 #include "qgsproject.h"
25 #include "qgsmapcanvas.h"
26 #include "qgsunittypes.h"
27
28 /**
29 * \ingroup UnitTests
30 * This is a unit test for the measure tool
31 */
32 class TestQgsMeasureTool : public QObject
33 {
34 Q_OBJECT
35 public:
36 TestQgsMeasureTool();
37
38 private slots:
39 void initTestCase();// will be called before the first testfunction is executed.
40 void cleanupTestCase();// will be called after the last testfunction was executed.
init()41 void init() {} // will be called before each testfunction is executed.
cleanup()42 void cleanup() {} // will be called after every testfunction.
43 void testLengthCalculationCartesian();
44 void testLengthCalculationProjected();
45 void testLengthCalculationNoCrs();
46 void testAreaCalculationCartesian();
47 void testAreaCalculationProjected();
48 void degreeDecimalPlaces();
49
50 private:
51 QgisApp *mQgisApp = nullptr;
52 QgsMapCanvas *mCanvas = nullptr;
53 };
54
55 TestQgsMeasureTool::TestQgsMeasureTool() = default;
56
57 //runs before all tests
initTestCase()58 void TestQgsMeasureTool::initTestCase()
59 {
60 qDebug() << "TestQgisAppClipboard::initTestCase()";
61 // init QGIS's paths - true means that all path will be inited from prefix
62 QgsApplication::init();
63 QgsApplication::initQgis();
64
65 // Set up the QgsSettings environment
66 QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) );
67 QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) );
68 QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) );
69
70 mQgisApp = new QgisApp();
71 mCanvas = new QgsMapCanvas();
72
73 // enforce C locale because the tests expect it
74 // (decimal separators / thousand separators)
75 QLocale::setDefault( QLocale::c() );
76 }
77
78 //runs after all tests
cleanupTestCase()79 void TestQgsMeasureTool::cleanupTestCase()
80 {
81 delete mCanvas;
82 QgsApplication::exitQgis();
83 }
84
testLengthCalculationCartesian()85 void TestQgsMeasureTool::testLengthCalculationCartesian()
86 {
87 //test length measurement
88 QgsSettings s;
89 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
90
91 // set project CRS and ellipsoid
92 QgsCoordinateReferenceSystem srs( QStringLiteral( "EPSG:3111" ) );
93 mCanvas->setDestinationCrs( srs );
94 QgsProject::instance()->setCrs( srs );
95 QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
96 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceMeters );
97
98 // run length calculation
99 std::unique_ptr< QgsMeasureTool > tool( new QgsMeasureTool( mCanvas, false ) );
100 std::unique_ptr< QgsMeasureDialog > dlg( new QgsMeasureDialog( tool.get() ) );
101
102 dlg->mCartesian->setChecked( true );
103
104 tool->restart();
105 tool->addPoint( QgsPointXY( 2484588, 2425722 ) );
106 tool->addPoint( QgsPointXY( 2482767, 2398853 ) );
107 //force dialog recalculation
108 dlg->addPoint();
109
110 // check result
111 QString measureString = dlg->editTotal->text();
112 double measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
113 double expected = 26930.637;
114 QGSCOMPARENEAR( measured, expected, 0.001 );
115
116 // change project length unit, check calculation respects unit
117 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceFeet );
118 std::unique_ptr< QgsMeasureTool > tool2( new QgsMeasureTool( mCanvas, false ) );
119 std::unique_ptr< QgsMeasureDialog > dlg2( new QgsMeasureDialog( tool2.get() ) );
120 dlg2->mCartesian->setChecked( true );
121
122 tool2->restart();
123 tool2->addPoint( QgsPointXY( 2484588, 2425722 ) );
124 tool2->addPoint( QgsPointXY( 2482767, 2398853 ) );
125 //force dialog recalculation
126 dlg2->addPoint();
127
128 // check result
129 measureString = dlg2->editTotal->text();
130 measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
131 expected = 88355.108;
132 QGSCOMPARENEAR( measured, expected, 0.001 );
133
134 // check new CoordinateReferenceSystem, points must be reprojected to paint them successfully (issue #15182)
135 QgsCoordinateReferenceSystem srs2( QStringLiteral( "EPSG:4326" ) );
136
137 QgsCoordinateTransform ct( srs, srs2, QgsProject::instance() );
138
139 QgsPointXY p0 = ct.transform( tool2->points()[0] );
140 QgsPointXY p1 = ct.transform( tool2->points()[1] );
141
142 mCanvas->setDestinationCrs( srs2 );
143
144 QgsPointXY n0 = tool2->points()[0];
145 QgsPointXY n1 = tool2->points()[1];
146
147 QGSCOMPARENEAR( p0.x(), n0.x(), 0.001 );
148 QGSCOMPARENEAR( p0.y(), n0.y(), 0.001 );
149 QGSCOMPARENEAR( p1.x(), n1.x(), 0.001 );
150 QGSCOMPARENEAR( p1.y(), n1.y(), 0.001 );
151
152 }
testLengthCalculationProjected()153 void TestQgsMeasureTool::testLengthCalculationProjected()
154 {
155 //test length measurement
156 QgsSettings s;
157 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
158
159 // set project CRS and ellipsoid
160 QgsCoordinateReferenceSystem srs( QStringLiteral( "EPSG:3111" ) );
161 mCanvas->setDestinationCrs( srs );
162 QgsProject::instance()->setCrs( srs );
163 QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
164 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceMeters );
165
166 // run length calculation
167 std::unique_ptr< QgsMeasureTool > tool( new QgsMeasureTool( mCanvas, false ) );
168 std::unique_ptr< QgsMeasureDialog > dlg( new QgsMeasureDialog( tool.get() ) );
169 dlg->mEllipsoidal->setChecked( true );
170
171 tool->restart();
172 tool->addPoint( QgsPointXY( 2484588, 2425722 ) );
173 tool->addPoint( QgsPointXY( 2482767, 2398853 ) );
174 //force dialog recalculation
175 dlg->addPoint();
176
177 // check result
178 QString measureString = dlg->editTotal->text();
179 double measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
180 double expected = 26932.156;
181 QGSCOMPARENEAR( measured, expected, 0.001 );
182
183 // change project length unit, check calculation respects unit
184 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceFeet );
185 std::unique_ptr< QgsMeasureTool > tool2( new QgsMeasureTool( mCanvas, false ) );
186 std::unique_ptr< QgsMeasureDialog > dlg2( new QgsMeasureDialog( tool2.get() ) );
187 dlg2->mEllipsoidal->setChecked( true );
188
189 tool2->restart();
190 tool2->addPoint( QgsPointXY( 2484588, 2425722 ) );
191 tool2->addPoint( QgsPointXY( 2482767, 2398853 ) );
192 //force dialog recalculation
193 dlg2->addPoint();
194
195 // check result
196 measureString = dlg2->editTotal->text();
197 measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
198 expected = 88360.0918635;
199 QGSCOMPARENEAR( measured, expected, 0.001 );
200
201 // check new CoordinateReferenceSystem, points must be reprojected to paint them successfully (issue #15182)
202 QgsCoordinateReferenceSystem srs2( QStringLiteral( "EPSG:4326" ) );
203
204 QgsCoordinateTransform ct( srs, srs2, QgsProject::instance() );
205
206 QgsPointXY p0 = ct.transform( tool2->points()[0] );
207 QgsPointXY p1 = ct.transform( tool2->points()[1] );
208
209 mCanvas->setDestinationCrs( srs2 );
210
211 QgsPointXY n0 = tool2->points()[0];
212 QgsPointXY n1 = tool2->points()[1];
213
214 QGSCOMPARENEAR( p0.x(), n0.x(), 0.001 );
215 QGSCOMPARENEAR( p0.y(), n0.y(), 0.001 );
216 QGSCOMPARENEAR( p1.x(), n1.x(), 0.001 );
217 QGSCOMPARENEAR( p1.y(), n1.y(), 0.001 );
218 }
219
220
testLengthCalculationNoCrs()221 void TestQgsMeasureTool::testLengthCalculationNoCrs()
222 {
223 // test length measurement when no projection is set
224 QSettings s;
225 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
226
227 // set project CRS and ellipsoid
228 mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem() );
229 QgsProject::instance()->setCrs( QgsCoordinateReferenceSystem() );
230
231 // run length calculation
232 std::unique_ptr< QgsMeasureTool > tool( new QgsMeasureTool( mCanvas, false ) );
233 std::unique_ptr< QgsMeasureDialog > dlg( new QgsMeasureDialog( tool.get() ) );
234
235 tool->restart();
236 tool->addPoint( QgsPointXY( 2484588, 2425722 ) );
237 tool->addPoint( QgsPointXY( 2482767, 2398853 ) );
238 //force dialog recalculation
239 dlg->addPoint();
240
241 // check result
242 QString measureString = dlg->editTotal->text();
243 double measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
244 double expected = 26930.63686584482;
245 QGSCOMPARENEAR( measured, expected, 0.001 );
246 }
247
testAreaCalculationCartesian()248 void TestQgsMeasureTool::testAreaCalculationCartesian()
249 {
250 //test area measurement
251 QgsSettings s;
252 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
253
254 // set project CRS and ellipsoid
255 QgsCoordinateReferenceSystem srs( QStringLiteral( "EPSG:3111" ) );
256 mCanvas->setDestinationCrs( srs );
257 QgsProject::instance()->setCrs( srs );
258 QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
259 QgsProject::instance()->setAreaUnits( QgsUnitTypes::AreaSquareMeters );
260
261 // run length calculation
262 std::unique_ptr< QgsMeasureTool > tool( new QgsMeasureTool( mCanvas, true ) );
263 std::unique_ptr< QgsMeasureDialog > dlg( new QgsMeasureDialog( tool.get() ) );
264
265 dlg->mCartesian->setChecked( true );
266
267 tool->restart();
268 tool->addPoint( QgsPointXY( 2484588, 2425722 ) );
269 tool->addPoint( QgsPointXY( 2482767, 2398853 ) );
270 tool->addPoint( QgsPointXY( 2520109, 2397715 ) );
271 tool->addPoint( QgsPointXY( 2520792, 2425494 ) );
272 //force dialog recalculation
273 dlg->addPoint();
274
275 // check result
276 QString measureString = dlg->editTotal->text();
277 double measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
278 double expected = 1005640568.0;
279 QGSCOMPARENEAR( measured, expected, 1.0 );
280
281 // change project area unit, check calculation respects unit
282 QgsProject::instance()->setAreaUnits( QgsUnitTypes::AreaSquareMiles );
283 std::unique_ptr< QgsMeasureTool > tool2( new QgsMeasureTool( mCanvas, true ) );
284 std::unique_ptr< QgsMeasureDialog > dlg2( new QgsMeasureDialog( tool2.get() ) );
285 dlg2->mCartesian->setChecked( true );
286
287 tool2->restart();
288 tool2->addPoint( QgsPointXY( 2484588, 2425722 ) );
289 tool2->addPoint( QgsPointXY( 2482767, 2398853 ) );
290 tool2->addPoint( QgsPointXY( 2520109, 2397715 ) );
291 tool2->addPoint( QgsPointXY( 2520792, 2425494 ) );
292 //force dialog recalculation
293 dlg2->addPoint();
294
295 // check result
296 measureString = dlg2->editTotal->text();
297 measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
298 expected = 388.280;
299 QGSCOMPARENEAR( measured, expected, 0.001 );
300 }
301
testAreaCalculationProjected()302 void TestQgsMeasureTool::testAreaCalculationProjected()
303 {
304 //test area measurement
305 QgsSettings s;
306 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
307
308 // set project CRS and ellipsoid
309 QgsCoordinateReferenceSystem srs( QStringLiteral( "EPSG:3111" ) );
310 mCanvas->setDestinationCrs( srs );
311 QgsProject::instance()->setCrs( srs );
312 QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
313 QgsProject::instance()->setAreaUnits( QgsUnitTypes::AreaSquareMeters );
314
315 // run length calculation
316 std::unique_ptr< QgsMeasureTool > tool( new QgsMeasureTool( mCanvas, true ) );
317 std::unique_ptr< QgsMeasureDialog > dlg( new QgsMeasureDialog( tool.get() ) );
318
319 dlg->mEllipsoidal->setChecked( true );
320
321 tool->restart();
322 tool->addPoint( QgsPointXY( 2484588, 2425722 ) );
323 tool->addPoint( QgsPointXY( 2482767, 2398853 ) );
324 tool->addPoint( QgsPointXY( 2520109, 2397715 ) );
325 tool->addPoint( QgsPointXY( 2520792, 2425494 ) );
326 //force dialog recalculation
327 dlg->addPoint();
328
329 // check result
330 QString measureString = dlg->editTotal->text();
331 double measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
332 double expected = 1005721496.780000;
333 QGSCOMPARENEAR( measured, expected, 1.0 );
334
335 // change project area unit, check calculation respects unit
336 QgsProject::instance()->setAreaUnits( QgsUnitTypes::AreaSquareMiles );
337 std::unique_ptr< QgsMeasureTool > tool2( new QgsMeasureTool( mCanvas, true ) );
338 std::unique_ptr< QgsMeasureDialog > dlg2( new QgsMeasureDialog( tool2.get() ) );
339
340 dlg2->mEllipsoidal->setChecked( true );
341
342 tool2->restart();
343 tool2->addPoint( QgsPointXY( 2484588, 2425722 ) );
344 tool2->addPoint( QgsPointXY( 2482767, 2398853 ) );
345 tool2->addPoint( QgsPointXY( 2520109, 2397715 ) );
346 tool2->addPoint( QgsPointXY( 2520792, 2425494 ) );
347 //force dialog recalculation
348 dlg2->addPoint();
349
350 // check result
351 measureString = dlg2->editTotal->text();
352 measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
353 expected = 388.311000;
354 QGSCOMPARENEAR( measured, expected, 0.001 );
355 }
356
degreeDecimalPlaces()357 void TestQgsMeasureTool::degreeDecimalPlaces()
358 {
359 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceDegrees );
360
361 QgsSettings s;
362 s.setValue( QStringLiteral( "qgis/measure/decimalplaces" ), 3 );
363
364 std::unique_ptr< QgsMeasureTool > tool( new QgsMeasureTool( mCanvas, true ) );
365 std::unique_ptr< QgsMeasureDialog > dlg( new QgsMeasureDialog( tool.get() ) );
366
367 QCOMPARE( dlg->formatDistance( 11, false ), QString( "11.000 deg" ) );
368 QCOMPARE( dlg->formatDistance( 0.005, false ), QString( "0.005 deg" ) );
369 QCOMPARE( dlg->formatDistance( 0.002, false ), QString( "0.0020 deg" ) );
370 QCOMPARE( dlg->formatDistance( 0.001, false ), QString( "0.0010 deg" ) );
371 QCOMPARE( dlg->formatDistance( 0.0001, false ), QString( "0.00010 deg" ) );
372 QCOMPARE( dlg->formatDistance( 0.00001, false ), QString( "0.000010 deg" ) );
373
374 }
375
376 QGSTEST_MAIN( TestQgsMeasureTool )
377 #include "testqgsmeasuretool.moc"
378