QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgscoordinatereferencesystem_p.h
Go to the documentation of this file.
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 
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 
33 
34 #if PROJ_VERSION_MAJOR>=6
35 #include <proj.h>
36 #include "qgsprojutils.h"
37 #include "qgsreadwritelocker.h"
38 #else
39 #include <ogr_srs_api.h>
40 #endif
41 
42 #ifdef DEBUG
43 typedef struct OGRSpatialReferenceHS *OGRSpatialReferenceH;
44 #else
45 typedef void *OGRSpatialReferenceH;
46 #endif
47 
48 class QgsCoordinateReferenceSystemPrivate : public QSharedData
49 {
50  public:
51 
52  explicit QgsCoordinateReferenceSystemPrivate()
53 #if PROJ_VERSION_MAJOR<6
54  : mCRS( OSRNewSpatialReference( nullptr ) )
55 #endif
56  {
57  }
58 
59  QgsCoordinateReferenceSystemPrivate( const QgsCoordinateReferenceSystemPrivate &other )
60  : QSharedData( other )
61  , mSrsId( other.mSrsId )
62  , mDescription( other.mDescription )
63  , mProjectionAcronym( other.mProjectionAcronym )
64  , mEllipsoidAcronym( other.mEllipsoidAcronym )
65  , mIsGeographic( other.mIsGeographic )
66  , mMapUnits( other.mMapUnits )
67  , mSRID( other.mSRID )
68  , mAuthId( other.mAuthId )
69  , mIsValid( other.mIsValid )
70 #if PROJ_VERSION_MAJOR >= 6
71  , mPj()
72 #else
73  , mCRS( nullptr )
74 #endif
75  , mProj4( other.mProj4 )
76  , mWktPreferred( other.mWktPreferred )
77  , mAxisInvertedDirty( other.mAxisInvertedDirty )
78  , mAxisInverted( other.mAxisInverted )
79 #if PROJ_VERSION_MAJOR >= 6
80  , mProjObjects()
81 #endif
82  {
83 #if PROJ_VERSION_MAJOR<6
84  if ( mIsValid )
85  {
86  mCRS = OSRClone( other.mCRS );
87  }
88  else
89  {
90  mCRS = OSRNewSpatialReference( nullptr );
91  }
92 #endif
93  }
94 
95  ~QgsCoordinateReferenceSystemPrivate()
96  {
97 #if PROJ_VERSION_MAJOR>=6
98  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
99  if ( !mProjObjects.empty() || mPj )
100  {
101  locker.changeMode( QgsReadWriteLocker::Write );
102  cleanPjObjects();
103  }
104 #else
105  OSRDestroySpatialReference( mCRS );
106 #endif
107  }
108 
110  long mSrsId = 0;
111 
113  QString mDescription;
114 
116  QString mProjectionAcronym;
117 
119  QString mEllipsoidAcronym;
120 
122  bool mIsGeographic = false;
123 
126 
128  long mSRID = 0;
129 
131  QString mAuthId;
132 
134  bool mIsValid = false;
135 
136 #if PROJ_VERSION_MAJOR>=6
137 
138  // this is the "master" proj object, to be used as a template for new proj objects created on different threads ONLY.
139  // Always use threadLocalProjObject() instead of this.
140 
141  private:
142  QgsProjUtils::proj_pj_unique_ptr mPj;
143  PJ_CONTEXT *mPjParentContext = nullptr;
144 
145  void cleanPjObjects()
146  {
147 
148  // During destruction of PJ* objects, the errno is set in the underlying
149  // context. Consequently the context attached to the PJ* must still exist !
150  // Which is not necessarily the case currently unfortunately. So
151  // create a temporary dummy context, and attach it to the PJ* before destroying
152  // it
153  PJ_CONTEXT *tmpContext = proj_context_create();
154  for ( auto it = mProjObjects.begin(); it != mProjObjects.end(); ++it )
155  {
156  proj_assign_context( it.value(), tmpContext );
157  proj_destroy( it.value() );
158  }
159  mProjObjects.clear();
160  if ( mPj )
161  {
162  proj_assign_context( mPj.get(), tmpContext );
163  mPj.reset();
164  }
165  proj_context_destroy( tmpContext );
166  }
167 
168  public:
169 
170  void setPj( QgsProjUtils::proj_pj_unique_ptr obj )
171  {
172  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write );
173  cleanPjObjects();
174 
175  mPj = std::move( obj );
176  mPjParentContext = QgsProjContext::get();
177  }
178 
179  bool hasPj() const
180  {
181  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
182  return static_cast< bool >( mPj );
183  }
184 
185 #else
186  OGRSpatialReferenceH mCRS = nullptr;
187 #endif
188 
189  mutable QString mProj4;
190 
191  mutable QString mWktPreferred;
192 
194  mutable bool mAxisInvertedDirty = false;
195 
197  mutable bool mAxisInverted = false;
198 
199 #if PROJ_VERSION_MAJOR>=6
200  private:
201  mutable QReadWriteLock mProjLock{};
202  mutable QMap < PJ_CONTEXT *, PJ * > mProjObjects{};
203 
204  public:
205 
206  PJ *threadLocalProjObject() const
207  {
208  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
209  if ( !mPj )
210  return nullptr;
211 
212  PJ_CONTEXT *context = QgsProjContext::get();
213  QMap < PJ_CONTEXT *, PJ * >::const_iterator it = mProjObjects.constFind( context );
214 
215  if ( it != mProjObjects.constEnd() )
216  {
217  return it.value();
218  }
219 
220  // proj object doesn't exist yet, so we need to create
221  locker.changeMode( QgsReadWriteLocker::Write );
222 
223  PJ *res = proj_clone( context, mPj.get() );
224  mProjObjects.insert( context, res );
225  return res;
226  }
227 
228  // Only meant to be called by QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread()
229  bool removeObjectsBelongingToCurrentThread( PJ_CONTEXT *pj_context )
230  {
231  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write );
232 
233  QMap < PJ_CONTEXT *, PJ * >::iterator it = mProjObjects.find( pj_context );
234  if ( it != mProjObjects.end() )
235  {
236  proj_destroy( it.value() );
237  mProjObjects.erase( it );
238  }
239 
240  if ( mPjParentContext == pj_context )
241  {
242  mPj.reset();
243  mPjParentContext = nullptr;
244  }
245 
246  return mProjObjects.isEmpty();
247  }
248 #endif
249 
250  private:
251  QgsCoordinateReferenceSystemPrivate &operator= ( const QgsCoordinateReferenceSystemPrivate & ) = delete;
252 
253 };
254 
256 
257 #endif //QGSCOORDINATEREFERENCESYSTEM_PRIVATE_H
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
@ Write
Lock for write.
@ Read
Lock for read.
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:68
@ DistanceUnknownUnit
Unknown distance unit.
Definition: qgsunittypes.h:78
void * OGRSpatialReferenceH
void PJ_CONTEXT
Definition: qgsprojutils.h:151