29 QList< QgsDatumTransform::TransformDetails > res;
35 PJ_OPERATION_FACTORY_CONTEXT *operationContext = proj_create_operation_factory_context( pjContext,
nullptr );
38 proj_operation_factory_context_set_grid_availability_use( pjContext, operationContext, PROJ_GRID_AVAILABILITY_IGNORED );
41 proj_operation_factory_context_set_spatial_criterion( pjContext, operationContext, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION );
43 if ( includeSuperseded )
44 proj_operation_factory_context_set_discard_superseded( pjContext, operationContext,
false );
46 if ( PJ_OBJ_LIST *ops = proj_create_operations( pjContext, source.
projObject(), destination.
projObject(), operationContext ) )
48 int count = proj_list_get_count( ops );
49 for (
int i = 0; i < count; ++i )
56 if ( !details.
proj.isEmpty() )
57 res.push_back( details );
60 proj_list_destroy( ops );
62 proj_operation_factory_context_destroy( operationContext );
68 QList< QgsDatumTransform::TransformPair > transformations;
73 if ( srcGeoId.isEmpty() || destGeoId.isEmpty() )
75 return transformations;
78 QStringList srcSplit = srcGeoId.split(
':' );
79 QStringList destSplit = destGeoId.split(
':' );
81 if ( srcSplit.size() < 2 || destSplit.size() < 2 )
83 return transformations;
86 int srcAuthCode = srcSplit.at( 1 ).toInt();
87 int destAuthCode = destSplit.at( 1 ).toInt();
89 if ( srcAuthCode == destAuthCode )
91 return transformations;
94 QList<int> directTransforms;
95 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 ),
97 QList<int> reverseDirectTransforms;
98 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 ),
99 reverseDirectTransforms );
100 QList<int> srcToWgs84;
101 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 ),
103 QList<int> destToWgs84;
104 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 ),
108 for (
int transform : std::as_const( directTransforms ) )
114 for (
int transform : std::as_const( reverseDirectTransforms ) )
119 for (
int srcTransform : std::as_const( srcToWgs84 ) )
121 for (
int destTransform : std::as_const( destToWgs84 ) )
127 return transformations;
130void QgsDatumTransform::searchDatumTransform(
const QString &sql, QList< int > &transforms )
134 if ( openResult != SQLITE_OK )
139 sqlite3_statement_unique_ptr statement;
141 statement = database.
prepare( sql, prepareRes );
142 if ( prepareRes != SQLITE_OK )
148 while ( statement.
step() == SQLITE_ROW )
151 transforms.push_back( cOpCode.toInt() );
157 QString transformString;
161 if ( openResult != SQLITE_OK )
163 return transformString;
167 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 );
169 statement = database.
prepare( sql, prepareRes );
170 if ( prepareRes != SQLITE_OK )
172 return transformString;
175 if ( statement.
step() == SQLITE_ROW )
179 if ( methodCode == 9615 )
181 transformString =
"+nadgrids=" + statement.
columnAsText( 1 );
183 else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
185 transformString += QLatin1String(
"+towgs84=" );
193 if ( methodCode == 9603 )
195 transformString += QStringLiteral(
"%1,%2,%3" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
199 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 ) );
204 return transformString;
211 if ( openResult != SQLITE_OK )
217 QString sql = QStringLiteral(
"SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7,coord_op_code FROM tbl_datum_transform" );
219 statement = database.
prepare( sql, prepareRes );
220 if ( prepareRes != SQLITE_OK )
225 while ( statement.
step() == SQLITE_ROW )
227 QString transformString;
230 if ( methodCode == 9615 )
232 transformString =
"+nadgrids=" + statement.
columnAsText( 1 );
234 else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
236 transformString += QLatin1String(
"+towgs84=" );
244 if ( methodCode == 9603 )
246 transformString += QStringLiteral(
"%1,%2,%3" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
250 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 ) );
254 if ( transformString.compare(
string, Qt::CaseInsensitive ) == 0 )
269 if ( openResult != SQLITE_OK )
275 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 );
277 statement = database.
prepare( sql, prepareRes );
278 if ( prepareRes != SQLITE_OK )
283 int srcCrsId, destCrsId;
284 if ( statement.
step() != SQLITE_ROW )
317 details.
proj = QString( proj_as_proj_string( pjContext, normalized.get(), PJ_PROJ_5,
nullptr ) );
319 if ( details.
proj.isEmpty() )
320 details.
proj = QString( proj_as_proj_string( pjContext, op, PJ_PROJ_5,
nullptr ) );
322 if ( details.
proj.isEmpty() )
325 details.
name = QString( proj_get_name( op ) );
326 details.
accuracy = proj_coordoperation_get_accuracy( pjContext, op );
327 details.
isAvailable = proj_coordoperation_is_instantiable( pjContext, op );
329 details.
authority = QString( proj_get_id_auth_name( op, 0 ) );
330 details.
code = QString( proj_get_id_code( op, 0 ) );
332 const char *areaOfUseName =
nullptr;
337 if ( proj_get_area_of_use( pjContext, op, &westLon, &southLat, &eastLon, &northLat, &areaOfUseName ) )
339 details.
areaOfUse = QString( areaOfUseName );
347 details.
remarks = QString( proj_get_remarks( op ) );
348 details.
scope = QString( proj_get_scope( op ) );
350 for (
int j = 0; j < proj_coordoperation_get_grid_used_count( pjContext, op ); ++j )
352 const char *shortName =
nullptr;
353 const char *fullName =
nullptr;
354 const char *packageName =
nullptr;
355 const char *url =
nullptr;
356 int directDownload = 0;
359 proj_coordoperation_get_grid_used( pjContext, op, j, &shortName, &fullName, &packageName, &url, &directDownload, &openLicense, &isAvailable );
361 gridDetails.
shortName = QString( shortName );
362 gridDetails.
fullName = QString( fullName );
364 gridDetails.
url = QString( url );
369 details.
grids.append( gridDetails );
372 if ( proj_get_type( op ) == PJ_TYPE_CONCATENATED_OPERATION )
374 for (
int j = 0; j < proj_concatoperation_get_step_count( pjContext, op ); ++j )
380 singleOpDetails.
remarks = QString( proj_get_remarks( step.get() ) );
381 singleOpDetails.
scope = QString( proj_get_scope( step.get() ) );
382 singleOpDetails.
authority = QString( proj_get_id_auth_name( step.get(), 0 ) );
383 singleOpDetails.
code = QString( proj_get_id_code( step.get(), 0 ) );
385 const char *areaOfUseName =
nullptr;
386 if ( proj_get_area_of_use( pjContext, step.get(),
nullptr,
nullptr,
nullptr,
nullptr, &areaOfUseName ) )
388 singleOpDetails.
areaOfUse = QString( areaOfUseName );
397 singleOpDetails.
remarks = QString( proj_get_remarks( op ) );
398 singleOpDetails.
scope = QString( proj_get_scope( op ) );
399 singleOpDetails.
authority = QString( proj_get_id_auth_name( op, 0 ) );
400 singleOpDetails.
code = QString( proj_get_id_code( op, 0 ) );
402 const char *areaOfUseName =
nullptr;
403 if ( proj_get_area_of_use( pjContext, op,
nullptr,
nullptr,
nullptr,
nullptr, &areaOfUseName ) )
405 singleOpDetails.
areaOfUse = QString( areaOfUseName );
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
Represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
PJ * projObject() const
Returns the underlying PROJ PJ object corresponding to the CRS, or nullptr if the CRS is invalid.
QString geographicCrsAuthId() const
Returns auth id of related geographic CRS.
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.
void setYMinimum(double y)
Set the minimum y value.
void setXMinimum(double x)
Set the minimum x value.
void setYMaximum(double y)
Set the maximum y value.
void setXMaximum(double x)
Set the maximum x value.
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
QString columnAsText(int column) const
Returns the column value from the current statement row as a string.
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.
qlonglong columnAsInt64(int column) const
Gets column value from the current statement row as a long long integer (64 bits).