Skip to content

Commit

Permalink
Merge pull request #59543 from nyalldawson/backport_59484
Browse files Browse the repository at this point in the history
Fix QgsCsException messages (LTR backport)
  • Loading branch information
troopa81 authored Nov 21, 2024
2 parents c43991a + 4e235c2 commit 5299842
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 12 deletions.
4 changes: 4 additions & 0 deletions src/core/proj/qgscoordinatereferencesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1627,7 +1627,11 @@ void QgsCoordinateReferenceSystem::setProjString( const QString &proj4String )
{
#ifdef QGISDEBUG
const int errNo = proj_context_errno( ctx );
#if PROJ_VERSION_MAJOR>=8
QgsDebugError( QStringLiteral( "proj string rejected: %1" ).arg( proj_context_errno_string( ctx, errNo ) ) );
#else
QgsDebugError( QStringLiteral( "proj string rejected: %1" ).arg( proj_errno_string( errNo ) ) );
#endif
#endif
d->mIsValid = false;
}
Expand Down
30 changes: 20 additions & 10 deletions src/core/proj/qgscoordinatetransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,7 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
}

mFallbackOperationOccurred = false;
bool errorOccurredDuringFallbackOperation = false;
if ( actualRes != 0
&& ( d->mAvailableOpCount > 1 || d->mAvailableOpCount == -1 ) // only use fallbacks if more than one operation is possible -- otherwise we've already tried it and it failed
&& ( d->mAllowFallbackTransforms || mBallparkTransformsAreAppropriate ) )
Expand All @@ -842,13 +843,14 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
// So here just check proj_errno() for single point transform
if ( numPoints == 1 )
{
projResult = proj_errno( transform );
// hmm - something very odd here. We can't trust proj_errno( transform ), as that's giving us incorrect error numbers
// (such as "failed to load datum shift file", which is definitely incorrect for a default proj created operation!)
// so we resort to testing values ourselves...
projResult = std::isinf( xprev[0] ) || std::isinf( yprev[0] ) || std::isinf( zprev[0] ) ? 1 : 0;
errorOccurredDuringFallbackOperation = std::isinf( xprev[0] ) || std::isinf( yprev[0] ) || std::isinf( zprev[0] );
}

if ( projResult == 0 )
if ( !errorOccurredDuringFallbackOperation )
{
memcpy( x, xprev.data(), sizeof( double ) * numPoints );
memcpy( y, yprev.data(), sizeof( double ) * numPoints );
Expand All @@ -873,25 +875,33 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
z[pos] = std::numeric_limits<double>::quiet_NaN();
}

if ( projResult != 0 )
if ( projResult != 0 || errorOccurredDuringFallbackOperation )
{
//something bad happened....
QString points;

const QChar delim = numPoints > 1 ? '\n' : ' ';
for ( int i = 0; i < numPoints; ++i )
{
points += QStringLiteral( "(%1, %2)\n" ).arg( x[i], 0, 'f' ).arg( y[i], 0, 'f' );
points += QStringLiteral( "(%1, %2)" ).arg( xprev[i], 0, 'f' ).arg( yprev[i], 0, 'f' ) + delim;
}

const QString dir = ( direction == Qgis::TransformDirection::Forward ) ? QObject::tr( "forward transform" ) : QObject::tr( "inverse transform" );
const QString dir = ( direction == Qgis::TransformDirection::Forward ) ? QObject::tr( "Forward transform" ) : QObject::tr( "Inverse transform" );

const QString msg = QObject::tr( "%1 of\n"
"%2"
"Error: %3" )
#if PROJ_VERSION_MAJOR>=8
PJ_CONTEXT *projContext = QgsProjContext::get();
const QString projError = !errorOccurredDuringFallbackOperation ? QString::fromUtf8( proj_context_errno_string( projContext, projResult ) ) : QObject::tr( "Fallback transform failed" );
#else
const QString projError = !errorOccurredDuringFallbackOperation ? QString::fromUtf8( proj_errno_string( projResult ) ) : QObject::tr( "Fallback transform failed" );
#endif

const QString msg = QObject::tr( "%1 (%2 to %3) of%4%5Error: %6" )
.arg( dir,
( direction == Qgis::TransformDirection::Forward ) ? d->mSourceCRS.authid() : d->mDestCRS.authid(),
( direction == Qgis::TransformDirection::Forward ) ? d->mDestCRS.authid() : d->mSourceCRS.authid(),
QString( delim ),
points,
projResult < 0 ? QString::fromUtf8( proj_errno_string( projResult ) ) : QObject::tr( "Fallback transform failed" ) );

projError );

// don't flood console with thousands of duplicate transform error messages
if ( msg != mLastError )
Expand Down
13 changes: 11 additions & 2 deletions src/core/proj/qgscoordinatetransform_p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,17 @@ ProjData QgsCoordinateTransformPrivate::threadLocalProjData()
{
// huh?
const int errNo = proj_context_errno( context );
if ( errNo && errNo != -61 )
if ( errNo )
{
#if PROJ_VERSION_MAJOR>=8
nonAvailableError = QString( proj_context_errno_string( context, errNo ) );
#else
nonAvailableError = QString( proj_errno_string( errNo ) );
#endif
}
else
{
// in theory should never be hit!
nonAvailableError = QObject::tr( "No coordinate operations are available between these two reference systems" );
}
}
Expand Down Expand Up @@ -463,9 +468,13 @@ ProjData QgsCoordinateTransformPrivate::threadLocalProjData()
{
const int errNo = proj_context_errno( context );
const QStringList projErrors = errorLogger.errors();
if ( errNo && errNo != -61 )
if ( errNo )
{
#if PROJ_VERSION_MAJOR>=8
nonAvailableError = QString( proj_context_errno_string( context, errNo ) );
#else
nonAvailableError = QString( proj_errno_string( errNo ) );
#endif
}
else if ( !projErrors.empty() )
{
Expand Down
19 changes: 19 additions & 0 deletions tests/src/python/test_qgscoordinatetransform.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
import qgis # NOQA

from qgis.core import (
Qgis,
QgsCoordinateReferenceSystem,
QgsCoordinateTransform,
QgsCoordinateTransformContext,
QgsProject,
QgsRectangle,
QgsPointXY,
QgsCsException
)
import unittest
from qgis.testing import start_app, QgisTestCase
Expand Down Expand Up @@ -162,6 +165,22 @@ def testTransformBoundingBoxFullWorldToWebMercator(self):
self.assertAlmostEqual(transformedExtent.xMaximum(), 20037508.343, delta=1e-3)
self.assertAlmostEqual(transformedExtent.yMaximum(), 44927335.427, delta=1e-3)

def test_cs_exception(self):
ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'),
QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance())
point = QgsPointXY(-7603859, -7324441)
with self.assertRaises(QgsCsException) as e:
ct.transform(point)
self.assertEqual(str(e.exception), 'Forward transform (EPSG:4326 to EPSG:3857) of (-7603859.000000, -7324441.000000) Error: Invalid coordinate')

# reverse transform
ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:3857'),
QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance())
point = QgsPointXY(-7603859, -7324441)
with self.assertRaises(QgsCsException) as e:
ct.transform(point, Qgis.TransformDirection.Reverse)
self.assertEqual(str(e.exception), 'Inverse transform (EPSG:4326 to EPSG:3857) of (-7603859.000000, -7324441.000000) Error: Invalid coordinate')


if __name__ == '__main__':
unittest.main()

0 comments on commit 5299842

Please sign in to comment.