23 #include <QRegularExpression>    25 #if PROJ_VERSION_MAJOR>=6    32 #if defined(USE_THREAD_LOCAL) && !defined(Q_OS_WIN)    35 QThreadStorage< QgsProjContext * > QgsProjContext::sProjContext;
    40 #if PROJ_VERSION_MAJOR>=6    41   mContext = proj_context_create();
    43   mContext = pj_ctx_alloc();
    49 #if PROJ_VERSION_MAJOR>=6    52   QgsCoordinateTransform::removeFromCacheObjectsBelongingToCurrentThread( mContext );
    53   QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread( mContext );
    54   proj_context_destroy( mContext );
    56   pj_ctx_free( mContext );
    62 #if defined(USE_THREAD_LOCAL) && !defined(Q_OS_WIN)    63   return sProjContext.mContext;
    66   if ( sProjContext.hasLocalData() )
    68     pContext = sProjContext.localData()->mContext;
    73     pContext = sProjContext.localData()->mContext;
    79 #if PROJ_VERSION_MAJOR>=6    80 void QgsProjUtils::ProjPJDeleter::operator()( PJ *
object )
    82   proj_destroy( 
object );
    85 bool QgsProjUtils::usesAngularUnit( 
const QString &projDef )
    87   const QString crsDef = QStringLiteral( 
"%1 +type=crs" ).arg( projDef );
    89   QgsProjUtils::proj_pj_unique_ptr projSingleOperation( proj_create( context, crsDef.toUtf8().constData() ) );
    90   if ( !projSingleOperation )
    93   QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( context, projSingleOperation.get() ) );
    94   if ( !coordinateSystem )
    97   const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
   100     const char *outUnitAuthName = 
nullptr;
   101     const char *outUnitAuthCode = 
nullptr;
   103     proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
   112     if ( outUnitAuthName && outUnitAuthCode )
   114       const char *unitCategory = 
nullptr;
   115       if ( proj_uom_get_info_from_database( context, outUnitAuthName, outUnitAuthCode, 
nullptr, 
nullptr, &unitCategory ) )
   117         return QString( unitCategory ).compare( QLatin1String( 
"angular" ), Qt::CaseInsensitive ) == 0;
   124 bool QgsProjUtils::axisOrderIsSwapped( 
const PJ *
crs )
   131   QgsProjUtils::proj_pj_unique_ptr pjCs( proj_crs_get_coordinate_system( context, crs ) );
   135   const int axisCount = proj_cs_get_axis_count( context, pjCs.get() );
   138     const char *outDirection = 
nullptr;
   141     proj_cs_get_axis_info( context, pjCs.get(), 0,
   150     return QString( outDirection ).compare( QLatin1String( 
"north" ), Qt::CaseInsensitive ) == 0;
   156 QgsProjUtils::proj_pj_unique_ptr QgsProjUtils::crsToSingleCrs( 
const PJ *
crs )
   162   switch ( proj_get_type( crs ) )
   164     case PJ_TYPE_BOUND_CRS:
   165       return QgsProjUtils::proj_pj_unique_ptr( proj_get_source_crs( context, crs ) );
   167     case PJ_TYPE_COMPOUND_CRS:
   170       QgsProjUtils::proj_pj_unique_ptr res( proj_crs_get_sub_crs( context, crs, i ) );
   171       while ( res && ( proj_get_type( res.get() ) == PJ_TYPE_VERTICAL_CRS || proj_get_type( res.get() ) == PJ_TYPE_TEMPORAL_CRS ) )
   174         res.reset( proj_crs_get_sub_crs( context, crs, i ) );
   182       return QgsProjUtils::proj_pj_unique_ptr( proj_clone( context, crs ) );
   185 #ifndef _MSC_VER  // unreachable   190 bool QgsProjUtils::identifyCrs( 
const PJ *
crs, QString &authName, QString &authCode, IdentifyFlags flags )
   198   int *confidence = 
nullptr;
   201     const int count = proj_list_get_count( crsList );
   202     int bestConfidence = 0;
   203     QgsProjUtils::proj_pj_unique_ptr matchedCrs;
   204     for ( 
int i = 0; i < count; ++i )
   206       if ( confidence[i] >= bestConfidence )
   208         QgsProjUtils::proj_pj_unique_ptr candidateCrs( proj_list_get( 
QgsProjContext::get(), crsList, i ) );
   209         switch ( proj_get_type( candidateCrs.get() ) )
   211           case PJ_TYPE_BOUND_CRS:
   214             if ( flags & FlagMatchBoundCrsToUnderlyingSourceCrs )
   223         candidateCrs = QgsProjUtils::crsToSingleCrs( candidateCrs.get() );
   224         const QString authName( proj_get_id_auth_name( candidateCrs.get(), 0 ) );
   226         if ( confidence[i] > bestConfidence || ( confidence[i] == bestConfidence && authName == QLatin1String( 
"EPSG" ) ) )
   228           bestConfidence = confidence[i];
   229           matchedCrs = std::move( candidateCrs );
   233     proj_list_destroy( crsList );
   234     proj_int_list_destroy( confidence );
   235     if ( matchedCrs && bestConfidence >= 70 )
   237       authName = QString( proj_get_id_auth_name( matchedCrs.get(), 0 ) );
   238       authCode = QString( proj_get_id_code( matchedCrs.get(), 0 ) );
   241   return !authName.isEmpty() && !authCode.isEmpty();
   244 bool QgsProjUtils::coordinateOperationIsAvailable( 
const QString &projDef )
   246   if ( projDef.isEmpty() )
   250   QgsProjUtils::proj_pj_unique_ptr coordinateOperation( proj_create( context, projDef.toUtf8().constData() ) );
   251   if ( !coordinateOperation )
   254   return static_cast< bool >( proj_coordoperation_is_instantiable( context, coordinateOperation.get() ) );
   257 QList<QgsDatumTransform::GridDetails> QgsProjUtils::gridsUsed( 
const QString &proj )
   259   static QRegularExpression sRegex( QStringLiteral( 
"\\+(?:nad)?grids=(.*?)\\s" ) );
   261   QList< QgsDatumTransform::GridDetails > grids;
   262   QRegularExpressionMatchIterator matches = sRegex.globalMatch( proj );
   263   while ( matches.hasNext() )
   265     const QRegularExpressionMatch match = matches.next();
   266     const QString gridName = match.captured( 1 );
   269     const char *fullName = 
nullptr;
   270     const char *packageName = 
nullptr;
   271     const char *url = 
nullptr;
   272     int directDownload = 0;
   275     proj_grid_get_info_from_database( 
QgsProjContext::get(), gridName.toUtf8().constData(), &fullName, &packageName, &url, &directDownload, &openLicense, &available );
   276     grid.
fullName = QString( fullName );
   278     grid.
url = QString( url );
   282     grids.append( grid );
   288 QStringList QgsProjUtils::nonAvailableGrids( 
const QString &projDef )
   290   if ( projDef.isEmpty() )
   291     return QStringList();
   294   QgsProjUtils::proj_pj_unique_ptr op( proj_create( context, projDef.toUtf8().constData() ) ); < ---- - 
this always fails 
if grids are missing
   296       return QStringList();
   299   for ( 
int j = 0; j < proj_coordoperation_get_grid_used_count( context, op.get() ); ++j )
   301     const char *shortName = 
nullptr;
   303     proj_coordoperation_get_grid_used( context, op.get(), j, &shortName, 
nullptr, 
nullptr, 
nullptr, 
nullptr, 
nullptr, &isAvailable );
   305       res << QString( shortName );
   315 #if PROJ_VERSION_MAJOR>=6   316   const QString path( proj_info().searchpath );
   319   paths = path.split( 
';' );
   321   paths = path.split( 
':' );
   324   QSet<QString> existing;
   327   res.reserve( paths.count() );
   328   for ( 
const QString &p : qgis::as_const( paths ) )
   330     if ( existing.contains( p ) )
   333     existing.insert( p );
   338   return QStringList();
 
const QgsCoordinateReferenceSystem & crs
 
Used to create and store a proj context object, correctly freeing the context upon destruction...
 
static QStringList searchPaths()
Returns the current list of Proj file search paths. 
 
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.