Skip to content

Commit

Permalink
Use a custom proj error handler to collect descriptive coordinate
Browse files Browse the repository at this point in the history
operation creation errors, and report these back to users

Because these errors contain useful information for users to debug,
e.g. "Source and target ellipsoid do not belong to the same celestial
body"
  • Loading branch information
nyalldawson committed Jun 11, 2019
1 parent d35197f commit 46f364a
Showing 1 changed file with 41 additions and 1 deletion.
42 changes: 41 additions & 1 deletion src/core/qgscoordinatetransform_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,26 @@ void QgsCoordinateTransformPrivate::calculateTransforms( const QgsCoordinateTran
#endif
}

#if PROJ_VERSION_MAJOR>=6
static void proj_collecting_logger( void *user_data, int /*level*/, const char *message )
{
QStringList *dest = reinterpret_cast< QStringList * >( user_data );
dest->append( QString( message ) );
}

static void proj_logger( void *, int level, const char *message )
{
if ( level == PJ_LOG_ERROR )
{
QgsDebugMsg( QString( message ) );
}
else if ( level == PJ_LOG_DEBUG )
{
QgsDebugMsgLevel( QString( message ), 3 );
}
}
#endif

ProjData QgsCoordinateTransformPrivate::threadLocalProjData()
{
QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
Expand Down Expand Up @@ -303,6 +323,10 @@ ProjData QgsCoordinateTransformPrivate::threadLocalProjData()
locker.changeMode( QgsReadWriteLocker::Write );

#if PROJ_VERSION_MAJOR>=6
// use a temporary proj error collector
QStringList projErrors;
proj_log_func( context, &projErrors, proj_collecting_logger );

QgsProjUtils::proj_pj_unique_ptr transform;
if ( !mProjCoordinateOperation.isEmpty() )
{
Expand Down Expand Up @@ -333,7 +357,10 @@ ProjData QgsCoordinateTransformPrivate::threadLocalProjData()
if ( !transform ) // fallback on default proj pathway
{
if ( !mSourceCRS.projObject() || ! mDestCRS.projObject() )
{
proj_log_func( context, nullptr, nullptr );
return nullptr;
}

PJ_OPERATION_FACTORY_CONTEXT *operationContext = proj_create_operation_factory_context( context, nullptr );

Expand Down Expand Up @@ -481,10 +508,20 @@ ProjData QgsCoordinateTransformPrivate::threadLocalProjData()
{
nonAvailableError = QString( proj_errno_string( errNo ) );
}
else
else if ( !projErrors.empty() )
{
nonAvailableError = projErrors.constLast();
}

if ( nonAvailableError.isEmpty() )
{
nonAvailableError = QObject::tr( "No coordinate operations are available between these two reference systems" );
}
else
{
// strip proj prefixes from error string, so that it's nicer for users
nonAvailableError = nonAvailableError.remove( QStringLiteral( "internal_proj_create_operations: " ) );
}
}

if ( !nonAvailableError.isEmpty() )
Expand All @@ -502,6 +539,9 @@ ProjData QgsCoordinateTransformPrivate::threadLocalProjData()
}
}

// reset logger to terminal output
proj_log_func( context, nullptr, proj_logger );

if ( !transform )
{
// ouch!
Expand Down

0 comments on commit 46f364a

Please sign in to comment.