Skip to content

Commit b712f3c

Browse files
committedFeb 7, 2016
Measure tool fixes:
- Make unit selection more robust (doesn't rely on translations) - Make calculation of lengths in degrees use a cartesian calculation when project CRS is in degrees - Fix display of calculation details, was misleading and inaccurate for many CRS/unit combinations
1 parent 33c37d0 commit b712f3c

File tree

3 files changed

+98
-43
lines changed

3 files changed

+98
-43
lines changed
 

‎src/app/qgsmeasuredialog.cpp

Lines changed: 96 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,17 @@ QgsMeasureDialog::QgsMeasureDialog( QgsMeasureTool* tool, Qt::WindowFlags f )
5050
mMeasureArea = tool->measureArea();
5151
mTotal = 0.;
5252

53-
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Meters ) );
54-
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Feet ) );
55-
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Degrees ) );
56-
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::NauticalMiles ) );
57-
53+
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Meters ), QGis::Meters );
54+
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Feet ), QGis::Feet );
55+
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Degrees ), QGis::Degrees );
56+
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::NauticalMiles ), QGis::NauticalMiles );
5857
QSettings settings;
5958
QString units = settings.value( "/qgis/measure/displayunits", QgsUnitTypes::encodeUnit( QGis::Meters ) ).toString();
60-
mUnitsCombo->setCurrentIndex( mUnitsCombo->findText( QgsUnitTypes::toString( QgsUnitTypes::decodeDistanceUnit( units ) ), Qt::MatchFixedString ) );
59+
mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( QgsUnitTypes::decodeDistanceUnit( units ) ) );
6160

6261
updateSettings();
6362

64-
connect( mUnitsCombo, SIGNAL( currentIndexChanged( const QString & ) ), this, SLOT( unitsChanged( const QString & ) ) );
63+
connect( mUnitsCombo, SIGNAL( currentIndexChanged( int ) ), this, SLOT( unitsChanged( int ) ) );
6564
connect( buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
6665

6766
groupBox->setCollapsed( true );
@@ -79,7 +78,7 @@ void QgsMeasureDialog::updateSettings()
7978
mDecimalPlaces = settings.value( "/qgis/measure/decimalplaces", "3" ).toInt();
8079
mCanvasUnits = mTool->canvas()->mapUnits();
8180
// Configure QgsDistanceArea
82-
mDisplayUnits = QgsUnitTypes::stringToDistanceUnit( mUnitsCombo->currentText() );
81+
mDisplayUnits = static_cast< QGis::UnitType >( mUnitsCombo->itemData( mUnitsCombo->currentIndex() ).toInt() );
8382
mDa.setSourceCrs( mTool->canvas()->mapSettings().destinationCrs().srsid() );
8483
mDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
8584
// Only use ellipsoidal calculation when project wide transformation is enabled.
@@ -103,9 +102,9 @@ void QgsMeasureDialog::updateSettings()
103102
updateUi();
104103
}
105104

106-
void QgsMeasureDialog::unitsChanged( const QString &units )
105+
void QgsMeasureDialog::unitsChanged( int index )
107106
{
108-
mDisplayUnits = QgsUnitTypes::stringToDistanceUnit( units );
107+
mDisplayUnits = static_cast< QGis::UnitType >( mUnitsCombo->itemData( index ).toInt() );
109108
mTable->clear();
110109
mTotal = 0.;
111110
updateUi();
@@ -243,12 +242,13 @@ void QgsMeasureDialog::saveWindowLocation()
243242
settings.setValue( key, height() );
244243
}
245244

246-
QString QgsMeasureDialog::formatDistance( double distance )
245+
QString QgsMeasureDialog::formatDistance( double distance, bool convertUnits )
247246
{
248247
QSettings settings;
249248
bool baseUnit = settings.value( "/qgis/measure/keepbaseunit", false ).toBool();
250249

251-
distance = convertLength( distance, mDisplayUnits );
250+
if ( convertUnits )
251+
distance = convertLength( distance, mDisplayUnits );
252252
return QgsDistanceArea::textUnit( distance, mDecimalPlaces, mDisplayUnits, false, baseUnit );
253253
}
254254

@@ -266,41 +266,88 @@ void QgsMeasureDialog::updateUi()
266266
{
267267
// Set tooltip to indicate how we calculate measurments
268268
QString toolTip = tr( "The calculations are based on:" );
269-
if ( ! mTool->canvas()->hasCrsTransformEnabled() )
269+
270+
bool forceCartesian = false;
271+
bool convertToDisplayUnits = true;
272+
273+
if ( mTool->canvas()->mapSettings().destinationCrs().mapUnits() == QGis::Degrees
274+
&& mDisplayUnits == QGis::Degrees )
270275
{
271-
toolTip += "<br> * " + tr( "Project CRS transformation is turned off." ) + ' ';
272-
toolTip += tr( "Canvas units setting is taken from project properties setting (%1)." ).arg( QgsUnitTypes::toString( mCanvasUnits ) );
273-
toolTip += "<br> * " + tr( "Ellipsoidal calculation is not possible, as project CRS is undefined." );
274-
setWindowTitle( tr( "Measure (OTF off)" ) );
276+
//both source and destination units are degrees
277+
toolTip += "<br> * " + tr( "Both project CRS (%1) and measured length are in degrees, so measurement is calculated using cartesian calculations in degrees." ).arg(
278+
mTool->canvas()->mapSettings().destinationCrs().description() );
279+
forceCartesian = true;
280+
convertToDisplayUnits = false; //not required since we will be measuring in degrees
275281
}
276282
else
277283
{
278-
if ( mDa.ellipsoidalEnabled() )
284+
QGis::UnitType resultUnit = QGis::UnknownUnit;
285+
if ( ! mTool->canvas()->hasCrsTransformEnabled() )
279286
{
280-
toolTip += "<br> * " + tr( "Project CRS transformation is turned on and ellipsoidal calculation is selected." ) + ' ';
281-
toolTip += "<br> * " + tr( "The coordinates are transformed to the chosen ellipsoid (%1), and the result is in meters" ).arg( mDa.ellipsoid() );
287+
resultUnit = mTool->canvas()->mapSettings().destinationCrs().mapUnits();
288+
toolTip += "<br> * " + tr( "Project CRS transformation is turned off." ) + ' ';
289+
toolTip += tr( "Distance is calculated in %1, based on project CRS (%2)." ).arg( QgsUnitTypes::toString( resultUnit ),
290+
mTool->canvas()->mapSettings().destinationCrs().description() );
291+
toolTip += "<br> * " + tr( "Ellipsoidal calculation is not possible with CRS transformation disabled." );
292+
setWindowTitle( tr( "Measure (OTF off)" ) );
282293
}
283294
else
284295
{
285-
toolTip += "<br> * " + tr( "Project CRS transformation is turned on but ellipsoidal calculation is not selected." );
286-
toolTip += "<br> * " + tr( "The canvas units setting is taken from the project CRS (%1)." ).arg( QgsUnitTypes::toString( mCanvasUnits ) );
296+
if ( mDa.willUseEllipsoid() )
297+
{
298+
resultUnit = QGis::Meters;
299+
toolTip += "<br> * " + tr( "Project CRS transformation is turned on and ellipsoidal calculation is selected." ) + ' ';
300+
toolTip += "<br> * " + tr( "The coordinates are transformed to the chosen ellipsoid (%1), and the measurement is calculated in %2." ).arg( mDa.ellipsoid(),
301+
QgsUnitTypes::toString( resultUnit ) );
302+
}
303+
else
304+
{
305+
resultUnit = mTool->canvas()->mapSettings().destinationCrs().mapUnits();
306+
toolTip += "<br> * " + tr( "Project CRS transformation is turned on but ellipsoidal calculation is not selected." ) + ' ';
307+
toolTip += tr( "Distance is calculated in %1, based on project CRS (%2)." ).arg( QgsUnitTypes::toString( resultUnit ),
308+
mTool->canvas()->mapSettings().destinationCrs().description() );
309+
}
310+
setWindowTitle( tr( "Measure (OTF on)" ) );
287311
}
288-
setWindowTitle( tr( "Measure (OTF on)" ) );
289-
}
290312

291-
if (( mCanvasUnits == QGis::Meters && mDisplayUnits == QGis::Feet ) || ( mCanvasUnits == QGis::Feet && mDisplayUnits == QGis::Meters ) )
292-
{
293-
toolTip += "<br> * " + tr( "Finally, the value is converted from %1 to %2." ).arg( QgsUnitTypes::toString( mCanvasUnits ), QgsUnitTypes::toString( mDisplayUnits ) );
313+
if ( QgsUnitTypes::unitType( resultUnit ) == QgsUnitTypes::Geographic &&
314+
QgsUnitTypes::unitType( mDisplayUnits ) == QgsUnitTypes::Standard )
315+
{
316+
toolTip += "<br> * Distance is roughly converted to meters by using scale at equator (1 degree = 111319.49 meters).";
317+
resultUnit = QGis::Meters;
318+
}
319+
else if ( QgsUnitTypes::unitType( resultUnit ) == QgsUnitTypes::Standard &&
320+
QgsUnitTypes::unitType( mDisplayUnits ) == QgsUnitTypes::Geographic )
321+
{
322+
toolTip += "<br> * Distance is roughly converted to degrees by using scale at equator (1 degree = 111319.49 meters).";
323+
resultUnit = QGis::Degrees;
324+
}
325+
326+
if ( resultUnit != mDisplayUnits )
327+
{
328+
if ( QgsUnitTypes::unitType( resultUnit ) == QgsUnitTypes::Standard &&
329+
QgsUnitTypes::unitType( mDisplayUnits ) == QgsUnitTypes::Standard )
330+
{
331+
// only shown if both conditions are true:
332+
// - the display unit is a standard distance measurement (eg feet)
333+
// - either the canvas units is also a standard distance OR we are using an ellipsoid (in which case the
334+
// value will be in meters)
335+
toolTip += "<br> * " + tr( "The value is converted from %1 to %2." ).arg( QgsUnitTypes::toString( resultUnit ),
336+
QgsUnitTypes::toString( mDisplayUnits ) );
337+
}
338+
else
339+
{
340+
//should not be possible!
341+
}
342+
}
294343
}
295344

296345
editTotal->setToolTip( toolTip );
297346
mTable->setToolTip( toolTip );
298347
mNotesLabel->setText( toolTip );
299348

300-
QGis::UnitType newDisplayUnits;
301-
double dummy = 1.0;
302-
convertMeasurement( dummy, newDisplayUnits, true );
303-
mTable->setHeaderLabels( QStringList( tr( "Segments [%1]" ).arg( QgsUnitTypes::toString( newDisplayUnits ) ) ) );
349+
mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( mDisplayUnits ) );
350+
mTable->setHeaderLabels( QStringList( tr( "Segments [%1]" ).arg( QgsUnitTypes::toString( mDisplayUnits ) ) ) );
304351

305352
if ( mMeasureArea )
306353
{
@@ -318,14 +365,24 @@ void QgsMeasureDialog::updateUi()
318365
bool b = true; // first point
319366

320367
QgsPoint p1, p2;
321-
368+
mTotal = 0;
322369
for ( it = mTool->points().constBegin(); it != mTool->points().constEnd(); ++it )
323370
{
324371
p2 = *it;
325372
if ( !b )
326373
{
327-
double d = mDa.measureLine( p1, p2 );
328-
d = convertLength( d, mDisplayUnits );
374+
double d = -1;
375+
if ( forceCartesian )
376+
{
377+
//cartesian calculation forced
378+
d = sqrt( p2.sqrDist( p1 ) );
379+
mTotal += d;
380+
}
381+
else
382+
{
383+
d = mDa.measureLine( p1, p2 );
384+
d = convertLength( d, mDisplayUnits );
385+
}
329386

330387
QTreeWidgetItem *item = new QTreeWidgetItem( QStringList( QLocale::system().toString( d, 'f', mDecimalPlaces ) ) );
331388
item->setTextAlignment( 0, Qt::AlignRight );
@@ -335,15 +392,17 @@ void QgsMeasureDialog::updateUi()
335392
p1 = p2;
336393
b = false;
337394
}
338-
mTotal = mDa.measureLine( mTool->points() );
395+
396+
if ( !forceCartesian )
397+
mTotal = mDa.measureLine( mTool->points() );
339398
mTable->show(); // Show the table with items
340-
editTotal->setText( formatDistance( mTotal ) );
399+
editTotal->setText( formatDistance( mTotal, convertToDisplayUnits ) );
341400
}
342401
}
343402

344403
void QgsMeasureDialog::convertMeasurement( double &measure, QGis::UnitType &u, bool isArea )
345404
{
346-
// Helper for converting between meters and feet
405+
// Helper for converting between units
347406
// The parameter &u is out only...
348407

349408
// Get the canvas units

‎src/app/qgsmeasuredialog.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,15 @@ class APP_EXPORT QgsMeasureDialog : public QDialog, private Ui::QgsMeasureBase
6666
void updateSettings();
6767

6868
private slots:
69-
void unitsChanged( const QString &units );
69+
void unitsChanged( int index );
7070

7171
//! Open configuration tab
7272
void openConfigTab();
7373

7474
private:
7575

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

7979
//! formats area to most appropriate units
8080
QString formatArea( double area );

‎src/app/qgsmeasuretool.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,8 @@ void QgsMeasureTool::restart()
108108
mRubberBand->reset( mMeasureArea ? QGis::Polygon : QGis::Line );
109109
mRubberBandPoints->reset( QGis::Point );
110110

111-
// re-read settings
112-
updateSettings();
113-
114111
mDone = true;
115112
mWrongProjectProjection = false;
116-
117113
}
118114

119115
void QgsMeasureTool::updateSettings()

0 commit comments

Comments
 (0)
Please sign in to comment.