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 );
63 proj_list_destroy( ops );
65 proj_operation_factory_context_destroy( operationContext );
71 QList< QgsDatumTransform::TransformPair > transformations;
76 if ( srcGeoId.isEmpty() || destGeoId.isEmpty() )
78 return transformations;
81 QStringList srcSplit = srcGeoId.split(
':' );
82 QStringList destSplit = destGeoId.split(
':' );
84 if ( srcSplit.size() < 2 || destSplit.size() < 2 )
86 return transformations;
89 int srcAuthCode = srcSplit.at( 1 ).toInt();
90 int destAuthCode = destSplit.at( 1 ).toInt();
92 if ( srcAuthCode == destAuthCode )
94 return transformations;
97 QList<int> directTransforms;
98 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 ), directTransforms );
99 QList<int> reverseDirectTransforms;
100 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 ), reverseDirectTransforms );
101 QList<int> srcToWgs84;
102 searchDatumTransform(
103 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
108 QList<int> destToWgs84;
109 searchDatumTransform(
110 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
117 for (
int transform : std::as_const( directTransforms ) )
123 for (
int transform : std::as_const( reverseDirectTransforms ) )
128 for (
int srcTransform : std::as_const( srcToWgs84 ) )
130 for (
int destTransform : std::as_const( destToWgs84 ) )
136 return transformations;
139void QgsDatumTransform::searchDatumTransform(
const QString &sql, QList< int > &transforms )
143 if ( openResult != SQLITE_OK )
148 sqlite3_statement_unique_ptr statement;
150 statement = database.
prepare( sql, prepareRes );
151 if ( prepareRes != SQLITE_OK )
157 while ( statement.
step() == SQLITE_ROW )
160 transforms.push_back( cOpCode.toInt() );
166 QString transformString;
170 if ( openResult != SQLITE_OK )
172 return transformString;
176 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 );
178 statement = database.
prepare( sql, prepareRes );
179 if ( prepareRes != SQLITE_OK )
181 return transformString;
184 if ( statement.
step() == SQLITE_ROW )
188 if ( methodCode == 9615 )
190 transformString =
"+nadgrids=" + statement.
columnAsText( 1 );
192 else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
194 transformString +=
"+towgs84="_L1;
202 if ( methodCode == 9603 )
204 transformString += u
"%1,%2,%3"_s.arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
209 += 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 ) );
214 return transformString;
221 if ( openResult != SQLITE_OK )
227 QString sql = u
"SELECT coord_op_method_code,p1,p2,p3,p4,p5,p6,p7,coord_op_code FROM tbl_datum_transform"_s;
229 statement = database.
prepare( sql, prepareRes );
230 if ( prepareRes != SQLITE_OK )
235 while ( statement.
step() == SQLITE_ROW )
237 QString transformString;
240 if ( methodCode == 9615 )
242 transformString =
"+nadgrids=" + statement.
columnAsText( 1 );
244 else if ( methodCode == 9603 || methodCode == 9606 || methodCode == 9607 )
246 transformString +=
"+towgs84="_L1;
254 if ( methodCode == 9603 )
256 transformString += u
"%1,%2,%3"_s.arg( QString::number( p1 ), QString::number( p2 ), QString::number( p3 ) );
261 += 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 ) );
265 if ( transformString.compare(
string, Qt::CaseInsensitive ) == 0 )
280 if ( openResult != SQLITE_OK )
286 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 );
288 statement = database.
prepare( sql, prepareRes );
289 if ( prepareRes != SQLITE_OK )
294 int srcCrsId, destCrsId;
295 if ( statement.
step() != SQLITE_ROW )
328 details.
proj = QString( proj_as_proj_string( pjContext, normalized.get(), PJ_PROJ_5,
nullptr ) );
330 if ( details.
proj.isEmpty() )
331 details.
proj = QString( proj_as_proj_string( pjContext, op, PJ_PROJ_5,
nullptr ) );
333 if ( details.
proj.isEmpty() )
336 details.
name = QString( proj_get_name( op ) );
337 details.
accuracy = proj_coordoperation_get_accuracy( pjContext, op );
338 details.
isAvailable = proj_coordoperation_is_instantiable( pjContext, op );
340 details.
authority = QString( proj_get_id_auth_name( op, 0 ) );
341 details.
code = QString( proj_get_id_code( op, 0 ) );
343 const char *areaOfUseName =
nullptr;
348 if ( proj_get_area_of_use( pjContext, op, &westLon, &southLat, &eastLon, &northLat, &areaOfUseName ) )
350 details.
areaOfUse = QString( areaOfUseName );
358 details.
remarks = QString( proj_get_remarks( op ) );
359 details.
scope = QString( proj_get_scope( op ) );
361 for (
int j = 0; j < proj_coordoperation_get_grid_used_count( pjContext, op ); ++j )
363 const char *shortName =
nullptr;
364 const char *fullName =
nullptr;
365 const char *packageName =
nullptr;
366 const char *url =
nullptr;
367 int directDownload = 0;
370 proj_coordoperation_get_grid_used( pjContext, op, j, &shortName, &fullName, &packageName, &url, &directDownload, &openLicense, &isAvailable );
372 gridDetails.
shortName = QString( shortName );
373 gridDetails.
fullName = QString( fullName );
375 gridDetails.
url = QString( url );
380 details.
grids.append( gridDetails );
383 if ( proj_get_type( op ) == PJ_TYPE_CONCATENATED_OPERATION )
385 for (
int j = 0; j < proj_concatoperation_get_step_count( pjContext, op ); ++j )
391 singleOpDetails.
remarks = QString( proj_get_remarks( step.get() ) );
392 singleOpDetails.
scope = QString( proj_get_scope( step.get() ) );
393 singleOpDetails.
authority = QString( proj_get_id_auth_name( step.get(), 0 ) );
394 singleOpDetails.
code = QString( proj_get_id_code( step.get(), 0 ) );
396 const char *areaOfUseName =
nullptr;
397 if ( proj_get_area_of_use( pjContext, step.get(),
nullptr,
nullptr,
nullptr,
nullptr, &areaOfUseName ) )
399 singleOpDetails.
areaOfUse = QString( areaOfUseName );
408 singleOpDetails.
remarks = QString( proj_get_remarks( op ) );
409 singleOpDetails.
scope = QString( proj_get_scope( op ) );
410 singleOpDetails.
authority = QString( proj_get_id_auth_name( op, 0 ) );
411 singleOpDetails.
code = QString( proj_get_id_code( op, 0 ) );
413 const char *areaOfUseName =
nullptr;
414 if ( proj_get_area_of_use( pjContext, op,
nullptr,
nullptr,
nullptr,
nullptr, &areaOfUseName ) )
416 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).