Skip to content

Commit 1241b3f

Browse files
committedJun 3, 2019
Always attempt to create the preferred Proj coordinate operation
for transforms, even if grids are not available. And then use custom handlers or message log to warn users that better operations are possible, just not available on their system. Also use similar approach to raise errors when either no operation is possible between two coordinate systems, or only ONE is yet it is not available on the current system (e.g. due to missing grid file) Sponsored by ICSM
1 parent f758bb7 commit 1241b3f

File tree

1 file changed

+130
-1
lines changed

1 file changed

+130
-1
lines changed
 

‎src/core/qgscoordinatetransform_p.cpp

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "qgslogger.h"
2020
#include "qgsapplication.h"
2121
#include "qgsreadwritelocker.h"
22+
#include "qgsmessagelog.h"
2223

2324
#if PROJ_VERSION_MAJOR>=6
2425
#include "qgsprojutils.h"
@@ -315,26 +316,154 @@ ProjData QgsCoordinateTransformPrivate::threadLocalProjData()
315316
if ( !mProjCoordinateOperation.isEmpty() )
316317
transform.reset( proj_create( context, mProjCoordinateOperation.toUtf8().constData() ) );
317318

319+
QString nonAvailableError;
318320
if ( !transform ) // fallback on default proj pathway
319321
{
320322
if ( !mSourceCRS.projObject() || ! mDestCRS.projObject() )
321323
return nullptr;
322324

323325
PJ_OPERATION_FACTORY_CONTEXT *operationContext = proj_create_operation_factory_context( context, nullptr );
324326

327+
// We want to check ALL grids, not just those available for use
328+
proj_operation_factory_context_set_grid_availability_use( context, operationContext, PROJ_GRID_AVAILABILITY_IGNORED );
329+
325330
// See https://lists.osgeo.org/pipermail/proj/2019-May/008604.html
326331
proj_operation_factory_context_set_spatial_criterion( context, operationContext, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION );
327332

328333
if ( PJ_OBJ_LIST *ops = proj_create_operations( context, mSourceCRS.projObject(), mDestCRS.projObject(), operationContext ) )
329334
{
330335
int count = proj_list_get_count( ops );
331-
if ( count > 0 )
336+
if ( count < 1 )
337+
{
338+
// huh?
339+
if ( int errNo = proj_context_errno( context ) )
340+
{
341+
nonAvailableError = QString( proj_errno_string( errNo ) );
342+
}
343+
else
344+
{
345+
nonAvailableError = QObject::tr( "No coordinate operations are available" );
346+
}
347+
}
348+
else if ( count == 1 )
349+
{
350+
// only a single operation available. Can we use it?
332351
transform.reset( proj_list_get( context, ops, 0 ) );
352+
if ( transform )
353+
{
354+
if ( !proj_coordoperation_is_instantiable( context, transform.get() ) )
355+
{
356+
// uh oh :( something is missing! find what it is
357+
for ( int j = 0; j < proj_coordoperation_get_grid_used_count( context, transform.get() ); ++j )
358+
{
359+
const char *shortName = nullptr;
360+
const char *fullName = nullptr;
361+
const char *packageName = nullptr;
362+
const char *url = nullptr;
363+
int directDownload = 0;
364+
int openLicense = 0;
365+
int isAvailable = 0;
366+
proj_coordoperation_get_grid_used( context, transform.get(), j, &shortName, &fullName, &packageName, &url, &directDownload, &openLicense, &isAvailable );
367+
if ( !isAvailable )
368+
{
369+
// found it!
370+
if ( sMissingRequiredGridHandler )
371+
{
372+
QgsDatumTransform::GridDetails gridDetails;
373+
gridDetails.shortName = QString( shortName );
374+
gridDetails.fullName = QString( fullName );
375+
gridDetails.packageName = QString( packageName );
376+
gridDetails.url = QString( url );
377+
gridDetails.directDownload = directDownload;
378+
gridDetails.openLicense = openLicense;
379+
gridDetails.isAvailable = isAvailable;
380+
sMissingRequiredGridHandler( mSourceCRS, mDestCRS, gridDetails );
381+
}
382+
else
383+
{
384+
const QString err = QObject::tr( "Cannot create transform between %1 and %2, missing required grid %3" ).arg( mSourceCRS.authid() )
385+
.arg( mDestCRS.authid() )
386+
.arg( shortName );
387+
QgsMessageLog::logMessage( err, QString(), Qgis::Critical );
388+
}
389+
break;
390+
}
391+
}
392+
}
393+
}
394+
}
395+
else
396+
{
397+
// multiple operations available. Can we use the best one?
398+
QgsDatumTransform::TransformDetails preferred;
399+
bool missingPreferred = false;
400+
for ( int i = 0; i < count; ++ i )
401+
{
402+
transform.reset( proj_list_get( context, ops, i ) );
403+
const bool isInstantiable = transform && proj_coordoperation_is_instantiable( context, transform.get() );
404+
if ( i == 0 && transform && !isInstantiable )
405+
{
406+
// uh oh :( something is missing blocking us from the preferred operation!
407+
missingPreferred = true;
408+
preferred = QgsDatumTransform::transformDetailsFromPj( transform.get() );
409+
}
410+
if ( transform && isInstantiable )
411+
{
412+
// found one
413+
break;
414+
}
415+
transform.reset();
416+
}
417+
418+
if ( transform && missingPreferred )
419+
{
420+
// found a transform, but it's not the preferred
421+
QgsDatumTransform::TransformDetails available = QgsDatumTransform::transformDetailsFromPj( transform.get() );
422+
if ( sMissingPreferredGridHandler )
423+
{
424+
sMissingPreferredGridHandler( mSourceCRS, mDestCRS, preferred, available );
425+
}
426+
else
427+
{
428+
const QString err = QObject::tr( "Using non-preferred coordinate operation between %1 and %2. Using %3, preferred %4." ).arg( mSourceCRS.authid() )
429+
.arg( mDestCRS.authid() )
430+
.arg( available.proj, preferred.proj );
431+
QgsMessageLog::logMessage( err, QString(), Qgis::Critical );
432+
}
433+
}
434+
}
333435
proj_list_destroy( ops );
334436
}
335437
proj_operation_factory_context_destroy( operationContext );
336438
}
337439

440+
if ( !transform && nonAvailableError.isEmpty() )
441+
{
442+
if ( int errNo = proj_context_errno( context ) )
443+
{
444+
nonAvailableError = QString( proj_errno_string( errNo ) );
445+
}
446+
else
447+
{
448+
nonAvailableError = QObject::tr( "No coordinate operations are available" );
449+
}
450+
}
451+
452+
if ( !nonAvailableError.isEmpty() )
453+
{
454+
if ( sCoordinateOperationCreationErrorHandler )
455+
{
456+
sCoordinateOperationCreationErrorHandler( mSourceCRS, mDestCRS, nonAvailableError );
457+
}
458+
else
459+
{
460+
const QString err = QObject::tr( "Cannot create transform between %1 and %2: %3" ).arg( mSourceCRS.authid() )
461+
.arg( mDestCRS.authid() )
462+
.arg( nonAvailableError );
463+
QgsMessageLog::logMessage( err, QString(), Qgis::Critical );
464+
}
465+
}
466+
338467
if ( !transform )
339468
{
340469
// ouch!

0 commit comments

Comments
 (0)
Please sign in to comment.