Skip to content

Commit 6453907

Browse files
committed
Fix project unit confusion (part 1)
- Remove existing (confusing and totally useless) "canvas units" setting. This setting was supposed to be used for a confusing number of totally different uses, eg changing the coordinate display format and changing the default measurement units, but it was so broken it did none of these things except change the coordinate display and it only did that if OTF was off. - Add a new "coordinate display" section in project settings, which allows choice of format for coordinate display via a combo box (this will also make it easy to add additional custom formats in future), and make this setting work regardless of whether OTF is on or off. This setting applies to both the coordinate display in the status bar and coordinates shown via the identify tool (refs #13209, fixes #9730)
1 parent a90be95 commit 6453907

11 files changed

+329
-325
lines changed

src/app/qgisapp.cpp

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
#include "qgsstatusbarcoordinateswidget.h"
126126
#include "qgsconfigureshortcutsdialog.h"
127127
#include "qgscoordinatetransform.h"
128+
#include "qgscoordinateutils.h"
128129
#include "qgscredentialdialog.h"
129130
#include "qgscursors.h"
130131
#include "qgscustomization.h"
@@ -9616,31 +9617,7 @@ void QgisApp::showRotation()
96169617

96179618
void QgisApp::updateMouseCoordinatePrecision()
96189619
{
9619-
// Work out what mouse display precision to use. This only needs to
9620-
// be when the settings change or the zoom level changes. This
9621-
// function needs to be called every time one of the above happens.
9622-
9623-
// Get the display precision from the project settings
9624-
bool automatic = QgsProject::instance()->readBoolEntry( "PositionPrecision", "/Automatic" );
9625-
int dp = 0;
9626-
9627-
if ( automatic )
9628-
{
9629-
// Work out a suitable number of decimal places for the mouse
9630-
// coordinates with the aim of always having enough decimal places
9631-
// to show the difference in position between adjacent pixels.
9632-
// Also avoid taking the log of 0.
9633-
if ( mapCanvas()->mapUnitsPerPixel() != 0.0 )
9634-
dp = static_cast<int>( ceil( -1.0 * log10( mapCanvas()->mapUnitsPerPixel() ) ) );
9635-
}
9636-
else
9637-
dp = QgsProject::instance()->readNumEntry( "PositionPrecision", "/DecimalPlaces" );
9638-
9639-
// Keep dp sensible
9640-
if ( dp < 0 )
9641-
dp = 0;
9642-
9643-
mCoordsEdit->setMouseCoordinatesPrecision( dp );
9620+
mCoordsEdit->setMouseCoordinatesPrecision( QgsCoordinateUtils::calculateCoordinatePrecision( mapCanvas()->mapUnitsPerPixel(), mapCanvas()->mapSettings().destinationCrs() ) );
96449621
}
96459622

96469623
void QgisApp::showStatusMessage( const QString& theMessage )

src/app/qgsprojectproperties.cpp

Lines changed: 71 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -80,34 +80,35 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa
8080
// and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
8181
initOptionsBase( false );
8282

83+
mCoordinateDisplayComboBox->addItem( tr( "Decimal degrees" ), DecimalDegrees );
84+
mCoordinateDisplayComboBox->addItem( tr( "Degrees, minutes" ), DegreesMinutes );
85+
mCoordinateDisplayComboBox->addItem( tr( "Degrees, minutes, seconds" ), DegreesMinutesSeconds );
86+
8387
connect( buttonBox->button( QDialogButtonBox::Apply ), SIGNAL( clicked() ), this, SLOT( apply() ) );
8488
connect( this, SIGNAL( accepted() ), this, SLOT( apply() ) );
85-
connect( projectionSelector, SIGNAL( sridSelected( QString ) ), this, SLOT( setMapUnitsToCurrentProjection() ) );
89+
connect( projectionSelector, SIGNAL( sridSelected( QString ) ), this, SLOT( srIdUpdated() ) );
8690
connect( projectionSelector, SIGNAL( initialized() ), this, SLOT( projectionSelectorInitialized() ) );
8791

8892
connect( cmbEllipsoid, SIGNAL( currentIndexChanged( int ) ), this, SLOT( updateEllipsoidUI( int ) ) );
8993

90-
connect( radMeters, SIGNAL( toggled( bool ) ), btnGrpDegreeDisplay, SLOT( setDisabled( bool ) ) );
91-
connect( radFeet, SIGNAL( toggled( bool ) ), btnGrpDegreeDisplay, SLOT( setDisabled( bool ) ) );
92-
connect( radNMiles, SIGNAL( toggled( bool ) ), btnGrpDegreeDisplay, SLOT( setDisabled( bool ) ) );
93-
connect( radDegrees, SIGNAL( toggled( bool ) ), btnGrpDegreeDisplay, SLOT( setEnabled( bool ) ) );
94-
95-
connect( radAutomatic, SIGNAL( toggled( bool ) ), mPrecisionFrame, SLOT( setDisabled( bool ) ) );
96-
connect( radManual, SIGNAL( toggled( bool ) ), mPrecisionFrame, SLOT( setEnabled( bool ) ) );
94+
connect( radAutomatic, SIGNAL( toggled( bool ) ), spinBoxDP, SLOT( setDisabled( bool ) ) );
95+
connect( radAutomatic, SIGNAL( toggled( bool ) ), labelDP, SLOT( setDisabled( bool ) ) );
96+
connect( radManual, SIGNAL( toggled( bool ) ), spinBoxDP, SLOT( setEnabled( bool ) ) );
97+
connect( radManual, SIGNAL( toggled( bool ) ), labelDP, SLOT( setEnabled( bool ) ) );
9798

9899
QSettings settings;
99100

100101
///////////////////////////////////////////////////////////
101102
// Properties stored in map canvas's QgsMapRenderer
102103
// these ones are propagated to QgsProject by a signal
103104

104-
QGis::UnitType myUnit = mMapCanvas->mapSettings().mapUnits();
105-
setMapUnits( myUnit );
106-
107105
// we need to initialize it, since the on_cbxProjectionEnabled_toggled()
108106
// slot triggered by setChecked() might use it.
109107
mProjectSrsId = mMapCanvas->mapSettings().destinationCrs().srsid();
110108

109+
QgsCoordinateReferenceSystem srs( mProjectSrsId, QgsCoordinateReferenceSystem::InternalCrsId );
110+
updateGuiForMapUnits( srs.mapUnits() );
111+
111112
QgsDebugMsg( "Read project CRSID: " + QString::number( mProjectSrsId ) );
112113
projectionSelector->setSelectedCrsId( mProjectSrsId );
113114

@@ -127,13 +128,17 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa
127128
if ( automaticPrecision )
128129
{
129130
radAutomatic->setChecked( true );
130-
mPrecisionFrame->setEnabled( false );
131+
spinBoxDP->setEnabled( false );
132+
labelDP->setEnabled( false );
131133
}
132134
else
133135
{
134136
radManual->setChecked( true );
135-
mPrecisionFrame->setEnabled( true );
137+
spinBoxDP->setEnabled( true );
138+
labelDP->setEnabled( true );
136139
}
140+
int dp = QgsProject::instance()->readNumEntry( "PositionPrecision", "/DecimalPlaces" );
141+
spinBoxDP->setValue( dp );
137142

138143
cbxAbsolutePath->setCurrentIndex( QgsProject::instance()->readBoolEntry( "Paths", "/Absolute", true ) ? 0 : 1 );
139144

@@ -142,17 +147,15 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa
142147
// be overridden in the meanwhile by the projection selector
143148
populateEllipsoidList();
144149

145-
146-
int dp = QgsProject::instance()->readNumEntry( "PositionPrecision", "/DecimalPlaces" );
147-
spinBoxDP->setValue( dp );
148-
149150
QString format = QgsProject::instance()->readEntry( "PositionPrecision", "/DegreeFormat", "D" );
150-
if ( format == "DM" )
151-
radDM->setChecked( true );
151+
if ( format == "MU" && mCoordinateDisplayComboBox->findData( MapUnits ) >= 0 )
152+
mCoordinateDisplayComboBox->setCurrentIndex( mCoordinateDisplayComboBox->findData( MapUnits ) );
153+
else if ( format == "DM" )
154+
mCoordinateDisplayComboBox->setCurrentIndex( mCoordinateDisplayComboBox->findData( DegreesMinutes ) );
152155
else if ( format == "DMS" )
153-
radDMS->setChecked( true );
156+
mCoordinateDisplayComboBox->setCurrentIndex( mCoordinateDisplayComboBox->findData( DegreesMinutesSeconds ) );
154157
else
155-
radD->setChecked( true );
158+
mCoordinateDisplayComboBox->setCurrentIndex( mCoordinateDisplayComboBox->findData( DecimalDegrees ) );
156159

157160
//get the color selections and set the button color accordingly
158161
int myRedInt = QgsProject::instance()->readNumEntry( "Gui", "/SelectionColorRedPart", 255 );
@@ -692,11 +695,6 @@ void QgsProjectProperties::setMapUnits( QGis::UnitType unit )
692695
unit = QGis::Meters;
693696
}
694697

695-
radMeters->setChecked( unit == QGis::Meters );
696-
radFeet->setChecked( unit == QGis::Feet );
697-
radNMiles->setChecked( unit == QGis::NauticalMiles );
698-
radDegrees->setChecked( unit == QGis::Degrees );
699-
700698
mMapCanvas->setMapUnits( unit );
701699
}
702700

@@ -714,28 +712,6 @@ void QgsProjectProperties::title( QString const & title )
714712
//when user clicks apply button
715713
void QgsProjectProperties::apply()
716714
{
717-
// Set the map units
718-
// Note. Qt 3.2.3 and greater have a function selectedId() that
719-
// can be used instead of the two part technique here
720-
QGis::UnitType mapUnit;
721-
if ( radDegrees->isChecked() )
722-
{
723-
mapUnit = QGis::Degrees;
724-
}
725-
else if ( radFeet->isChecked() )
726-
{
727-
mapUnit = QGis::Feet;
728-
}
729-
else if ( radNMiles->isChecked() )
730-
{
731-
mapUnit = QGis::NauticalMiles;
732-
}
733-
else
734-
{
735-
mapUnit = QGis::Meters;
736-
}
737-
738-
mMapCanvas->setMapUnits( mapUnit );
739715
mMapCanvas->setCrsTransformEnabled( cbxProjectionEnabled->isChecked() );
740716

741717
mMapCanvas->enableMapTileRendering( mMapTileRenderingCheckBox->isChecked() );
@@ -781,8 +757,24 @@ void QgsProjectProperties::apply()
781757
// can be used instead of the two part technique here
782758
QgsProject::instance()->writeEntry( "PositionPrecision", "/Automatic", radAutomatic->isChecked() );
783759
QgsProject::instance()->writeEntry( "PositionPrecision", "/DecimalPlaces", spinBoxDP->value() );
784-
QgsProject::instance()->writeEntry( "PositionPrecision", "/DegreeFormat",
785-
QString( radDM->isChecked() ? "DM" : radDMS->isChecked() ? "DMS" : "D" ) );
760+
QString degreeFormat;
761+
switch ( static_cast< CoordinateFormat >( mCoordinateDisplayComboBox->itemData( mCoordinateDisplayComboBox->currentIndex() ).toInt() ) )
762+
{
763+
case DegreesMinutes:
764+
degreeFormat = "DM";
765+
break;
766+
case DegreesMinutesSeconds:
767+
degreeFormat = "DMS";
768+
break;
769+
case MapUnits:
770+
degreeFormat = "MU";
771+
break;
772+
case DecimalDegrees:
773+
default:
774+
degreeFormat = "D";
775+
break;
776+
}
777+
QgsProject::instance()->writeEntry( "PositionPrecision", "/DegreeFormat", degreeFormat );
786778

787779
// Announce that we may have a new display precision setting
788780
emit displayPrecisionChanged();
@@ -1148,7 +1140,6 @@ void QgsProjectProperties::showProjectionsTab()
11481140
void QgsProjectProperties::on_cbxProjectionEnabled_toggled( bool onFlyEnabled )
11491141
{
11501142
QString measureOnFlyState = tr( "Measure tool (CRS transformation: %1)" );
1151-
QString unitsOnFlyState = tr( "Canvas units (CRS transformation: %1)" );
11521143
if ( !onFlyEnabled )
11531144
{
11541145
// reset projection to default
@@ -1169,20 +1160,10 @@ void QgsProjectProperties::on_cbxProjectionEnabled_toggled( bool onFlyEnabled )
11691160
mProjectSrsId = mLayerSrsId;
11701161
projectionSelector->setSelectedCrsId( mLayerSrsId );
11711162

1172-
QgsCoordinateReferenceSystem srs( mLayerSrsId, QgsCoordinateReferenceSystem::InternalCrsId );
1173-
//set radio button to crs map unit type
1174-
QGis::UnitType units = srs.mapUnits();
1175-
1176-
radMeters->setChecked( units == QGis::Meters );
1177-
radFeet->setChecked( units == QGis::Feet );
1178-
radNMiles->setChecked( units == QGis::NauticalMiles );
1179-
radDegrees->setChecked( units == QGis::Degrees );
1180-
11811163
// unset ellipsoid
11821164
mEllipsoidIndex = 0;
11831165

11841166
btnGrpMeasureEllipsoid->setTitle( measureOnFlyState.arg( tr( "OFF" ) ) );
1185-
btnGrpMapUnits->setTitle( unitsOnFlyState.arg( tr( "OFF" ) ) );
11861167
}
11871168
else
11881169
{
@@ -1193,14 +1174,12 @@ void QgsProjectProperties::on_cbxProjectionEnabled_toggled( bool onFlyEnabled )
11931174
projectionSelector->setSelectedCrsId( mProjectSrsId );
11941175

11951176
btnGrpMeasureEllipsoid->setTitle( measureOnFlyState.arg( tr( "ON" ) ) );
1196-
btnGrpMapUnits->setTitle( unitsOnFlyState.arg( tr( "ON" ) ) );
11971177
}
11981178

1199-
setMapUnitsToCurrentProjection();
1179+
srIdUpdated();
12001180

12011181
// Enable/Disable selector and update tool-tip
12021182
updateEllipsoidUI( mEllipsoidIndex ); // maybe already done by setMapUnitsToCurrentProjection
1203-
12041183
}
12051184

12061185
void QgsProjectProperties::cbxWFSPubliedStateChanged( int aIdx )
@@ -1237,7 +1216,33 @@ void QgsProjectProperties::cbxWCSPubliedStateChanged( int aIdx )
12371216
}
12381217
}
12391218

1240-
void QgsProjectProperties::setMapUnitsToCurrentProjection()
1219+
void QgsProjectProperties::updateGuiForMapUnits( QGis::UnitType units )
1220+
{
1221+
int idx = mCoordinateDisplayComboBox->findData( MapUnits );
1222+
if ( units == QGis::Degrees )
1223+
{
1224+
//remove map units option from coordinate display combo
1225+
if ( idx >= 0 )
1226+
{
1227+
mCoordinateDisplayComboBox->removeItem( idx );
1228+
}
1229+
}
1230+
else
1231+
{
1232+
//make sure map units option is shown in coordinate display combo
1233+
QString mapUnitString = tr( "Map units (%1)" ).arg( QGis::tr( units ) );
1234+
if ( idx < 0 )
1235+
{
1236+
mCoordinateDisplayComboBox->insertItem( 0, mapUnitString, MapUnits );
1237+
}
1238+
else
1239+
{
1240+
mCoordinateDisplayComboBox->setItemText( idx, mapUnitString );
1241+
}
1242+
}
1243+
}
1244+
1245+
void QgsProjectProperties::srIdUpdated()
12411246
{
12421247
long myCRSID = projectionSelector->selectedCrsId();
12431248
if ( !isProjected() || !myCRSID )
@@ -1247,10 +1252,7 @@ void QgsProjectProperties::setMapUnitsToCurrentProjection()
12471252
//set radio button to crs map unit type
12481253
QGis::UnitType units = srs.mapUnits();
12491254

1250-
radMeters->setChecked( units == QGis::Meters );
1251-
radFeet->setChecked( units == QGis::Feet );
1252-
radNMiles->setChecked( units == QGis::NauticalMiles );
1253-
radDegrees->setChecked( units == QGis::Degrees );
1255+
updateGuiForMapUnits( units );
12541256

12551257
// attempt to reset the projection ellipsoid according to the srs
12561258
int myIndex = 0;

src/app/qgsprojectproperties.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ class APP_EXPORT QgsProjectProperties : public QgsOptionsDialogBase, private Ui:
156156
/*!
157157
* If user changes the CRS, set the corresponding map units
158158
*/
159-
void setMapUnitsToCurrentProjection();
159+
void srIdUpdated();
160160

161161
/* Update ComboBox accorindg to the selected new index
162162
* Also sets the new selected Ellipsoid. */
@@ -180,6 +180,16 @@ class APP_EXPORT QgsProjectProperties : public QgsOptionsDialogBase, private Ui:
180180
void refresh();
181181

182182
private:
183+
184+
//! Formats for displaying coordinates
185+
enum CoordinateFormat
186+
{
187+
DecimalDegrees, /*!< Decimal degrees */
188+
DegreesMinutes, /*!< Degrees, decimal minutes */
189+
DegreesMinutesSeconds, /*!< Degrees, minutes, seconds */
190+
MapUnits, /*! Show coordinates in map units */
191+
};
192+
183193
QgsRelationManagerDialog *mRelationManagerDlg;
184194
QgsMapCanvas* mMapCanvas;
185195
QgsStyleV2* mStyle;
@@ -230,4 +240,5 @@ class APP_EXPORT QgsProjectProperties : public QgsOptionsDialogBase, private Ui:
230240

231241
static const char * GEO_NONE_DESC;
232242

243+
void updateGuiForMapUnits( QGis::UnitType units );
233244
};

src/app/qgsstatusbarcoordinateswidget.cpp

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "qgsapplication.h"
2727
#include "qgsmapcanvas.h"
2828
#include "qgsproject.h"
29+
#include "qgscoordinateutils.h"
2930

3031

3132
QgsStatusBarCoordinatesWidget::QgsStatusBarCoordinatesWidget( QWidget *parent )
@@ -225,30 +226,8 @@ void QgsStatusBarCoordinatesWidget::showMouseCoordinates( const QgsPoint & p )
225226
return;
226227
}
227228

228-
if ( mMapCanvas->mapUnits() == QGis::Degrees )
229-
{
230-
if ( !mMapCanvas->mapSettings().destinationCrs().isValid() )
231-
return;
232-
233-
QgsPoint geo = p;
234-
if ( !mMapCanvas->mapSettings().destinationCrs().geographicFlag() )
235-
{
236-
QgsCoordinateTransform ct( mMapCanvas->mapSettings().destinationCrs(), QgsCoordinateReferenceSystem( GEOSRID ) );
237-
geo = ct.transform( p );
238-
}
239-
QString format = QgsProject::instance()->readEntry( "PositionPrecision", "/DegreeFormat", "D" );
240-
241-
if ( format == "DM" )
242-
mLineEdit->setText( geo.toDegreesMinutes( mMousePrecisionDecimalPlaces ) );
243-
else if ( format == "DMS" )
244-
mLineEdit->setText( geo.toDegreesMinutesSeconds( mMousePrecisionDecimalPlaces ) );
245-
else
246-
mLineEdit->setText( geo.toString( mMousePrecisionDecimalPlaces ) );
247-
}
248-
else
249-
{
250-
mLineEdit->setText( p.toString( mMousePrecisionDecimalPlaces ) );
251-
}
229+
mLineEdit->setText( QgsCoordinateUtils::formatCoordinateForProject( p, mMapCanvas->mapSettings().destinationCrs(),
230+
mMousePrecisionDecimalPlaces ) );
252231

253232
if ( mLineEdit->width() > mLineEdit->minimumWidth() )
254233
{

src/core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ SET(QGIS_CORE_SRCS
8888
qgscontexthelp_texts.cpp
8989
qgscoordinatereferencesystem.cpp
9090
qgscoordinatetransform.cpp
91+
qgscoordinateutils.cpp
9192
qgscredentials.cpp
9293
qgscrscache.cpp
9394
qgsdartmeasurement.cpp
@@ -585,6 +586,7 @@ SET(QGIS_CORE_HDRS
585586
qgscontexthelp.h
586587
qgsconditionalstyle.h
587588
qgscoordinatereferencesystem.h
589+
qgscoordinateutils.h
588590
qgscrscache.h
589591
qgscsexception.h
590592
qgsdartmeasurement.h

src/core/qgscoordinatereferencesystem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
325325
/** Returns whether the CRS is a geographic CRS.
326326
* @returns true if CRS is geographic, or false if it is a projected CRS
327327
*/
328+
//TODO QGIS 3.0 - rename to isGeographic
328329
bool geographicFlag() const;
329330

330331
/** Returns whether axis is inverted (eg. for WMS 1.3) for the CRS.

0 commit comments

Comments
 (0)