Skip to content

Commit

Permalink
Make measure tool respect project area unit setting
Browse files Browse the repository at this point in the history
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
  • Loading branch information
nyalldawson committed Feb 15, 2016
1 parent 6dc0b69 commit 479d90a
Show file tree
Hide file tree
Showing 6 changed files with 397 additions and 96 deletions.
273 changes: 188 additions & 85 deletions src/app/qgsmeasuredialog.cpp

Large diffs are not rendered by default.

27 changes: 18 additions & 9 deletions src/app/qgsmeasuredialog.h
Expand Up @@ -42,10 +42,10 @@ class APP_EXPORT QgsMeasureDialog : public QDialog, private Ui::QgsMeasureBase
void restorePosition( void );

//! Add new point
void addPoint( QgsPoint &point );
void addPoint( const QgsPoint &point );

//! Mose move
void mouseMove( QgsPoint &point );
void mouseMove( const QgsPoint &point );

//! Remove last point
void removeLastPoint();
Expand Down Expand Up @@ -74,18 +74,22 @@ class APP_EXPORT QgsMeasureDialog : public QDialog, private Ui::QgsMeasureBase
private:

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

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

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

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

double convertLength( double length, QGis::UnitType toUnit );
double convertLength( double length, QGis::UnitType toUnit ) const;

double convertArea( double area, QgsUnitTypes::AreaUnit toUnit ) const;

double mTotal;

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

//! Current unit for output values
QGis::UnitType mDisplayUnits;
//! Current unit for distance values
QGis::UnitType mDistanceUnits;

//! Current unit for area values
QgsUnitTypes::AreaUnit mAreaUnits;

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

QgsPoint mLastMousePoint;

friend class TestQgsMeasureTool;
};

#endif
2 changes: 1 addition & 1 deletion src/app/qgsmeasuretool.cpp
Expand Up @@ -213,7 +213,7 @@ void QgsMeasureTool::keyPressEvent( QKeyEvent* e )
}


void QgsMeasureTool::addPoint( QgsPoint &point )
void QgsMeasureTool::addPoint( const QgsPoint &point )
{
QgsDebugMsg( "point=" + point.toString() );

Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsmeasuretool.h
Expand Up @@ -46,7 +46,7 @@ class APP_EXPORT QgsMeasureTool : public QgsMapTool
void restart();

//! Add new point
void addPoint( QgsPoint &point );
void addPoint( const QgsPoint &point );

//! Returns reference to array of the points
const QList<QgsPoint>& points();
Expand Down
1 change: 1 addition & 0 deletions tests/src/app/CMakeLists.txt
Expand Up @@ -105,3 +105,4 @@ ADD_QGIS_TEST(qgisappclipboard testqgisappclipboard.cpp)
ADD_QGIS_TEST(attributetabletest testqgsattributetable.cpp)
ADD_QGIS_TEST(fieldcalculatortest testqgsfieldcalculator.cpp)
ADD_QGIS_TEST(maptoolidentifyaction testqgsmaptoolidentifyaction.cpp)
ADD_QGIS_TEST(measuretool testqgsmeasuretool.cpp)
188 changes: 188 additions & 0 deletions tests/src/app/testqgsmeasuretool.cpp
@@ -0,0 +1,188 @@
/***************************************************************************
testqgsmeasuretool.cpp
----------------------
Date : 2016-02-14
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 <QtTest/QtTest>
#include "qgisapp.h"
#include "qgsapplication.h"
#include "qgsvectorlayer.h"
#include "qgsfeature.h"
#include "qgsgeometry.h"
#include "qgsvectordataprovider.h"
#include "qgsmeasuretool.h"
#include "qgsmeasuredialog.h"
#include "qgsproject.h"
#include "qgsmapcanvas.h"
#include "qgsunittypes.h"

/** \ingroup UnitTests
* This is a unit test for the measure tool
*/
class TestQgsMeasureTool : public QObject
{
Q_OBJECT
public:
TestQgsMeasureTool();

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 testLengthCalculation();
void testAreaCalculation();

private:
QgisApp * mQgisApp;
QgsMapCanvas* mCanvas;
};

TestQgsMeasureTool::TestQgsMeasureTool()
: mQgisApp( nullptr )
, mCanvas( nullptr )
{

}

//runs before all tests
void TestQgsMeasureTool::initTestCase()
{
qDebug() << "TestQgisAppClipboard::initTestCase()";
// init QGIS's paths - true means that all path will be inited from prefix
QgsApplication::init();
QgsApplication::initQgis();

// Set up the QSettings environment
QCoreApplication::setOrganizationName( "QGIS" );
QCoreApplication::setOrganizationDomain( "qgis.org" );
QCoreApplication::setApplicationName( "QGIS-TEST" );

mQgisApp = new QgisApp();
mCanvas = new QgsMapCanvas();
}

//runs after all tests
void TestQgsMeasureTool::cleanupTestCase()
{
delete mCanvas;
QgsApplication::exitQgis();
}

void TestQgsMeasureTool::testLengthCalculation()
{
//test length measurement
QSettings s;
s.setValue( "/qgis/measure/keepbaseunit", true );

// set project CRS and ellipsoid
QgisApp::instance()->mapCanvas()->setCrsTransformEnabled( true );
QgsCoordinateReferenceSystem srs( 3111, QgsCoordinateReferenceSystem::EpsgCrsId );
mCanvas->setCrsTransformEnabled( true );
mCanvas->setDestinationCrs( srs );
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCRSProj4String", srs.toProj4() );
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCRSID", ( int ) srs.srsid() );
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCrs", srs.authid() );
QgsProject::instance()->writeEntry( "Measure", "/Ellipsoid", QString( "WGS84" ) );
QgsProject::instance()->writeEntry( "Measurement", "/DistanceUnits", QgsUnitTypes::encodeUnit( QGis::Meters ) );

// run length calculation
QScopedPointer< QgsMeasureTool > tool( new QgsMeasureTool( mCanvas, false ) );
QScopedPointer< QgsMeasureDialog > dlg( new QgsMeasureDialog( tool.data() ) );

tool->restart();
tool->addPoint( QgsPoint( 2484588, 2425722 ) );
tool->addPoint( QgsPoint( 2482767, 2398853 ) );
//force dialog recalculation
dlg->addPoint( QgsPoint( 0, 0 ) );

// check result
QString measureString = dlg->editTotal->text();
double measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
double expected = 26932.156;
QVERIFY( qgsDoubleNear( measured, expected, 0.001 ) );

// change project length unit, check calculation respects unit
QgsProject::instance()->writeEntry( "Measurement", "/DistanceUnits", QgsUnitTypes::encodeUnit( QGis::Feet ) );
QScopedPointer< QgsMeasureTool > tool2( new QgsMeasureTool( mCanvas, false ) );
QScopedPointer< QgsMeasureDialog > dlg2( new QgsMeasureDialog( tool2.data() ) );

tool2->restart();
tool2->addPoint( QgsPoint( 2484588, 2425722 ) );
tool2->addPoint( QgsPoint( 2482767, 2398853 ) );
//force dialog recalculation
dlg2->addPoint( QgsPoint( 0, 0 ) );

// check result
measureString = dlg2->editTotal->text();
measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
expected = 88360.0918635;
QVERIFY( qgsDoubleNear( measured, expected, 0.001 ) );
}

void TestQgsMeasureTool::testAreaCalculation()
{
//test area measurement
QSettings s;
s.setValue( "/qgis/measure/keepbaseunit", true );

// set project CRS and ellipsoid
QgisApp::instance()->mapCanvas()->setCrsTransformEnabled( true );
QgsCoordinateReferenceSystem srs( 3111, QgsCoordinateReferenceSystem::EpsgCrsId );
mCanvas->setCrsTransformEnabled( true );
mCanvas->setDestinationCrs( srs );
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCRSProj4String", srs.toProj4() );
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCRSID", ( int ) srs.srsid() );
QgsProject::instance()->writeEntry( "SpatialRefSys", "/ProjectCrs", srs.authid() );
QgsProject::instance()->writeEntry( "Measure", "/Ellipsoid", QString( "WGS84" ) );
QgsProject::instance()->writeEntry( "Measurement", "/AreaUnits", QgsUnitTypes::encodeUnit( QgsUnitTypes::SquareMeters ) );

// run length calculation
QScopedPointer< QgsMeasureTool > tool( new QgsMeasureTool( mCanvas, true ) );
QScopedPointer< QgsMeasureDialog > dlg( new QgsMeasureDialog( tool.data() ) );

tool->restart();
tool->addPoint( QgsPoint( 2484588, 2425722 ) );
tool->addPoint( QgsPoint( 2482767, 2398853 ) );
tool->addPoint( QgsPoint( 2520109, 2397715 ) );
tool->addPoint( QgsPoint( 2520792, 2425494 ) );
//force dialog recalculation
dlg->addPoint( QgsPoint( 0, 0 ) );

// check result
QString measureString = dlg->editTotal->text();
double measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
double expected = 1009089817.0;
QVERIFY( qgsDoubleNear( measured, expected, 1.0 ) );

// change project area unit, check calculation respects unit
QgsProject::instance()->writeEntry( "Measurement", "/AreaUnits", QgsUnitTypes::encodeUnit( QgsUnitTypes::SquareMiles ) );
QScopedPointer< QgsMeasureTool > tool2( new QgsMeasureTool( mCanvas, true ) );
QScopedPointer< QgsMeasureDialog > dlg2( new QgsMeasureDialog( tool2.data() ) );

tool2->restart();
tool2->addPoint( QgsPoint( 2484588, 2425722 ) );
tool2->addPoint( QgsPoint( 2482767, 2398853 ) );
tool2->addPoint( QgsPoint( 2520109, 2397715 ) );
tool2->addPoint( QgsPoint( 2520792, 2425494 ) );
//force dialog recalculation
dlg2->addPoint( QgsPoint( 0, 0 ) );

// check result
measureString = dlg2->editTotal->text();
measured = measureString.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
expected = 389.6117565069;
QVERIFY( qgsDoubleNear( measured, expected, 0.001 ) );
}

QTEST_MAIN( TestQgsMeasureTool )
#include "testqgsmeasuretool.moc"

0 comments on commit 479d90a

Please sign in to comment.