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