23 #if PROJ_VERSION_MAJOR>=6
30 QList< QgsDatumTransform::TransformDetails > res;
31 #if PROJ_VERSION_MAJOR<6
33 Q_UNUSED( destination )
34 Q_UNUSED( includeSuperseded )
36 if ( !source.projObject() || !destination.projObject() )
41 PJ_OPERATION_FACTORY_CONTEXT *operationContext = proj_create_operation_factory_context( pjContext,
nullptr );
44 proj_operation_factory_context_set_grid_availability_use( pjContext, operationContext, PROJ_GRID_AVAILABILITY_IGNORED );
47 proj_operation_factory_context_set_spatial_criterion( pjContext, operationContext, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION );
49 if ( includeSuperseded )
50 proj_operation_factory_context_set_discard_superseded( pjContext, operationContext,
false );
52 if ( PJ_OBJ_LIST *ops = proj_create_operations( pjContext, source.projObject(), destination.projObject(), operationContext ) )
54 int count = proj_list_get_count( ops );
55 for (
int i = 0; i < count; ++i )
57 QgsProjUtils::proj_pj_unique_ptr op( proj_list_get( pjContext, ops, i ) );
62 if ( !details.
proj.isEmpty() )
63 res.push_back( details );
66 proj_list_destroy( ops );
68 proj_operation_factory_context_destroy( operationContext );
75 QList< QgsDatumTransform::TransformPair > transformations;
80 if ( srcGeoId.isEmpty() || destGeoId.isEmpty() )
82 return transformations;
85 QStringList srcSplit = srcGeoId.split(
':' );
86 QStringList destSplit = destGeoId.split(
':' );
88 if ( srcSplit.size() < 2 || destSplit.size() < 2 )
90 return transformations;
93 int srcAuthCode = srcSplit.at( 1 ).toInt();
94 int destAuthCode = destSplit.at( 1 ).toInt();
96 if ( srcAuthCode == destAuthCode )
98 return transformations;
101 QList<int> directTransforms;
102 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 ),
104 QList<int> reverseDirectTransforms;
105 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 ),
106 reverseDirectTransforms );
107 QList<int> srcToWgs84;
108 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 ),
110 QList<int> destToWgs84;
111 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 ),
115 for (
int transform : qgis::as_const( directTransforms ) )
121 for (
int transform : qgis::as_const( reverseDirectTransforms ) )
126 for (
int srcTransform : qgis::as_const( srcToWgs84 ) )
128 for (
int destTransform : qgis::as_const( destToWgs84 ) )
134 return transformations;
137 void QgsDatumTransform::searchDatumTransform(
const QString &sql, QList< int > &transforms )
141 if ( openResult != SQLITE_OK )
148 statement = database.
prepare( sql, prepareRes );
149 if ( prepareRes != SQLITE_OK )
155 while ( statement.
step() == SQLITE_ROW )
158 transforms.push_back( cOpCode.toInt() );
164 QString transformString;
168 if ( openResult != SQLITE_OK )
170 return transformString;
174 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 );
176 statement = database.
prepare( sql, prepareRes );
177 if ( prepareRes != SQLITE_OK )
179 return transformString;
182 if ( statement.
step() == SQLITE_ROW )
186 if ( methodCode == 9615 )
188 transformString =
"+nadgrids=" + statement.
columnAsText( 1 );
190 else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
192 transformString += QLatin1String(
"+towgs84=" );
200 if ( methodCode == 9603 )
202 transformString += QStringLiteral(
"%1,%2,%3" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
206 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 ) );
211 return transformString;
218 if ( openResult != SQLITE_OK )
224 QString sql = QStringLiteral(
"SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7,coord_op_code FROM tbl_datum_transform" );
226 statement = database.
prepare( sql, prepareRes );
227 if ( prepareRes != SQLITE_OK )
232 while ( statement.
step() == SQLITE_ROW )
234 QString transformString;
237 if ( methodCode == 9615 )
239 transformString =
"+nadgrids=" + statement.
columnAsText( 1 );
241 else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
243 transformString += QLatin1String(
"+towgs84=" );
251 if ( methodCode == 9603 )
253 transformString += QStringLiteral(
"%1,%2,%3" ).arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
257 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 ) );
261 if ( transformString.compare(
string, Qt::CaseInsensitive ) == 0 )
276 if ( openResult != SQLITE_OK )
282 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 );
284 statement = database.
prepare( sql, prepareRes );
285 if ( prepareRes != SQLITE_OK )
290 int srcCrsId, destCrsId;
291 if ( statement.
step() != SQLITE_ROW )
315 #if PROJ_VERSION_MAJOR>=6
319 TransformDetails details;
323 QgsProjUtils::proj_pj_unique_ptr normalized( proj_normalize_for_visualization( pjContext, op ) );
325 details.proj = QString( proj_as_proj_string( pjContext, normalized.get(), PJ_PROJ_5,
nullptr ) );
327 if ( details.proj.isEmpty() )
328 details.proj = QString( proj_as_proj_string( pjContext, op, PJ_PROJ_5,
nullptr ) );
330 if ( details.proj.isEmpty() )
333 details.name = QString( proj_get_name( op ) );
334 details.accuracy = proj_coordoperation_get_accuracy( pjContext, op );
335 details.isAvailable = proj_coordoperation_is_instantiable( pjContext, op );
337 details.authority = QString( proj_get_id_auth_name( op, 0 ) );
338 details.code = QString( proj_get_id_code( op, 0 ) );
340 const char *areaOfUseName =
nullptr;
345 if ( proj_get_area_of_use( pjContext, op, &westLon, &southLat, &eastLon, &northLat, &areaOfUseName ) )
347 details.areaOfUse = QString( areaOfUseName );
349 details.bounds.setXMinimum( westLon );
350 details.bounds.setYMinimum( southLat );
351 details.bounds.setXMaximum( eastLon );
352 details.bounds.setYMaximum( northLat );
355 details.remarks = QString( proj_get_remarks( op ) );
356 details.scope = QString( proj_get_scope( op ) );
358 for (
int j = 0; j < proj_coordoperation_get_grid_used_count( pjContext, op ); ++j )
360 const char *shortName =
nullptr;
361 const char *fullName =
nullptr;
362 const char *packageName =
nullptr;
363 const char *url =
nullptr;
364 int directDownload = 0;
367 proj_coordoperation_get_grid_used( pjContext, op, j, &shortName, &fullName, &packageName, &url, &directDownload, &openLicense, &isAvailable );
368 GridDetails gridDetails;
369 gridDetails.shortName = QString( shortName );
370 gridDetails.fullName = QString( fullName );
371 gridDetails.packageName = QString( packageName );
372 gridDetails.url = QString( url );
373 gridDetails.directDownload = directDownload;
374 gridDetails.openLicense = openLicense;
375 gridDetails.isAvailable = isAvailable;
377 details.grids.append( gridDetails );
380 if ( proj_get_type( op ) == PJ_TYPE_CONCATENATED_OPERATION )
382 for (
int j = 0; j < proj_concatoperation_get_step_count( pjContext, op ); ++j )
384 QgsProjUtils::proj_pj_unique_ptr step( proj_concatoperation_get_step( pjContext, op, j ) );
387 SingleOperationDetails singleOpDetails;
388 singleOpDetails.remarks = QString( proj_get_remarks( step.get() ) );
389 singleOpDetails.scope = QString( proj_get_scope( step.get() ) );
390 singleOpDetails.authority = QString( proj_get_id_auth_name( step.get(), 0 ) );
391 singleOpDetails.code = QString( proj_get_id_code( step.get(), 0 ) );
393 const char *areaOfUseName =
nullptr;
394 if ( proj_get_area_of_use( pjContext, step.get(),
nullptr,
nullptr,
nullptr,
nullptr, &areaOfUseName ) )
396 singleOpDetails.areaOfUse = QString( areaOfUseName );
398 details.operationDetails.append( singleOpDetails );
404 SingleOperationDetails singleOpDetails;
405 singleOpDetails.remarks = QString( proj_get_remarks( op ) );
406 singleOpDetails.scope = QString( proj_get_scope( op ) );
407 singleOpDetails.authority = QString( proj_get_id_auth_name( op, 0 ) );
408 singleOpDetails.code = QString( proj_get_id_code( op, 0 ) );
410 const char *areaOfUseName =
nullptr;
411 if ( proj_get_area_of_use( pjContext, op,
nullptr,
nullptr,
nullptr,
nullptr, &areaOfUseName ) )
413 singleOpDetails.areaOfUse = QString( areaOfUseName );
415 details.operationDetails.append( singleOpDetails );
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
This class 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.
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
QString authid() const
Returns the authority identifier for the CRS.
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.
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).