29using namespace Qt::StringLiterals;
33 QList< QgsDatumTransform::TransformDetails > res;
39 PJ_OPERATION_FACTORY_CONTEXT *operationContext = proj_create_operation_factory_context( pjContext,
nullptr );
42 proj_operation_factory_context_set_grid_availability_use( pjContext, operationContext, PROJ_GRID_AVAILABILITY_IGNORED );
45 proj_operation_factory_context_set_spatial_criterion( pjContext, operationContext, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION );
47 if ( includeSuperseded )
48 proj_operation_factory_context_set_discard_superseded( pjContext, operationContext,
false );
50 if ( PJ_OBJ_LIST *ops = proj_create_operations( pjContext, source.
projObject(), destination.
projObject(), operationContext ) )
52 int count = proj_list_get_count( ops );
53 for (
int i = 0; i < count; ++i )
60 if ( !details.
proj.isEmpty() )
61 res.push_back( details );
64 proj_list_destroy( ops );
66 proj_operation_factory_context_destroy( operationContext );
72 QList< QgsDatumTransform::TransformPair > transformations;
77 if ( srcGeoId.isEmpty() || destGeoId.isEmpty() )
79 return transformations;
82 QStringList srcSplit = srcGeoId.split(
':' );
83 QStringList destSplit = destGeoId.split(
':' );
85 if ( srcSplit.size() < 2 || destSplit.size() < 2 )
87 return transformations;
90 int srcAuthCode = srcSplit.at( 1 ).toInt();
91 int destAuthCode = destSplit.at( 1 ).toInt();
93 if ( srcAuthCode == destAuthCode )
95 return transformations;
98 QList<int> directTransforms;
99 searchDatumTransform( u
"SELECT coord_op_code FROM tbl_datum_transform WHERE source_crs_code=%1 AND target_crs_code=%2 ORDER BY deprecated ASC,preferred DESC"_s.arg( srcAuthCode ).arg( destAuthCode ),
101 QList<int> reverseDirectTransforms;
102 searchDatumTransform( u
"SELECT coord_op_code FROM tbl_datum_transform WHERE source_crs_code = %1 AND target_crs_code=%2 ORDER BY deprecated ASC,preferred DESC"_s.arg( destAuthCode ).arg( srcAuthCode ),
103 reverseDirectTransforms );
104 QList<int> srcToWgs84;
105 searchDatumTransform( u
"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"_s.arg( srcAuthCode ).arg( 4326 ),
107 QList<int> destToWgs84;
108 searchDatumTransform( u
"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"_s.arg( destAuthCode ).arg( 4326 ),
112 for (
int transform : std::as_const( directTransforms ) )
118 for (
int transform : std::as_const( reverseDirectTransforms ) )
123 for (
int srcTransform : std::as_const( srcToWgs84 ) )
125 for (
int destTransform : std::as_const( destToWgs84 ) )
131 return transformations;
134void QgsDatumTransform::searchDatumTransform(
const QString &sql, QList< int > &transforms )
138 if ( openResult != SQLITE_OK )
143 sqlite3_statement_unique_ptr statement;
145 statement = database.
prepare( sql, prepareRes );
146 if ( prepareRes != SQLITE_OK )
152 while ( statement.
step() == SQLITE_ROW )
155 transforms.push_back( cOpCode.toInt() );
161 QString transformString;
165 if ( openResult != SQLITE_OK )
167 return transformString;
171 QString sql = u
"SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7 FROM tbl_datum_transform WHERE coord_op_code=%1"_s.arg( datumTransform );
173 statement = database.
prepare( sql, prepareRes );
174 if ( prepareRes != SQLITE_OK )
176 return transformString;
179 if ( statement.
step() == SQLITE_ROW )
183 if ( methodCode == 9615 )
185 transformString =
"+nadgrids=" + statement.
columnAsText( 1 );
187 else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
189 transformString +=
"+towgs84="_L1;
197 if ( methodCode == 9603 )
199 transformString += u
"%1,%2,%3"_s.arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
203 transformString += u
"%1,%2,%3,%4,%5,%6,%7"_s.arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ), QString::number( p4 ), QString::number( p5 ), QString::number( p6 ), QString::number( p7 ) );
208 return transformString;
215 if ( openResult != SQLITE_OK )
221 QString sql = u
"SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7,coord_op_code FROM tbl_datum_transform"_s;
223 statement = database.
prepare( sql, prepareRes );
224 if ( prepareRes != SQLITE_OK )
229 while ( statement.
step() == SQLITE_ROW )
231 QString transformString;
234 if ( methodCode == 9615 )
236 transformString =
"+nadgrids=" + statement.
columnAsText( 1 );
238 else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
240 transformString +=
"+towgs84="_L1;
248 if ( methodCode == 9603 )
250 transformString += u
"%1,%2,%3"_s.arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
254 transformString += u
"%1,%2,%3,%4,%5,%6,%7"_s.arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ), QString::number( p4 ), QString::number( p5 ), QString::number( p6 ), QString::number( p7 ) );
258 if ( transformString.compare(
string, Qt::CaseInsensitive ) == 0 )
273 if ( openResult != SQLITE_OK )
279 QString sql = u
"SELECT epsg_nr,source_crs_code,target_crs_code,remarks,scope,preferred,deprecated FROM tbl_datum_transform WHERE coord_op_code=%1"_s.arg( datumTransform );
281 statement = database.
prepare( sql, prepareRes );
282 if ( prepareRes != SQLITE_OK )
287 int srcCrsId, destCrsId;
288 if ( statement.
step() != SQLITE_ROW )
321 details.
proj = QString( proj_as_proj_string( pjContext, normalized.get(), PJ_PROJ_5,
nullptr ) );
323 if ( details.
proj.isEmpty() )
324 details.
proj = QString( proj_as_proj_string( pjContext, op, PJ_PROJ_5,
nullptr ) );
326 if ( details.
proj.isEmpty() )
329 details.
name = QString( proj_get_name( op ) );
330 details.
accuracy = proj_coordoperation_get_accuracy( pjContext, op );
331 details.
isAvailable = proj_coordoperation_is_instantiable( pjContext, op );
333 details.
authority = QString( proj_get_id_auth_name( op, 0 ) );
334 details.
code = QString( proj_get_id_code( op, 0 ) );
336 const char *areaOfUseName =
nullptr;
341 if ( proj_get_area_of_use( pjContext, op, &westLon, &southLat, &eastLon, &northLat, &areaOfUseName ) )
343 details.
areaOfUse = QString( areaOfUseName );
351 details.
remarks = QString( proj_get_remarks( op ) );
352 details.
scope = QString( proj_get_scope( op ) );
354 for (
int j = 0; j < proj_coordoperation_get_grid_used_count( pjContext, op ); ++j )
356 const char *shortName =
nullptr;
357 const char *fullName =
nullptr;
358 const char *packageName =
nullptr;
359 const char *url =
nullptr;
360 int directDownload = 0;
363 proj_coordoperation_get_grid_used( pjContext, op, j, &shortName, &fullName, &packageName, &url, &directDownload, &openLicense, &isAvailable );
365 gridDetails.
shortName = QString( shortName );
366 gridDetails.
fullName = QString( fullName );
368 gridDetails.
url = QString( url );
373 details.
grids.append( gridDetails );
376 if ( proj_get_type( op ) == PJ_TYPE_CONCATENATED_OPERATION )
378 for (
int j = 0; j < proj_concatoperation_get_step_count( pjContext, op ); ++j )
384 singleOpDetails.
remarks = QString( proj_get_remarks( step.get() ) );
385 singleOpDetails.
scope = QString( proj_get_scope( step.get() ) );
386 singleOpDetails.
authority = QString( proj_get_id_auth_name( step.get(), 0 ) );
387 singleOpDetails.
code = QString( proj_get_id_code( step.get(), 0 ) );
389 const char *areaOfUseName =
nullptr;
390 if ( proj_get_area_of_use( pjContext, step.get(),
nullptr,
nullptr,
nullptr,
nullptr, &areaOfUseName ) )
392 singleOpDetails.
areaOfUse = QString( areaOfUseName );
401 singleOpDetails.
remarks = QString( proj_get_remarks( op ) );
402 singleOpDetails.
scope = QString( proj_get_scope( op ) );
403 singleOpDetails.
authority = QString( proj_get_id_auth_name( op, 0 ) );
404 singleOpDetails.
code = QString( proj_get_id_code( op, 0 ) );
406 const char *areaOfUseName =
nullptr;
407 if ( proj_get_area_of_use( pjContext, op,
nullptr,
nullptr,
nullptr,
nullptr, &areaOfUseName ) )
409 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).