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 proj_context_destroy( mContext );
55 pj_ctx_free( mContext );
61 #if defined(USE_THREAD_LOCAL) && !defined(Q_OS_WIN) 62 return sProjContext.mContext;
65 if ( sProjContext.hasLocalData() )
67 pContext = sProjContext.localData()->mContext;
72 pContext = sProjContext.localData()->mContext;
78 #if PROJ_VERSION_MAJOR>=6 79 void QgsProjUtils::ProjPJDeleter::operator()( PJ *
object )
81 proj_destroy(
object );
84 bool QgsProjUtils::usesAngularUnit(
const QString &projDef )
86 const QString crsDef = QStringLiteral(
"%1 +type=crs" ).arg( projDef );
88 QgsProjUtils::proj_pj_unique_ptr projSingleOperation( proj_create( context, crsDef.toUtf8().constData() ) );
89 if ( !projSingleOperation )
92 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( context, projSingleOperation.get() ) );
93 if ( !coordinateSystem )
96 const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
99 const char *outUnitAuthName =
nullptr;
100 const char *outUnitAuthCode =
nullptr;
102 proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
111 if ( outUnitAuthName && outUnitAuthCode )
113 const char *unitCategory =
nullptr;
114 if ( proj_uom_get_info_from_database( context, outUnitAuthName, outUnitAuthCode,
nullptr,
nullptr, &unitCategory ) )
116 return QString( unitCategory ).compare( QLatin1String(
"angular" ), Qt::CaseInsensitive ) == 0;
123 bool QgsProjUtils::axisOrderIsSwapped(
const PJ *
crs )
130 QgsProjUtils::proj_pj_unique_ptr pjCs( proj_crs_get_coordinate_system( context, crs ) );
134 const int axisCount = proj_cs_get_axis_count( context, pjCs.get() );
137 const char *outDirection =
nullptr;
140 proj_cs_get_axis_info( context, pjCs.get(), 0,
149 return QString( outDirection ).compare( QLatin1String(
"north" ), Qt::CaseInsensitive ) == 0;
155 QgsProjUtils::proj_pj_unique_ptr QgsProjUtils::crsToSingleCrs(
const PJ *
crs )
161 switch ( proj_get_type( crs ) )
163 case PJ_TYPE_BOUND_CRS:
164 return QgsProjUtils::proj_pj_unique_ptr( proj_get_source_crs( context, crs ) );
166 case PJ_TYPE_COMPOUND_CRS:
169 QgsProjUtils::proj_pj_unique_ptr res( proj_crs_get_sub_crs( context, crs, i ) );
170 while ( res && ( proj_get_type( res.get() ) == PJ_TYPE_VERTICAL_CRS || proj_get_type( res.get() ) == PJ_TYPE_TEMPORAL_CRS ) )
173 res.reset( proj_crs_get_sub_crs( context, crs, i ) );
181 return QgsProjUtils::proj_pj_unique_ptr( proj_clone( context, crs ) );
187 bool QgsProjUtils::coordinateOperationIsAvailable(
const QString &projDef )
189 if ( projDef.isEmpty() )
193 QgsProjUtils::proj_pj_unique_ptr coordinateOperation( proj_create( context, projDef.toUtf8().constData() ) );
194 if ( !coordinateOperation )
197 return static_cast< bool >( proj_coordoperation_is_instantiable( context, coordinateOperation.get() ) );
200 QList<QgsDatumTransform::GridDetails> QgsProjUtils::gridsUsed(
const QString &proj )
202 static QRegularExpression sRegex( QStringLiteral(
"\\+(?:nad)?grids=(.*?)\\s" ) );
204 QList< QgsDatumTransform::GridDetails > grids;
205 QRegularExpressionMatchIterator matches = sRegex.globalMatch( proj );
206 while ( matches.hasNext() )
208 const QRegularExpressionMatch match = matches.next();
209 const QString gridName = match.captured( 1 );
212 #if PROJ_VERSION_MAJOR>6 || (PROJ_VERSION_MAJOR==6 && PROJ_VERSION_MINOR>=2) 213 const char *fullName =
nullptr;
214 const char *packageName =
nullptr;
215 const char *url =
nullptr;
216 int directDownload = 0;
219 proj_grid_get_info_from_database(
QgsProjContext::get(), gridName.toUtf8().constData(), &fullName, &packageName, &url, &directDownload, &openLicense, &available );
220 grid.
fullName = QString( fullName );
222 grid.
url = QString( url );
227 grids.append( grid );
233 QStringList QgsProjUtils::nonAvailableGrids(
const QString &projDef )
235 if ( projDef.isEmpty() )
236 return QStringList();
239 QgsProjUtils::proj_pj_unique_ptr op( proj_create( context, projDef.toUtf8().constData() ) ); < ---- -
this always fails
if grids are missing
241 return QStringList();
244 for (
int j = 0; j < proj_coordoperation_get_grid_used_count( context, op.get() ); ++j )
246 const char *shortName =
nullptr;
248 proj_coordoperation_get_grid_used( context, op.get(), j, &shortName,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr, &isAvailable );
250 res << QString( shortName );
260 #if PROJ_VERSION_MAJOR>=6 261 const QString path( proj_info().searchpath );
263 #if PROJ_VERSION_MINOR==1 && PROJ_VERSION_PATCH==0 265 paths = path.split(
';' );
268 paths = path.split(
';' );
270 paths = path.split(
':' );
274 QSet<QString> existing;
277 res.reserve( paths.count() );
278 for (
const QString &p : qgis::as_const( paths ) )
280 if ( existing.contains( p ) )
283 existing.insert( p );
288 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.