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