QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 #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  explicit QgsCoordinateReferenceSystemPrivate()
49  {
50  }
51 
52  QgsCoordinateReferenceSystemPrivate( const QgsCoordinateReferenceSystemPrivate &other )
53  : QSharedData( other )
54  , mSrsId( other.mSrsId )
55  , mDescription( other.mDescription )
56  , mProjectionAcronym( other.mProjectionAcronym )
57  , mEllipsoidAcronym( other.mEllipsoidAcronym )
58  , mIsGeographic( other.mIsGeographic )
59  , mMapUnits( other.mMapUnits )
60  , mSRID( other.mSRID )
61  , mAuthId( other.mAuthId )
62  , mIsValid( other.mIsValid )
63  , mCoordinateEpoch( other.mCoordinateEpoch )
64  , mPj()
65  , mProj4( other.mProj4 )
66  , mWktPreferred( other.mWktPreferred )
67  , mAxisInvertedDirty( other.mAxisInvertedDirty )
68  , mAxisInverted( other.mAxisInverted )
69  , mProjObjects()
70  {
71  }
72 
73  ~QgsCoordinateReferenceSystemPrivate()
74  {
75  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
76  if ( !mProjObjects.empty() || mPj )
77  {
78  locker.changeMode( QgsReadWriteLocker::Write );
79  cleanPjObjects();
80  }
81  }
82 
84  long mSrsId = 0;
85 
87  QString mDescription;
88 
90  QString mProjectionAcronym;
91 
93  QString mEllipsoidAcronym;
94 
96  bool mIsGeographic = false;
97 
100 
102  long mSRID = 0;
103 
105  QString mAuthId;
106 
108  bool mIsValid = false;
109 
111  double mCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
112 
113  // this is the "master" proj object, to be used as a template for new proj objects created on different threads ONLY.
114  // Always use threadLocalProjObject() instead of this.
115 
116  private:
118  PJ_CONTEXT *mPjParentContext = nullptr;
119 
120  void cleanPjObjects()
121  {
122 
123  // During destruction of PJ* objects, the errno is set in the underlying
124  // context. Consequently the context attached to the PJ* must still exist !
125  // Which is not necessarily the case currently unfortunately. So
126  // create a temporary dummy context, and attach it to the PJ* before destroying
127  // it
128  PJ_CONTEXT *tmpContext = proj_context_create();
129  for ( auto it = mProjObjects.begin(); it != mProjObjects.end(); ++it )
130  {
131  proj_assign_context( it.value(), tmpContext );
132  proj_destroy( it.value() );
133  }
134  mProjObjects.clear();
135  if ( mPj )
136  {
137  proj_assign_context( mPj.get(), tmpContext );
138  mPj.reset();
139  }
140  proj_context_destroy( tmpContext );
141  }
142 
143  public:
144 
145  void setPj( QgsProjUtils::proj_pj_unique_ptr obj )
146  {
147  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write );
148  cleanPjObjects();
149 
150  mPj = std::move( obj );
151  mPjParentContext = QgsProjContext::get();
152  }
153 
154  bool hasPj() const
155  {
156  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
157  return static_cast< bool >( mPj );
158  }
159 
160  mutable QString mProj4;
161 
162  mutable QString mWktPreferred;
163 
165  mutable bool mAxisInvertedDirty = false;
166 
168  mutable bool mAxisInverted = false;
169 
170  private:
171  mutable QReadWriteLock mProjLock{};
172  mutable QMap < PJ_CONTEXT *, PJ * > mProjObjects{};
173 
174  public:
175 
176  PJ *threadLocalProjObject() const
177  {
178  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
179  if ( !mPj )
180  return nullptr;
181 
182  PJ_CONTEXT *context = QgsProjContext::get();
183  QMap < PJ_CONTEXT *, PJ * >::const_iterator it = mProjObjects.constFind( context );
184 
185  if ( it != mProjObjects.constEnd() )
186  {
187  return it.value();
188  }
189 
190  // proj object doesn't exist yet, so we need to create
191  locker.changeMode( QgsReadWriteLocker::Write );
192 
193  PJ *res = proj_clone( context, mPj.get() );
194  mProjObjects.insert( context, res );
195  return res;
196  }
197 
198  // Only meant to be called by QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread()
199  bool removeObjectsBelongingToCurrentThread( PJ_CONTEXT *pj_context )
200  {
201  QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write );
202 
203  QMap < PJ_CONTEXT *, PJ * >::iterator it = mProjObjects.find( pj_context );
204  if ( it != mProjObjects.end() )
205  {
206  proj_destroy( it.value() );
207  mProjObjects.erase( it );
208  }
209 
210  if ( mPjParentContext == pj_context )
211  {
212  mPj.reset();
213  mPjParentContext = nullptr;
214  }
215 
216  return mProjObjects.isEmpty();
217  }
218 
219  private:
220  QgsCoordinateReferenceSystemPrivate &operator= ( const QgsCoordinateReferenceSystemPrivate & ) = delete;
221 
222 };
223 
225 
226 #endif //QGSCOORDINATEREFERENCESYSTEM_PRIVATE_H
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
std::unique_ptr< PJ, ProjPJDeleter > proj_pj_unique_ptr
Scoped Proj PJ object.
Definition: qgsprojutils.h:141
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
struct PJconsts PJ
struct projCtx_t PJ_CONTEXT