31#include <QRegularExpression>
51#include <proj_experimental.h>
54#include <ogr_srs_api.h>
66bool QgsCoordinateReferenceSystem::sDisableSrIdCache =
false;
70bool QgsCoordinateReferenceSystem::sDisableOgcCache =
false;
74bool QgsCoordinateReferenceSystem::sDisableProjCache =
false;
78bool QgsCoordinateReferenceSystem::sDisableWktCache =
false;
82bool QgsCoordinateReferenceSystem::sDisableSrsIdCache =
false;
86bool QgsCoordinateReferenceSystem::sDisableStringCache =
false;
95 if (
const char *proj4src = proj_as_proj_string(
QgsProjContext::get(), boundCrs.get(), PJ_PROJ_4,
nullptr ) )
97 return QString( proj4src );
114 d =
new QgsCoordinateReferenceSystemPrivate();
120 d =
new QgsCoordinateReferenceSystemPrivate();
128 , mValidationHint( srs.mValidationHint )
129 , mNativeFormat( srs.mNativeFormat )
136 mValidationHint = srs.mValidationHint;
137 mNativeFormat = srs.mNativeFormat;
147 const auto constDbs = dbs;
148 for (
const QString &db : constDbs )
150 QFileInfo myInfo( db );
151 if ( !myInfo.exists() )
161 int result = openDatabase( db, database );
162 if ( result != SQLITE_OK )
168 QString sql = QStringLiteral(
"select srs_id from tbl_srs" );
170 statement = database.
prepare( sql, rc );
174 int ret = statement.
step();
176 if ( ret == SQLITE_DONE )
182 if ( ret == SQLITE_ROW )
188 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
193 std::sort( results.begin(), results.end() );
266 QgsDebugError( QStringLiteral(
"Unexpected case reached!" ) );
273 if ( definition.isEmpty() )
277 if ( !sDisableStringCache )
279 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sStringCache()->constFind( definition );
280 if ( crsIt != sStringCache()->constEnd() )
283 *
this = crsIt.value();
290 const thread_local QRegularExpression reCrsId( QStringLiteral(
"^(epsg|esri|osgeo|ignf|ogc|nkg|zangi|iau_2015|iau2000|postgis|internal|user)\\:(\\w+)$" ), QRegularExpression::CaseInsensitiveOption );
291 QRegularExpressionMatch match = reCrsId.match( definition );
292 if ( match.capturedStart() == 0 )
294 QString authName = match.captured( 1 ).toLower();
295 if ( authName == QLatin1String(
"epsg" ) )
299 else if ( authName == QLatin1String(
"postgis" ) )
301 const long id = match.captured( 2 ).toLong();
306 else if ( authName == QLatin1String(
"esri" )
307 || authName == QLatin1String(
"osgeo" )
308 || authName == QLatin1String(
"ignf" )
309 || authName == QLatin1String(
"zangi" )
310 || authName == QLatin1String(
"iau2000" )
311 || authName == QLatin1String(
"ogc" )
312 || authName == QLatin1String(
"nkg" )
313 || authName == QLatin1String(
"iau_2015" )
320 const long id = match.captured( 2 ).toLong();
328 const thread_local QRegularExpression reCrsStr( QStringLiteral(
"^(?:(wkt|proj4|proj)\\:)?(.+)$" ), QRegularExpression::CaseInsensitiveOption );
329 match = reCrsStr.match( definition );
330 if ( match.capturedStart() == 0 )
332 if ( match.captured( 1 ).startsWith( QLatin1String(
"proj" ), Qt::CaseInsensitive ) )
344 if ( !sDisableStringCache )
345 sStringCache()->insert( definition, *
this );
351 if ( definition.isEmpty() )
357 if ( OSRSetFromUserInput(
crs, definition.toLocal8Bit().constData() ) == OGRERR_NONE )
360 OSRDestroySpatialReference(
crs );
370 const char *configOld = CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" );
371 const char *configNew =
"GEOGCS";
373 if ( strcmp( configOld,
"" ) == 0 )
375 CPLSetConfigOption(
"GDAL_FIX_ESRI_WKT", configNew );
376 if ( strcmp( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) != 0 )
378 .arg( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) );
379 QgsDebugMsgLevel( QStringLiteral(
"set GDAL_FIX_ESRI_WKT : %1" ).arg( configNew ), 4 );
383 QgsDebugMsgLevel( QStringLiteral(
"GDAL_FIX_ESRI_WKT was already set : %1" ).arg( configNew ), 4 );
393 if ( !sDisableOgcCache )
395 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sOgcCache()->constFind(
crs );
396 if ( crsIt != sOgcCache()->constEnd() )
399 *
this = crsIt.value();
405 QString wmsCrs =
crs;
410 const QString authorityLower = authority.toLower();
412 ( authorityLower == QLatin1String(
"user" ) ||
413 authorityLower == QLatin1String(
"custom" ) ||
414 authorityLower == QLatin1String(
"qgis" ) ) )
419 if ( !sDisableOgcCache )
420 sOgcCache()->insert(
crs, *
this );
426 wmsCrs = authority +
':' + code;
430 const QString legacyKey = wmsCrs.toLower();
433 if ( it.key().compare( legacyKey, Qt::CaseInsensitive ) == 0 )
435 const QStringList parts = it.key().split(
':' );
436 const QString auth = parts.at( 0 );
437 const QString code = parts.at( 1 );
438 if ( loadFromAuthCode( auth, code ) )
441 if ( !sDisableOgcCache )
442 sOgcCache()->insert(
crs, *
this );
451 if ( !sDisableOgcCache )
452 sOgcCache()->insert(
crs, *
this );
457 if ( wmsCrs.compare( QLatin1String(
"CRS:27" ), Qt::CaseInsensitive ) == 0 ||
458 wmsCrs.compare( QLatin1String(
"OGC:CRS27" ), Qt::CaseInsensitive ) == 0 )
465 if ( wmsCrs.compare( QLatin1String(
"CRS:83" ), Qt::CaseInsensitive ) == 0 ||
466 wmsCrs.compare( QLatin1String(
"OGC:CRS83" ), Qt::CaseInsensitive ) == 0 )
473 if ( wmsCrs.compare( QLatin1String(
"CRS:84" ), Qt::CaseInsensitive ) == 0 ||
474 wmsCrs.compare( QLatin1String(
"OGC:CRS84" ), Qt::CaseInsensitive ) == 0 )
478 d->mAxisInverted =
false;
479 d->mAxisInvertedDirty =
false;
483 if ( !sDisableOgcCache )
484 sOgcCache()->insert(
crs, *
this );
491 if ( !authority.isEmpty() && !code.isEmpty() && loadFromAuthCode( authority, code ) )
494 if ( !sDisableOgcCache )
495 sOgcCache()->insert(
crs, *
this );
500 if ( !sDisableOgcCache )
510 if ( d->mIsValid || !sCustomSrsValidation )
514 if ( sCustomSrsValidation )
515 sCustomSrsValidation( *
this );
521 if ( !sDisableSrIdCache )
523 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrIdCache()->constFind(
id );
524 if ( crsIt != sSrIdCache()->constEnd() )
527 *
this = crsIt.value();
536 if ( it.value().endsWith( QStringLiteral(
",%1" ).arg(
id ) ) )
538 const QStringList parts = it.key().split(
':' );
539 const QString auth = parts.at( 0 );
540 const QString code = parts.at( 1 );
541 if ( loadFromAuthCode( auth, code ) )
544 if ( !sDisableSrIdCache )
545 sSrIdCache()->insert(
id, *
this );
555 if ( !sDisableSrIdCache )
556 sSrIdCache()->insert(
id, *
this );
564 if ( !sDisableSrsIdCache )
566 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrsIdCache()->constFind(
id );
567 if ( crsIt != sSrsIdCache()->constEnd() )
570 *
this = crsIt.value();
579 if ( it.value().startsWith( QString::number(
id ) +
',' ) )
581 const QStringList parts = it.key().split(
':' );
582 const QString auth = parts.at( 0 );
583 const QString code = parts.at( 1 );
584 if ( loadFromAuthCode( auth, code ) )
587 if ( !sDisableSrsIdCache )
588 sSrsIdCache()->insert(
id, *
this );
596 QStringLiteral(
"srs_id" ), QString::number(
id ) );
599 if ( !sDisableSrsIdCache )
600 sSrsIdCache()->insert(
id, *
this );
604bool QgsCoordinateReferenceSystem::loadFromDatabase(
const QString &db,
const QString &expression,
const QString &value )
608 QgsDebugMsgLevel(
"load CRS from " + db +
" where " + expression +
" is " + value, 3 );
610 d->mWktPreferred.clear();
612 QFileInfo myInfo( db );
613 if ( !myInfo.exists() )
623 myResult = openDatabase( db, database );
624 if ( myResult != SQLITE_OK )
641 QString mySql =
"select srs_id,description,projection_acronym,"
642 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo,wkt "
644 statement = database.
prepare( mySql, myResult );
647 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
652 d->mEllipsoidAcronym.clear();
654 d->mWktPreferred.clear();
657 d->mIsGeographic = statement.
columnAsText( 7 ).toInt() != 0;
659 d->mAxisInvertedDirty =
true;
661 if ( d->mSrsId >=
USER_CRS_START_ID && ( d->mAuthId.isEmpty() || d->mAuthId == QChar(
':' ) ) )
663 d->mAuthId = QStringLiteral(
"USER:%1" ).arg( d->mSrsId );
665 else if ( !d->mAuthId.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive ) )
667 QStringList parts = d->mAuthId.split(
':' );
668 QString auth = parts.at( 0 );
669 QString code = parts.at( 1 );
676 d->mIsValid = d->hasPj();
682 if ( !wkt.isEmpty() )
690 setProjString( d->mProj4 );
700void QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread(
PJ_CONTEXT *pj_context )
707 if ( !sDisableSrIdCache )
710 if ( !sDisableSrIdCache )
712 for (
auto it = sSrIdCache()->begin(); it != sSrIdCache()->end(); )
714 auto &v = it.value();
715 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
716 it = sSrIdCache()->erase( it );
722 if ( !sDisableOgcCache )
725 if ( !sDisableOgcCache )
727 for (
auto it = sOgcCache()->begin(); it != sOgcCache()->end(); )
729 auto &v = it.value();
730 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
731 it = sOgcCache()->erase( it );
737 if ( !sDisableProjCache )
740 if ( !sDisableProjCache )
742 for (
auto it = sProj4Cache()->begin(); it != sProj4Cache()->end(); )
744 auto &v = it.value();
745 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
746 it = sProj4Cache()->erase( it );
752 if ( !sDisableWktCache )
755 if ( !sDisableWktCache )
757 for (
auto it = sWktCache()->begin(); it != sWktCache()->end(); )
759 auto &v = it.value();
760 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
761 it = sWktCache()->erase( it );
767 if ( !sDisableSrsIdCache )
770 if ( !sDisableSrsIdCache )
772 for (
auto it = sSrsIdCache()->begin(); it != sSrsIdCache()->end(); )
774 auto &v = it.value();
775 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
776 it = sSrsIdCache()->erase( it );
782 if ( !sDisableStringCache )
785 if ( !sDisableStringCache )
787 for (
auto it = sStringCache()->begin(); it != sStringCache()->end(); )
789 auto &v = it.value();
790 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
791 it = sStringCache()->erase( it );
801 if ( d->mAxisInvertedDirty )
804 d->mAxisInvertedDirty =
false;
807 return d->mAxisInverted;
821 const thread_local QMap< Qgis::CrsAxisDirection, QString > mapping =
864 QList< Qgis::CrsAxisDirection > res;
865 const int axisCount = proj_cs_get_axis_count( context, pjCs.get() );
868 res.reserve( axisCount );
870 for (
int i = 0; i < axisCount; ++i )
872 const char *outDirection =
nullptr;
873 proj_cs_get_axis_info( context, pjCs.get(), i,
883 const thread_local QRegularExpression rx( QStringLiteral(
"([^\\s]+).*" ) );
884 const QRegularExpressionMatch match = rx.match( QString( outDirection ) );
885 if ( !match.hasMatch() )
888 const QString direction = match.captured( 1 );
890 for (
auto it = mapping.constBegin(); it != mapping.constEnd(); ++it )
892 if ( it.value().compare( direction, Qt::CaseInsensitive ) == 0 )
907 return createFromWktInternal( wkt, QString() );
910bool QgsCoordinateReferenceSystem::createFromWktInternal(
const QString &wkt,
const QString &description )
918 if ( !sDisableWktCache )
920 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sWktCache()->constFind( wkt );
921 if ( crsIt != sWktCache()->constEnd() )
924 *
this = crsIt.value();
926 if ( !
description.isEmpty() && d->mDescription.isEmpty() )
931 sWktCache()->insert( wkt, *
this );
940 d->mWktPreferred.clear();
943 QgsDebugMsgLevel( QStringLiteral(
"theWkt is uninitialized, operation failed" ), 4 );
948 QgsCoordinateReferenceSystem::RecordMap record = getRecord(
"select * from tbl_srs where wkt=" +
QgsSqliteUtils::quotedString( wkt ) +
" order by deprecated" );
949 if ( !record.empty() )
951 long srsId = record[QStringLiteral(
"srs_id" )].toLong();
964 if ( d->mSrsId == 0 )
967 long id = matchToUserCrs();
976 if ( !sDisableWktCache )
977 sWktCache()->insert( wkt, *
this );
995 if ( projString.isEmpty() )
1000 if ( projString.trimmed().isEmpty() )
1002 d->mIsValid =
false;
1004 d->mWktPreferred.clear();
1009 if ( !sDisableProjCache )
1011 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sProj4Cache()->constFind( projString );
1012 if ( crsIt != sProj4Cache()->constEnd() )
1015 *
this = crsIt.value();
1029 QString myProj4String = projString.trimmed();
1030 myProj4String.remove( QStringLiteral(
"+type=crs" ) );
1031 myProj4String = myProj4String.trimmed();
1033 d->mIsValid =
false;
1034 d->mWktPreferred.clear();
1039 const QString projCrsString = myProj4String + ( myProj4String.contains( QStringLiteral(
"+type=crs" ) ) ? QString() : QStringLiteral(
" +type=crs" ) );
1047 const QString
authid = QStringLiteral(
"%1:%2" ).arg( authName, authCode );
1051 if ( !sDisableProjCache )
1052 sProj4Cache()->insert( projString, *
this );
1059 QgsCoordinateReferenceSystem::RecordMap myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
1061 if ( !myRecord.empty() )
1063 id = myRecord[QStringLiteral(
"srs_id" )].toLong();
1072 setProjString( myProj4String );
1075 id = matchToUserCrs();
1084 setProjString( myProj4String );
1088 if ( !sDisableProjCache )
1089 sProj4Cache()->insert( projString, *
this );
1095QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord(
const QString &sql )
1097 QString myDatabaseFileName;
1098 QgsCoordinateReferenceSystem::RecordMap myMap;
1099 QString myFieldName;
1100 QString myFieldValue;
1107 QFileInfo myInfo( myDatabaseFileName );
1108 if ( !myInfo.exists() )
1110 QgsDebugError(
"failed : " + myDatabaseFileName +
" does not exist!" );
1115 myResult = openDatabase( myDatabaseFileName, database );
1116 if ( myResult != SQLITE_OK )
1121 statement = database.
prepare( sql, myResult );
1123 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1127 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1129 myFieldName = statement.
columnName( myColNo );
1131 myMap[myFieldName] = myFieldValue;
1133 if ( statement.
step() != SQLITE_DONE )
1135 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1144 if ( myMap.empty() )
1147 QFileInfo myFileInfo;
1148 myFileInfo.setFile( myDatabaseFileName );
1149 if ( !myFileInfo.exists() )
1151 QgsDebugError( QStringLiteral(
"user qgis.db not found" ) );
1156 myResult = openDatabase( myDatabaseFileName, database );
1157 if ( myResult != SQLITE_OK )
1162 statement = database.
prepare( sql, myResult );
1164 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1168 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1170 myFieldName = statement.
columnName( myColNo );
1172 myMap[myFieldName] = myFieldValue;
1175 if ( statement.
step() != SQLITE_DONE )
1177 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1208 if ( d->mDescription.isNull() )
1214 return d->mDescription;
1221 if ( !
authid().isEmpty() )
1231 id =
isValid() ? QObject::tr(
"Custom CRS" ) : QObject::tr(
"Unknown CRS" );
1233 id = QObject::tr(
"Custom CRS: %1" ).arg(
1236 else if ( !
toProj().isEmpty() )
1239 if ( !
id.isEmpty() && !std::isnan( d->mCoordinateEpoch ) )
1240 id += QStringLiteral(
" @ %1" ).arg( d->mCoordinateEpoch );
1247 if ( d->mProjectionAcronym.isNull() )
1253 return d->mProjectionAcronym;
1259 if ( d->mEllipsoidAcronym.isNull() )
1261 if (
PJ *obj = d->threadLocalProjObject() )
1266 const QString ellipsoidAuthName( proj_get_id_auth_name( ellipsoid.get(), 0 ) );
1267 const QString ellipsoidAuthCode( proj_get_id_code( ellipsoid.get(), 0 ) );
1268 if ( !ellipsoidAuthName.isEmpty() && !ellipsoidAuthCode.isEmpty() )
1269 d->mEllipsoidAcronym = QStringLiteral(
"%1:%2" ).arg( ellipsoidAuthName, ellipsoidAuthCode );
1272 double semiMajor, semiMinor, invFlattening;
1273 int semiMinorComputed = 0;
1274 if ( proj_ellipsoid_get_parameters(
QgsProjContext::get(), ellipsoid.get(), &semiMajor, &semiMinor, &semiMinorComputed, &invFlattening ) )
1276 d->mEllipsoidAcronym = QStringLiteral(
"PARAMETER:%1:%2" ).arg(
qgsDoubleToString( semiMajor ),
1281 d->mEllipsoidAcronym.clear();
1286 return d->mEllipsoidAcronym;
1290 return d->mEllipsoidAcronym;
1304 if ( d->mProj4.isEmpty() )
1306 if (
PJ *obj = d->threadLocalProjObject() )
1312 return d->mProj4.trimmed();
1318 switch ( d->mProjType )
1320 case PJ_TYPE_UNKNOWN:
1323 case PJ_TYPE_ELLIPSOID:
1324 case PJ_TYPE_PRIME_MERIDIAN:
1325 case PJ_TYPE_GEODETIC_REFERENCE_FRAME:
1326 case PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME:
1327 case PJ_TYPE_VERTICAL_REFERENCE_FRAME:
1328 case PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME:
1329 case PJ_TYPE_DATUM_ENSEMBLE:
1330 case PJ_TYPE_CONVERSION:
1331 case PJ_TYPE_TRANSFORMATION:
1332 case PJ_TYPE_CONCATENATED_OPERATION:
1333 case PJ_TYPE_OTHER_COORDINATE_OPERATION:
1334 case PJ_TYPE_TEMPORAL_DATUM:
1335 case PJ_TYPE_ENGINEERING_DATUM:
1336 case PJ_TYPE_PARAMETRIC_DATUM:
1340 case PJ_TYPE_GEOGRAPHIC_CRS:
1344 case PJ_TYPE_GEODETIC_CRS:
1346 case PJ_TYPE_GEOCENTRIC_CRS:
1348 case PJ_TYPE_GEOGRAPHIC_2D_CRS:
1350 case PJ_TYPE_GEOGRAPHIC_3D_CRS:
1352 case PJ_TYPE_VERTICAL_CRS:
1354 case PJ_TYPE_PROJECTED_CRS:
1356 case PJ_TYPE_COMPOUND_CRS:
1358 case PJ_TYPE_TEMPORAL_CRS:
1360 case PJ_TYPE_ENGINEERING_CRS:
1362 case PJ_TYPE_BOUND_CRS:
1364 case PJ_TYPE_OTHER_CRS:
1366#if PROJ_VERSION_MAJOR>9 || (PROJ_VERSION_MAJOR==9 && PROJ_VERSION_MINOR>=2)
1367 case PJ_TYPE_DERIVED_PROJECTED_CRS:
1369 case PJ_TYPE_COORDINATE_METADATA:
1383 return proj_is_deprecated( pj );
1388 return d->mIsGeographic;
1406#if PROJ_VERSION_MAJOR>8 || (PROJ_VERSION_MAJOR==8 && PROJ_VERSION_MINOR>=1)
1409 return QString( proj_get_celestial_body_name( context, pj ) );
1411 throw QgsNotSupportedException( QObject::tr(
"Retrieving celestial body requires a QGIS build based on PROJ 8.1 or later" ) );
1417 if ( d->mCoordinateEpoch == epoch )
1423 d->mCoordinateEpoch = epoch;
1424 d->setPj( std::move( clone ) );
1429 return d->mCoordinateEpoch;
1441#if PROJ_VERSION_MAJOR>=8
1449 res.mName = QString( proj_get_name( ensemble.get() ) );
1450 res.mAuthority = QString( proj_get_id_auth_name( ensemble.get(), 0 ) );
1451 res.mCode = QString( proj_get_id_code( ensemble.get(), 0 ) );
1452 res.mRemarks = QString( proj_get_remarks( ensemble.get() ) );
1453 res.mScope = QString( proj_get_scope( ensemble.get() ) );
1454 res.mAccuracy = proj_datum_ensemble_get_accuracy( context, ensemble.get() );
1456 const int memberCount = proj_datum_ensemble_get_member_count( context, ensemble.get() );
1457 for (
int i = 0; i < memberCount; ++i )
1464 details.mName = QString( proj_get_name( member.get() ) );
1465 details.mAuthority = QString( proj_get_id_auth_name( member.get(), 0 ) );
1466 details.mCode = QString( proj_get_id_code( member.get(), 0 ) );
1467 details.mRemarks = QString( proj_get_remarks( member.get() ) );
1468 details.mScope = QString( proj_get_scope( member.get() ) );
1470 res.mMembers << details;
1474 throw QgsNotSupportedException( QObject::tr(
"Calculating datum ensembles requires a QGIS build based on PROJ 8.0 or later" ) );
1483 QString projString =
toProj();
1484 projString.replace( QLatin1String(
"+type=crs" ), QString() );
1487 if ( !transformation )
1490 PJ_COORD coord = proj_coord( 0, 0, 0, HUGE_VAL );
1491 coord.uv.u = point.
x() * M_PI / 180.0;
1492 coord.uv.v = point.
y() * M_PI / 180.0;
1494 proj_errno_reset( transformation.get() );
1495 const PJ_FACTORS pjFactors = proj_factors( transformation.get(), coord );
1496 if ( proj_errno( transformation.get() ) )
1501 res.mIsValid =
true;
1502 res.mMeridionalScale = pjFactors.meridional_scale;
1503 res.mParallelScale = pjFactors.parallel_scale;
1504 res.mArealScale = pjFactors.areal_scale;
1505 res.mAngularDistortion = pjFactors.angular_distortion;
1506 res.mMeridianParallelAngle = pjFactors.meridian_parallel_angle * 180 / M_PI;
1507 res.mMeridianConvergence = pjFactors.meridian_convergence * 180 / M_PI;
1508 res.mTissotSemimajor = pjFactors.tissot_semimajor;
1509 res.mTissotSemiminor = pjFactors.tissot_semiminor;
1510 res.mDxDlam = pjFactors.dx_dlam;
1511 res.mDxDphi = pjFactors.dx_dphi;
1512 res.mDyDlam = pjFactors.dy_dlam;
1513 res.mDyDphi = pjFactors.dy_dphi;
1525 QString projString =
toProj();
1526 projString.replace( QLatin1String(
"+type=crs" ), QString() );
1527 if ( projString.isEmpty() )
1531 if ( !transformation )
1534 PJ_PROJ_INFO info = proj_pj_info( transformation.get() );
1549 return d->mMapUnits;
1557 PJ *obj = d->threadLocalProjObject();
1562 double southLat = 0;
1564 double northLat = 0;
1567 &westLon, &southLat, &eastLon, &northLat,
nullptr ) )
1582 const auto parts {
authid().split(
':' ) };
1583 if ( parts.length() == 2 )
1585 if ( parts[0] == QLatin1String(
"EPSG" ) )
1586 return QStringLiteral(
"http://www.opengis.net/def/crs/EPSG/0/%1" ).arg( parts[1] ) ;
1587 else if ( parts[0] == QLatin1String(
"OGC" ) )
1589 return QStringLiteral(
"http://www.opengis.net/def/crs/OGC/1.3/%1" ).arg( parts[1] ) ;
1619void QgsCoordinateReferenceSystem::setProjString(
const QString &proj4String )
1622 d->mProj4 = proj4String;
1623 d->mWktPreferred.clear();
1626 QString trimmed = proj4String.trimmed();
1628 trimmed += QLatin1String(
" +type=crs" );
1638 const int errNo = proj_context_errno( ctx );
1639 QgsDebugError( QStringLiteral(
"proj string rejected: %1" ).arg( proj_errno_string( errNo ) ) );
1641 d->mIsValid =
false;
1645 d->mEllipsoidAcronym.clear();
1652bool QgsCoordinateReferenceSystem::setWktString(
const QString &wkt )
1655 d->mIsValid =
false;
1656 d->mWktPreferred.clear();
1658 PROJ_STRING_LIST warnings =
nullptr;
1659 PROJ_STRING_LIST grammerErrors =
nullptr;
1667 QgsDebugMsgLevel( QStringLiteral(
"\n---------------------------------------------------------------" ), 2 );
1668 QgsDebugMsgLevel( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ), 2 );
1670 for (
auto iter = warnings; iter && *iter; ++iter )
1672 for (
auto iter = grammerErrors; iter && *iter; ++iter )
1674 QgsDebugMsgLevel( QStringLiteral(
"---------------------------------------------------------------\n" ), 2 );
1676 proj_string_list_destroy( warnings );
1677 proj_string_list_destroy( grammerErrors );
1683 if ( !sDisableWktCache )
1684 sWktCache()->insert( wkt, *
this );
1691 QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
1692 QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
1694 if ( authName.isEmpty() || authCode.isEmpty() )
1700 if ( !authName.isEmpty() && !authCode.isEmpty() )
1702 if ( loadFromAuthCode( authName, authCode ) )
1705 if ( !sDisableWktCache )
1706 sWktCache()->insert( wkt, *
this );
1714 d->mDescription = QString( proj_get_name( d->threadLocalProjObject() ) );
1722void QgsCoordinateReferenceSystem::setMapUnits()
1749 if ( !coordinateSystem )
1755 const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
1756 if ( axisCount > 0 )
1758 const char *outUnitName =
nullptr;
1760 proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
1769 const QString unitName( outUnitName );
1773 if ( unitName.compare( QLatin1String(
"degree" ), Qt::CaseInsensitive ) == 0 ||
1774 unitName.compare( QLatin1String(
"degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1775 unitName.compare( QLatin1String(
"degree minute second hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1776 unitName.compare( QLatin1String(
"degree minute" ), Qt::CaseInsensitive ) == 0 ||
1777 unitName.compare( QLatin1String(
"degree hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1778 unitName.compare( QLatin1String(
"degree minute hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1779 unitName.compare( QLatin1String(
"hemisphere degree" ), Qt::CaseInsensitive ) == 0 ||
1780 unitName.compare( QLatin1String(
"hemisphere degree minute" ), Qt::CaseInsensitive ) == 0 ||
1781 unitName.compare( QLatin1String(
"hemisphere degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1782 unitName.compare( QLatin1String(
"degree (supplier to define representation)" ), Qt::CaseInsensitive ) == 0 )
1784 else if ( unitName.compare( QLatin1String(
"metre" ), Qt::CaseInsensitive ) == 0
1785 || unitName.compare( QLatin1String(
"m" ), Qt::CaseInsensitive ) == 0
1786 || unitName.compare( QLatin1String(
"meter" ), Qt::CaseInsensitive ) == 0 )
1789 else if ( unitName.compare( QLatin1String(
"US survey foot" ), Qt::CaseInsensitive ) == 0 ||
1790 unitName.compare( QLatin1String(
"foot" ), Qt::CaseInsensitive ) == 0 )
1792 else if ( unitName.compare( QLatin1String(
"kilometre" ), Qt::CaseInsensitive ) == 0 )
1794 else if ( unitName.compare( QLatin1String(
"centimetre" ), Qt::CaseInsensitive ) == 0 )
1796 else if ( unitName.compare( QLatin1String(
"millimetre" ), Qt::CaseInsensitive ) == 0 )
1798 else if ( unitName.compare( QLatin1String(
"Statute mile" ), Qt::CaseInsensitive ) == 0 )
1800 else if ( unitName.compare( QLatin1String(
"nautical mile" ), Qt::CaseInsensitive ) == 0 )
1802 else if ( unitName.compare( QLatin1String(
"yard" ), Qt::CaseInsensitive ) == 0 )
1819 if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
1822 QgsDebugMsgLevel(
"QgsCoordinateReferenceSystem::findMatchingProj will only "
1823 "work if prj acr ellipsoid acr and proj4string are set"
1824 " and the current projection is valid!", 4 );
1834 QString mySql = QString(
"select srs_id,parameters from tbl_srs where "
1835 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1842 myResult = openDatabase( myDatabaseFileName, database );
1843 if ( myResult != SQLITE_OK )
1848 statement = database.
prepare( mySql, myResult );
1849 if ( myResult == SQLITE_OK )
1852 while ( statement.
step() == SQLITE_ROW )
1856 if (
toProj() == myProj4String.trimmed() )
1858 return mySrsId.toLong();
1869 myResult = openDatabase( myDatabaseFileName, database );
1870 if ( myResult != SQLITE_OK )
1875 statement = database.
prepare( mySql, myResult );
1877 if ( myResult == SQLITE_OK )
1879 while ( statement.
step() == SQLITE_ROW )
1883 if (
toProj() == myProj4String.trimmed() )
1885 return mySrsId.toLong();
1899 if ( !d->mIsValid && !srs.d->mIsValid )
1902 if ( !d->mIsValid || !srs.d->mIsValid )
1910 if ( isUser != otherIsUser )
1914 if ( !isUser && ( !d->mAuthId.isEmpty() || !srs.d->mAuthId.isEmpty() ) )
1915 return d->mAuthId == srs.d->mAuthId;
1922 return !( *
this == srs );
1927 if (
PJ *obj = d->threadLocalProjObject() )
1930 if ( isDefaultPreferredFormat && !d->mWktPreferred.isEmpty() )
1933 return d->mWktPreferred;
1936 PJ_WKT_TYPE
type = PJ_WKT1_GDAL;
1940 type = PJ_WKT1_GDAL;
1943 type = PJ_WKT1_ESRI;
1946 type = PJ_WKT2_2015;
1949 type = PJ_WKT2_2015_SIMPLIFIED;
1952 type = PJ_WKT2_2019;
1955 type = PJ_WKT2_2019_SIMPLIFIED;
1959 const QByteArray multiLineOption = QStringLiteral(
"MULTILINE=%1" ).arg( multiline ? QStringLiteral(
"YES" ) : QStringLiteral(
"NO" ) ).toLocal8Bit();
1960 const QByteArray indentatationWidthOption = QStringLiteral(
"INDENTATION_WIDTH=%1" ).arg( multiline ? QString::number( indentationWidth ) : QStringLiteral(
"0" ) ).toLocal8Bit();
1961 const char *
const options[] = {multiLineOption.constData(), indentatationWidthOption.constData(),
nullptr};
1964 if ( isDefaultPreferredFormat )
1967 d->mWktPreferred = res;
1979 QDomNode srsNode = node.namedItem( QStringLiteral(
"spatialrefsys" ) );
1981 if ( ! srsNode.isNull() )
1983 bool initialized =
false;
1986 long srsid = srsNode.namedItem( QStringLiteral(
"srsid" ) ).toElement().text().toLong( &ok );
1992 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
1993 if ( !node.isNull() )
2004 node = srsNode.namedItem( QStringLiteral(
"epsg" ) );
2005 if ( !node.isNull() )
2023 const QString
description = srsNode.namedItem( QStringLiteral(
"description" ) ).toElement().text();
2025 const QString wkt = srsNode.namedItem( QStringLiteral(
"wkt" ) ).toElement().text();
2026 initialized = createFromWktInternal( wkt,
description );
2031 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
2032 const QString proj4 = node.toElement().text();
2039 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
2040 const QString proj4 = node.toElement().text();
2041 if ( !proj4.trimmed().isEmpty() )
2042 setProjString( node.toElement().text() );
2044 node = srsNode.namedItem( QStringLiteral(
"srsid" ) );
2045 d->mSrsId = node.toElement().text().toLong();
2047 node = srsNode.namedItem( QStringLiteral(
"srid" ) );
2048 d->mSRID = node.toElement().text().toLong();
2050 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
2051 d->mAuthId = node.toElement().text();
2053 node = srsNode.namedItem( QStringLiteral(
"description" ) );
2054 d->mDescription = node.toElement().text();
2056 node = srsNode.namedItem( QStringLiteral(
"projectionacronym" ) );
2057 d->mProjectionAcronym = node.toElement().text();
2059 node = srsNode.namedItem( QStringLiteral(
"ellipsoidacronym" ) );
2060 d->mEllipsoidAcronym = node.toElement().text();
2062 node = srsNode.namedItem( QStringLiteral(
"geographicflag" ) );
2063 d->mIsGeographic = node.toElement().text() == QLatin1String(
"true" );
2065 d->mWktPreferred.clear();
2071 const QString epoch = srsNode.toElement().attribute( QStringLiteral(
"coordinateEpoch" ) );
2072 if ( !epoch.isEmpty() )
2074 bool epochOk =
false;
2075 d->mCoordinateEpoch = epoch.toDouble( &epochOk );
2077 d->mCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
2081 d->mCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
2084 mNativeFormat = qgsEnumKeyToValue<Qgis::CrsDefinitionFormat>( srsNode.toElement().attribute( QStringLiteral(
"nativeFormat" ) ),
Qgis::CrsDefinitionFormat::Wkt );
2089 d =
new QgsCoordinateReferenceSystemPrivate();
2097 QDomElement layerNode = node.toElement();
2098 QDomElement srsElement = doc.createElement( QStringLiteral(
"spatialrefsys" ) );
2100 srsElement.setAttribute( QStringLiteral(
"nativeFormat" ), qgsEnumValueToKey<Qgis::CrsDefinitionFormat>( mNativeFormat ) );
2102 if ( std::isfinite( d->mCoordinateEpoch ) )
2104 srsElement.setAttribute( QStringLiteral(
"coordinateEpoch" ), d->mCoordinateEpoch );
2107 QDomElement wktElement = doc.createElement( QStringLiteral(
"wkt" ) );
2109 srsElement.appendChild( wktElement );
2111 QDomElement proj4Element = doc.createElement( QStringLiteral(
"proj4" ) );
2112 proj4Element.appendChild( doc.createTextNode(
toProj() ) );
2113 srsElement.appendChild( proj4Element );
2115 QDomElement srsIdElement = doc.createElement( QStringLiteral(
"srsid" ) );
2116 srsIdElement.appendChild( doc.createTextNode( QString::number(
srsid() ) ) );
2117 srsElement.appendChild( srsIdElement );
2119 QDomElement sridElement = doc.createElement( QStringLiteral(
"srid" ) );
2120 sridElement.appendChild( doc.createTextNode( QString::number(
postgisSrid() ) ) );
2121 srsElement.appendChild( sridElement );
2123 QDomElement authidElement = doc.createElement( QStringLiteral(
"authid" ) );
2124 authidElement.appendChild( doc.createTextNode(
authid() ) );
2125 srsElement.appendChild( authidElement );
2127 QDomElement descriptionElement = doc.createElement( QStringLiteral(
"description" ) );
2128 descriptionElement.appendChild( doc.createTextNode(
description() ) );
2129 srsElement.appendChild( descriptionElement );
2131 QDomElement projectionAcronymElement = doc.createElement( QStringLiteral(
"projectionacronym" ) );
2132 projectionAcronymElement.appendChild( doc.createTextNode(
projectionAcronym() ) );
2133 srsElement.appendChild( projectionAcronymElement );
2135 QDomElement ellipsoidAcronymElement = doc.createElement( QStringLiteral(
"ellipsoidacronym" ) );
2136 ellipsoidAcronymElement.appendChild( doc.createTextNode(
ellipsoidAcronym() ) );
2137 srsElement.appendChild( ellipsoidAcronymElement );
2139 QDomElement geographicFlagElement = doc.createElement( QStringLiteral(
"geographicflag" ) );
2140 QString geoFlagText = QStringLiteral(
"false" );
2143 geoFlagText = QStringLiteral(
"true" );
2146 geographicFlagElement.appendChild( doc.createTextNode( geoFlagText ) );
2147 srsElement.appendChild( geographicFlagElement );
2149 layerNode.appendChild( srsElement );
2161QString QgsCoordinateReferenceSystem::projFromSrsId(
const int srsId )
2163 QString myDatabaseFileName;
2164 QString myProjString;
2165 QString mySql = QStringLiteral(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( srsId );
2174 QFileInfo myFileInfo;
2175 myFileInfo.setFile( myDatabaseFileName );
2176 if ( !myFileInfo.exists() )
2178 QgsDebugError( QStringLiteral(
"users qgis.db not found" ) );
2191 rc = openDatabase( myDatabaseFileName, database );
2197 statement = database.
prepare( mySql, rc );
2199 if ( rc == SQLITE_OK )
2201 if ( statement.
step() == SQLITE_ROW )
2207 return myProjString;
2214 myResult = database.
open_v2( path, SQLITE_OPEN_READONLY,
nullptr );
2216 myResult = database.
open( path );
2218 if ( myResult != SQLITE_OK )
2227 .arg( database.
errorMessage() ), QObject::tr(
"CRS" ) );
2234 sCustomSrsValidation = f;
2239 return sCustomSrsValidation;
2242void QgsCoordinateReferenceSystem::debugPrint()
2245 QgsDebugMsgLevel(
"* Valid : " + ( d->mIsValid ? QString(
"true" ) : QString(
"false" ) ), 1 );
2266 mValidationHint = html;
2271 return mValidationHint;
2281 mNativeFormat = format;
2286 return mNativeFormat;
2289long QgsCoordinateReferenceSystem::getRecordCount()
2294 long myRecordCount = 0;
2297 if ( myResult != SQLITE_OK )
2303 QString mySql = QStringLiteral(
"select count(*) from tbl_srs" );
2304 statement = database.
prepare( mySql, myResult );
2305 if ( myResult == SQLITE_OK )
2307 if ( statement.
step() == SQLITE_ROW )
2309 QString myRecordCountString = statement.
columnAsText( 0 );
2310 myRecordCount = myRecordCountString.toLong();
2313 return myRecordCount;
2319 bool isGeographic =
false;
2321 if ( coordinateSystem )
2323 const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
2324 if ( axisCount > 0 )
2326 const char *outUnitAuthName =
nullptr;
2327 const char *outUnitAuthCode =
nullptr;
2329 proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
2338 if ( outUnitAuthName && outUnitAuthCode )
2340 const char *unitCategory =
nullptr;
2341 if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode,
nullptr,
nullptr, &unitCategory ) )
2343 isGeographic = QString( unitCategory ).compare( QLatin1String(
"angular" ), Qt::CaseInsensitive ) == 0;
2348 return isGeographic;
2353 thread_local const QRegularExpression projRegExp( QStringLiteral(
"\\+proj=(\\S+)" ) );
2354 const QRegularExpressionMatch projMatch = projRegExp.match( proj );
2355 if ( !projMatch.hasMatch() )
2357 QgsDebugMsgLevel( QStringLiteral(
"no +proj argument found [%2]" ).arg( proj ), 2 );
2360 operation = projMatch.captured( 1 );
2362 const QRegularExpressionMatch ellipseMatch = projRegExp.match( proj );
2363 if ( ellipseMatch.hasMatch() )
2365 ellipsoid = ellipseMatch.captured( 1 );
2379bool QgsCoordinateReferenceSystem::loadFromAuthCode(
const QString &auth,
const QString &code )
2385 d->mIsValid =
false;
2386 d->mWktPreferred.clear();
2398 proj4.replace( QLatin1String(
"+type=crs" ), QString() );
2399 proj4 = proj4.trimmed();
2403 d->mWktPreferred.clear();
2404 d->mDescription = QString( proj_get_name(
crs.get() ) );
2405 d->mAuthId = QStringLiteral(
"%1:%2" ).arg( auth, code );
2407 d->mAxisInvertedDirty =
true;
2412 d->mEllipsoidAcronym.clear();
2413 d->setPj( std::move(
crs ) );
2415 const QString dbVals =
sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( auth, code ).toUpper() );
2416 if ( !dbVals.isEmpty() )
2418 const QStringList parts = dbVals.split(
',' );
2419 d->mSrsId = parts.at( 0 ).toInt();
2420 d->mSRID = parts.at( 1 ).toInt();
2428QList<long> QgsCoordinateReferenceSystem::userSrsIds()
2430 QList<long> results;
2434 QFileInfo myInfo( db );
2435 if ( !myInfo.exists() )
2445 int result = openDatabase( db, database );
2446 if ( result != SQLITE_OK )
2448 QgsDebugError(
"failed : " + db +
" could not be opened!" );
2452 QString sql = QStringLiteral(
"select srs_id from tbl_srs where srs_id >= %1" ).arg(
USER_CRS_START_ID );
2454 statement = database.
prepare( sql, rc );
2457 int ret = statement.
step();
2459 if ( ret == SQLITE_DONE )
2465 if ( ret == SQLITE_ROW )
2471 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
2479long QgsCoordinateReferenceSystem::matchToUserCrs()
const
2481 PJ *obj = d->threadLocalProjObject();
2485 const QList< long > ids = userSrsIds();
2486 for (
long id : ids )
2489 if ( candidate.
projObject() && proj_is_equivalent_to( obj, candidate.
projObject(), PJ_COMP_EQUIVALENT ) )
2497static void sync_db_proj_logger(
void * ,
int level,
const char *message )
2502 if ( level == PJ_LOG_ERROR )
2506 else if ( level == PJ_LOG_DEBUG )
2514 setlocale( LC_ALL,
"C" );
2517 int inserted = 0, updated = 0, deleted = 0, errors = 0;
2522 if ( database.
open( dbFilePath ) != SQLITE_OK )
2528 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2536 char *errMsg =
nullptr;
2538 bool createdTypeColumn =
false;
2539 if ( sqlite3_exec( database.get(),
"ALTER TABLE tbl_srs ADD COLUMN srs_type text",
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
2541 createdTypeColumn =
true;
2542 if ( sqlite3_exec( database.get(),
"CREATE INDEX srs_type ON tbl_srs(srs_type)",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2544 QgsDebugError( QStringLiteral(
"Could not create index for srs_type" ) );
2549 if ( sqlite3_exec( database.get(),
"create table tbl_info (proj_major INT, proj_minor INT, proj_patch INT)",
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
2551 QString sql = QStringLiteral(
"INSERT INTO tbl_info(proj_major, proj_minor, proj_patch) VALUES (%1, %2,%3)" )
2552 .arg( QString::number( PROJ_VERSION_MAJOR ),
2553 QString::number( PROJ_VERSION_MINOR ),
2554 QString::number( PROJ_VERSION_PATCH ) );
2555 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2557 QgsDebugError( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2560 errMsg ? errMsg :
"(unknown error)" ) );
2562 sqlite3_free( errMsg );
2569 QString sql = QStringLiteral(
"SELECT proj_major, proj_minor, proj_patch FROM tbl_info" );
2570 statement = database.
prepare( sql, result );
2571 if ( result != SQLITE_OK )
2576 if ( statement.
step() == SQLITE_ROW )
2581 if ( !createdTypeColumn && major == PROJ_VERSION_MAJOR && minor == PROJ_VERSION_MINOR && patch == PROJ_VERSION_PATCH )
2587 QgsDebugError( QStringLiteral(
"Could not retrieve previous CRS sync PROJ version number" ) );
2594 proj_log_func( pjContext,
nullptr, sync_db_proj_logger );
2596 PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
2598 int nextSrsId = 67218;
2599 int nextSrId = 520007218;
2600 for (
auto authIter = authorities; authIter && *authIter; ++authIter )
2602 const QString authority( *authIter );
2603 QgsDebugMsgLevel( QStringLiteral(
"Loading authority '%1'" ).arg( authority ), 2 );
2604 PROJ_STRING_LIST codes = proj_get_codes_from_database( pjContext, *authIter, PJ_TYPE_CRS,
true );
2606 QStringList allCodes;
2608 for (
auto codesIter = codes; codesIter && *codesIter; ++codesIter )
2610 const QString code( *codesIter );
2616 QgsDebugError( QStringLiteral(
"Could not load '%1:%2'" ).arg( authority, code ) );
2620 const PJ_TYPE pjType = proj_get_type(
crs.get( ) );
2622 QString srsTypeString;
2627 case PJ_TYPE_ELLIPSOID:
2628 case PJ_TYPE_PRIME_MERIDIAN:
2629 case PJ_TYPE_GEODETIC_REFERENCE_FRAME:
2630 case PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME:
2631 case PJ_TYPE_VERTICAL_REFERENCE_FRAME:
2632 case PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME:
2633 case PJ_TYPE_DATUM_ENSEMBLE:
2634 case PJ_TYPE_CONVERSION:
2635 case PJ_TYPE_TRANSFORMATION:
2636 case PJ_TYPE_CONCATENATED_OPERATION:
2637 case PJ_TYPE_OTHER_COORDINATE_OPERATION:
2638 case PJ_TYPE_TEMPORAL_DATUM:
2639 case PJ_TYPE_ENGINEERING_DATUM:
2640 case PJ_TYPE_PARAMETRIC_DATUM:
2641 case PJ_TYPE_UNKNOWN:
2645 case PJ_TYPE_GEOGRAPHIC_CRS:
2648 case PJ_TYPE_GEODETIC_CRS:
2652 case PJ_TYPE_GEOCENTRIC_CRS:
2656 case PJ_TYPE_GEOGRAPHIC_2D_CRS:
2660 case PJ_TYPE_GEOGRAPHIC_3D_CRS:
2664 case PJ_TYPE_PROJECTED_CRS:
2668 case PJ_TYPE_COMPOUND_CRS:
2672 case PJ_TYPE_TEMPORAL_CRS:
2676 case PJ_TYPE_ENGINEERING_CRS:
2680 case PJ_TYPE_BOUND_CRS:
2684 case PJ_TYPE_VERTICAL_CRS:
2688#if PROJ_VERSION_MAJOR>9 || (PROJ_VERSION_MAJOR==9 && PROJ_VERSION_MINOR>=2)
2689 case PJ_TYPE_DERIVED_PROJECTED_CRS:
2692 case PJ_TYPE_COORDINATE_METADATA:
2695 case PJ_TYPE_OTHER_CRS:
2704 proj4.replace( QLatin1String(
"+type=crs" ), QString() );
2705 proj4 = proj4.trimmed();
2707 if ( proj4.isEmpty() )
2709 QgsDebugMsgLevel( QStringLiteral(
"No proj4 for '%1:%2'" ).arg( authority, code ), 2 );
2720 if ( translatedOperation.isEmpty() && !
operation.isEmpty() )
2722 std::cout << QStringLiteral(
"Operation needs translation in QgsCoordinateReferenceSystemUtils::translateProjection: %1" ).arg(
operation ).toLocal8Bit().constData() << std::endl;
2723 qFatal(
"aborted" );
2726 const bool deprecated = proj_is_deprecated(
crs.get() );
2727 const QString name( proj_get_name(
crs.get() ) );
2729 QString sql = QStringLiteral(
"SELECT parameters,description,deprecated,srs_type FROM tbl_srs WHERE auth_name='%1' AND auth_id='%2'" ).arg( authority, code );
2730 statement = database.
prepare( sql, result );
2731 if ( result != SQLITE_OK )
2740 bool dbSrsDeprecated = deprecated;
2741 if ( statement.
step() == SQLITE_ROW )
2745 dbSrsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2749 if ( !dbSrsProj4.isEmpty() || !dbSrsDesc.isEmpty() )
2751 if ( proj4 != dbSrsProj4 || name != dbSrsDesc || deprecated != dbSrsDeprecated || dbSrsType != srsTypeString )
2754 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3, srs_type=%4 WHERE auth_name=%5 AND auth_id=%6" )
2757 .arg( deprecated ? 1 : 0 )
2761 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2763 QgsDebugError( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2766 errMsg ? errMsg :
"(unknown error)" ) );
2768 sqlite3_free( errMsg );
2782 const QString dbVals =
sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( authority, code ) );
2785 if ( !dbVals.isEmpty() )
2787 const QStringList parts = dbVals.split(
',' );
2788 srsId = parts.at( 0 );
2789 srId = parts.at( 1 );
2791 if ( srId.isEmpty() )
2793 srId = QString::number( nextSrId );
2796 if ( srsId.isEmpty() )
2798 srsId = QString::number( nextSrsId );
2802 if ( !srsId.isEmpty() )
2804 sql = QStringLiteral(
"INSERT INTO tbl_srs(srs_id, description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated,srs_type) VALUES (%1, %2,%3,%4,%5,%6,%7,%8,%9,%10,%11)" )
2814 .arg( deprecated ? 1 : 0 )
2819 sql = QStringLiteral(
"INSERT INTO tbl_srs(description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated,srs_type) VALUES (%1,%2,%3,%4,%5,%6,%7,%8,%9,%10)" )
2828 .arg( deprecated ? 1 : 0 )
2833 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2839 qCritical(
"Could not execute: %s [%s/%s]\n",
2840 sql.toLocal8Bit().constData(),
2841 sqlite3_errmsg( database.get() ),
2842 errMsg ? errMsg :
"(unknown error)" );
2846 sqlite3_free( errMsg );
2851 proj_string_list_destroy( codes );
2853 const QString sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='%1' AND NOT auth_id IN (%2)" ).arg( authority, allCodes.join(
',' ) );
2854 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
2856 deleted = sqlite3_changes( database.get() );
2861 qCritical(
"Could not execute: %s [%s]\n",
2862 sql.toLocal8Bit().constData(),
2863 sqlite3_errmsg( database.get() ) );
2867 proj_string_list_destroy( authorities );
2869 QString sql = QStringLiteral(
"UPDATE tbl_info set proj_major=%1,proj_minor=%2,proj_patch=%3" )
2870 .arg( QString::number( PROJ_VERSION_MAJOR ),
2871 QString::number( PROJ_VERSION_MINOR ),
2872 QString::number( PROJ_VERSION_PATCH ) );
2873 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2875 QgsDebugError( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2878 errMsg ? errMsg :
"(unknown error)" ) );
2880 sqlite3_free( errMsg );
2884 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2886 QgsDebugError( QStringLiteral(
"Could not commit transaction: %1 [%2]\n" ).arg(
2888 sqlite3_errmsg( database.get() ) )
2894 QgsDebugMsgLevel( QStringLiteral(
"CRS update (inserted:%1 updated:%2 deleted:%3 errors:%4)" ).arg( inserted ).arg( updated ).arg( deleted ).arg( errors ), 4 );
2902 return updated + inserted;
2905const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::stringCache()
2907 return *sStringCache();
2910const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::projCache()
2912 return *sProj4Cache();
2915const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::ogcCache()
2917 return *sOgcCache();
2920const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::wktCache()
2922 return *sWktCache();
2925const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srIdCache()
2927 return *sSrIdCache();
2930const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srsIdCache()
2932 return *sSrsIdCache();
2942 if (
PJ *obj = d->threadLocalProjObject() )
2970 else if (
PJ *obj = d->threadLocalProjObject() )
2973 return geoCrs ? QStringLiteral(
"%1:%2" ).arg( proj_get_id_auth_name( geoCrs.get(), 0 ), proj_get_id_code( geoCrs.get(), 0 ) ) : QString();
2983 return d->threadLocalProjObject();
2996 d->mIsValid =
false;
2998 d->mWktPreferred.clear();
3005 switch ( proj_get_type(
object ) )
3007 case PJ_TYPE_GEODETIC_CRS:
3008 case PJ_TYPE_GEOCENTRIC_CRS:
3009 case PJ_TYPE_GEOGRAPHIC_CRS:
3010 case PJ_TYPE_GEOGRAPHIC_2D_CRS:
3011 case PJ_TYPE_GEOGRAPHIC_3D_CRS:
3012 case PJ_TYPE_VERTICAL_CRS:
3013 case PJ_TYPE_PROJECTED_CRS:
3014 case PJ_TYPE_COMPOUND_CRS:
3015 case PJ_TYPE_TEMPORAL_CRS:
3016 case PJ_TYPE_ENGINEERING_CRS:
3017 case PJ_TYPE_BOUND_CRS:
3018 case PJ_TYPE_OTHER_CRS:
3034 const QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
3035 const QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
3036 if ( !authName.isEmpty() && !authCode.isEmpty() && loadFromAuthCode( authName, authCode ) )
3044 d->mDescription = QString( proj_get_name( d->threadLocalProjObject() ) );
3055 QStringList projections;
3057 projections.reserve( res.size() );
3060 projections << QString::number(
crs.
srsid() );
3087 sSrIdCacheLock()->lockForWrite();
3088 if ( !sDisableSrIdCache )
3091 sDisableSrIdCache =
true;
3092 sSrIdCache()->clear();
3094 sSrIdCacheLock()->unlock();
3096 sOgcLock()->lockForWrite();
3097 if ( !sDisableOgcCache )
3100 sDisableOgcCache =
true;
3101 sOgcCache()->clear();
3103 sOgcLock()->unlock();
3105 sProj4CacheLock()->lockForWrite();
3106 if ( !sDisableProjCache )
3109 sDisableProjCache =
true;
3110 sProj4Cache()->clear();
3112 sProj4CacheLock()->unlock();
3114 sCRSWktLock()->lockForWrite();
3115 if ( !sDisableWktCache )
3118 sDisableWktCache =
true;
3119 sWktCache()->clear();
3121 sCRSWktLock()->unlock();
3123 sCRSSrsIdLock()->lockForWrite();
3124 if ( !sDisableSrsIdCache )
3127 sDisableSrsIdCache =
true;
3128 sSrsIdCache()->clear();
3130 sCRSSrsIdLock()->unlock();
3132 sCrsStringLock()->lockForWrite();
3133 if ( !sDisableStringCache )
3136 sDisableStringCache =
true;
3137 sStringCache()->clear();
3139 sCrsStringLock()->unlock();
3148 if ( !c1.d->mIsValid && !c2.d->mIsValid )
3151 if ( !c1.d->mIsValid && c2.d->mIsValid )
3154 if ( c1.d->mIsValid && !c2.d->mIsValid )
3160 if ( c1IsUser && !c2IsUser )
3163 if ( !c1IsUser && c2IsUser )
3166 if ( !c1IsUser && !c2IsUser && !c1.d->mAuthId.isEmpty() && !c2.d->mAuthId.isEmpty() )
3168 if ( c1.d->mAuthId != c2.d->mAuthId )
3169 return c1.d->mAuthId > c2.d->mAuthId;
3177 if ( c1.d->mCoordinateEpoch == c2.d->mCoordinateEpoch )
3180 if ( std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3183 if ( std::isnan( c1.d->mCoordinateEpoch ) && !std::isnan( c2.d->mCoordinateEpoch ) )
3186 if ( !std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3189 return c1.d->mCoordinateEpoch > c2.d->mCoordinateEpoch;
3197 if ( !c1.d->mIsValid && !c2.d->mIsValid )
3200 if ( c1.d->mIsValid && !c2.d->mIsValid )
3203 if ( !c1.d->mIsValid && c2.d->mIsValid )
3209 if ( !c1IsUser && c2IsUser )
3212 if ( c1IsUser && !c2IsUser )
3215 if ( !c1IsUser && !c2IsUser && !c1.d->mAuthId.isEmpty() && !c2.d->mAuthId.isEmpty() )
3217 if ( c1.d->mAuthId != c2.d->mAuthId )
3218 return c1.d->mAuthId < c2.d->mAuthId;
3226 if ( c1.d->mCoordinateEpoch == c2.d->mCoordinateEpoch )
3229 if ( std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3232 if ( !std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3235 if ( std::isnan( c1.d->mCoordinateEpoch ) && !std::isnan( c2.d->mCoordinateEpoch ) )
3238 return c1.d->mCoordinateEpoch < c2.d->mCoordinateEpoch;
3243 return !( c1 < c2 );
3247 return !( c1 > c2 );
CrsIdentifierType
Available identifier string types for representing coordinate reference systems.
@ ShortString
A heavily abbreviated string, for use when a compact representation is required.
@ MediumString
A medium-length string, recommended for general purpose use.
DistanceUnit
Units of distance.
@ Centimeters
Centimeters.
@ Millimeters
Millimeters.
@ Miles
Terrestrial miles.
@ Unknown
Unknown distance unit.
@ Degrees
Degrees, for planar geographic CRS distance measurements.
@ NauticalMiles
Nautical miles.
@ Critical
Critical/error message.
CrsType
Data provider flags.
@ Compound
Compound (horizontal + vertical) CRS.
@ Projected
Projected CRS.
@ DerivedProjected
Derived projected CRS.
@ Engineering
Engineering CRS.
@ Geographic3d
3D geopraphic CRS
@ Geographic2d
2D geographic CRS
@ Geocentric
Geocentric CRS.
CrsDefinitionFormat
CRS definition formats.
@ Wkt
WKT format (always recommended over proj string format)
CrsAxisDirection
Coordinate reference system axis directions.
@ ColumnPositive
Column positive.
@ SouthSouthEast
South South East.
@ ColumnNegative
Column negative.
@ RowPositive
Row positive.
@ DisplayDown
Display down.
@ GeocentricZ
Geocentric (Z)
@ DisplayRight
Display right.
@ WestSouthWest
West South West.
@ RowNegative
Row negative.
@ NorthNorthEast
North North East.
@ EastNorthEast
East North East.
@ Unspecified
Unspecified.
@ NorthNorthWest
North North West.
@ GeocentricY
Geocentric (Y)
@ CounterClockwise
Counter clockwise.
@ SouthSouthWest
South South West.
@ DisplayLeft
Display left.
@ WestNorthWest
West North West.
@ EastSouthEast
East South East.
@ GeocentricX
Geocentric (X)
CrsWktVariant
Coordinate reference system WKT formatting variants.
@ Wkt2_2019Simplified
WKT2_2019 with the simplification rule of WKT2_SIMPLIFIED.
@ Wkt2_2015Simplified
Same as WKT2_2015 with the following exceptions: UNIT keyword used. ID node only on top element....
@ Wkt1Esri
WKT1 as traditionally output by ESRI software, deriving from OGC 99-049.
@ Preferred
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
@ Wkt2_2019
Full WKT2 string, conforming to ISO 19162:2019 / OGC 18-010, with all possible nodes and new keyword ...
@ Wkt2_2015
Full WKT2 string, conforming to ISO 19162:2015(E) / OGC 12-063r5 with all possible nodes and new keyw...
@ Wkt1Gdal
WKT1 as traditionally output by GDAL, deriving from OGC 01-009. A notable departure from WKT1_GDAL wi...
static QgsCoordinateReferenceSystemRegistry * coordinateReferenceSystemRegistry()
Returns the application's coordinate reference system (CRS) registry, which handles known CRS definit...
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
void removeRecent(const QgsCoordinateReferenceSystem &crs)
Removes a CRS from the list of recently used CRS.
long addUserCrs(const QgsCoordinateReferenceSystem &crs, const QString &name, Qgis::CrsDefinitionFormat nativeFormat=Qgis::CrsDefinitionFormat::Wkt)
Adds a new crs definition as a custom ("USER") CRS.
void clearRecent()
Cleans the list of recently used CRS.
QList< QgsCoordinateReferenceSystem > recentCrs()
Returns a list of recently used CRS.
void pushRecent(const QgsCoordinateReferenceSystem &crs)
Pushes a recently used CRS to the top of the recent CRS list.
QMap< QString, QgsProjOperation > projOperations() const
Returns a map of all valid PROJ operations.
static QString translateProjection(const QString &projection)
Returns a translated string for a projection method.
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.
bool createFromOgcWmsCrs(const QString &crs)
Sets this CRS to the given OGC WMS-format Coordinate Reference Systems.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool createFromWkt(const QString &wkt)
Sets this CRS using a WKT definition.
bool createFromString(const QString &definition)
Set up this CRS from a string definition.
void validate()
Perform some validation on this CRS.
~QgsCoordinateReferenceSystem()
QgsRectangle bounds() const
Returns the approximate bounds for the region the CRS is usable within.
QString toProj() const
Returns a Proj string representation of this CRS.
static CUSTOM_CRS_VALIDATION customCrsValidation()
Gets custom function.
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
static Q_INVOKABLE QgsCoordinateReferenceSystem fromEpsgId(long epsg)
Creates a CRS from a given EPSG ID.
Q_DECL_DEPRECATED bool createFromProj4(const QString &projString)
Sets this CRS by passing it a PROJ style formatted string.
static Q_DECL_DEPRECATED QStringList recentProjections()
Returns a list of recently used projections.
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
QString toOgcUri() const
Returns the crs as OGC URI (format: http://www.opengis.net/def/crs/OGC/1.3/CRS84) Returns an empty st...
static void setCustomCrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS.
static Q_DECL_DEPRECATED void pushRecentCoordinateReferenceSystem(const QgsCoordinateReferenceSystem &crs)
Pushes a recently used CRS to the top of the recent CRS list.
long postgisSrid() const
Returns PostGIS SRID for the CRS.
Q_DECL_DEPRECATED long findMatchingProj()
Walks the CRS databases (both system and user database) trying to match stored PROJ string to a datab...
static QList< long > validSrsIds()
Returns a list of all valid SRS IDs present in the CRS database.
QgsProjectionFactors factors(const QgsPoint &point) const
Calculate various cartographic properties, such as scale factors, angular distortion and meridian con...
void setValidationHint(const QString &html)
Set user hint for validation.
Q_DECL_DEPRECATED QString toProj4() const
Returns a Proj string representation of this CRS.
bool operator==(const QgsCoordinateReferenceSystem &srs) const
Overloaded == operator used to compare to CRS's.
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
QString userFriendlyIdentifier(Qgis::CrsIdentifierType type=Qgis::CrsIdentifierType::MediumString) const
Returns a user friendly identifier for the CRS.
Qgis::CrsDefinitionFormat nativeFormat() const
Returns the native format for the CRS definition.
CrsType
Enumeration of types of IDs accepted in createFromId() method.
@ InternalCrsId
Internal ID used by QGIS in the local SQLite database.
@ PostgisCrsId
SRID used in PostGIS. DEPRECATED – DO NOT USE.
bool createFromUserInput(const QString &definition)
Set up this CRS from various text formats.
QgsCoordinateReferenceSystem()
Constructs an invalid CRS object.
static int syncDatabase()
Update proj.4 parameters in our database from proj.4.
bool operator!=(const QgsCoordinateReferenceSystem &srs) const
Overloaded != operator used to compare to CRS's.
void setNativeFormat(Qgis::CrsDefinitionFormat format)
Sets the native format for the CRS definition.
bool createFromProj(const QString &projString, bool identify=true)
Sets this CRS by passing it a PROJ style formatted string.
static Q_DECL_DEPRECATED void removeRecentCoordinateReferenceSystem(const QgsCoordinateReferenceSystem &crs)
Removes a CRS from the list of recently used CRS.
QgsDatumEnsemble datumEnsemble() const
Attempts to retrieve datum ensemble details from the CRS.
QgsCoordinateReferenceSystem toGeographicCrs() const
Returns the geographic CRS associated with this CRS object.
bool isDynamic() const
Returns true if the CRS is a dynamic CRS.
bool createFromSrsId(long srsId)
Sets this CRS by lookup of internal QGIS CRS ID in the CRS database.
Q_DECL_DEPRECATED bool createFromId(long id, CrsType type=PostgisCrsId)
Sets this CRS by lookup of the given ID in the CRS database.
static QgsCoordinateReferenceSystem fromProjObject(PJ *object)
Constructs a QgsCoordinateReferenceSystem from a PROJ PJ object.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
QgsCoordinateReferenceSystem & operator=(const QgsCoordinateReferenceSystem &srs)
Assignment operator.
void updateDefinition()
Updates the definition and parameters of the coordinate reference system to their latest values.
static QgsCoordinateReferenceSystem fromProj(const QString &proj)
Creates a CRS from a proj style formatted string.
static Q_DECL_DEPRECATED void setupESRIWktFix()
Make sure that ESRI WKT import is done properly.
static Q_DECL_DEPRECATED QList< QgsCoordinateReferenceSystem > recentCoordinateReferenceSystems()
Returns a list of recently used CRS.
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
PJ * projObject() const
Returns the underlying PROJ PJ object corresponding to the CRS, or nullptr if the CRS is invalid.
void setCoordinateEpoch(double epoch)
Sets the coordinate epoch, as a decimal year.
Q_DECL_DEPRECATED bool createFromSrid(long srid)
Sets this CRS by lookup of the given PostGIS SRID in the CRS database.
long saveAsUserCrs(const QString &name, Qgis::CrsDefinitionFormat nativeFormat=Qgis::CrsDefinitionFormat::Wkt)
Saves the CRS as a new custom ("USER") CRS.
static Q_DECL_DEPRECATED void clearRecentCoordinateReferenceSystems()
Cleans the list of recently used CRS.
QString celestialBodyName() const
Attempts to retrieve the name of the celestial body associated with the CRS (e.g.
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
static QgsCoordinateReferenceSystem fromSrsId(long srsId)
Creates a CRS from a specified QGIS SRS ID.
double coordinateEpoch() const
Returns the coordinate epoch, as a decimal year.
QString geographicCrsAuthId() const
Returns auth id of related geographic CRS.
QString validationHint() const
Gets user hint for validation.
QgsProjOperation operation() const
Returns information about the PROJ operation associated with the coordinate reference system,...
QList< Qgis::CrsAxisDirection > axisOrdering() const
Returns an ordered list of the axis directions reflecting the native axis order for the CRS.
long srsid() const
Returns the internal CRS ID, if available.
Qgis::CrsType type() const
Returns the type of the CRS.
Qgis::DistanceUnit mapUnits
bool hasAxisInverted() const
Returns whether the axis order is inverted for the CRS compared to the order east/north (longitude/la...
bool createFromProjObject(PJ *object)
Sets this CRS by passing it a PROJ PJ object, corresponding to a PROJ CRS object.
bool isDeprecated() const
Returns true if the CRS is considered deprecated.
static Q_DECL_DEPRECATED QgsCoordinateReferenceSystem fromProj4(const QString &proj4)
Creates a CRS from a proj style formatted string.
Contains information about a member of a datum ensemble.
Contains information about a datum ensemble.
static void warning(const QString &msg)
Goes to qWarning.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Custom exception class which is raised when an operation is not supported.
@ AUTH_CODE
unknown/unhandled flavor
static CRSFlavor parseCrsName(const QString &crsName, QString &authority, QString &code)
Parse a CRS name in one of the flavors of OGC services, and decompose it as authority and code.
static QString OGRSpatialReferenceToWkt(OGRSpatialReferenceH srs)
Returns a WKT string corresponding to the specified OGR srs object.
Point geometry type, with support for z-dimension and m-values.
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
Contains information about a PROJ operation.
static proj_pj_unique_ptr crsToHorizontalCrs(const PJ *crs)
Given a PROJ crs (which may be a compound or bound crs, or some other type), extract the horizontal c...
@ FlagMatchBoundCrsToUnderlyingSourceCrs
Allow matching a BoundCRS object to its underlying SourceCRS.
static bool isDynamic(const PJ *crs)
Returns true if the given proj coordinate system is a dynamic CRS.
static proj_pj_unique_ptr unboundCrs(const PJ *crs)
Given a PROJ crs (which may be a compound or bound crs, or some other type), ensure that it is not a ...
static bool identifyCrs(const PJ *crs, QString &authName, QString &authCode, IdentifyFlags flags=IdentifyFlags())
Attempts to identify a crs, matching it to a known authority and code within an acceptable level of t...
static proj_pj_unique_ptr crsToDatumEnsemble(const PJ *crs)
Given a PROJ crs, attempt to retrieve the datum ensemble from it.
std::unique_ptr< PJ, ProjPJDeleter > proj_pj_unique_ptr
Scoped Proj PJ object.
static bool axisOrderIsSwapped(const PJ *crs)
Returns true if the given proj coordinate system uses requires y/x coordinate order instead of x/y.
contains various cartographic properties, such as scale factors, angular distortion and meridian conv...
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
void unlock()
Unlocks the lock.
void changeMode(Mode mode)
Change the mode of the lock to mode.
A rectangle specified with double values.
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.
static QString quotedString(const QString &value)
Returns a quoted string value, surround by ' characters and with special characters correctly escaped...
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(const QString &path)
Opens the database at the specified file path.
QString errorMessage() const
Returns the most recent error message encountered by the database.
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.
QString columnName(int column) const
Returns the name of column.
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).
int columnCount() const
Gets the number of columns that this statement returns.
#define Q_NOWARN_DEPRECATED_POP
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
#define Q_NOWARN_DEPRECATED_PUSH
bool qgsNanCompatibleEquals(double a, double b)
Compare two doubles, treating nan values as equal.
const int USER_CRS_START_ID
Magick number that determines whether a projection crsid is a system (srs.db) or user (~/....
QString getFullProjString(PJ *obj)
bool operator>=(const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2)
bool operator<(const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2)
bool testIsGeographic(PJ *crs)
void getOperationAndEllipsoidFromProjString(const QString &proj, QString &operation, QString &ellipsoid)
QHash< QString, QgsCoordinateReferenceSystem > StringCrsCacheHash
bool operator<=(const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2)
QHash< long, QgsCoordinateReferenceSystem > SrIdCrsCacheHash
bool operator>(const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2)
void * OGRSpatialReferenceH
struct projCtx_t PJ_CONTEXT
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
const QMap< QString, QString > sAuthIdToQgisSrsIdMap
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
const QgsCoordinateReferenceSystem & crs