30
30
31
31
#include < QSharedData>
32
32
#include " qgscoordinatereferencesystem.h"
33
- #include " qgslogger.h"
34
- #include " qgsapplication.h"
35
33
36
- extern " C"
37
- {
38
- #include < proj_api.h>
39
- }
40
- #include < sqlite3.h>
41
-
42
- #include < QStringList>
34
+ typedef void *projPJ;
43
35
44
36
class QgsCoordinateTransformPrivate : public QSharedData
45
37
{
46
38
47
39
public:
48
40
49
- explicit QgsCoordinateTransformPrivate ()
50
- : mIsValid( false )
51
- , mShortCircuit( false )
52
- , mSourceProjection( nullptr )
53
- , mDestinationProjection( nullptr )
54
- , mSourceDatumTransform( -1 )
55
- , mDestinationDatumTransform( -1 )
56
- {
57
- setFinder ();
58
- }
41
+ explicit QgsCoordinateTransformPrivate ();
59
42
60
43
QgsCoordinateTransformPrivate ( const QgsCoordinateReferenceSystem &source,
61
- const QgsCoordinateReferenceSystem &destination )
62
- : mIsValid ( false )
63
- , mShortCircuit ( false )
64
- , mSourceCRS ( source )
65
- , mDestCRS ( destination )
66
- , mSourceProjection ( nullptr )
67
- , mDestinationProjection ( nullptr )
68
- , mSourceDatumTransform ( -1 )
69
- , mDestinationDatumTransform ( -1 )
70
- {
71
- setFinder ();
72
- initialize ();
73
- }
74
-
75
- QgsCoordinateTransformPrivate ( const QgsCoordinateTransformPrivate &other )
76
- : QSharedData( other )
77
- , mIsValid ( other.mIsValid )
78
- , mShortCircuit ( other.mShortCircuit )
79
- , mSourceCRS ( other.mSourceCRS )
80
- , mDestCRS ( other.mDestCRS )
81
- , mSourceProjection ( nullptr )
82
- , mDestinationProjection ( nullptr )
83
- , mSourceDatumTransform ( other.mSourceDatumTransform )
84
- , mDestinationDatumTransform ( other.mDestinationDatumTransform )
85
- {
86
- // must reinitialize to setup mSourceProjection and mDestinationProjection
87
- initialize ();
88
- }
89
-
90
- ~QgsCoordinateTransformPrivate ()
91
- {
92
- // free the proj objects
93
- if ( mSourceProjection )
94
- {
95
- pj_free ( mSourceProjection );
96
- }
97
- if ( mDestinationProjection )
98
- {
99
- pj_free ( mDestinationProjection );
100
- }
101
- }
102
-
103
- bool initialize ()
104
- {
105
- mShortCircuit = true ;
106
- mIsValid = false ;
107
-
108
- if ( !mSourceCRS .isValid () )
109
- {
110
- // Pass through with no projection since we have no idea what the layer
111
- // coordinates are and projecting them may not be appropriate
112
- QgsDebugMsgLevel ( " Source CRS is invalid!" , 4 );
113
- return false ;
114
- }
115
-
116
- if ( !mDestCRS .isValid () )
117
- {
118
- // No destination projection is set so we set the default output projection to
119
- // be the same as input proj.
120
- mDestCRS = mSourceCRS ;
121
- QgsDebugMsgLevel ( " Destination CRS is invalid!" , 4 );
122
- return false ;
123
- }
124
-
125
- mIsValid = true ;
44
+ const QgsCoordinateReferenceSystem &destination );
126
45
127
- bool useDefaultDatumTransform = ( mSourceDatumTransform == - 1 && mDestinationDatumTransform == - 1 );
46
+ QgsCoordinateTransformPrivate ( const QgsCoordinateTransformPrivate &other );
128
47
129
- // init the projections (destination and source)
130
-
131
- pj_free ( mSourceProjection );
132
- QString sourceProjString = mSourceCRS .toProj4 ();
133
- if ( !useDefaultDatumTransform )
134
- {
135
- sourceProjString = stripDatumTransform ( sourceProjString );
136
- }
137
- if ( mSourceDatumTransform != -1 )
138
- {
139
- sourceProjString += ( ' ' + datumTransformString ( mSourceDatumTransform ) );
140
- }
141
-
142
- pj_free ( mDestinationProjection );
143
- QString destProjString = mDestCRS .toProj4 ();
144
- if ( !useDefaultDatumTransform )
145
- {
146
- destProjString = stripDatumTransform ( destProjString );
147
- }
148
- if ( mDestinationDatumTransform != -1 )
149
- {
150
- destProjString += ( ' ' + datumTransformString ( mDestinationDatumTransform ) );
151
- }
152
-
153
- if ( !useDefaultDatumTransform )
154
- {
155
- addNullGridShifts ( sourceProjString, destProjString );
156
- }
157
-
158
- mSourceProjection = pj_init_plus ( sourceProjString.toUtf8 () );
159
- mDestinationProjection = pj_init_plus ( destProjString.toUtf8 () );
160
-
161
- #ifdef COORDINATE_TRANSFORM_VERBOSE
162
- QgsDebugMsg ( " From proj : " + mSourceCRS .toProj4 () );
163
- QgsDebugMsg ( " To proj : " + mDestCRS .toProj4 () );
164
- #endif
165
-
166
- if ( !mDestinationProjection || !mSourceProjection )
167
- {
168
- mIsValid = false ;
169
- }
170
-
171
- #ifdef COORDINATE_TRANSFORM_VERBOSE
172
- if ( mIsValid )
173
- {
174
- QgsDebugMsg ( " ------------------------------------------------------------" );
175
- QgsDebugMsg ( " The OGR Coordinate transformation for this layer was set to" );
176
- QgsLogger::debug<QgsCoordinateReferenceSystem>( " Input" , mSourceCRS , __FILE__, __FUNCTION__, __LINE__ );
177
- QgsLogger::debug<QgsCoordinateReferenceSystem>( " Output" , mDestCRS , __FILE__, __FUNCTION__, __LINE__ );
178
- QgsDebugMsg ( " ------------------------------------------------------------" );
179
- }
180
- else
181
- {
182
- QgsDebugMsg ( " ------------------------------------------------------------" );
183
- QgsDebugMsg ( " The OGR Coordinate transformation FAILED TO INITIALIZE!" );
184
- QgsDebugMsg ( " ------------------------------------------------------------" );
185
- }
186
- #else
187
- if ( !mIsValid )
188
- {
189
- QgsDebugMsg ( " Coordinate transformation failed to initialize!" );
190
- }
191
- #endif
192
-
193
- // XXX todo overload == operator for QgsCoordinateReferenceSystem
194
- // at the moment srs.parameters contains the whole proj def...soon it won't...
195
- // if (mSourceCRS->toProj4() == mDestCRS->toProj4())
196
- if ( mSourceCRS == mDestCRS )
197
- {
198
- // If the source and destination projection are the same, set the short
199
- // circuit flag (no transform takes place)
200
- mShortCircuit = true ;
201
- QgsDebugMsgLevel ( " Source/Dest CRS equal, shortcircuit is set." , 3 );
202
- }
203
- else
204
- {
205
- // Transform must take place
206
- mShortCircuit = false ;
207
- QgsDebugMsgLevel ( " Source/Dest CRS not equal, shortcircuit is not set." , 3 );
208
- }
209
- return mIsValid ;
210
- }
211
-
212
- // ! Removes +nadgrids and +towgs84 from proj4 string
213
- QString stripDatumTransform ( const QString &proj4 ) const
214
- {
215
- QStringList parameterSplit = proj4.split ( ' +' , QString::SkipEmptyParts );
216
- QString currentParameter;
217
- QString newProjString;
218
-
219
- for ( int i = 0 ; i < parameterSplit.size (); ++i )
220
- {
221
- currentParameter = parameterSplit.at ( i );
222
- if ( !currentParameter.startsWith ( QLatin1String ( " towgs84" ), Qt::CaseInsensitive )
223
- && !currentParameter.startsWith ( QLatin1String ( " nadgrids" ), Qt::CaseInsensitive ) )
224
- {
225
- newProjString.append ( ' +' );
226
- newProjString.append ( currentParameter );
227
- newProjString.append ( ' ' );
228
- }
229
- }
230
- return newProjString;
231
- }
232
-
233
- static QString datumTransformString ( int datumTransform )
234
- {
235
- QString transformString;
236
-
237
- sqlite3 *db = nullptr ;
238
- int openResult = sqlite3_open_v2 ( QgsApplication::srsDatabaseFilePath ().toUtf8 ().constData (), &db, SQLITE_OPEN_READONLY, 0 );
239
- if ( openResult != SQLITE_OK )
240
- {
241
- sqlite3_close ( db );
242
- return transformString;
243
- }
244
-
245
- sqlite3_stmt *stmt = nullptr ;
246
- QString sql = QStringLiteral ( " SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7 FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg ( datumTransform );
247
- int prepareRes = sqlite3_prepare ( db, sql.toLatin1 (), sql.size (), &stmt, nullptr );
248
- if ( prepareRes != SQLITE_OK )
249
- {
250
- sqlite3_finalize ( stmt );
251
- sqlite3_close ( db );
252
- return transformString;
253
- }
254
-
255
- if ( sqlite3_step ( stmt ) == SQLITE_ROW )
256
- {
257
- // coord_op_methode_code
258
- int methodCode = sqlite3_column_int ( stmt, 0 );
259
- if ( methodCode == 9615 ) // ntv2
260
- {
261
- transformString = " +nadgrids=" + QString ( reinterpret_cast < const char * >( sqlite3_column_text ( stmt, 1 ) ) );
262
- }
263
- else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
264
- {
265
- transformString += QLatin1String ( " +towgs84=" );
266
- double p1 = sqlite3_column_double ( stmt, 1 );
267
- double p2 = sqlite3_column_double ( stmt, 2 );
268
- double p3 = sqlite3_column_double ( stmt, 3 );
269
- double p4 = sqlite3_column_double ( stmt, 4 );
270
- double p5 = sqlite3_column_double ( stmt, 5 );
271
- double p6 = sqlite3_column_double ( stmt, 6 );
272
- double p7 = sqlite3_column_double ( stmt, 7 );
273
- if ( methodCode == 9603 ) // 3 parameter transformation
274
- {
275
- transformString += QStringLiteral ( " %1,%2,%3" ).arg ( p1 ).arg ( p2 ).arg ( p3 );
276
- }
277
- else // 7 parameter transformation
278
- {
279
- transformString += QStringLiteral ( " %1,%2,%3,%4,%5,%6,%7" ).arg ( p1 ).arg ( p2 ).arg ( p3 ).arg ( p4 ).arg ( p5 ).arg ( p6 ).arg ( p7 );
280
- }
281
- }
282
- }
283
-
284
- sqlite3_finalize ( stmt );
285
- sqlite3_close ( db );
286
- return transformString;
287
- }
288
-
289
- // ! In certain situations, null grid shifts have to be added to src / dst proj string
290
- void addNullGridShifts ( QString &srcProjString, QString &destProjString ) const
291
- {
292
- // if one transformation uses ntv2, the other one needs to be null grid shift
293
- if ( mDestinationDatumTransform == -1 && srcProjString.contains ( QLatin1String ( " +nadgrids" ) ) ) // add null grid if source transformation is ntv2
294
- {
295
- destProjString += QLatin1String ( " +nadgrids=@null" );
296
- return ;
297
- }
298
- if ( mSourceDatumTransform == -1 && destProjString.contains ( QLatin1String ( " +nadgrids" ) ) )
299
- {
300
- srcProjString += QLatin1String ( " +nadgrids=@null" );
301
- return ;
302
- }
303
-
304
- // add null shift grid for google mercator
305
- // (see e.g. http://trac.osgeo.org/proj/wiki/FAQ#ChangingEllipsoidWhycantIconvertfromWGS84toGoogleEarthVirtualGlobeMercator)
306
- if ( mSourceCRS .authid ().compare ( QLatin1String ( " EPSG:3857" ), Qt::CaseInsensitive ) == 0 && mSourceDatumTransform == -1 )
307
- {
308
- srcProjString += QLatin1String ( " +nadgrids=@null" );
309
- }
310
- if ( mDestCRS .authid ().compare ( QLatin1String ( " EPSG:3857" ), Qt::CaseInsensitive ) == 0 && mDestinationDatumTransform == -1 )
311
- {
312
- destProjString += QLatin1String ( " +nadgrids=@null" );
313
- }
314
- }
48
+ ~QgsCoordinateTransformPrivate ();
315
49
50
+ bool initialize ();
316
51
317
52
// ! Flag to indicate whether the transform is valid (ie has a valid
318
53
// ! source and destination crs)
@@ -339,21 +74,17 @@ class QgsCoordinateTransformPrivate : public QSharedData
339
74
int mSourceDatumTransform ;
340
75
int mDestinationDatumTransform ;
341
76
342
- void setFinder ()
343
- {
344
- #if 0
345
- // Attention! It should be possible to set PROJ_LIB
346
- // but it can happen that it was previously set by installer
347
- // (version 0.7) and the old installation was deleted
77
+ static QString datumTransformString ( int datumTransform );
78
+
79
+ private:
348
80
349
- // Another problem: PROJ checks if pj_finder was set before
350
- // PROJ_LIB environment variable. pj_finder is probably set in
351
- // GRASS gproj library when plugin is loaded, consequently
352
- // PROJ_LIB is ignored
81
+ // ! Removes +nadgrids and +towgs84 from proj4 string
82
+ QString stripDatumTransform ( const QString &proj4 ) const ;
83
+
84
+ // ! In certain situations, null grid shifts have to be added to src / dst proj string
85
+ void addNullGridShifts ( QString &srcProjString, QString &destProjString ) const ;
353
86
354
- pj_set_finder( finder );
355
- #endif
356
- }
87
+ void setFinder ();
357
88
};
358
89
359
90
// / @endcond
0 commit comments