Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgscoordinatereferencesystem_p.h 3 : : 4 : : -------------------------------- 5 : : begin : 2016 6 : : copyright : (C) 2016 by Nyall Dawson 7 : : email : nyall dot dawson at gmail dot com 8 : : ***************************************************************************/ 9 : : 10 : : /*************************************************************************** 11 : : * * 12 : : * This program is free software; you can redistribute it and/or modify * 13 : : * it under the terms of the GNU General Public License as published by * 14 : : * the Free Software Foundation; either version 2 of the License, or * 15 : : * (at your option) any later version. * 16 : : * * 17 : : ***************************************************************************/ 18 : : #ifndef QGSCOORDINATEREFERENCESYSTEM_PRIVATE_H 19 : : #define QGSCOORDINATEREFERENCESYSTEM_PRIVATE_H 20 : : 21 : : /// @cond PRIVATE 22 : : 23 : : // 24 : : // W A R N I N G 25 : : // ------------- 26 : : // 27 : : // This file is not part of the QGIS API. It exists purely as an 28 : : // implementation detail. This header file may change from version to 29 : : // version without notice, or even be removed. 30 : : // 31 : : 32 : : #include "qgscoordinatereferencesystem.h" 33 : : 34 : : #include <proj.h> 35 : : #include "qgsprojutils.h" 36 : : #include "qgsreadwritelocker.h" 37 : : 38 : : #ifdef DEBUG 39 : : typedef struct OGRSpatialReferenceHS *OGRSpatialReferenceH; 40 : : #else 41 : : typedef void *OGRSpatialReferenceH; 42 : : #endif 43 : : 44 : : class QgsCoordinateReferenceSystemPrivate : public QSharedData 45 : : { 46 : : public: 47 : : 48 : 58 : explicit QgsCoordinateReferenceSystemPrivate() 49 : 58 : { 50 : 58 : } 51 : : 52 : 5 : QgsCoordinateReferenceSystemPrivate( const QgsCoordinateReferenceSystemPrivate &other ) 53 : 5 : : QSharedData( other ) 54 : 5 : , mSrsId( other.mSrsId ) 55 : 5 : , mDescription( other.mDescription ) 56 : 5 : , mProjectionAcronym( other.mProjectionAcronym ) 57 : 5 : , mEllipsoidAcronym( other.mEllipsoidAcronym ) 58 : 5 : , mIsGeographic( other.mIsGeographic ) 59 : 5 : , mMapUnits( other.mMapUnits ) 60 : 5 : , mSRID( other.mSRID ) 61 : 5 : , mAuthId( other.mAuthId ) 62 : 5 : , mIsValid( other.mIsValid ) 63 : 5 : , mPj() 64 : 5 : , mProj4( other.mProj4 ) 65 : 5 : , mWktPreferred( other.mWktPreferred ) 66 : 5 : , mAxisInvertedDirty( other.mAxisInvertedDirty ) 67 : 5 : , mAxisInverted( other.mAxisInverted ) 68 : 5 : , mProjObjects() 69 : 5 : { 70 : 5 : } 71 : : 72 : 57 : ~QgsCoordinateReferenceSystemPrivate() 73 : : { 74 : 57 : QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read ); 75 : 57 : if ( !mProjObjects.empty() || mPj ) 76 : : { 77 : 8 : locker.changeMode( QgsReadWriteLocker::Write ); 78 : 8 : cleanPjObjects(); 79 : 8 : } 80 : 57 : } 81 : : 82 : : //! The internal sqlite3 srs.db primary key for this CRS 83 : 58 : long mSrsId = 0; 84 : : 85 : : //! A textual description of the CRS 86 : : QString mDescription; 87 : : 88 : : //! The official proj4 acronym for the projection family 89 : : QString mProjectionAcronym; 90 : : 91 : : //! The official proj4 acronym for the ellipsoid 92 : : QString mEllipsoidAcronym; 93 : : 94 : : //! Whether this is a geographic or projected coordinate system 95 : 58 : bool mIsGeographic = false; 96 : : 97 : : //! The map units for the CRS 98 : 58 : QgsUnitTypes::DistanceUnit mMapUnits = QgsUnitTypes::DistanceUnknownUnit; 99 : : 100 : : //! If available, the PostGIS spatial_ref_sys identifier for this CRS (defaults to 0) 101 : 58 : long mSRID = 0; 102 : : 103 : : //! If available the authority identifier for this CRS 104 : : QString mAuthId; 105 : : 106 : : //! Whether this CRS is properly defined and valid 107 : 58 : bool mIsValid = false; 108 : : 109 : : // this is the "master" proj object, to be used as a template for new proj objects created on different threads ONLY. 110 : : // Always use threadLocalProjObject() instead of this. 111 : : 112 : : private: 113 : : QgsProjUtils::proj_pj_unique_ptr mPj; 114 : 63 : PJ_CONTEXT *mPjParentContext = nullptr; 115 : : 116 : 19 : void cleanPjObjects() 117 : : { 118 : : 119 : : // During destruction of PJ* objects, the errno is set in the underlying 120 : : // context. Consequently the context attached to the PJ* must still exist ! 121 : : // Which is not necessarily the case currently unfortunately. So 122 : : // create a temporary dummy context, and attach it to the PJ* before destroying 123 : : // it 124 : 19 : PJ_CONTEXT *tmpContext = proj_context_create(); 125 : 28 : for ( auto it = mProjObjects.begin(); it != mProjObjects.end(); ++it ) 126 : : { 127 : 9 : proj_assign_context( it.value(), tmpContext ); 128 : 9 : proj_destroy( it.value() ); 129 : 9 : } 130 : 19 : mProjObjects.clear(); 131 : 19 : if ( mPj ) 132 : : { 133 : 9 : proj_assign_context( mPj.get(), tmpContext ); 134 : 9 : mPj.reset(); 135 : 9 : } 136 : 19 : proj_context_destroy( tmpContext ); 137 : 19 : } 138 : : 139 : : public: 140 : : 141 : 11 : void setPj( QgsProjUtils::proj_pj_unique_ptr obj ) 142 : : { 143 : 11 : QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write ); 144 : 11 : cleanPjObjects(); 145 : : 146 : 11 : mPj = std::move( obj ); 147 : 11 : mPjParentContext = QgsProjContext::get(); 148 : 11 : } 149 : : 150 : 12 : bool hasPj() const 151 : : { 152 : 12 : QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read ); 153 : 12 : return static_cast< bool >( mPj ); 154 : 12 : } 155 : : 156 : : mutable QString mProj4; 157 : : 158 : : mutable QString mWktPreferred; 159 : : 160 : : //! True if presence of an inverted axis needs to be recalculated 161 : 58 : mutable bool mAxisInvertedDirty = false; 162 : : 163 : : //! Whether this is a coordinate system has inverted axis 164 : 58 : mutable bool mAxisInverted = false; 165 : : 166 : : private: 167 : 63 : mutable QReadWriteLock mProjLock{}; 168 : 58 : mutable QMap < PJ_CONTEXT *, PJ * > mProjObjects{}; 169 : : 170 : : public: 171 : : 172 : 18 : PJ *threadLocalProjObject() const 173 : : { 174 : 18 : QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read ); 175 : 18 : if ( !mPj ) 176 : 2 : return nullptr; 177 : : 178 : 16 : PJ_CONTEXT *context = QgsProjContext::get(); 179 : 16 : QMap < PJ_CONTEXT *, PJ * >::const_iterator it = mProjObjects.constFind( context ); 180 : : 181 : 16 : if ( it != mProjObjects.constEnd() ) 182 : : { 183 : 5 : return it.value(); 184 : : } 185 : : 186 : : // proj object doesn't exist yet, so we need to create 187 : 11 : locker.changeMode( QgsReadWriteLocker::Write ); 188 : : 189 : 11 : PJ *res = proj_clone( context, mPj.get() ); 190 : 11 : mProjObjects.insert( context, res ); 191 : 11 : return res; 192 : 18 : } 193 : : 194 : : // Only meant to be called by QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread() 195 : 0 : bool removeObjectsBelongingToCurrentThread( PJ_CONTEXT *pj_context ) 196 : : { 197 : 0 : QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write ); 198 : : 199 : 0 : QMap < PJ_CONTEXT *, PJ * >::iterator it = mProjObjects.find( pj_context ); 200 : 0 : if ( it != mProjObjects.end() ) 201 : : { 202 : 0 : proj_destroy( it.value() ); 203 : 0 : mProjObjects.erase( it ); 204 : 0 : } 205 : : 206 : 0 : if ( mPjParentContext == pj_context ) 207 : : { 208 : 0 : mPj.reset(); 209 : 0 : mPjParentContext = nullptr; 210 : 0 : } 211 : : 212 : 0 : return mProjObjects.isEmpty(); 213 : 0 : } 214 : : 215 : : private: 216 : : QgsCoordinateReferenceSystemPrivate &operator= ( const QgsCoordinateReferenceSystemPrivate & ) = delete; 217 : : 218 : : }; 219 : : 220 : : /// @endcond 221 : : 222 : : #endif //QGSCOORDINATEREFERENCESYSTEM_PRIVATE_H