Skip to content

Commit

Permalink
Implement MapGeographic vs CustomCrs
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn authored and nyalldawson committed Sep 5, 2022
1 parent 1570643 commit b20cc30
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 42 deletions.
7 changes: 4 additions & 3 deletions python/core/auto_additions/qgis.py
Expand Up @@ -1917,8 +1917,9 @@
# --
Qgis.RelationshipCardinality.baseClass = Qgis
# monkey patching scoped based enum
Qgis.CoordinateDisplayType.Geographic.__doc__ = "Geographic"
Qgis.CoordinateDisplayType.MapUnits.__doc__ = "Map units"
Qgis.CoordinateDisplayType.__doc__ = 'Formats for displaying coordinates\n\n.. versionadded:: 3.28\n\n' + '* ``Geographic``: ' + Qgis.CoordinateDisplayType.Geographic.__doc__ + '\n' + '* ``MapUnits``: ' + Qgis.CoordinateDisplayType.MapUnits.__doc__
Qgis.CoordinateDisplayType.MapCrs.__doc__ = "Map CRS"
Qgis.CoordinateDisplayType.MapGeographic.__doc__ = "Map Geographic CRS equivalent (stays unchanged if the map CRS is geographic)"
Qgis.CoordinateDisplayType.CustomCrs.__doc__ = "Custom CRS"
Qgis.CoordinateDisplayType.__doc__ = 'Formats for displaying coordinates\n\n.. versionadded:: 3.28\n\n' + '* ``MapCrs``: ' + Qgis.CoordinateDisplayType.MapCrs.__doc__ + '\n' + '* ``MapGeographic``: ' + Qgis.CoordinateDisplayType.MapGeographic.__doc__ + '\n' + '* ``CustomCrs``: ' + Qgis.CoordinateDisplayType.CustomCrs.__doc__
# --
Qgis.CoordinateDisplayType.baseClass = Qgis
Expand Up @@ -96,6 +96,10 @@ Sets the default coordinate ``type`` for the project.
.. versionadded:: 3.28
%End

QgsCoordinateReferenceSystem coordinateCustomCrs() const;

void setCoordinateCustomCrs( const QgsCoordinateReferenceSystem &crs );

bool readXml( const QDomElement &element, const QgsReadWriteContext &context );
%Docstring
Reads the settings's state from a DOM element.
Expand Down Expand Up @@ -141,6 +145,8 @@ Emitted when the default coordinate format changes.
.. versionadded:: 3.28
%End

void coordinateCustomCrsChanged();

};

/************************************************************************
Expand Down
5 changes: 3 additions & 2 deletions python/core/auto_generated/qgis.sip.in
Expand Up @@ -1240,8 +1240,9 @@ The development version

enum class CoordinateDisplayType
{
Geographic,
MapUnits,
MapCrs,
MapGeographic,
CustomCrs,
};

static const double DEFAULT_SEARCH_RADIUS_MM;
Expand Down
77 changes: 72 additions & 5 deletions src/app/qgsprojectproperties.cpp
Expand Up @@ -129,14 +129,17 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas *mapCanvas, QWidget *pa
connect( mButtonAddStyleDatabase, &QAbstractButton::clicked, this, &QgsProjectProperties::addStyleDatabase );
connect( mButtonRemoveStyleDatabase, &QAbstractButton::clicked, this, &QgsProjectProperties::removeStyleDatabase );
connect( mButtonNewStyleDatabase, &QAbstractButton::clicked, this, &QgsProjectProperties::newStyleDatabase );
connect( mCoordinateDisplayComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int ) { updateGuiForCoordinateType(); } );
connect( mCoordinateCrs, &QgsProjectionSelectionWidget::crsChanged, this, [ = ]( const QgsCoordinateReferenceSystem & ) { updateGuiForCoordinateCrs(); } );

// QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
// switching vertical tabs between icon/text to icon-only modes (splitter collapsed to left),
// and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
initOptionsBase( false );

mCoordinateDisplayComboBox->addItem( tr( "Map Units" ), static_cast<int>( Qgis::CoordinateDisplayType::MapUnits ) );
mCoordinateDisplayComboBox->addItem( tr( "Geographic (Latitude / Longitude)" ), static_cast<int>( Qgis::CoordinateDisplayType::Geographic ) );
mCoordinateDisplayComboBox->addItem( tr( "Map Units" ), static_cast<int>( Qgis::CoordinateDisplayType::MapCrs ) );
mCoordinateDisplayComboBox->addItem( tr( "Map Geographic (degrees)" ), static_cast<int>( Qgis::CoordinateDisplayType::MapGeographic ) );
mCoordinateDisplayComboBox->addItem( tr( "Custom Projection Units" ), static_cast<int>( Qgis::CoordinateDisplayType::CustomCrs ) );

mCoordinateOrderComboBox->addItem( tr( "Default" ), static_cast< int >( Qgis::CoordinateOrder::Default ) );
mCoordinateOrderComboBox->addItem( tr( "Easting, Northing (Longitude, Latitude)" ), static_cast< int >( Qgis::CoordinateOrder::XY ) );
Expand Down Expand Up @@ -382,7 +385,23 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas *mapCanvas, QWidget *pa
updateEllipsoidUI( index );
}

mCoordinateDisplayComboBox->setCurrentIndex( mCoordinateDisplayComboBox->findData( static_cast<int>( QgsProject::instance()->displaySettings()->coordinateType() ) ) );
const Qgis::CoordinateDisplayType coordinateType = QgsProject::instance()->displaySettings()->coordinateType();
mCoordinateDisplayComboBox->setCurrentIndex( mCoordinateDisplayComboBox->findData( static_cast<int>( coordinateType ) ) );
switch ( coordinateType )
{
case Qgis::CoordinateDisplayType::MapCrs:
mCoordinateCrs->setEnabled( false );
mCoordinateCrs->setCrs( mCrs );
break;
case Qgis::CoordinateDisplayType::MapGeographic:
mCoordinateCrs->setEnabled( false );
mCoordinateCrs->setCrs( !mCrs.isGeographic() ? mCrs.toGeographicCrs() : mCrs );
break;
case Qgis::CoordinateDisplayType::CustomCrs:
mCoordinateCrs->setEnabled( true );
mCoordinateCrs->setCrs( QgsProject::instance()->displaySettings()->coordinateCustomCrs() );
break;
}

const Qgis::CoordinateOrder axisOrder = qgsEnumKeyToValue( QgsProject::instance()->readEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/CoordinateOrder" ) ), Qgis::CoordinateOrder::Default );
mCoordinateOrderComboBox->setCurrentIndex( mCoordinateOrderComboBox->findData( static_cast< int >( axisOrder ) ) );
Expand Down Expand Up @@ -1186,6 +1205,15 @@ void QgsProjectProperties::apply()

const Qgis::CoordinateDisplayType coordinateType = static_cast< Qgis::CoordinateDisplayType >( mCoordinateDisplayComboBox->currentData().toInt() );
QgsProject::instance()->displaySettings()->setCoordinateType( coordinateType );
if ( coordinateType == Qgis::CoordinateDisplayType::CustomCrs )
{
QgsProject::instance()->displaySettings()->setCoordinateCustomCrs( mCoordinateCrs->crs() );
}
else
{
QgsProject::instance()->displaySettings()->setCoordinateCustomCrs( QgsCoordinateReferenceSystem( "EPSG:4326" ) );
}

QgsProject::instance()->writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/CoordinateOrder" ), qgsEnumValueToKey( static_cast< Qgis::CoordinateOrder >( mCoordinateOrderComboBox->currentData().toInt() ) ) );

// Announce that we may have a new display precision setting
Expand Down Expand Up @@ -1829,6 +1857,45 @@ void QgsProjectProperties::cbxWCSPubliedStateChanged( int aIdx )
}
}

void QgsProjectProperties::updateGuiForCoordinateCrs()
{
const Qgis::CoordinateDisplayType coordinateType = static_cast<Qgis::CoordinateDisplayType>( mCoordinateDisplayComboBox->currentData().toInt() );
const int customIndex = mCoordinateDisplayComboBox->findData( static_cast<int>( Qgis::CoordinateDisplayType::CustomCrs ) );
if ( coordinateType == Qgis::CoordinateDisplayType::CustomCrs )
{
const QgsUnitTypes::DistanceUnit units = mCoordinateCrs->crs().mapUnits();
mCoordinateDisplayComboBox->setItemText( customIndex, tr( "Custom Projection Units (%1)" ).arg( QgsUnitTypes::toString( units ) ) );
}
else
{
mCoordinateDisplayComboBox->setItemText( customIndex, tr( "Custom Projection Units" ) );
}
}

void QgsProjectProperties::updateGuiForCoordinateType()
{
const Qgis::CoordinateDisplayType coordinateType = static_cast<Qgis::CoordinateDisplayType>( mCoordinateDisplayComboBox->currentData().toInt() );
switch ( coordinateType )
{
case Qgis::CoordinateDisplayType::MapCrs:
mCoordinateCrs->setEnabled( false );
mCoordinateCrs->setCrs( mCrs );
break;

case Qgis::CoordinateDisplayType::MapGeographic:
mCoordinateCrs->setEnabled( false );
mCoordinateCrs->setCrs( !mCrs.isGeographic() ? mCrs.toGeographicCrs() : mCrs );
break;

case Qgis::CoordinateDisplayType::CustomCrs:
mCoordinateCrs->setEnabled( true );
mCoordinateCrs->setCrs( QgsProject::instance()->displaySettings()->coordinateCustomCrs() );
break;
}

updateGuiForCoordinateCrs();
}

void QgsProjectProperties::updateGuiForMapUnits()
{
if ( !mCrs.isValid() )
Expand All @@ -1846,7 +1913,7 @@ void QgsProjectProperties::updateGuiForMapUnits()
mAreaUnitsCombo->setItemText( idx, tr( "Unknown Units" ) );
mAreaUnitsCombo->setCurrentIndex( idx );
}
idx = mCoordinateDisplayComboBox->findData( static_cast<int>( Qgis::CoordinateDisplayType::MapUnits ) );
idx = mCoordinateDisplayComboBox->findData( static_cast<int>( Qgis::CoordinateDisplayType::MapCrs ) );
if ( idx >= 0 )
{
mCoordinateDisplayComboBox->setItemText( idx, tr( "Unknown Units" ) );
Expand All @@ -1865,7 +1932,7 @@ void QgsProjectProperties::updateGuiForMapUnits()
mCoordinateDisplayComboBox->setEnabled( true );

//make sure map units option is shown in coordinate display combo
int idx = mCoordinateDisplayComboBox->findData( static_cast<int>( Qgis::CoordinateDisplayType::MapUnits ) );
int idx = mCoordinateDisplayComboBox->findData( static_cast<int>( Qgis::CoordinateDisplayType::MapCrs ) );
QString mapUnitString = tr( "Map Units (%1)" ).arg( QgsUnitTypes::toString( units ) );
mCoordinateDisplayComboBox->setItemText( idx, mapUnitString );

Expand Down
3 changes: 3 additions & 0 deletions src/app/qgsprojectproperties.h
Expand Up @@ -260,6 +260,9 @@ class APP_EXPORT QgsProjectProperties : public QgsOptionsDialogBase, private Ui:
static const char *GEO_NONE_DESC;

void updateGuiForMapUnits();
void updateGuiForCoordinateType();
void updateGuiForCoordinateCrs();

void addStyleDatabasePrivate( bool createNew );

void showHelp();
Expand Down
37 changes: 35 additions & 2 deletions src/core/project/qgsprojectdisplaysettings.cpp
Expand Up @@ -41,11 +41,13 @@ void QgsProjectDisplaySettings::reset()
mBearingFormat.reset( QgsLocalDefaultSettings::bearingFormat() );
mGeographicCoordinateFormat.reset( QgsLocalDefaultSettings::geographicCoordinateFormat() );

mCoordinateType = Qgis::CoordinateDisplayType::MapUnits;
mCoordinateType = Qgis::CoordinateDisplayType::MapCrs;
mCoordinateCustomCrs = QgsCoordinateReferenceSystem( "EPSG:4326" );

emit bearingFormatChanged();
emit geographicCoordinateFormatChanged();
emit coordinateTypeChanged();
emit coordinateCustomCrsChanged();
}

void QgsProjectDisplaySettings::setBearingFormat( QgsBearingNumericFormat *format )
Expand Down Expand Up @@ -80,6 +82,16 @@ void QgsProjectDisplaySettings::setCoordinateType( Qgis::CoordinateDisplayType t
emit coordinateTypeChanged();
}

void QgsProjectDisplaySettings::setCoordinateCustomCrs( const QgsCoordinateReferenceSystem &crs )
{
if ( mCoordinateCustomCrs == crs )
return;

mCoordinateCustomCrs = crs;

emit coordinateCustomCrsChanged();
}

bool QgsProjectDisplaySettings::readXml( const QDomElement &element, const QgsReadWriteContext &context )
{
{
Expand Down Expand Up @@ -134,10 +146,25 @@ bool QgsProjectDisplaySettings::readXml( const QDomElement &element, const QgsRe
const QString format = project->readEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DegreeFormat" ), QString() );
if ( !format.isEmpty() )
{
mCoordinateType = format == QStringLiteral( "MU" ) ? Qgis::CoordinateDisplayType::MapUnits : Qgis::CoordinateDisplayType::Geographic;
if ( format != QStringLiteral( "MU" ) && !project->crs().isGeographic() )
{
mCoordinateType = Qgis::CoordinateDisplayType::CustomCrs;
}
else
{
mCoordinateType = Qgis::CoordinateDisplayType::MapCrs;
}
}
}
emit coordinateTypeChanged();

QDomNodeList crsNodeList = element.elementsByTagName( QStringLiteral( "CoordinateCustomCrs" ) );
if ( !crsNodeList.isEmpty() )
{
QDomElement crsElem = crsNodeList.at( 0 ).toElement();
mCoordinateCustomCrs.readXml( crsElem );
}
emit coordinateCustomCrsChanged();
}

return true;
Expand All @@ -160,6 +187,12 @@ QDomElement QgsProjectDisplaySettings::writeXml( QDomDocument &doc, const QgsRea
}

element.setAttribute( QStringLiteral( "CoordinateType" ), static_cast<int>( mCoordinateType ) );
if ( mCoordinateCustomCrs.isValid() )
{
QDomElement crsElem = doc.createElement( QStringLiteral( "CoordinateCustomCrs" ) );
mCoordinateCustomCrs.writeXml( crsElem, doc );
element.appendChild( crsElem );
}

return element;
}
10 changes: 9 additions & 1 deletion src/core/project/qgsprojectdisplaysettings.h
Expand Up @@ -19,6 +19,7 @@
#include "qgis_sip.h"
#include "qgis.h"
#include "qgsunittypes.h"
#include "qgscoordinatereferencesystem.h"

#include <QObject>
#include <QVector>
Expand Down Expand Up @@ -109,6 +110,10 @@ class CORE_EXPORT QgsProjectDisplaySettings : public QObject
*/
void setCoordinateType( Qgis::CoordinateDisplayType type );

QgsCoordinateReferenceSystem coordinateCustomCrs() const { return mCoordinateCustomCrs; }

void setCoordinateCustomCrs( const QgsCoordinateReferenceSystem &crs );

/**
* Reads the settings's state from a DOM element.
* \see writeXml()
Expand Down Expand Up @@ -148,11 +153,14 @@ class CORE_EXPORT QgsProjectDisplaySettings : public QObject
*/
void coordinateTypeChanged();

void coordinateCustomCrsChanged();

private:
std::unique_ptr< QgsBearingNumericFormat > mBearingFormat;
std::unique_ptr< QgsGeographicCoordinateNumericFormat > mGeographicCoordinateFormat;

Qgis::CoordinateDisplayType mCoordinateType = Qgis::CoordinateDisplayType::MapUnits;
Qgis::CoordinateDisplayType mCoordinateType = Qgis::CoordinateDisplayType::MapCrs;
QgsCoordinateReferenceSystem mCoordinateCustomCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) );

};

Expand Down
5 changes: 3 additions & 2 deletions src/core/qgis.h
Expand Up @@ -2129,8 +2129,9 @@ class CORE_EXPORT Qgis
*/
enum class CoordinateDisplayType : int
{
Geographic, //!< Geographic
MapUnits, //!< Map units
MapCrs, //!< Map CRS
MapGeographic, //!< Map Geographic CRS equivalent (stays unchanged if the map CRS is geographic)
CustomCrs, //!< Custom CRS
};
Q_ENUM( CoordinateDisplayType )

Expand Down
53 changes: 37 additions & 16 deletions src/core/qgscoordinateutils.cpp
Expand Up @@ -42,7 +42,9 @@ int QgsCoordinateUtils::calculateCoordinatePrecision( double mapUnitsPerPixel, c

if ( automatic )
{
const bool formatGeographic = project->displaySettings()->coordinateType() == Qgis::CoordinateDisplayType::Geographic;
const bool formatGeographic = project->displaySettings()->coordinateType() == Qgis::CoordinateDisplayType::MapGeographic ||
( project->displaySettings()->coordinateType() == Qgis::CoordinateDisplayType::CustomCrs &&
project->displaySettings()->coordinateCustomCrs().isGeographic() );

// we can only calculate an automatic precision if one of these is true:
// - both map CRS and format are geographic
Expand Down Expand Up @@ -111,39 +113,58 @@ QString QgsCoordinateUtils::formatCoordinateForProject( QgsProject *project, con
return QString();

const Qgis::CoordinateOrder axisOrder = qgsEnumKeyToValue( project->readEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/CoordinateOrder" ) ), Qgis::CoordinateOrder::Default );
const bool formatGeographic = project->displaySettings()->coordinateType() == Qgis::CoordinateDisplayType::Geographic;

QgsPointXY geo = point;
if ( formatGeographic )
QgsCoordinateReferenceSystem crs = destCrs;
QgsPointXY p = point;
bool isGeographic = false;
if ( project->displaySettings()->coordinateType() == Qgis::CoordinateDisplayType::MapGeographic )
{
// degrees
QgsCoordinateReferenceSystem geographicCrs = destCrs;
isGeographic = true;
if ( destCrs.isValid() && !destCrs.isGeographic() )
{
// default to EPSG:4326 if the project CRS isn't already geographic
geographicCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) );
// need to transform to geographic coordinates
const QgsCoordinateTransform ct( destCrs, geographicCrs, project );
// use the associated geographic projection to the destination CRS.
crs = destCrs.toGeographicCrs();
const QgsCoordinateTransform ct( destCrs, crs, project );
try
{
geo = ct.transform( point );
p = ct.transform( point );
}
catch ( QgsCsException & )
{
return QString();
}
}
}
else if ( project->displaySettings()->coordinateType() == Qgis::CoordinateDisplayType::CustomCrs )
{
crs = project->displaySettings()->coordinateCustomCrs();
if ( destCrs != crs )
{
isGeographic = crs.isGeographic();
const QgsCoordinateTransform ct( destCrs, crs, project );
try
{
p = ct.transform( point );
}
catch ( QgsCsException & )
{
return QString();
}
}
}

const Qgis::CoordinateOrder order = axisOrder == Qgis::CoordinateOrder::Default ? QgsCoordinateReferenceSystemUtils::defaultCoordinateOrderForCrs( geographicCrs ) : axisOrder;
if ( isGeographic )
{
const Qgis::CoordinateOrder order = axisOrder == Qgis::CoordinateOrder::Default ? QgsCoordinateReferenceSystemUtils::defaultCoordinateOrderForCrs( crs ) : axisOrder;

std::unique_ptr< QgsGeographicCoordinateNumericFormat > format( project->displaySettings()->geographicCoordinateFormat()->clone() );
format->setNumberDecimalPlaces( precision );

QgsNumericFormatContext context;
context.setInterpretation( QgsNumericFormatContext::Interpretation::Longitude );
const QString formattedX = format->formatDouble( geo.x(), context );
const QString formattedX = format->formatDouble( p.x(), context );
context.setInterpretation( QgsNumericFormatContext::Interpretation::Latitude );
const QString formattedY = format->formatDouble( geo.y(), context );
const QString formattedY = format->formatDouble( p.y(), context );

switch ( order )
{
Expand All @@ -159,8 +180,8 @@ QString QgsCoordinateUtils::formatCoordinateForProject( QgsProject *project, con
else
{
// coordinates in map units
const Qgis::CoordinateOrder order = axisOrder == Qgis::CoordinateOrder::Default ? QgsCoordinateReferenceSystemUtils::defaultCoordinateOrderForCrs( destCrs ) : axisOrder;
return QgsCoordinateFormatter::asPair( point.x(), point.y(), precision, order );
const Qgis::CoordinateOrder order = axisOrder == Qgis::CoordinateOrder::Default ? QgsCoordinateReferenceSystemUtils::defaultCoordinateOrderForCrs( crs ) : axisOrder;
return QgsCoordinateFormatter::asPair( p.x(), p.y(), precision, order );
}
}

Expand Down

0 comments on commit b20cc30

Please sign in to comment.