21 #include <QRegularExpression> 23 #if PROJ_VERSION_MAJOR>=6 30 #if defined(USE_THREAD_LOCAL) && !defined(Q_OS_WIN) 33 QThreadStorage< QgsProjContext * > QgsProjContext::sProjContext;
38 #if PROJ_VERSION_MAJOR>=6 39 mContext = proj_context_create();
41 mContext = pj_ctx_alloc();
47 #if PROJ_VERSION_MAJOR>=6 48 proj_context_destroy( mContext );
50 pj_ctx_free( mContext );
56 #if defined(USE_THREAD_LOCAL) && !defined(Q_OS_WIN) 57 return sProjContext.mContext;
60 if ( sProjContext.hasLocalData() )
62 pContext = sProjContext.localData()->mContext;
67 pContext = sProjContext.localData()->mContext;
73 #if PROJ_VERSION_MAJOR>=6 74 void QgsProjUtils::ProjPJDeleter::operator()( PJ *
object )
76 proj_destroy(
object );
79 bool QgsProjUtils::usesAngularUnit(
const QString &projDef )
81 const QString crsDef = QStringLiteral(
"%1 +type=crs" ).arg( projDef );
83 QgsProjUtils::proj_pj_unique_ptr projSingleOperation( proj_create( context, crsDef.toUtf8().constData() ) );
84 if ( !projSingleOperation )
87 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( context, projSingleOperation.get() ) );
88 if ( !coordinateSystem )
91 const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
94 const char *outUnitAuthName =
nullptr;
95 const char *outUnitAuthCode =
nullptr;
97 proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
106 if ( outUnitAuthName && outUnitAuthCode )
108 const char *unitCategory =
nullptr;
109 if ( proj_uom_get_info_from_database( context, outUnitAuthName, outUnitAuthCode,
nullptr,
nullptr, &unitCategory ) )
111 return QString( unitCategory ).compare( QLatin1String(
"angular" ), Qt::CaseInsensitive ) == 0;
118 bool QgsProjUtils::axisOrderIsSwapped(
const PJ *
crs )
125 QgsProjUtils::proj_pj_unique_ptr pjCs( proj_crs_get_coordinate_system( context, crs ) );
129 const int axisCount = proj_cs_get_axis_count( context, pjCs.get() );
132 const char *outDirection =
nullptr;
135 proj_cs_get_axis_info( context, pjCs.get(), 0,
144 return QString( outDirection ).compare( QLatin1String(
"north" ), Qt::CaseInsensitive ) == 0;
150 QgsProjUtils::proj_pj_unique_ptr QgsProjUtils::crsToSingleCrs(
const PJ *
crs )
156 switch ( proj_get_type( crs ) )
158 case PJ_TYPE_BOUND_CRS:
159 return QgsProjUtils::proj_pj_unique_ptr( proj_get_source_crs( context, crs ) );
161 case PJ_TYPE_COMPOUND_CRS:
164 QgsProjUtils::proj_pj_unique_ptr res( proj_crs_get_sub_crs( context, crs, i ) );
165 while ( res && ( proj_get_type( res.get() ) == PJ_TYPE_VERTICAL_CRS || proj_get_type( res.get() ) == PJ_TYPE_TEMPORAL_CRS ) )
168 res.reset( proj_crs_get_sub_crs( context, crs, i ) );
176 return QgsProjUtils::proj_pj_unique_ptr( proj_clone( context, crs ) );
182 bool QgsProjUtils::coordinateOperationIsAvailable(
const QString &projDef )
184 if ( projDef.isEmpty() )
188 QgsProjUtils::proj_pj_unique_ptr coordinateOperation( proj_create( context, projDef.toUtf8().constData() ) );
189 if ( !coordinateOperation )
192 return static_cast< bool >( proj_coordoperation_is_instantiable( context, coordinateOperation.get() ) );
195 QList<QgsDatumTransform::GridDetails> QgsProjUtils::gridsUsed(
const QString &proj )
197 static QRegularExpression sRegex( QStringLiteral(
"\\+(?:nad)?grids=(.*?)\\s" ) );
199 QList< QgsDatumTransform::GridDetails > grids;
200 QRegularExpressionMatchIterator matches = sRegex.globalMatch( proj );
201 while ( matches.hasNext() )
203 const QRegularExpressionMatch match = matches.next();
204 const QString gridName = match.captured( 1 );
207 #if PROJ_VERSION_MAJOR >= 6 208 #if PROJ_VERSION_MINOR >= 2 209 const char *fullName =
nullptr;
210 const char *packageName =
nullptr;
211 const char *url =
nullptr;
212 int directDownload = 0;
215 proj_grid_get_info_from_database(
QgsProjContext::get(), gridName.toUtf8().constData(), &fullName, &packageName, &url, &directDownload, &openLicense, &available );
216 grid.
fullName = QString( fullName );
218 grid.
url = QString( url );
224 grids.append( grid );
230 QStringList QgsProjUtils::nonAvailableGrids(
const QString &projDef )
232 if ( projDef.isEmpty() )
233 return QStringList();
236 QgsProjUtils::proj_pj_unique_ptr op( proj_create( context, projDef.toUtf8().constData() ) ); < ---- -
this always fails
if grids are missing
238 return QStringList();
241 for (
int j = 0; j < proj_coordoperation_get_grid_used_count( context, op.get() ); ++j )
243 const char *shortName =
nullptr;
245 proj_coordoperation_get_grid_used( context, op.get(), j, &shortName,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr, &isAvailable );
247 res << QString( shortName );
257 #if PROJ_VERSION_MAJOR >= 6 258 const QString path( proj_info().searchpath );
261 #if 1 // -- see https://github.com/OSGeo/proj.4/pull/1497 262 paths = path.split(
';' );
264 paths = path.split(
':' );
267 QSet<QString> existing;
270 res.reserve( paths.count() );
271 for (
const QString &p : qgis::as_const( paths ) )
273 if ( existing.contains( p ) )
276 existing.insert( p );
281 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.