QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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::Write );
99  cleanPjObjects();
100 #else
101  OSRDestroySpatialReference( mCRS );
102 #endif
103  }
104 
106  long mSrsId = 0;
107 
109  QString mDescription;
110 
112  QString mProjectionAcronym;
113 
115  QString mEllipsoidAcronym;
116 
118  bool mIsGeographic = false;
119 
122 
124  long mSRID = 0;
125 
127  QString mAuthId;
128 
130  bool mIsValid = false;
131 
132 #if PROJ_VERSION_MAJOR>=6
133 
134  // this is the "master" proj object, to be used as a template for new proj objects created on different threads ONLY.
135  // Always use threadLocalProjObject() instead of this.
136 
137  private:
138  QgsProjUtils::proj_pj_unique_ptr mPj;
139  PJ_CONTEXT *mPjParentContext = nullptr;
140 
141  void cleanPjObjects()
142  {
143 
144  // During destruction of PJ* objects, the errno is set in the underlying
145  // context. Consequently the context attached to the PJ* must still exist !
146  // Which is not necessarily the case currently unfortunately. So
147  // create a temporary dummy context, and attach it to the PJ* before destroying
148  // it
149  PJ_CONTEXT *tmpContext = proj_context_create();
150  for ( auto it = mProjObjects.begin(); it != mProjObjects.end(); ++it )
151  {
152  proj_assign_context( it.value(), tmpContext );
153  proj_destroy( it.value() );
154  }
155  mProjObjects.clear();
156  if ( mPj )
157  {
158  proj_assign_context( mPj.get(), tmpContext );
159  mPj.reset();
160  }
161  proj_context_destroy( tmpContext );
162  }
163 
164  public:
165 
166  void setPj( QgsProjUtils::proj_pj_unique_ptr obj )
167  {
168  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write );
169  cleanPjObjects();
170 
171  mPj = std::move( obj );
172  mPjParentContext = QgsProjContext::get();
173  }
174 
175  bool hasPj() const
176  {
177  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
178  return static_cast< bool >( mPj );
179  }
180 
181 #else
182  OGRSpatialReferenceH mCRS = nullptr;
183 #endif
184 
185  mutable QString mProj4;
186 
187  mutable QString mWktPreferred;
188 
190  mutable bool mAxisInvertedDirty = false;
191 
193  mutable bool mAxisInverted = false;
194 
195 #if PROJ_VERSION_MAJOR>=6
196  private:
197  mutable QReadWriteLock mProjLock{};
198  mutable QMap < PJ_CONTEXT *, PJ * > mProjObjects{};
199 
200  public:
201 
202  PJ *threadLocalProjObject() const
203  {
204  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
205  if ( !mPj )
206  return nullptr;
207 
208  PJ_CONTEXT *context = QgsProjContext::get();
209  QMap < PJ_CONTEXT *, PJ * >::const_iterator it = mProjObjects.constFind( context );
210 
211  if ( it != mProjObjects.constEnd() )
212  {
213  return it.value();
214  }
215 
216  // proj object doesn't exist yet, so we need to create
217  locker.changeMode( QgsReadWriteLocker::Write );
218 
219  PJ *res = proj_clone( context, mPj.get() );
220  mProjObjects.insert( context, res );
221  return res;
222  }
223 
224  // Only meant to be called by QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread()
225  bool removeObjectsBelongingToCurrentThread( PJ_CONTEXT *pj_context )
226  {
227  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write );
228 
229  QMap < PJ_CONTEXT *, PJ * >::iterator it = mProjObjects.find( pj_context );
230  if ( it != mProjObjects.end() )
231  {
232  proj_destroy( it.value() );
233  mProjObjects.erase( it );
234  }
235 
236  if ( mPjParentContext == pj_context )
237  {
238  mPj.reset();
239  mPjParentContext = nullptr;
240  }
241 
242  return mProjObjects.isEmpty();
243  }
244 #endif
245 
246  private:
247  QgsCoordinateReferenceSystemPrivate &operator= ( const QgsCoordinateReferenceSystemPrivate & ) = delete;
248 
249 };
250 
252 
253 #endif //QGSCOORDINATEREFERENCESYSTEM_PRIVATE_H
QgsProjContext::get
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
Definition: qgsprojutils.cpp:60
qgsreadwritelocker.h
QgsReadWriteLocker::Read
@ Read
Lock for read.
Definition: qgsreadwritelocker.h:49
QgsUnitTypes::DistanceUnknownUnit
@ DistanceUnknownUnit
Unknown distance unit.
Definition: qgsunittypes.h:78
QgsUnitTypes::DistanceUnit
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:68
QgsReadWriteLocker
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
Definition: qgsreadwritelocker.h:41
OGRSpatialReferenceH
void * OGRSpatialReferenceH
Definition: qgscoordinatereferencesystem.h:60
QgsReadWriteLocker::Write
@ Write
Lock for write.
Definition: qgsreadwritelocker.h:50
qgsprojutils.h
PJ_CONTEXT
void PJ_CONTEXT
Definition: qgsprojutils.h:151
qgscoordinatereferencesystem.h