QGIS API Documentation 3.41.0-Master (1deb1daf037)
Loading...
Searching...
No Matches
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
38class QgsCoordinateReferenceSystemPrivate : public QSharedData
39{
40 public:
41
42 explicit QgsCoordinateReferenceSystemPrivate()
43 {
44 }
45
46 QgsCoordinateReferenceSystemPrivate( const QgsCoordinateReferenceSystemPrivate &other )
47 : QSharedData( other )
48 , mSrsId( other.mSrsId )
49 , mDescription( other.mDescription )
50 , mProjectionAcronym( other.mProjectionAcronym )
51 , mEllipsoidAcronym( other.mEllipsoidAcronym )
52 , mProjType( other.mProjType )
53 , mIsGeographic( other.mIsGeographic )
54 , mMapUnits( other.mMapUnits )
55 , mSRID( other.mSRID )
56 , mAuthId( other.mAuthId )
57 , mIsValid( other.mIsValid )
58 , mCoordinateEpoch( other.mCoordinateEpoch )
59 , mPj()
60 , mPjParentContext( nullptr )
61 , mProj4( other.mProj4 )
62 , mWktPreferred( other.mWktPreferred )
63 , mAxisInvertedDirty( other.mAxisInvertedDirty )
64 , mAxisInverted( other.mAxisInverted )
65 , mProjLock{}
66 , mProjObjects()
67 {
68 }
69
70 ~QgsCoordinateReferenceSystemPrivate()
71 {
73 if ( !mProjObjects.empty() || mPj )
74 {
75 locker.changeMode( QgsReadWriteLocker::Write );
76 cleanPjObjects();
77 }
78 }
79
81 long mSrsId = 0;
82
84 QString mDescription;
85
87 QString mProjectionAcronym;
88
90 QString mEllipsoidAcronym;
91
92 PJ_TYPE mProjType = PJ_TYPE::PJ_TYPE_UNKNOWN;
93
95 bool mIsGeographic = false;
96
99
101 long mSRID = 0;
102
104 QString mAuthId;
105
107 bool mIsValid = false;
108
110 double mCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
111
112 // this is the "master" proj object, to be used as a template for new proj objects created on different threads ONLY.
113 // Always use threadLocalProjObject() instead of this.
114
115 private:
117 PJ_CONTEXT *mPjParentContext = nullptr;
118
119 void cleanPjObjects()
120 {
121
122 // During destruction of PJ* objects, the errno is set in the underlying
123 // context. Consequently the context attached to the PJ* must still exist !
124 // Which is not necessarily the case currently unfortunately. So
125 // create a temporary dummy context, and attach it to the PJ* before destroying
126 // it
127 PJ_CONTEXT *tmpContext = proj_context_create();
128 for ( auto it = mProjObjects.begin(); it != mProjObjects.end(); ++it )
129 {
130 proj_assign_context( it.value(), tmpContext );
131 proj_destroy( it.value() );
132 }
133 mProjObjects.clear();
134 if ( mPj )
135 {
136 proj_assign_context( mPj.get(), tmpContext );
137 mPj.reset();
138 }
139 proj_context_destroy( tmpContext );
140 }
141
142 public:
143
144 void setPj( QgsProjUtils::proj_pj_unique_ptr obj )
145 {
146 const QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write );
147 cleanPjObjects();
148
149 mPj = std::move( obj );
150 mPjParentContext = QgsProjContext::get();
151
152 if ( mPj )
153 {
154 mProjType = proj_get_type( mPj.get() );
155 }
156 else
157 {
158 mProjType = PJ_TYPE_UNKNOWN;
159 }
160 }
161
162 bool hasPj() const
163 {
164 const QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
165 return static_cast< bool >( mPj );
166 }
167
168 mutable QString mProj4;
169
170 mutable QString mWktPreferred;
171
173 mutable bool mAxisInvertedDirty = false;
174
176 mutable bool mAxisInverted = false;
177
178 private:
179 mutable QReadWriteLock mProjLock{};
180 mutable QMap < PJ_CONTEXT *, PJ * > mProjObjects{};
181
182 public:
183
184 PJ *threadLocalProjObject() const
185 {
186 QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Read );
187 if ( !mPj )
188 return nullptr;
189
190 PJ_CONTEXT *context = QgsProjContext::get();
191 const QMap < PJ_CONTEXT *, PJ * >::const_iterator it = mProjObjects.constFind( context );
192
193 if ( it != mProjObjects.constEnd() )
194 {
195 return it.value();
196 }
197
198 // proj object doesn't exist yet, so we need to create
199 locker.changeMode( QgsReadWriteLocker::Write );
200
201 PJ *res = proj_clone( context, mPj.get() );
202 mProjObjects.insert( context, res );
203 return res;
204 }
205
206 // Only meant to be called by QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread()
207 bool removeObjectsBelongingToCurrentThread( PJ_CONTEXT *pj_context )
208 {
209 const QgsReadWriteLocker locker( mProjLock, QgsReadWriteLocker::Write );
210
211 const QMap < PJ_CONTEXT *, PJ * >::iterator it = mProjObjects.find( pj_context );
212 if ( it != mProjObjects.end() )
213 {
214 proj_destroy( it.value() );
215 mProjObjects.erase( it );
216 }
217
218 if ( mPjParentContext == pj_context )
219 {
220 mPj.reset();
221 mPjParentContext = nullptr;
222 }
223
224 return mProjObjects.isEmpty();
225 }
226
227 private:
228 QgsCoordinateReferenceSystemPrivate &operator= ( const QgsCoordinateReferenceSystemPrivate & ) = delete;
229
230};
231
233
234#endif //QGSCOORDINATEREFERENCESYSTEM_PRIVATE_H
DistanceUnit
Units of distance.
Definition qgis.h:4779
@ Unknown
Unknown distance unit.
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.
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
@ Write
Lock for write.
struct pj_ctx PJ_CONTEXT
struct PJconsts PJ