1 /*************************************************************************** 2 qgsprojutils.h 3 ------------------- 4 begin : March 2019 5 copyright : (C) 2019 by Nyall Dawson 6 email : nyall dot dawson at gmail dot com 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 #ifndef QGSPROJUTILS_H 18 #define QGSPROJUTILS_H 19 20 #include <QtGlobal> 21 22 #include "qgis_core.h" 23 #include "qgis_sip.h" 24 #include "qgsconfig.h" 25 #include "qgsdatumtransform.h" 26 #include <memory> 27 #include <QStringList> 28 29 #if !defined(USE_THREAD_LOCAL) || defined(Q_OS_WIN) 30 #include <QThreadStorage> 31 #endif 32 33 #ifndef SIP_RUN 34 struct PJconsts; 35 typedef struct PJconsts PJ; 36 #endif 37 38 /** 39 * \class QgsProjUtils 40 * \ingroup core 41 * \brief Utility functions for working with the proj library. 42 * \since QGIS 3.8 43 */ 44 class CORE_EXPORT QgsProjUtils 45 { 46 public: 47 48 /** 49 * Returns the proj library major version number. 50 */ 51 static int projVersionMajor(); 52 53 /** 54 * Returns the proj library minor version number. 55 * 56 * \since QGIS 3.20 57 */ 58 static int projVersionMinor(); 59 60 /** 61 * Returns the EPSG registry database version used by the proj library (e.g. "v9.8.6"). 62 * 63 * \see epsgRegistryDate() 64 * \since QGIS 3.20 65 */ 66 static QString epsgRegistryVersion(); 67 68 /** 69 * Returns the EPSG registry database release date used by the proj library. 70 * 71 * \see epsgRegistryVersion() 72 * \since QGIS 3.20 73 */ 74 static QDate epsgRegistryDate(); 75 76 /** 77 * Returns the ESRI projection engine database version used by the proj library (e.g. "ArcMap 10.8.0"). 78 * 79 * \see esriDatabaseDate() 80 * \since QGIS 3.20 81 */ 82 static QString esriDatabaseVersion(); 83 84 /** 85 * Returns the ESRI projection engine database release date used by the proj library. 86 * 87 * \see esriDatabaseVersion() 88 * \since QGIS 3.20 89 */ 90 static QDate esriDatabaseDate(); 91 92 /** 93 * Returns the IGNF database version used by the proj library (e.g. "3.1.0"). 94 * 95 * \see ignfDatabaseDate() 96 * \since QGIS 3.20 97 */ 98 static QString ignfDatabaseVersion(); 99 100 /** 101 * Returns the IGNF database release date used by the proj library. 102 * 103 * \see ignfDatabaseVersion() 104 * \since QGIS 3.20 105 */ 106 static QDate ignfDatabaseDate(); 107 108 /** 109 * Returns the current list of Proj file search paths. 110 * 111 * \note Only available on builds based on Proj >= 6.0. Builds based on 112 * earlier Proj versions will always return an empty list. 113 */ 114 static QStringList searchPaths(); 115 116 #ifndef SIP_RUN 117 118 //! Flags controlling CRS identification behavior 119 enum IdentifyFlag 120 { 121 FlagMatchBoundCrsToUnderlyingSourceCrs = 1 << 0, //!< Allow matching a BoundCRS object to its underlying SourceCRS 122 }; 123 Q_DECLARE_FLAGS( IdentifyFlags, IdentifyFlag ) 124 125 /** 126 * Destroys Proj PJ objects. 127 */ 128 struct ProjPJDeleter 129 { 130 131 /** 132 * Destroys an PJ \a object, using the correct proj calls. 133 */ 134 void CORE_EXPORT operator()( PJ *object ); 135 136 }; 137 138 /** 139 * Scoped Proj PJ object. 140 */ 141 using proj_pj_unique_ptr = std::unique_ptr< PJ, ProjPJDeleter >; 142 143 /** 144 * Returns TRUE if the given proj coordinate system uses angular units. \a projDef must be 145 * a proj string defining a CRS object. 146 */ 147 static bool usesAngularUnit( const QString &projDef ); 148 149 //TODO - remove when proj 6.1 is minimum supported version, and replace with proj_normalize_for_visualization 150 151 /** 152 * Returns TRUE if the given proj coordinate system uses requires y/x coordinate 153 * order instead of x/y. 154 */ 155 static bool axisOrderIsSwapped( const PJ *crs ); 156 157 /** 158 * Returns TRUE if the given proj coordinate system is a dynamic CRS. 159 * 160 * A dynamic CRS relies on a dynamic datum, that is a datum that is not 161 * plate-fixed. 162 * 163 * \since QGIS 3.20 164 */ 165 static bool isDynamic( const PJ *crs ); 166 167 /** 168 * Given a PROJ crs (which may be a compound or bound crs, or some other type), extract a single crs 169 * from it. 170 */ 171 static proj_pj_unique_ptr crsToSingleCrs( const PJ *crs ); 172 173 /** 174 * Given a PROJ \a crs, attempt to retrieve the datum ensemble from it. 175 * 176 * \warning This method requires PROJ 8.0 or later 177 * 178 * \throws QgsNotSupportedException on QGIS builds based on PROJ 7 or earlier. 179 * 180 * \since QGIS 3.20 181 */ 182 static proj_pj_unique_ptr crsToDatumEnsemble( const PJ *crs ); 183 184 /** 185 * Attempts to identify a \a crs, matching it to a known authority and code within 186 * an acceptable level of tolerance. 187 * 188 * Returns TRUE if a matching authority and code was found. 189 */ 190 static bool identifyCrs( const PJ *crs, QString &authName, QString &authCode, IdentifyFlags flags = IdentifyFlags() ); 191 192 /** 193 * Returns TRUE if a coordinate operation (specified via proj string) is available. 194 */ 195 static bool coordinateOperationIsAvailable( const QString &projDef ); 196 197 /** 198 * Returns a list of grids used by the given \a proj string. 199 */ 200 static QList< QgsDatumTransform::GridDetails > gridsUsed( const QString &proj ); 201 202 #if 0 // not possible in current Proj 6 API 203 204 /** 205 * Given a coordinate operation (specified via proj string), returns a list of 206 * any required grids which are not currently available for use. 207 */ 208 static QStringList nonAvailableGrids( const QString &projDef ); 209 #endif 210 #endif 211 }; 212 213 #ifndef SIP_RUN 214 215 #if PROJ_VERSION_MAJOR>=8 216 struct pj_ctx; 217 typedef struct pj_ctx PJ_CONTEXT; 218 #else 219 struct projCtx_t; 220 typedef struct projCtx_t PJ_CONTEXT; 221 #endif 222 223 /** 224 * \class QgsProjContext 225 * \ingroup core 226 * \brief Used to create and store a proj context object, correctly freeing the context upon destruction. 227 * \note Not available in Python bindings 228 * \since QGIS 3.8 229 */ 230 class CORE_EXPORT QgsProjContext 231 { 232 public: 233 234 QgsProjContext(); 235 ~QgsProjContext(); 236 237 /** 238 * Returns a thread local instance of a proj context, safe for use in the current thread. 239 */ 240 static PJ_CONTEXT *get(); 241 242 private: 243 PJ_CONTEXT *mContext = nullptr; 244 245 /** 246 * Thread local proj context storage. A new proj context will be created 247 * for every thread. 248 */ 249 #if defined(USE_THREAD_LOCAL) && !defined(Q_OS_WIN) 250 static thread_local QgsProjContext sProjContext; 251 #else 252 static QThreadStorage< QgsProjContext * > sProjContext; 253 #endif 254 }; 255 256 Q_DECLARE_OPERATORS_FOR_FLAGS( QgsProjUtils::IdentifyFlags ) 257 #endif 258 #endif // QGSPROJUTILS_H 259