Skip to content

Commit 479d90a

Browse files
committed
Make measure tool respect project area unit setting
Also add unit tests for measure tool length and area measurement to ensure they return the same results as field calculator and identify tool Refs #13209, #4252
1 parent 6dc0b69 commit 479d90a

File tree

6 files changed

+397
-96
lines changed

6 files changed

+397
-96
lines changed

src/app/qgsmeasuredialog.cpp

Lines changed: 188 additions & 85 deletions
Large diffs are not rendered by default.

src/app/qgsmeasuredialog.h

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ class APP_EXPORT QgsMeasureDialog : public QDialog, private Ui::QgsMeasureBase
4242
void restorePosition( void );
4343

4444
//! Add new point
45-
void addPoint( QgsPoint &point );
45+
void addPoint( const QgsPoint &point );
4646

4747
//! Mose move
48-
void mouseMove( QgsPoint &point );
48+
void mouseMove( const QgsPoint &point );
4949

5050
//! Remove last point
5151
void removeLastPoint();
@@ -74,18 +74,22 @@ class APP_EXPORT QgsMeasureDialog : public QDialog, private Ui::QgsMeasureBase
7474
private:
7575

7676
//! formats distance to most appropriate units
77-
QString formatDistance( double distance, bool convertUnits = true );
77+
QString formatDistance( double distance, bool convertUnits = true ) const;
7878

7979
//! formats area to most appropriate units
80-
QString formatArea( double area );
80+
QString formatArea( double area, bool convertUnits = true ) const;
8181

8282
//! shows/hides table, shows correct units
8383
void updateUi();
8484

85-
//! Converts the measurement, depending on settings in options and current transformation
86-
void convertMeasurement( double &measure, QGis::UnitType &u, bool isArea );
85+
/** Resets the units combo box to display either distance or area units
86+
* @param isArea set to true to populate with areal units, or false to show distance units
87+
*/
88+
void repopulateComboBoxUnits( bool isArea );
8789

88-
double convertLength( double length, QGis::UnitType toUnit );
90+
double convertLength( double length, QGis::UnitType toUnit ) const;
91+
92+
double convertArea( double area, QgsUnitTypes::AreaUnit toUnit ) const;
8993

9094
double mTotal;
9195

@@ -98,8 +102,11 @@ class APP_EXPORT QgsMeasureDialog : public QDialog, private Ui::QgsMeasureBase
98102
//! Current unit for input values
99103
QGis::UnitType mCanvasUnits;
100104

101-
//! Current unit for output values
102-
QGis::UnitType mDisplayUnits;
105+
//! Current unit for distance values
106+
QGis::UnitType mDistanceUnits;
107+
108+
//! Current unit for area values
109+
QgsUnitTypes::AreaUnit mAreaUnits;
103110

104111
//! Our measurement object
105112
QgsDistanceArea mDa;
@@ -108,6 +115,8 @@ class APP_EXPORT QgsMeasureDialog : public QDialog, private Ui::QgsMeasureBase
108115
QgsMeasureTool* mTool;
109116

110117
QgsPoint mLastMousePoint;
118+
119+
friend class TestQgsMeasureTool;
111120
};
112121

113122
#endif

src/app/qgsmeasuretool.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ void QgsMeasureTool::keyPressEvent( QKeyEvent* e )
213213
}
214214

215215

216-
void QgsMeasureTool::addPoint( QgsPoint &point )
216+
void QgsMeasureTool::addPoint( const QgsPoint &point )
217217
{
218218
QgsDebugMsg( "point=" + point.toString() );
219219

src/app/qgsmeasuretool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class APP_EXPORT QgsMeasureTool : public QgsMapTool
4646
void restart();
4747

4848
//! Add new point
49-
void addPoint( QgsPoint &point );
49+
void addPoint( const QgsPoint &point );
5050

5151
//! Returns reference to array of the points
5252
const QList<QgsPoint>& points();

tests/src/app/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,4 @@ ADD_QGIS_TEST(qgisappclipboard testqgisappclipboard.cpp)
105105
ADD_QGIS_TEST(attributetabletest testqgsattributetable.cpp)
106106
ADD_QGIS_TEST(fieldcalculatortest testqgsfieldcalculator.cpp)
107107
ADD_QGIS_TEST(maptoolidentifyaction testqgsmaptoolidentifyaction.cpp)
108+
ADD_QGIS_TEST(measuretool testqgsmeasuretool.cpp)
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
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 <QtTest/QtTest>
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+
/** \ingroup UnitTests
29+
* This is a unit test for the measure tool
30+
*/
31+
class TestQgsMeasureTool : public QObject
32+
{
33+
Q_OBJECT
34+
public:
35+
TestQgsMeasureTool();
36+
37+
private slots:
38+
void initTestCase();// will be called before the first testfunction is executed.
39+
void cleanupTestCase();// will be called after the last testfunction was executed.
40+
void init() {} // will be called before each testfunction is executed.
41+
void cleanup() {} // will be called after every testfunction.
42+
void testLengthCalculation();
43+
void testAreaCalculation();
44+
45+
private:
46+
QgisApp * mQgisApp;
47+
QgsMapCanvas* mCanvas;
48+
};
49+
50+
TestQgsMeasureTool::TestQgsMeasureTool()
51+
: mQgisApp( nullptr )
52+
, mCanvas( nullptr )
53+
{
54+
55+
}
56+
57+
//runs before all tests
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 QSettings environment
66+
QCoreApplication::setOrganizationName( "QGIS" );
67+
QCoreApplication::setOrganizationDomain( "qgis.org" );
68+
QCoreApplication::setApplicationName( "QGIS-TEST" );
69+
70+
mQgisApp = new QgisApp();
71+
mCanvas = new QgsMapCanvas();
72+
}
73+
74+
//runs after all tests
75+
void TestQgsMeasureTool::cleanupTestCase()
76+
{
77+
delete mCanvas;
78+
QgsApplication::exitQgis();
79+
}
80+
81+
void TestQgsMeasureTool::testLengthCalculation()
82+
{
83+
//test length measurement
84+
QSettings s;
85+
s.setValue( "/qgis/measure/keepbaseunit", true );
86+
87+
// set project CRS and ellipsoid
88+
QgisApp::instance()->mapCanvas()->setCrsTransformEnabled( true );
89+
QgsCoordinateReferenceSystem srs( 3111, QgsCoordinateReferenceSystem::EpsgCrsId );
90+
mCanvas->setCrsTransformEnabled( true );
91+
mCanvas->setDestinationCrs( srs );
92+
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCRSProj4String", srs.toProj4() );
93+
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCRSID", ( int ) srs.srsid() );
94+
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCrs", srs.authid() );
95+
QgsProject::instance()->writeEntry( "Measure", "/Ellipsoid", QString( "WGS84" ) );
96+
QgsProject::instance()->writeEntry( "Measurement", "/DistanceUnits", QgsUnitTypes::encodeUnit( QGis::Meters ) );
97+
98+
// run length calculation
99+
QScopedPointer< QgsMeasureTool > tool( new QgsMeasureTool( mCanvas, false ) );
100+
QScopedPointer< QgsMeasureDialog > dlg( new QgsMeasureDialog( tool.data() ) );
101+
102+
tool->restart();
103+
tool->addPoint( QgsPoint( 2484588, 2425722 ) );
104+
tool->addPoint( QgsPoint( 2482767, 2398853 ) );
105+
//force dialog recalculation
106+
dlg->addPoint( QgsPoint( 0, 0 ) );
107+
108+
// check result
109+
QString measureString = dlg->editTotal->text();
110+
double measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
111+
double expected = 26932.156;
112+
QVERIFY( qgsDoubleNear( measured, expected, 0.001 ) );
113+
114+
// change project length unit, check calculation respects unit
115+
QgsProject::instance()->writeEntry( "Measurement", "/DistanceUnits", QgsUnitTypes::encodeUnit( QGis::Feet ) );
116+
QScopedPointer< QgsMeasureTool > tool2( new QgsMeasureTool( mCanvas, false ) );
117+
QScopedPointer< QgsMeasureDialog > dlg2( new QgsMeasureDialog( tool2.data() ) );
118+
119+
tool2->restart();
120+
tool2->addPoint( QgsPoint( 2484588, 2425722 ) );
121+
tool2->addPoint( QgsPoint( 2482767, 2398853 ) );
122+
//force dialog recalculation
123+
dlg2->addPoint( QgsPoint( 0, 0 ) );
124+
125+
// check result
126+
measureString = dlg2->editTotal->text();
127+
measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
128+
expected = 88360.0918635;
129+
QVERIFY( qgsDoubleNear( measured, expected, 0.001 ) );
130+
}
131+
132+
void TestQgsMeasureTool::testAreaCalculation()
133+
{
134+
//test area measurement
135+
QSettings s;
136+
s.setValue( "/qgis/measure/keepbaseunit", true );
137+
138+
// set project CRS and ellipsoid
139+
QgisApp::instance()->mapCanvas()->setCrsTransformEnabled( true );
140+
QgsCoordinateReferenceSystem srs( 3111, QgsCoordinateReferenceSystem::EpsgCrsId );
141+
mCanvas->setCrsTransformEnabled( true );
142+
mCanvas->setDestinationCrs( srs );
143+
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCRSProj4String", srs.toProj4() );
144+
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCRSID", ( int ) srs.srsid() );
145+
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCrs", srs.authid() );
146+
QgsProject::instance()->writeEntry( "Measure", "/Ellipsoid", QString( "WGS84" ) );
147+
QgsProject::instance()->writeEntry( "Measurement", "/AreaUnits", QgsUnitTypes::encodeUnit( QgsUnitTypes::SquareMeters ) );
148+
149+
// run length calculation
150+
QScopedPointer< QgsMeasureTool > tool( new QgsMeasureTool( mCanvas, true ) );
151+
QScopedPointer< QgsMeasureDialog > dlg( new QgsMeasureDialog( tool.data() ) );
152+
153+
tool->restart();
154+
tool->addPoint( QgsPoint( 2484588, 2425722 ) );
155+
tool->addPoint( QgsPoint( 2482767, 2398853 ) );
156+
tool->addPoint( QgsPoint( 2520109, 2397715 ) );
157+
tool->addPoint( QgsPoint( 2520792, 2425494 ) );
158+
//force dialog recalculation
159+
dlg->addPoint( QgsPoint( 0, 0 ) );
160+
161+
// check result
162+
QString measureString = dlg->editTotal->text();
163+
double measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
164+
double expected = 1009089817.0;
165+
QVERIFY( qgsDoubleNear( measured, expected, 1.0 ) );
166+
167+
// change project area unit, check calculation respects unit
168+
QgsProject::instance()->writeEntry( "Measurement", "/AreaUnits", QgsUnitTypes::encodeUnit( QgsUnitTypes::SquareMiles ) );
169+
QScopedPointer< QgsMeasureTool > tool2( new QgsMeasureTool( mCanvas, true ) );
170+
QScopedPointer< QgsMeasureDialog > dlg2( new QgsMeasureDialog( tool2.data() ) );
171+
172+
tool2->restart();
173+
tool2->addPoint( QgsPoint( 2484588, 2425722 ) );
174+
tool2->addPoint( QgsPoint( 2482767, 2398853 ) );
175+
tool2->addPoint( QgsPoint( 2520109, 2397715 ) );
176+
tool2->addPoint( QgsPoint( 2520792, 2425494 ) );
177+
//force dialog recalculation
178+
dlg2->addPoint( QgsPoint( 0, 0 ) );
179+
180+
// check result
181+
measureString = dlg2->editTotal->text();
182+
measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
183+
expected = 389.6117565069;
184+
QVERIFY( qgsDoubleNear( measured, expected, 0.001 ) );
185+
}
186+
187+
QTEST_MAIN( TestQgsMeasureTool )
188+
#include "testqgsmeasuretool.moc"

0 commit comments

Comments
 (0)