QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsdatumtransform.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdatumtransform.cpp
3  ------------------------
4  begin : Dec 2017
5  copyright : (C) 2017 Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 #include "qgsdatumtransform.h"
19 #include "qgsapplication.h"
20 #include "qgssqliteutils.h"
21 #include <sqlite3.h>
22 
23 QList< QgsDatumTransform::TransformPair > QgsDatumTransform::datumTransformations( const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destCRS )
24 {
25  QList< QgsDatumTransform::TransformPair > transformations;
26 
27  QString srcGeoId = srcCRS.geographicCrsAuthId();
28  QString destGeoId = destCRS.geographicCrsAuthId();
29 
30  if ( srcGeoId.isEmpty() || destGeoId.isEmpty() )
31  {
32  return transformations;
33  }
34 
35  QStringList srcSplit = srcGeoId.split( ':' );
36  QStringList destSplit = destGeoId.split( ':' );
37 
38  if ( srcSplit.size() < 2 || destSplit.size() < 2 )
39  {
40  return transformations;
41  }
42 
43  int srcAuthCode = srcSplit.at( 1 ).toInt();
44  int destAuthCode = destSplit.at( 1 ).toInt();
45 
46  if ( srcAuthCode == destAuthCode )
47  {
48  return transformations; //crs have the same datum
49  }
50 
51  QList<int> directTransforms;
52  searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE source_crs_code=%1 AND target_crs_code=%2 ORDER BY deprecated ASC,preferred DESC" ).arg( srcAuthCode ).arg( destAuthCode ),
53  directTransforms );
54  QList<int> reverseDirectTransforms;
55  searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE source_crs_code = %1 AND target_crs_code=%2 ORDER BY deprecated ASC,preferred DESC" ).arg( destAuthCode ).arg( srcAuthCode ),
56  reverseDirectTransforms );
57  QList<int> srcToWgs84;
58  searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE (source_crs_code=%1 AND target_crs_code=%2) OR (source_crs_code=%2 AND target_crs_code=%1) ORDER BY deprecated ASC,preferred DESC" ).arg( srcAuthCode ).arg( 4326 ),
59  srcToWgs84 );
60  QList<int> destToWgs84;
61  searchDatumTransform( QStringLiteral( "SELECT coord_op_code FROM tbl_datum_transform WHERE (source_crs_code=%1 AND target_crs_code=%2) OR (source_crs_code=%2 AND target_crs_code=%1) ORDER BY deprecated ASC,preferred DESC" ).arg( destAuthCode ).arg( 4326 ),
62  destToWgs84 );
63 
64  //add direct datum transformations
65  for ( int transform : qgis::as_const( directTransforms ) )
66  {
67  transformations.push_back( QgsDatumTransform::TransformPair( transform, -1 ) );
68  }
69 
70  //add direct datum transformations
71  for ( int transform : qgis::as_const( reverseDirectTransforms ) )
72  {
73  transformations.push_back( QgsDatumTransform::TransformPair( -1, transform ) );
74  }
75 
76  for ( int srcTransform : qgis::as_const( srcToWgs84 ) )
77  {
78  for ( int destTransform : qgis::as_const( destToWgs84 ) )
79  {
80  transformations.push_back( QgsDatumTransform::TransformPair( srcTransform, destTransform ) );
81  }
82  }
83 
84  return transformations;
85 }
86 
87 void QgsDatumTransform::searchDatumTransform( const QString &sql, QList< int > &transforms )
88 {
90  int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
91  if ( openResult != SQLITE_OK )
92  {
93  return;
94  }
95 
97  int prepareRes;
98  statement = database.prepare( sql, prepareRes );
99  if ( prepareRes != SQLITE_OK )
100  {
101  return;
102  }
103 
104  QString cOpCode;
105  while ( statement.step() == SQLITE_ROW )
106  {
107  cOpCode = statement.columnAsText( 0 );
108  transforms.push_back( cOpCode.toInt() );
109  }
110 }
111 
112 QString QgsDatumTransform::datumTransformToProj( int datumTransform )
113 {
114  QString transformString;
115 
117  int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
118  if ( openResult != SQLITE_OK )
119  {
120  return transformString;
121  }
122 
124  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 );
125  int prepareRes;
126  statement = database.prepare( sql, prepareRes );
127  if ( prepareRes != SQLITE_OK )
128  {
129  return transformString;
130  }
131 
132  if ( statement.step() == SQLITE_ROW )
133  {
134  //coord_op_methode_code
135  int methodCode = statement.columnAsInt64( 0 );
136  if ( methodCode == 9615 ) //ntv2
137  {
138  transformString = "+nadgrids=" + statement.columnAsText( 1 );
139  }
140  else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
141  {
142  transformString += QLatin1String( "+towgs84=" );
143  double p1 = statement.columnAsDouble( 1 );
144  double p2 = statement.columnAsDouble( 2 );
145  double p3 = statement.columnAsDouble( 3 );
146  double p4 = statement.columnAsDouble( 4 );
147  double p5 = statement.columnAsDouble( 5 );
148  double p6 = statement.columnAsDouble( 6 );
149  double p7 = statement.columnAsDouble( 7 );
150  if ( methodCode == 9603 ) //3 parameter transformation
151  {
152  transformString += QStringLiteral( "%1,%2,%3" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
153  }
154  else //7 parameter transformation
155  {
156  transformString += QStringLiteral( "%1,%2,%3,%4,%5,%6,%7" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ), QString::number( p4 ), QString::number( p5 ), QString::number( p6 ), QString::number( p7 ) );
157  }
158  }
159  }
160 
161  return transformString;
162 }
163 
165 {
167  int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
168  if ( openResult != SQLITE_OK )
169  {
170  return -1;
171  }
172 
174  QString sql = QStringLiteral( "SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7,coord_op_code FROM tbl_datum_transform" );
175  int prepareRes;
176  statement = database.prepare( sql, prepareRes );
177  if ( prepareRes != SQLITE_OK )
178  {
179  return -1;
180  }
181 
182  while ( statement.step() == SQLITE_ROW )
183  {
184  QString transformString;
185  //coord_op_methode_code
186  int methodCode = statement.columnAsInt64( 0 );
187  if ( methodCode == 9615 ) //ntv2
188  {
189  transformString = "+nadgrids=" + statement.columnAsText( 1 );
190  }
191  else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
192  {
193  transformString += QLatin1String( "+towgs84=" );
194  double p1 = statement.columnAsDouble( 1 );
195  double p2 = statement.columnAsDouble( 2 );
196  double p3 = statement.columnAsDouble( 3 );
197  double p4 = statement.columnAsDouble( 4 );
198  double p5 = statement.columnAsDouble( 5 );
199  double p6 = statement.columnAsDouble( 6 );
200  double p7 = statement.columnAsDouble( 7 );
201  if ( methodCode == 9603 ) //3 parameter transformation
202  {
203  transformString += QStringLiteral( "%1,%2,%3" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
204  }
205  else //7 parameter transformation
206  {
207  transformString += QStringLiteral( "%1,%2,%3,%4,%5,%6,%7" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ), QString::number( p4 ), QString::number( p5 ), QString::number( p6 ), QString::number( p7 ) );
208  }
209  }
210 
211  if ( transformString.compare( string, Qt::CaseInsensitive ) == 0 )
212  {
213  return statement.columnAsInt64( 8 );
214  }
215  }
216 
217  return -1;
218 }
219 
221 {
223 
225  int openResult = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
226  if ( openResult != SQLITE_OK )
227  {
228  return info;
229  }
230 
232  QString sql = QStringLiteral( "SELECT epsg_nr,source_crs_code,target_crs_code,remarks,scope,preferred,deprecated FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( datumTransform );
233  int prepareRes;
234  statement = database.prepare( sql, prepareRes );
235  if ( prepareRes != SQLITE_OK )
236  {
237  return info;
238  }
239 
240  int srcCrsId, destCrsId;
241  if ( statement.step() != SQLITE_ROW )
242  {
243  return info;
244  }
245 
246  info.datumTransformId = datumTransform;
247  info.epsgCode = statement.columnAsInt64( 0 );
248  srcCrsId = statement.columnAsInt64( 1 );
249  destCrsId = statement.columnAsInt64( 2 );
250  info.remarks = statement.columnAsText( 3 );
251  info.scope = statement.columnAsText( 4 );
252  info.preferred = statement.columnAsInt64( 5 ) != 0;
253  info.deprecated = statement.columnAsInt64( 6 ) != 0;
254 
255  QgsCoordinateReferenceSystem srcCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "EPSG:%1" ).arg( srcCrsId ) );
256  info.sourceCrsDescription = srcCrs.description();
257  info.sourceCrsAuthId = srcCrs.authid();
258  QgsCoordinateReferenceSystem destCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( QStringLiteral( "EPSG:%1" ).arg( destCrsId ) );
259  info.destinationCrsDescription = destCrs.description();
260  info.destinationCrsAuthId = destCrs.authid();
261 
262  return info;
263 }
QString geographicCrsAuthId() const
Returns auth id of related geographic CRS.
QString destinationCrsDescription
Destination CRS description.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
int datumTransformId
Datum transform ID.
qlonglong columnAsInt64(int column) const
Gets column value from the current statement row as a long long integer (64 bits).
bool deprecated
True if transform is deprecated.
static QList< QgsDatumTransform::TransformPair > datumTransformations(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination)
Returns a list of datum transformations which are available for the given source and destination CRS...
QString sourceCrsDescription
Source CRS description.
double columnAsDouble(int column) const
Gets column value from the current statement row as a double.
int step()
Steps to the next record in the statement, returning the sqlite3 result code.
Contains datum transform information.
QString destinationCrsAuthId
Destination CRS auth ID.
bool preferred
True if transform is the preferred transform to use for the source/destination CRS combination...
int epsgCode
EPSG code for the transform, or 0 if not found in EPSG database.
QString sourceCrsAuthId
Source CRS auth ID.
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
Contains datum transform information.
This class represents a coordinate reference system (CRS).
QString authid() const
Returns the authority identifier for the CRS.
static QString datumTransformToProj(int datumTransformId)
Returns a proj string representing the specified datumTransformId datum transform ID...
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
static int projStringToDatumTransformId(const QString &string)
Returns the datum transform ID corresponding to a specified proj string.
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
QString columnAsText(int column) const
Returns the column value from the current statement row as a string.
QString remarks
Transform remarks.
static QgsDatumTransform::TransformInfo datumTransformInfo(int datumTransformId)
Returns detailed information about the specified datumTransformId.
QString scope
Scope of transform.