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