mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-25 00:03:06 -04:00
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
This commit is contained in:
parent
33c37d0cb2
commit
b712f3cf4b
@ -50,18 +50,17 @@ QgsMeasureDialog::QgsMeasureDialog( QgsMeasureTool* tool, Qt::WindowFlags f )
|
|||||||
mMeasureArea = tool->measureArea();
|
mMeasureArea = tool->measureArea();
|
||||||
mTotal = 0.;
|
mTotal = 0.;
|
||||||
|
|
||||||
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Meters ) );
|
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Meters ), QGis::Meters );
|
||||||
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Feet ) );
|
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Feet ), QGis::Feet );
|
||||||
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Degrees ) );
|
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::Degrees ), QGis::Degrees );
|
||||||
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::NauticalMiles ) );
|
mUnitsCombo->addItem( QgsUnitTypes::toString( QGis::NauticalMiles ), QGis::NauticalMiles );
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
QString units = settings.value( "/qgis/measure/displayunits", QgsUnitTypes::encodeUnit( QGis::Meters ) ).toString();
|
QString units = settings.value( "/qgis/measure/displayunits", QgsUnitTypes::encodeUnit( QGis::Meters ) ).toString();
|
||||||
mUnitsCombo->setCurrentIndex( mUnitsCombo->findText( QgsUnitTypes::toString( QgsUnitTypes::decodeDistanceUnit( units ) ), Qt::MatchFixedString ) );
|
mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( QgsUnitTypes::decodeDistanceUnit( units ) ) );
|
||||||
|
|
||||||
updateSettings();
|
updateSettings();
|
||||||
|
|
||||||
connect( mUnitsCombo, SIGNAL( currentIndexChanged( const QString & ) ), this, SLOT( unitsChanged( const QString & ) ) );
|
connect( mUnitsCombo, SIGNAL( currentIndexChanged( int ) ), this, SLOT( unitsChanged( int ) ) );
|
||||||
connect( buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
|
connect( buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
|
||||||
|
|
||||||
groupBox->setCollapsed( true );
|
groupBox->setCollapsed( true );
|
||||||
@ -79,7 +78,7 @@ void QgsMeasureDialog::updateSettings()
|
|||||||
mDecimalPlaces = settings.value( "/qgis/measure/decimalplaces", "3" ).toInt();
|
mDecimalPlaces = settings.value( "/qgis/measure/decimalplaces", "3" ).toInt();
|
||||||
mCanvasUnits = mTool->canvas()->mapUnits();
|
mCanvasUnits = mTool->canvas()->mapUnits();
|
||||||
// Configure QgsDistanceArea
|
// Configure QgsDistanceArea
|
||||||
mDisplayUnits = QgsUnitTypes::stringToDistanceUnit( mUnitsCombo->currentText() );
|
mDisplayUnits = static_cast< QGis::UnitType >( mUnitsCombo->itemData( mUnitsCombo->currentIndex() ).toInt() );
|
||||||
mDa.setSourceCrs( mTool->canvas()->mapSettings().destinationCrs().srsid() );
|
mDa.setSourceCrs( mTool->canvas()->mapSettings().destinationCrs().srsid() );
|
||||||
mDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
|
mDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
|
||||||
// Only use ellipsoidal calculation when project wide transformation is enabled.
|
// Only use ellipsoidal calculation when project wide transformation is enabled.
|
||||||
@ -103,9 +102,9 @@ void QgsMeasureDialog::updateSettings()
|
|||||||
updateUi();
|
updateUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsMeasureDialog::unitsChanged( const QString &units )
|
void QgsMeasureDialog::unitsChanged( int index )
|
||||||
{
|
{
|
||||||
mDisplayUnits = QgsUnitTypes::stringToDistanceUnit( units );
|
mDisplayUnits = static_cast< QGis::UnitType >( mUnitsCombo->itemData( index ).toInt() );
|
||||||
mTable->clear();
|
mTable->clear();
|
||||||
mTotal = 0.;
|
mTotal = 0.;
|
||||||
updateUi();
|
updateUi();
|
||||||
@ -243,12 +242,13 @@ void QgsMeasureDialog::saveWindowLocation()
|
|||||||
settings.setValue( key, height() );
|
settings.setValue( key, height() );
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QgsMeasureDialog::formatDistance( double distance )
|
QString QgsMeasureDialog::formatDistance( double distance, bool convertUnits )
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
bool baseUnit = settings.value( "/qgis/measure/keepbaseunit", false ).toBool();
|
bool baseUnit = settings.value( "/qgis/measure/keepbaseunit", false ).toBool();
|
||||||
|
|
||||||
distance = convertLength( distance, mDisplayUnits );
|
if ( convertUnits )
|
||||||
|
distance = convertLength( distance, mDisplayUnits );
|
||||||
return QgsDistanceArea::textUnit( distance, mDecimalPlaces, mDisplayUnits, false, baseUnit );
|
return QgsDistanceArea::textUnit( distance, mDecimalPlaces, mDisplayUnits, false, baseUnit );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,41 +266,88 @@ void QgsMeasureDialog::updateUi()
|
|||||||
{
|
{
|
||||||
// Set tooltip to indicate how we calculate measurments
|
// Set tooltip to indicate how we calculate measurments
|
||||||
QString toolTip = tr( "The calculations are based on:" );
|
QString toolTip = tr( "The calculations are based on:" );
|
||||||
if ( ! mTool->canvas()->hasCrsTransformEnabled() )
|
|
||||||
|
bool forceCartesian = false;
|
||||||
|
bool convertToDisplayUnits = true;
|
||||||
|
|
||||||
|
if ( mTool->canvas()->mapSettings().destinationCrs().mapUnits() == QGis::Degrees
|
||||||
|
&& mDisplayUnits == QGis::Degrees )
|
||||||
{
|
{
|
||||||
toolTip += "<br> * " + tr( "Project CRS transformation is turned off." ) + ' ';
|
//both source and destination units are degrees
|
||||||
toolTip += tr( "Canvas units setting is taken from project properties setting (%1)." ).arg( QgsUnitTypes::toString( mCanvasUnits ) );
|
toolTip += "<br> * " + tr( "Both project CRS (%1) and measured length are in degrees, so measurement is calculated using cartesian calculations in degrees." ).arg(
|
||||||
toolTip += "<br> * " + tr( "Ellipsoidal calculation is not possible, as project CRS is undefined." );
|
mTool->canvas()->mapSettings().destinationCrs().description() );
|
||||||
setWindowTitle( tr( "Measure (OTF off)" ) );
|
forceCartesian = true;
|
||||||
|
convertToDisplayUnits = false; //not required since we will be measuring in degrees
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( mDa.ellipsoidalEnabled() )
|
QGis::UnitType resultUnit = QGis::UnknownUnit;
|
||||||
|
if ( ! mTool->canvas()->hasCrsTransformEnabled() )
|
||||||
{
|
{
|
||||||
toolTip += "<br> * " + tr( "Project CRS transformation is turned on and ellipsoidal calculation is selected." ) + ' ';
|
resultUnit = mTool->canvas()->mapSettings().destinationCrs().mapUnits();
|
||||||
toolTip += "<br> * " + tr( "The coordinates are transformed to the chosen ellipsoid (%1), and the result is in meters" ).arg( mDa.ellipsoid() );
|
toolTip += "<br> * " + tr( "Project CRS transformation is turned off." ) + ' ';
|
||||||
|
toolTip += tr( "Distance is calculated in %1, based on project CRS (%2)." ).arg( QgsUnitTypes::toString( resultUnit ),
|
||||||
|
mTool->canvas()->mapSettings().destinationCrs().description() );
|
||||||
|
toolTip += "<br> * " + tr( "Ellipsoidal calculation is not possible with CRS transformation disabled." );
|
||||||
|
setWindowTitle( tr( "Measure (OTF off)" ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
toolTip += "<br> * " + tr( "Project CRS transformation is turned on but ellipsoidal calculation is not selected." );
|
if ( mDa.willUseEllipsoid() )
|
||||||
toolTip += "<br> * " + tr( "The canvas units setting is taken from the project CRS (%1)." ).arg( QgsUnitTypes::toString( mCanvasUnits ) );
|
{
|
||||||
|
resultUnit = QGis::Meters;
|
||||||
|
toolTip += "<br> * " + tr( "Project CRS transformation is turned on and ellipsoidal calculation is selected." ) + ' ';
|
||||||
|
toolTip += "<br> * " + tr( "The coordinates are transformed to the chosen ellipsoid (%1), and the measurement is calculated in %2." ).arg( mDa.ellipsoid(),
|
||||||
|
QgsUnitTypes::toString( resultUnit ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultUnit = mTool->canvas()->mapSettings().destinationCrs().mapUnits();
|
||||||
|
toolTip += "<br> * " + tr( "Project CRS transformation is turned on but ellipsoidal calculation is not selected." ) + ' ';
|
||||||
|
toolTip += tr( "Distance is calculated in %1, based on project CRS (%2)." ).arg( QgsUnitTypes::toString( resultUnit ),
|
||||||
|
mTool->canvas()->mapSettings().destinationCrs().description() );
|
||||||
|
}
|
||||||
|
setWindowTitle( tr( "Measure (OTF on)" ) );
|
||||||
}
|
}
|
||||||
setWindowTitle( tr( "Measure (OTF on)" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (( mCanvasUnits == QGis::Meters && mDisplayUnits == QGis::Feet ) || ( mCanvasUnits == QGis::Feet && mDisplayUnits == QGis::Meters ) )
|
if ( QgsUnitTypes::unitType( resultUnit ) == QgsUnitTypes::Geographic &&
|
||||||
{
|
QgsUnitTypes::unitType( mDisplayUnits ) == QgsUnitTypes::Standard )
|
||||||
toolTip += "<br> * " + tr( "Finally, the value is converted from %1 to %2." ).arg( QgsUnitTypes::toString( mCanvasUnits ), QgsUnitTypes::toString( mDisplayUnits ) );
|
{
|
||||||
|
toolTip += "<br> * Distance is roughly converted to meters by using scale at equator (1 degree = 111319.49 meters).";
|
||||||
|
resultUnit = QGis::Meters;
|
||||||
|
}
|
||||||
|
else if ( QgsUnitTypes::unitType( resultUnit ) == QgsUnitTypes::Standard &&
|
||||||
|
QgsUnitTypes::unitType( mDisplayUnits ) == QgsUnitTypes::Geographic )
|
||||||
|
{
|
||||||
|
toolTip += "<br> * Distance is roughly converted to degrees by using scale at equator (1 degree = 111319.49 meters).";
|
||||||
|
resultUnit = QGis::Degrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( resultUnit != mDisplayUnits )
|
||||||
|
{
|
||||||
|
if ( QgsUnitTypes::unitType( resultUnit ) == QgsUnitTypes::Standard &&
|
||||||
|
QgsUnitTypes::unitType( mDisplayUnits ) == QgsUnitTypes::Standard )
|
||||||
|
{
|
||||||
|
// only shown if both conditions are true:
|
||||||
|
// - the display unit is a standard distance measurement (eg feet)
|
||||||
|
// - either the canvas units is also a standard distance OR we are using an ellipsoid (in which case the
|
||||||
|
// value will be in meters)
|
||||||
|
toolTip += "<br> * " + tr( "The value is converted from %1 to %2." ).arg( QgsUnitTypes::toString( resultUnit ),
|
||||||
|
QgsUnitTypes::toString( mDisplayUnits ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//should not be possible!
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
editTotal->setToolTip( toolTip );
|
editTotal->setToolTip( toolTip );
|
||||||
mTable->setToolTip( toolTip );
|
mTable->setToolTip( toolTip );
|
||||||
mNotesLabel->setText( toolTip );
|
mNotesLabel->setText( toolTip );
|
||||||
|
|
||||||
QGis::UnitType newDisplayUnits;
|
mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( mDisplayUnits ) );
|
||||||
double dummy = 1.0;
|
mTable->setHeaderLabels( QStringList( tr( "Segments [%1]" ).arg( QgsUnitTypes::toString( mDisplayUnits ) ) ) );
|
||||||
convertMeasurement( dummy, newDisplayUnits, true );
|
|
||||||
mTable->setHeaderLabels( QStringList( tr( "Segments [%1]" ).arg( QgsUnitTypes::toString( newDisplayUnits ) ) ) );
|
|
||||||
|
|
||||||
if ( mMeasureArea )
|
if ( mMeasureArea )
|
||||||
{
|
{
|
||||||
@ -318,14 +365,24 @@ void QgsMeasureDialog::updateUi()
|
|||||||
bool b = true; // first point
|
bool b = true; // first point
|
||||||
|
|
||||||
QgsPoint p1, p2;
|
QgsPoint p1, p2;
|
||||||
|
mTotal = 0;
|
||||||
for ( it = mTool->points().constBegin(); it != mTool->points().constEnd(); ++it )
|
for ( it = mTool->points().constBegin(); it != mTool->points().constEnd(); ++it )
|
||||||
{
|
{
|
||||||
p2 = *it;
|
p2 = *it;
|
||||||
if ( !b )
|
if ( !b )
|
||||||
{
|
{
|
||||||
double d = mDa.measureLine( p1, p2 );
|
double d = -1;
|
||||||
d = convertLength( d, mDisplayUnits );
|
if ( forceCartesian )
|
||||||
|
{
|
||||||
|
//cartesian calculation forced
|
||||||
|
d = sqrt( p2.sqrDist( p1 ) );
|
||||||
|
mTotal += d;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d = mDa.measureLine( p1, p2 );
|
||||||
|
d = convertLength( d, mDisplayUnits );
|
||||||
|
}
|
||||||
|
|
||||||
QTreeWidgetItem *item = new QTreeWidgetItem( QStringList( QLocale::system().toString( d, 'f', mDecimalPlaces ) ) );
|
QTreeWidgetItem *item = new QTreeWidgetItem( QStringList( QLocale::system().toString( d, 'f', mDecimalPlaces ) ) );
|
||||||
item->setTextAlignment( 0, Qt::AlignRight );
|
item->setTextAlignment( 0, Qt::AlignRight );
|
||||||
@ -335,15 +392,17 @@ void QgsMeasureDialog::updateUi()
|
|||||||
p1 = p2;
|
p1 = p2;
|
||||||
b = false;
|
b = false;
|
||||||
}
|
}
|
||||||
mTotal = mDa.measureLine( mTool->points() );
|
|
||||||
|
if ( !forceCartesian )
|
||||||
|
mTotal = mDa.measureLine( mTool->points() );
|
||||||
mTable->show(); // Show the table with items
|
mTable->show(); // Show the table with items
|
||||||
editTotal->setText( formatDistance( mTotal ) );
|
editTotal->setText( formatDistance( mTotal, convertToDisplayUnits ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsMeasureDialog::convertMeasurement( double &measure, QGis::UnitType &u, bool isArea )
|
void QgsMeasureDialog::convertMeasurement( double &measure, QGis::UnitType &u, bool isArea )
|
||||||
{
|
{
|
||||||
// Helper for converting between meters and feet
|
// Helper for converting between units
|
||||||
// The parameter &u is out only...
|
// The parameter &u is out only...
|
||||||
|
|
||||||
// Get the canvas units
|
// Get the canvas units
|
||||||
|
@ -66,7 +66,7 @@ class APP_EXPORT QgsMeasureDialog : public QDialog, private Ui::QgsMeasureBase
|
|||||||
void updateSettings();
|
void updateSettings();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void unitsChanged( const QString &units );
|
void unitsChanged( int index );
|
||||||
|
|
||||||
//! Open configuration tab
|
//! Open configuration tab
|
||||||
void openConfigTab();
|
void openConfigTab();
|
||||||
@ -74,7 +74,7 @@ class APP_EXPORT QgsMeasureDialog : public QDialog, private Ui::QgsMeasureBase
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
//! formats distance to most appropriate units
|
//! formats distance to most appropriate units
|
||||||
QString formatDistance( double distance );
|
QString formatDistance( double distance, bool convertUnits = true );
|
||||||
|
|
||||||
//! formats area to most appropriate units
|
//! formats area to most appropriate units
|
||||||
QString formatArea( double area );
|
QString formatArea( double area );
|
||||||
|
@ -108,12 +108,8 @@ void QgsMeasureTool::restart()
|
|||||||
mRubberBand->reset( mMeasureArea ? QGis::Polygon : QGis::Line );
|
mRubberBand->reset( mMeasureArea ? QGis::Polygon : QGis::Line );
|
||||||
mRubberBandPoints->reset( QGis::Point );
|
mRubberBandPoints->reset( QGis::Point );
|
||||||
|
|
||||||
// re-read settings
|
|
||||||
updateSettings();
|
|
||||||
|
|
||||||
mDone = true;
|
mDone = true;
|
||||||
mWrongProjectProjection = false;
|
mWrongProjectProjection = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsMeasureTool::updateSettings()
|
void QgsMeasureTool::updateSettings()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user