From 1684ff1d67beab0a8f38ab35b5f935cac76f02dd Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 5 Feb 2020 16:13:21 +1000 Subject: [PATCH] Show warnings on fallback transform --- src/app/qgsappcoordinateoperationhandlers.cpp | 33 +++++++++++++++++++ src/app/qgsappcoordinateoperationhandlers.h | 11 +++++++ src/core/qgscoordinatetransform.cpp | 22 +++++++++++++ src/core/qgscoordinatetransform.h | 19 +++++++++++ 4 files changed, 85 insertions(+) diff --git a/src/app/qgsappcoordinateoperationhandlers.cpp b/src/app/qgsappcoordinateoperationhandlers.cpp index 8a4c346b2620..e6d6b9b35b73 100644 --- a/src/app/qgsappcoordinateoperationhandlers.cpp +++ b/src/app/qgsappcoordinateoperationhandlers.cpp @@ -56,10 +56,19 @@ QgsAppMissingGridHandler::QgsAppMissingGridHandler( QObject *parent ) emit missingGridUsedByContextHandler( sourceCrs, destinationCrs, desired ); } ); + QgsCoordinateTransform::setFallbackOperationOccurredHandler( [ = ]( const QgsCoordinateReferenceSystem & sourceCrs, + const QgsCoordinateReferenceSystem & destinationCrs, + const QgsDatumTransform::TransformDetails & desired, + const QgsDatumTransform::TransformDetails & used ) + { + emit fallbackOperationOccurred( sourceCrs, destinationCrs, desired, used ); + } ); + connect( this, &QgsAppMissingGridHandler::missingRequiredGrid, this, &QgsAppMissingGridHandler::onMissingRequiredGrid, Qt::QueuedConnection ); connect( this, &QgsAppMissingGridHandler::missingPreferredGrid, this, &QgsAppMissingGridHandler::onMissingPreferredGrid, Qt::QueuedConnection ); connect( this, &QgsAppMissingGridHandler::coordinateOperationCreationError, this, &QgsAppMissingGridHandler::onCoordinateOperationCreationError, Qt::QueuedConnection ); connect( this, &QgsAppMissingGridHandler::missingGridUsedByContextHandler, this, &QgsAppMissingGridHandler::onMissingGridUsedByContextHandler, Qt::QueuedConnection ); + connect( this, &QgsAppMissingGridHandler::fallbackOperationOccurred, this, &QgsAppMissingGridHandler::onFallbackOperationOccurred, Qt::QueuedConnection ); connect( QgsProject::instance(), &QgsProject::cleared, this, [ = ] { mAlreadyWarnedPairsForProject.clear(); } ); @@ -265,6 +274,30 @@ void QgsAppMissingGridHandler::onMissingGridUsedByContextHandler( const QgsCoord bar->pushWidget( widget, Qgis::Critical, 0 ); } +void QgsAppMissingGridHandler::onFallbackOperationOccurred( const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, const QgsDatumTransform::TransformDetails &desired, const QgsDatumTransform::TransformDetails &used ) +{ + // if ( !shouldWarnAboutPairForCurrentProject( sourceCrs, destinationCrs ) ) + // return; + + const QString shortMessage = tr( "Used a fallback transform from %1 to %2" ).arg( sourceCrs.userFriendlyIdentifier( QgsCoordinateReferenceSystem::ShortString ), destinationCrs.userFriendlyIdentifier( QgsCoordinateReferenceSystem::ShortString ) ); + const QString longMessage = tr( "

An alternative transform was used when transforming coordinates between %1 and %2.

I wanted to use %3

" ).arg( sourceCrs.userFriendlyIdentifier(), destinationCrs.userFriendlyIdentifier(), desired.proj ); + + QgsMessageBar *bar = QgisApp::instance()->messageBar(); + QgsMessageBarItem *widget = bar->createMessage( QString(), shortMessage ); + QPushButton *detailsButton = new QPushButton( tr( "Details" ) ); + connect( detailsButton, &QPushButton::clicked, this, [longMessage] + { + // dlg has deleted on close + QgsMessageOutput * dlg( QgsMessageOutput::createMessageOutput() ); + dlg->setTitle( tr( "Fallback Transform Occurred" ) ); + dlg->setMessage( longMessage, QgsMessageOutput::MessageHtml ); + dlg->showMessage(); + } ); + + widget->layout()->addWidget( detailsButton ); + bar->pushWidget( widget, Qgis::Critical, 0 ); +} + bool QgsAppMissingGridHandler::shouldWarnAboutPair( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &dest ) { if ( mAlreadyWarnedPairs.contains( qMakePair( source, dest ) ) || mAlreadyWarnedPairs.contains( qMakePair( dest, source ) ) ) diff --git a/src/app/qgsappcoordinateoperationhandlers.h b/src/app/qgsappcoordinateoperationhandlers.h index 083e7e353446..1a0299580bc7 100644 --- a/src/app/qgsappcoordinateoperationhandlers.h +++ b/src/app/qgsappcoordinateoperationhandlers.h @@ -49,6 +49,11 @@ class QgsAppMissingGridHandler : public QObject const QgsCoordinateReferenceSystem &destinationCrs, const QgsDatumTransform::TransformDetails &desired ); + void fallbackOperationOccurred( const QgsCoordinateReferenceSystem &sourceCrs, + const QgsCoordinateReferenceSystem &destinationCrs, + const QgsDatumTransform::TransformDetails &desired, + const QgsDatumTransform::TransformDetails &used ); + private slots: void onMissingRequiredGrid( const QgsCoordinateReferenceSystem &sourceCrs, @@ -67,6 +72,12 @@ class QgsAppMissingGridHandler : public QObject void onMissingGridUsedByContextHandler( const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, const QgsDatumTransform::TransformDetails &desired ); + + void onFallbackOperationOccurred( const QgsCoordinateReferenceSystem &sourceCrs, + const QgsCoordinateReferenceSystem &destinationCrs, + const QgsDatumTransform::TransformDetails &desired, + const QgsDatumTransform::TransformDetails &used ); + private: bool shouldWarnAboutPair( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &dest ); diff --git a/src/core/qgscoordinatetransform.cpp b/src/core/qgscoordinatetransform.cpp index ef047c8a6e24..cccddf37f6c6 100644 --- a/src/core/qgscoordinatetransform.cpp +++ b/src/core/qgscoordinatetransform.cpp @@ -49,6 +49,11 @@ QReadWriteLock QgsCoordinateTransform::sCacheLock; QMultiHash< QPair< QString, QString >, QgsCoordinateTransform > QgsCoordinateTransform::sTransforms; //same auth_id pairs might have different datum transformations bool QgsCoordinateTransform::sDisableCache = false; +std::function< void( const QgsCoordinateReferenceSystem &sourceCrs, + const QgsCoordinateReferenceSystem &destinationCrs, + const QgsDatumTransform::TransformDetails &desiredOperation, + const QgsDatumTransform::TransformDetails &usedOperation )> QgsCoordinateTransform::sFallbackOperationOccurredHandler = nullptr; + QgsCoordinateTransform::QgsCoordinateTransform() { d = new QgsCoordinateTransformPrivate(); @@ -637,12 +642,14 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double * return; } +#if PROJ_VERSION_MAJOR>=6 double *xprev = new double[ numPoints ]; memcpy( xprev, x, sizeof( double ) * numPoints ); double *yprev = new double[ numPoints ]; memcpy( yprev, y, sizeof( double ) * numPoints ); double *zprev = new double[ numPoints ]; memcpy( zprev, z, sizeof( double ) * numPoints ); +#endif #ifdef COORDINATE_TRANSFORM_VERBOSE double xorg = *x; @@ -753,11 +760,21 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double * memcpy( y, yprev, sizeof( double ) * numPoints ); memcpy( z, zprev, sizeof( double ) * numPoints ); } + + if ( sFallbackOperationOccurredHandler ) + { + QgsDatumTransform::TransformDetails desired = instantiatedCoordinateOperationDetails(); + QgsDatumTransform::TransformDetails used = QgsDatumTransform::transformDetailsFromPj( transform ); + sFallbackOperationOccurredHandler( d->mSourceCRS, d->mDestCRS, desired, used ); + } } } delete [] xprev; + xprev = nullptr; delete [] yprev; + yprev = nullptr; delete [] zprev; + zprev = nullptr; #endif if ( projResult != 0 ) { @@ -1091,3 +1108,8 @@ void QgsCoordinateTransform::setCustomMissingGridUsedByContextHandler( const std { QgsCoordinateTransformPrivate::setCustomMissingGridUsedByContextHandler( handler ); } + +void QgsCoordinateTransform::setFallbackOperationOccurredHandler( const std::function &handler ) +{ + sFallbackOperationOccurredHandler = handler; +} diff --git a/src/core/qgscoordinatetransform.h b/src/core/qgscoordinatetransform.h index 4f6880e60bfc..d24f2900bdea 100644 --- a/src/core/qgscoordinatetransform.h +++ b/src/core/qgscoordinatetransform.h @@ -555,6 +555,19 @@ class CORE_EXPORT QgsCoordinateTransform static void setCustomMissingGridUsedByContextHandler( const std::function< void( const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, const QgsDatumTransform::TransformDetails &desiredOperation )> &handler ); + + + /** + * Sets a custom \a handler to use when the desired coordinate operation for use between \a sourceCrs and + * \a destinationCrs failed and an alternative fallback \a usedOperation was utilised instead. + * + * \since QGIS 3.10.3 + */ + static void setFallbackOperationOccurredHandler( const std::function< void( const QgsCoordinateReferenceSystem &sourceCrs, + const QgsCoordinateReferenceSystem &destinationCrs, + const QgsDatumTransform::TransformDetails &desiredOperation, + const QgsDatumTransform::TransformDetails &usedOperation )> &handler ); + #endif #ifndef SIP_RUN @@ -596,6 +609,12 @@ class CORE_EXPORT QgsCoordinateTransform static QMultiHash< QPair< QString, QString >, QgsCoordinateTransform > sTransforms; //same auth_id pairs might have different datum transformations static bool sDisableCache; + + static std::function< void( const QgsCoordinateReferenceSystem &sourceCrs, + const QgsCoordinateReferenceSystem &destinationCrs, + const QgsDatumTransform::TransformDetails &desiredOperation, + const QgsDatumTransform::TransformDetails &usedOperation )> sFallbackOperationOccurredHandler; + }; //! Output stream operator