@@ -37,12 +37,12 @@ extern "C"
37
37
// if defined shows all information about transform to stdout
38
38
// #define COORDINATE_TRANSFORM_VERBOSE
39
39
40
+ QThreadStorage< QgsCoordinateTransform::QgsProjContextStore* > QgsCoordinateTransform::mProjContext ;
41
+
40
42
QgsCoordinateTransform::QgsCoordinateTransform ()
41
43
: QObject()
42
44
, mShortCircuit( false )
43
45
, mInitialisedFlag( false )
44
- , mSourceProjection( nullptr )
45
- , mDestinationProjection( nullptr )
46
46
, mSourceDatumTransform( -1 )
47
47
, mDestinationDatumTransform( -1 )
48
48
{
@@ -53,8 +53,6 @@ QgsCoordinateTransform::QgsCoordinateTransform( const QgsCoordinateReferenceSyst
53
53
: QObject()
54
54
, mShortCircuit( false )
55
55
, mInitialisedFlag( false )
56
- , mSourceProjection( nullptr )
57
- , mDestinationProjection( nullptr )
58
56
, mSourceDatumTransform( -1 )
59
57
, mDestinationDatumTransform( -1 )
60
58
{
@@ -69,8 +67,6 @@ QgsCoordinateTransform::QgsCoordinateTransform( long theSourceSrsId, long theDes
69
67
, mInitialisedFlag( false )
70
68
, mSourceCRS( QgsCRSCache::instance()->crsBySrsId( theSourceSrsId ) )
71
69
, mDestCRS( QgsCRSCache::instance()->crsBySrsId( theDestSrsId ) )
72
- , mSourceProjection( nullptr )
73
- , mDestinationProjection( nullptr )
74
70
, mSourceDatumTransform( -1 )
75
71
, mDestinationDatumTransform( -1 )
76
72
{
@@ -80,8 +76,6 @@ QgsCoordinateTransform::QgsCoordinateTransform( long theSourceSrsId, long theDes
80
76
QgsCoordinateTransform::QgsCoordinateTransform ( const QString& theSourceCRS, const QString& theDestCRS )
81
77
: QObject()
82
78
, mInitialisedFlag( false )
83
- , mSourceProjection( nullptr )
84
- , mDestinationProjection( nullptr )
85
79
, mSourceDatumTransform( -1 )
86
80
, mDestinationDatumTransform( -1 )
87
81
{
@@ -100,8 +94,6 @@ QgsCoordinateTransform::QgsCoordinateTransform( long theSourceSrid,
100
94
QgsCoordinateReferenceSystem::CrsType theSourceCRSType )
101
95
: QObject()
102
96
, mInitialisedFlag( false )
103
- , mSourceProjection( nullptr )
104
- , mDestinationProjection( nullptr )
105
97
, mSourceDatumTransform( -1 )
106
98
, mDestinationDatumTransform( -1 )
107
99
{
@@ -118,15 +110,7 @@ QgsCoordinateTransform::QgsCoordinateTransform( long theSourceSrid,
118
110
119
111
QgsCoordinateTransform::~QgsCoordinateTransform ()
120
112
{
121
- // free the proj objects
122
- if ( mSourceProjection )
123
- {
124
- pj_free ( mSourceProjection );
125
- }
126
- if ( mDestinationProjection )
127
- {
128
- pj_free ( mDestinationProjection );
129
- }
113
+ freeProj ();
130
114
}
131
115
132
116
QgsCoordinateTransform* QgsCoordinateTransform::clone () const
@@ -180,49 +164,47 @@ void QgsCoordinateTransform::initialise()
180
164
181
165
bool useDefaultDatumTransform = ( mSourceDatumTransform == - 1 && mDestinationDatumTransform == -1 );
182
166
183
- // init the projections (destination and source)
167
+ freeProj ();
184
168
185
- pj_free ( mSourceProjection );
186
- QString sourceProjString = mSourceCRS .toProj4 ();
169
+ mSourceProjString = mSourceCRS .toProj4 ();
187
170
if ( !useDefaultDatumTransform )
188
171
{
189
- sourceProjString = stripDatumTransform ( sourceProjString );
172
+ mSourceProjString = stripDatumTransform ( mSourceProjString );
190
173
}
191
174
if ( mSourceDatumTransform != -1 )
192
175
{
193
- sourceProjString += ( ' ' + datumTransformString ( mSourceDatumTransform ) );
176
+ mSourceProjString += ( ' ' + datumTransformString ( mSourceDatumTransform ) );
194
177
}
195
178
196
- pj_free ( mDestinationProjection );
197
- QString destProjString = mDestCRS .toProj4 ();
179
+ mDestProjString = mDestCRS .toProj4 ();
198
180
if ( !useDefaultDatumTransform )
199
181
{
200
- destProjString = stripDatumTransform ( destProjString );
182
+ mDestProjString = stripDatumTransform ( mDestProjString );
201
183
}
202
184
if ( mDestinationDatumTransform != -1 )
203
185
{
204
- destProjString += ( ' ' + datumTransformString ( mDestinationDatumTransform ) );
186
+ mDestProjString += ( ' ' + datumTransformString ( mDestinationDatumTransform ) );
205
187
}
206
188
207
189
if ( !useDefaultDatumTransform )
208
190
{
209
- addNullGridShifts ( sourceProjString, destProjString );
191
+ addNullGridShifts ( mSourceProjString , mDestProjString );
210
192
}
211
193
212
- mSourceProjection = pj_init_plus ( sourceProjString. toUtf8 () );
213
- mDestinationProjection = pj_init_plus ( destProjString. toUtf8 () );
194
+ // create proj projections for current thread
195
+ QPair< projPJ, projPJ > res = threadLocalProjData ( );
214
196
215
197
#ifdef COORDINATE_TRANSFORM_VERBOSE
216
198
QgsDebugMsg ( " From proj : " + mSourceCRS .toProj4 () );
217
199
QgsDebugMsg ( " To proj : " + mDestCRS .toProj4 () );
218
200
#endif
219
201
220
202
mInitialisedFlag = true ;
221
- if ( !mDestinationProjection )
203
+ if ( !res. second )
222
204
{
223
205
mInitialisedFlag = false ;
224
206
}
225
- if ( !mSourceProjection )
207
+ if ( !res. first )
226
208
{
227
209
mInitialisedFlag = false ;
228
210
}
@@ -661,8 +643,12 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
661
643
QString dir;
662
644
// if the source/destination projection is lat/long, convert the points to radians
663
645
// prior to transforming
664
- if (( pj_is_latlong ( mDestinationProjection ) && ( direction == ReverseTransform ) )
665
- || ( pj_is_latlong ( mSourceProjection ) && ( direction == ForwardTransform ) ) )
646
+ QPair< projPJ, projPJ > projData = threadLocalProjData ();
647
+ projPJ sourceProj = projData.first ;
648
+ projPJ destProj = projData.second ;
649
+
650
+ if (( pj_is_latlong ( destProj ) && ( direction == ReverseTransform ) )
651
+ || ( pj_is_latlong ( sourceProj ) && ( direction == ForwardTransform ) ) )
666
652
{
667
653
for ( int i = 0 ; i < numPoints; ++i )
668
654
{
@@ -674,13 +660,13 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
674
660
int projResult;
675
661
if ( direction == ReverseTransform )
676
662
{
677
- projResult = pj_transform ( mDestinationProjection , mSourceProjection , numPoints, 0 , x, y, z );
663
+ projResult = pj_transform ( destProj, sourceProj , numPoints, 0 , x, y, z );
678
664
}
679
665
else
680
666
{
681
- Q_ASSERT ( mSourceProjection );
682
- Q_ASSERT ( mDestinationProjection );
683
- projResult = pj_transform ( mSourceProjection , mDestinationProjection , numPoints, 0 , x, y, z );
667
+ Q_ASSERT ( sourceProj );
668
+ Q_ASSERT ( destProj );
669
+ projResult = pj_transform ( sourceProj, destProj , numPoints, 0 , x, y, z );
684
670
}
685
671
686
672
if ( projResult != 0 )
@@ -702,8 +688,8 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
702
688
703
689
dir = ( direction == ForwardTransform ) ? tr ( " forward transform" ) : tr ( " inverse transform" );
704
690
705
- char *srcdef = pj_get_def ( mSourceProjection , 0 );
706
- char *dstdef = pj_get_def ( mDestinationProjection , 0 );
691
+ char *srcdef = pj_get_def ( sourceProj , 0 );
692
+ char *dstdef = pj_get_def ( destProj , 0 );
707
693
708
694
QString msg = tr ( " %1 of\n "
709
695
" %2"
@@ -728,8 +714,8 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double *
728
714
729
715
// if the result is lat/long, convert the results from radians back
730
716
// to degrees
731
- if (( pj_is_latlong ( mDestinationProjection ) && ( direction == ForwardTransform ) )
732
- || ( pj_is_latlong ( mSourceProjection ) && ( direction == ReverseTransform ) ) )
717
+ if (( pj_is_latlong ( destProj ) && ( direction == ForwardTransform ) )
718
+ || ( pj_is_latlong ( sourceProj ) && ( direction == ReverseTransform ) ) )
733
719
{
734
720
for ( int i = 0 ; i < numPoints; ++i )
735
721
{
@@ -1055,3 +1041,56 @@ void QgsCoordinateTransform::addNullGridShifts( QString& srcProjString, QString&
1055
1041
destProjString += " +nadgrids=@null" ;
1056
1042
}
1057
1043
}
1044
+
1045
+ QPair<projPJ, projPJ> QgsCoordinateTransform::threadLocalProjData () const
1046
+ {
1047
+ mProjLock .lockForRead ();
1048
+ projCtx pContext = nullptr ;
1049
+ if ( mProjContext .hasLocalData () )
1050
+ pContext = mProjContext .localData ()->get ();
1051
+ else
1052
+ {
1053
+ mProjContext .setLocalData ( new QgsProjContextStore () );
1054
+ pContext = mProjContext .localData ()->get ();
1055
+ }
1056
+
1057
+ QMap< uintptr_t , QPair< projPJ, projPJ > >::const_iterator it = mProjProjections .constFind ( reinterpret_cast < uintptr_t >( pContext ) );
1058
+ if ( it != mProjProjections .constEnd () )
1059
+ {
1060
+ QPair< projPJ, projPJ > res = it.value ();
1061
+ mProjLock .unlock ();
1062
+ return res;
1063
+ }
1064
+
1065
+ // proj projections don't exist yet, so we need to create
1066
+ mProjLock .unlock ();
1067
+ mProjLock .lockForWrite ();
1068
+ QPair< projPJ, projPJ > res = qMakePair ( pj_init_plus_ctx ( pContext, mSourceProjString .toUtf8 () ),
1069
+ pj_init_plus_ctx ( pContext, mDestProjString .toUtf8 () ) );
1070
+ mProjProjections .insert ( reinterpret_cast < uintptr_t >( pContext ), res );
1071
+ mProjLock .unlock ();
1072
+ return res;
1073
+ }
1074
+
1075
+ void QgsCoordinateTransform::freeProj ()
1076
+ {
1077
+ mProjLock .lockForWrite ();
1078
+ QMap< uintptr_t , QPair< projPJ, projPJ > >::const_iterator it = mProjProjections .constBegin ();
1079
+ for ( ; it != mProjProjections .constEnd (); ++it )
1080
+ {
1081
+ pj_free ( it.value ().first );
1082
+ pj_free ( it.value ().second );
1083
+ }
1084
+ mProjProjections .clear ();
1085
+ mProjLock .unlock ();
1086
+ }
1087
+
1088
+ QgsCoordinateTransform::QgsProjContextStore::QgsProjContextStore ()
1089
+ {
1090
+ context = pj_ctx_alloc ();
1091
+ }
1092
+
1093
+ QgsCoordinateTransform::QgsProjContextStore::~QgsProjContextStore ()
1094
+ {
1095
+ pj_ctx_free ( context );
1096
+ }
0 commit comments