31#include <QRegularExpression>
50#include <proj_experimental.h>
53#include <ogr_srs_api.h>
65bool QgsCoordinateReferenceSystem::sDisableSrIdCache =
false;
69bool QgsCoordinateReferenceSystem::sDisableOgcCache =
false;
73bool QgsCoordinateReferenceSystem::sDisableProjCache =
false;
77bool QgsCoordinateReferenceSystem::sDisableWktCache =
false;
81bool QgsCoordinateReferenceSystem::sDisableSrsIdCache =
false;
85bool QgsCoordinateReferenceSystem::sDisableStringCache =
false;
94 if (
const char *proj4src = proj_as_proj_string(
QgsProjContext::get(), boundCrs.get(), PJ_PROJ_4,
nullptr ) )
96 return QString( proj4src );
113 d =
new QgsCoordinateReferenceSystemPrivate();
119 d =
new QgsCoordinateReferenceSystemPrivate();
127 , mValidationHint( srs.mValidationHint )
128 , mNativeFormat( srs.mNativeFormat )
135 mValidationHint = srs.mValidationHint;
136 mNativeFormat = srs.mNativeFormat;
146 const auto constDbs = dbs;
147 for (
const QString &db : constDbs )
149 QFileInfo myInfo( db );
150 if ( !myInfo.exists() )
160 int result = openDatabase( db, database );
161 if ( result != SQLITE_OK )
167 QString sql = QStringLiteral(
"select srs_id from tbl_srs" );
169 statement = database.
prepare( sql, rc );
173 int ret = statement.
step();
175 if ( ret == SQLITE_DONE )
181 if ( ret == SQLITE_ROW )
187 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
192 std::sort( results.begin(), results.end() );
265 QgsDebugError( QStringLiteral(
"Unexpected case reached!" ) );
272 if ( definition.isEmpty() )
276 if ( !sDisableStringCache )
278 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sStringCache()->constFind( definition );
279 if ( crsIt != sStringCache()->constEnd() )
282 *
this = crsIt.value();
289 const thread_local QRegularExpression reCrsId( QStringLiteral(
"^(epsg|esri|osgeo|ignf|ogc|nkg|zangi|iau_2015|iau2000|postgis|internal|user)\\:(\\w+)$" ), QRegularExpression::CaseInsensitiveOption );
290 QRegularExpressionMatch match = reCrsId.match( definition );
291 if ( match.capturedStart() == 0 )
293 QString authName = match.captured( 1 ).toLower();
294 if ( authName == QLatin1String(
"epsg" ) )
298 else if ( authName == QLatin1String(
"postgis" ) )
300 const long id = match.captured( 2 ).toLong();
305 else if ( authName == QLatin1String(
"esri" )
306 || authName == QLatin1String(
"osgeo" )
307 || authName == QLatin1String(
"ignf" )
308 || authName == QLatin1String(
"zangi" )
309 || authName == QLatin1String(
"iau2000" )
310 || authName == QLatin1String(
"ogc" )
311 || authName == QLatin1String(
"nkg" )
312 || authName == QLatin1String(
"iau_2015" )
319 const long id = match.captured( 2 ).toLong();
327 const thread_local QRegularExpression reCrsStr( QStringLiteral(
"^(?:(wkt|proj4|proj)\\:)?(.+)$" ), QRegularExpression::CaseInsensitiveOption );
328 match = reCrsStr.match( definition );
329 if ( match.capturedStart() == 0 )
331 if ( match.captured( 1 ).startsWith( QLatin1String(
"proj" ), Qt::CaseInsensitive ) )
343 if ( !sDisableStringCache )
344 sStringCache()->insert( definition, *
this );
350 if ( definition.isEmpty() )
356 if ( OSRSetFromUserInput(
crs, definition.toLocal8Bit().constData() ) == OGRERR_NONE )
359 OSRDestroySpatialReference(
crs );
369 const char *configOld = CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" );
370 const char *configNew =
"GEOGCS";
372 if ( strcmp( configOld,
"" ) == 0 )
374 CPLSetConfigOption(
"GDAL_FIX_ESRI_WKT", configNew );
375 if ( strcmp( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) != 0 )
377 .arg( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) );
378 QgsDebugMsgLevel( QStringLiteral(
"set GDAL_FIX_ESRI_WKT : %1" ).arg( configNew ), 4 );
382 QgsDebugMsgLevel( QStringLiteral(
"GDAL_FIX_ESRI_WKT was already set : %1" ).arg( configNew ), 4 );
392 if ( !sDisableOgcCache )
394 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sOgcCache()->constFind(
crs );
395 if ( crsIt != sOgcCache()->constEnd() )
398 *
this = crsIt.value();
404 QString wmsCrs =
crs;
409 const QString authorityLower = authority.toLower();
411 ( authorityLower == QLatin1String(
"user" ) ||
412 authorityLower == QLatin1String(
"custom" ) ||
413 authorityLower == QLatin1String(
"qgis" ) ) )
418 if ( !sDisableOgcCache )
419 sOgcCache()->insert(
crs, *
this );
425 wmsCrs = authority +
':' + code;
429 const QString legacyKey = wmsCrs.toLower();
432 if ( it.key().compare( legacyKey, Qt::CaseInsensitive ) == 0 )
434 const QStringList parts = it.key().split(
':' );
435 const QString auth = parts.at( 0 );
436 const QString code = parts.at( 1 );
437 if ( loadFromAuthCode( auth, code ) )
440 if ( !sDisableOgcCache )
441 sOgcCache()->insert(
crs, *
this );
450 if ( !sDisableOgcCache )
451 sOgcCache()->insert(
crs, *
this );
456 if ( wmsCrs.compare( QLatin1String(
"CRS:27" ), Qt::CaseInsensitive ) == 0 ||
457 wmsCrs.compare( QLatin1String(
"OGC:CRS27" ), Qt::CaseInsensitive ) == 0 )
464 if ( wmsCrs.compare( QLatin1String(
"CRS:83" ), Qt::CaseInsensitive ) == 0 ||
465 wmsCrs.compare( QLatin1String(
"OGC:CRS83" ), Qt::CaseInsensitive ) == 0 )
472 if ( wmsCrs.compare( QLatin1String(
"CRS:84" ), Qt::CaseInsensitive ) == 0 ||
473 wmsCrs.compare( QLatin1String(
"OGC:CRS84" ), Qt::CaseInsensitive ) == 0 )
477 d->mAxisInverted =
false;
478 d->mAxisInvertedDirty =
false;
482 if ( !sDisableOgcCache )
483 sOgcCache()->insert(
crs, *
this );
489 if ( !sDisableOgcCache )
499 if ( d->mIsValid || !sCustomSrsValidation )
503 if ( sCustomSrsValidation )
504 sCustomSrsValidation( *
this );
510 if ( !sDisableSrIdCache )
512 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrIdCache()->constFind(
id );
513 if ( crsIt != sSrIdCache()->constEnd() )
516 *
this = crsIt.value();
525 if ( it.value().endsWith( QStringLiteral(
",%1" ).arg(
id ) ) )
527 const QStringList parts = it.key().split(
':' );
528 const QString auth = parts.at( 0 );
529 const QString code = parts.at( 1 );
530 if ( loadFromAuthCode( auth, code ) )
533 if ( !sDisableSrIdCache )
534 sSrIdCache()->insert(
id, *
this );
544 if ( !sDisableSrIdCache )
545 sSrIdCache()->insert(
id, *
this );
553 if ( !sDisableSrsIdCache )
555 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrsIdCache()->constFind(
id );
556 if ( crsIt != sSrsIdCache()->constEnd() )
559 *
this = crsIt.value();
568 if ( it.value().startsWith( QString::number(
id ) +
',' ) )
570 const QStringList parts = it.key().split(
':' );
571 const QString auth = parts.at( 0 );
572 const QString code = parts.at( 1 );
573 if ( loadFromAuthCode( auth, code ) )
576 if ( !sDisableSrsIdCache )
577 sSrsIdCache()->insert(
id, *
this );
585 QStringLiteral(
"srs_id" ), QString::number(
id ) );
588 if ( !sDisableSrsIdCache )
589 sSrsIdCache()->insert(
id, *
this );
593bool QgsCoordinateReferenceSystem::loadFromDatabase(
const QString &db,
const QString &expression,
const QString &value )
597 QgsDebugMsgLevel(
"load CRS from " + db +
" where " + expression +
" is " + value, 3 );
599 d->mWktPreferred.clear();
601 QFileInfo myInfo( db );
602 if ( !myInfo.exists() )
612 myResult = openDatabase( db, database );
613 if ( myResult != SQLITE_OK )
630 QString mySql =
"select srs_id,description,projection_acronym,"
631 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo,wkt "
633 statement = database.
prepare( mySql, myResult );
636 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
641 d->mEllipsoidAcronym.clear();
643 d->mWktPreferred.clear();
646 d->mIsGeographic = statement.
columnAsText( 7 ).toInt() != 0;
648 d->mAxisInvertedDirty =
true;
650 if ( d->mSrsId >=
USER_CRS_START_ID && ( d->mAuthId.isEmpty() || d->mAuthId == QChar(
':' ) ) )
652 d->mAuthId = QStringLiteral(
"USER:%1" ).arg( d->mSrsId );
654 else if ( !d->mAuthId.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive ) )
656 QStringList parts = d->mAuthId.split(
':' );
657 QString auth = parts.at( 0 );
658 QString code = parts.at( 1 );
665 d->mIsValid = d->hasPj();
671 if ( !wkt.isEmpty() )
679 setProjString( d->mProj4 );
689void QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread(
PJ_CONTEXT *pj_context )
696 if ( !sDisableSrIdCache )
699 if ( !sDisableSrIdCache )
701 for (
auto it = sSrIdCache()->begin(); it != sSrIdCache()->end(); )
703 auto &v = it.value();
704 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
705 it = sSrIdCache()->erase( it );
711 if ( !sDisableOgcCache )
714 if ( !sDisableOgcCache )
716 for (
auto it = sOgcCache()->begin(); it != sOgcCache()->end(); )
718 auto &v = it.value();
719 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
720 it = sOgcCache()->erase( it );
726 if ( !sDisableProjCache )
729 if ( !sDisableProjCache )
731 for (
auto it = sProj4Cache()->begin(); it != sProj4Cache()->end(); )
733 auto &v = it.value();
734 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
735 it = sProj4Cache()->erase( it );
741 if ( !sDisableWktCache )
744 if ( !sDisableWktCache )
746 for (
auto it = sWktCache()->begin(); it != sWktCache()->end(); )
748 auto &v = it.value();
749 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
750 it = sWktCache()->erase( it );
756 if ( !sDisableSrsIdCache )
759 if ( !sDisableSrsIdCache )
761 for (
auto it = sSrsIdCache()->begin(); it != sSrsIdCache()->end(); )
763 auto &v = it.value();
764 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
765 it = sSrsIdCache()->erase( it );
771 if ( !sDisableStringCache )
774 if ( !sDisableStringCache )
776 for (
auto it = sStringCache()->begin(); it != sStringCache()->end(); )
778 auto &v = it.value();
779 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
780 it = sStringCache()->erase( it );
790 if ( d->mAxisInvertedDirty )
793 d->mAxisInvertedDirty =
false;
796 return d->mAxisInverted;
810 const thread_local QMap< Qgis::CrsAxisDirection, QString > mapping =
853 QList< Qgis::CrsAxisDirection > res;
854 const int axisCount = proj_cs_get_axis_count( context, pjCs.get() );
857 res.reserve( axisCount );
859 for (
int i = 0; i < axisCount; ++i )
861 const char *outDirection =
nullptr;
862 proj_cs_get_axis_info( context, pjCs.get(), i,
872 const thread_local QRegularExpression rx( QStringLiteral(
"([^\\s]+).*" ) );
873 const QRegularExpressionMatch match = rx.match( QString( outDirection ) );
874 if ( !match.hasMatch() )
877 const QString direction = match.captured( 1 );
879 for (
auto it = mapping.constBegin(); it != mapping.constEnd(); ++it )
881 if ( it.value().compare( direction, Qt::CaseInsensitive ) == 0 )
896 return createFromWktInternal( wkt, QString() );
899bool QgsCoordinateReferenceSystem::createFromWktInternal(
const QString &wkt,
const QString &description )
907 if ( !sDisableWktCache )
909 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sWktCache()->constFind( wkt );
910 if ( crsIt != sWktCache()->constEnd() )
913 *
this = crsIt.value();
915 if ( !
description.isEmpty() && d->mDescription.isEmpty() )
920 sWktCache()->insert( wkt, *
this );
929 d->mWktPreferred.clear();
932 QgsDebugMsgLevel( QStringLiteral(
"theWkt is uninitialized, operation failed" ), 4 );
937 QgsCoordinateReferenceSystem::RecordMap record = getRecord(
"select * from tbl_srs where wkt=" +
QgsSqliteUtils::quotedString( wkt ) +
" order by deprecated" );
938 if ( !record.empty() )
940 long srsId = record[QStringLiteral(
"srs_id" )].toLong();
953 if ( d->mSrsId == 0 )
956 long id = matchToUserCrs();
965 if ( !sDisableWktCache )
966 sWktCache()->insert( wkt, *
this );
984 if ( projString.isEmpty() )
989 if ( projString.trimmed().isEmpty() )
993 d->mWktPreferred.clear();
998 if ( !sDisableProjCache )
1000 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sProj4Cache()->constFind( projString );
1001 if ( crsIt != sProj4Cache()->constEnd() )
1004 *
this = crsIt.value();
1018 QString myProj4String = projString.trimmed();
1019 myProj4String.remove( QStringLiteral(
"+type=crs" ) );
1020 myProj4String = myProj4String.trimmed();
1022 d->mIsValid =
false;
1023 d->mWktPreferred.clear();
1028 const QString projCrsString = myProj4String + ( myProj4String.contains( QStringLiteral(
"+type=crs" ) ) ? QString() : QStringLiteral(
" +type=crs" ) );
1036 const QString
authid = QStringLiteral(
"%1:%2" ).arg( authName, authCode );
1040 if ( !sDisableProjCache )
1041 sProj4Cache()->insert( projString, *
this );
1048 QgsCoordinateReferenceSystem::RecordMap myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
1050 if ( !myRecord.empty() )
1052 id = myRecord[QStringLiteral(
"srs_id" )].toLong();
1061 setProjString( myProj4String );
1064 id = matchToUserCrs();
1073 setProjString( myProj4String );
1077 if ( !sDisableProjCache )
1078 sProj4Cache()->insert( projString, *
this );
1084QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord(
const QString &sql )
1086 QString myDatabaseFileName;
1087 QgsCoordinateReferenceSystem::RecordMap myMap;
1088 QString myFieldName;
1089 QString myFieldValue;
1096 QFileInfo myInfo( myDatabaseFileName );
1097 if ( !myInfo.exists() )
1099 QgsDebugError(
"failed : " + myDatabaseFileName +
" does not exist!" );
1104 myResult = openDatabase( myDatabaseFileName, database );
1105 if ( myResult != SQLITE_OK )
1110 statement = database.
prepare( sql, myResult );
1112 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1116 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1118 myFieldName = statement.
columnName( myColNo );
1120 myMap[myFieldName] = myFieldValue;
1122 if ( statement.
step() != SQLITE_DONE )
1124 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1133 if ( myMap.empty() )
1136 QFileInfo myFileInfo;
1137 myFileInfo.setFile( myDatabaseFileName );
1138 if ( !myFileInfo.exists() )
1140 QgsDebugError( QStringLiteral(
"user qgis.db not found" ) );
1145 myResult = openDatabase( myDatabaseFileName, database );
1146 if ( myResult != SQLITE_OK )
1151 statement = database.
prepare( sql, myResult );
1153 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1157 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1159 myFieldName = statement.
columnName( myColNo );
1161 myMap[myFieldName] = myFieldValue;
1164 if ( statement.
step() != SQLITE_DONE )
1166 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1197 if ( d->mDescription.isNull() )
1203 return d->mDescription;
1210 if ( !
authid().isEmpty() )
1220 id =
isValid() ? QObject::tr(
"Custom CRS" ) : QObject::tr(
"Unknown CRS" );
1222 id = QObject::tr(
"Custom CRS: %1" ).arg(
1225 else if ( !
toProj().isEmpty() )
1226 id = QObject::tr(
"Custom CRS: %1" ).arg( type ==
MediumString ? (
toProj().left( 50 ) + QString( QChar( 0x2026 ) ) )
1228 if ( !
id.isEmpty() && !std::isnan( d->mCoordinateEpoch ) )
1229 id += QStringLiteral(
" @ %1" ).arg( d->mCoordinateEpoch );
1236 if ( d->mProjectionAcronym.isNull() )
1242 return d->mProjectionAcronym;
1248 if ( d->mEllipsoidAcronym.isNull() )
1250 if (
PJ *obj = d->threadLocalProjObject() )
1255 const QString ellipsoidAuthName( proj_get_id_auth_name( ellipsoid.get(), 0 ) );
1256 const QString ellipsoidAuthCode( proj_get_id_code( ellipsoid.get(), 0 ) );
1257 if ( !ellipsoidAuthName.isEmpty() && !ellipsoidAuthCode.isEmpty() )
1258 d->mEllipsoidAcronym = QStringLiteral(
"%1:%2" ).arg( ellipsoidAuthName, ellipsoidAuthCode );
1261 double semiMajor, semiMinor, invFlattening;
1262 int semiMinorComputed = 0;
1263 if ( proj_ellipsoid_get_parameters(
QgsProjContext::get(), ellipsoid.get(), &semiMajor, &semiMinor, &semiMinorComputed, &invFlattening ) )
1265 d->mEllipsoidAcronym = QStringLiteral(
"PARAMETER:%1:%2" ).arg(
qgsDoubleToString( semiMajor ),
1270 d->mEllipsoidAcronym.clear();
1275 return d->mEllipsoidAcronym;
1279 return d->mEllipsoidAcronym;
1293 if ( d->mProj4.isEmpty() )
1295 if (
PJ *obj = d->threadLocalProjObject() )
1301 return d->mProj4.trimmed();
1306 return d->mIsGeographic;
1324#if PROJ_VERSION_MAJOR>8 || (PROJ_VERSION_MAJOR==8 && PROJ_VERSION_MINOR>=1)
1327 return QString( proj_get_celestial_body_name( context, pj ) );
1329 throw QgsNotSupportedException( QObject::tr(
"Retrieving celestial body requires a QGIS build based on PROJ 8.1 or later" ) );
1335 if ( d->mCoordinateEpoch == epoch )
1341 d->mCoordinateEpoch = epoch;
1342 d->setPj( std::move( clone ) );
1347 return d->mCoordinateEpoch;
1359#if PROJ_VERSION_MAJOR>=8
1367 res.mName = QString( proj_get_name( ensemble.get() ) );
1368 res.mAuthority = QString( proj_get_id_auth_name( ensemble.get(), 0 ) );
1369 res.mCode = QString( proj_get_id_code( ensemble.get(), 0 ) );
1370 res.mRemarks = QString( proj_get_remarks( ensemble.get() ) );
1371 res.mScope = QString( proj_get_scope( ensemble.get() ) );
1372 res.mAccuracy = proj_datum_ensemble_get_accuracy( context, ensemble.get() );
1374 const int memberCount = proj_datum_ensemble_get_member_count( context, ensemble.get() );
1375 for (
int i = 0; i < memberCount; ++i )
1382 details.mName = QString( proj_get_name( member.get() ) );
1383 details.mAuthority = QString( proj_get_id_auth_name( member.get(), 0 ) );
1384 details.mCode = QString( proj_get_id_code( member.get(), 0 ) );
1385 details.mRemarks = QString( proj_get_remarks( member.get() ) );
1386 details.mScope = QString( proj_get_scope( member.get() ) );
1388 res.mMembers << details;
1392 throw QgsNotSupportedException( QObject::tr(
"Calculating datum ensembles requires a QGIS build based on PROJ 8.0 or later" ) );
1401 QString projString =
toProj();
1402 projString.replace( QLatin1String(
"+type=crs" ), QString() );
1405 if ( !transformation )
1408 PJ_COORD coord = proj_coord( 0, 0, 0, HUGE_VAL );
1409 coord.uv.u = point.
x() * M_PI / 180.0;
1410 coord.uv.v = point.
y() * M_PI / 180.0;
1412 proj_errno_reset( transformation.get() );
1413 const PJ_FACTORS pjFactors = proj_factors( transformation.get(), coord );
1414 if ( proj_errno( transformation.get() ) )
1419 res.mIsValid =
true;
1420 res.mMeridionalScale = pjFactors.meridional_scale;
1421 res.mParallelScale = pjFactors.parallel_scale;
1422 res.mArealScale = pjFactors.areal_scale;
1423 res.mAngularDistortion = pjFactors.angular_distortion;
1424 res.mMeridianParallelAngle = pjFactors.meridian_parallel_angle * 180 / M_PI;
1425 res.mMeridianConvergence = pjFactors.meridian_convergence * 180 / M_PI;
1426 res.mTissotSemimajor = pjFactors.tissot_semimajor;
1427 res.mTissotSemiminor = pjFactors.tissot_semiminor;
1428 res.mDxDlam = pjFactors.dx_dlam;
1429 res.mDxDphi = pjFactors.dx_dphi;
1430 res.mDyDlam = pjFactors.dy_dlam;
1431 res.mDyDphi = pjFactors.dy_dphi;
1443 QString projString =
toProj();
1444 projString.replace( QLatin1String(
"+type=crs" ), QString() );
1445 if ( projString.isEmpty() )
1449 if ( !transformation )
1452 PJ_PROJ_INFO info = proj_pj_info( transformation.get() );
1465 return Qgis::DistanceUnit::Unknown;
1467 return d->mMapUnits;
1475 PJ *obj = d->threadLocalProjObject();
1480 double southLat = 0;
1482 double northLat = 0;
1485 &westLon, &southLat, &eastLon, &northLat,
nullptr ) )
1500 const auto parts {
authid().split(
':' ) };
1501 if ( parts.length() == 2 )
1503 if ( parts[0] == QLatin1String(
"EPSG" ) )
1504 return QStringLiteral(
"http://www.opengis.net/def/crs/EPSG/0/%1" ).arg( parts[1] ) ;
1505 else if ( parts[0] == QLatin1String(
"OGC" ) )
1507 return QStringLiteral(
"http://www.opengis.net/def/crs/OGC/1.3/%1" ).arg( parts[1] ) ;
1511 QgsMessageLog::logMessage( QStringLiteral(
"Error converting published CRS to URI %1: (not OGC or EPSG)" ).arg(
authid() ), QStringLiteral(
"CRS" ), Qgis::MessageLevel::Critical );
1516 QgsMessageLog::logMessage( QStringLiteral(
"Error converting published CRS to URI: %1" ).arg(
authid() ), QStringLiteral(
"CRS" ), Qgis::MessageLevel::Critical );
1537void QgsCoordinateReferenceSystem::setProjString(
const QString &proj4String )
1540 d->mProj4 = proj4String;
1541 d->mWktPreferred.clear();
1544 QString trimmed = proj4String.trimmed();
1546 trimmed += QLatin1String(
" +type=crs" );
1556 const int errNo = proj_context_errno( ctx );
1557 QgsDebugError( QStringLiteral(
"proj string rejected: %1" ).arg( proj_errno_string( errNo ) ) );
1559 d->mIsValid =
false;
1563 d->mEllipsoidAcronym.clear();
1570bool QgsCoordinateReferenceSystem::setWktString(
const QString &wkt )
1573 d->mIsValid =
false;
1574 d->mWktPreferred.clear();
1576 PROJ_STRING_LIST warnings =
nullptr;
1577 PROJ_STRING_LIST grammerErrors =
nullptr;
1585 QgsDebugMsgLevel( QStringLiteral(
"\n---------------------------------------------------------------" ), 2 );
1586 QgsDebugMsgLevel( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ), 2 );
1588 for (
auto iter = warnings; iter && *iter; ++iter )
1590 for (
auto iter = grammerErrors; iter && *iter; ++iter )
1592 QgsDebugMsgLevel( QStringLiteral(
"---------------------------------------------------------------\n" ), 2 );
1594 proj_string_list_destroy( warnings );
1595 proj_string_list_destroy( grammerErrors );
1601 if ( !sDisableWktCache )
1602 sWktCache()->insert( wkt, *
this );
1609 QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
1610 QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
1612 if ( authName.isEmpty() || authCode.isEmpty() )
1618 if ( !authName.isEmpty() && !authCode.isEmpty() )
1620 if ( loadFromAuthCode( authName, authCode ) )
1623 if ( !sDisableWktCache )
1624 sWktCache()->insert( wkt, *
this );
1632 d->mDescription = QString( proj_get_name( d->threadLocalProjObject() ) );
1640void QgsCoordinateReferenceSystem::setMapUnits()
1644 d->mMapUnits = Qgis::DistanceUnit::Unknown;
1650 d->mMapUnits = Qgis::DistanceUnit::Unknown;
1657 if ( !coordinateSystem )
1659 d->mMapUnits = Qgis::DistanceUnit::Unknown;
1663 const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
1664 if ( axisCount > 0 )
1666 const char *outUnitName =
nullptr;
1668 proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
1677 const QString unitName( outUnitName );
1681 if ( unitName.compare( QLatin1String(
"degree" ), Qt::CaseInsensitive ) == 0 ||
1682 unitName.compare( QLatin1String(
"degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1683 unitName.compare( QLatin1String(
"degree minute second hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1684 unitName.compare( QLatin1String(
"degree minute" ), Qt::CaseInsensitive ) == 0 ||
1685 unitName.compare( QLatin1String(
"degree hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1686 unitName.compare( QLatin1String(
"degree minute hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1687 unitName.compare( QLatin1String(
"hemisphere degree" ), Qt::CaseInsensitive ) == 0 ||
1688 unitName.compare( QLatin1String(
"hemisphere degree minute" ), Qt::CaseInsensitive ) == 0 ||
1689 unitName.compare( QLatin1String(
"hemisphere degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1690 unitName.compare( QLatin1String(
"degree (supplier to define representation)" ), Qt::CaseInsensitive ) == 0 )
1691 d->mMapUnits = Qgis::DistanceUnit::Degrees;
1692 else if ( unitName.compare( QLatin1String(
"metre" ), Qt::CaseInsensitive ) == 0
1693 || unitName.compare( QLatin1String(
"m" ), Qt::CaseInsensitive ) == 0
1694 || unitName.compare( QLatin1String(
"meter" ), Qt::CaseInsensitive ) == 0 )
1695 d->mMapUnits = Qgis::DistanceUnit::Meters;
1697 else if ( unitName.compare( QLatin1String(
"US survey foot" ), Qt::CaseInsensitive ) == 0 ||
1698 unitName.compare( QLatin1String(
"foot" ), Qt::CaseInsensitive ) == 0 )
1699 d->mMapUnits = Qgis::DistanceUnit::Feet;
1700 else if ( unitName.compare( QLatin1String(
"kilometre" ), Qt::CaseInsensitive ) == 0 )
1701 d->mMapUnits = Qgis::DistanceUnit::Kilometers;
1702 else if ( unitName.compare( QLatin1String(
"centimetre" ), Qt::CaseInsensitive ) == 0 )
1703 d->mMapUnits = Qgis::DistanceUnit::Centimeters;
1704 else if ( unitName.compare( QLatin1String(
"millimetre" ), Qt::CaseInsensitive ) == 0 )
1705 d->mMapUnits = Qgis::DistanceUnit::Millimeters;
1706 else if ( unitName.compare( QLatin1String(
"Statute mile" ), Qt::CaseInsensitive ) == 0 )
1707 d->mMapUnits = Qgis::DistanceUnit::Miles;
1708 else if ( unitName.compare( QLatin1String(
"nautical mile" ), Qt::CaseInsensitive ) == 0 )
1709 d->mMapUnits = Qgis::DistanceUnit::NauticalMiles;
1710 else if ( unitName.compare( QLatin1String(
"yard" ), Qt::CaseInsensitive ) == 0 )
1711 d->mMapUnits = Qgis::DistanceUnit::Yards;
1714 d->mMapUnits = Qgis::DistanceUnit::Unknown;
1719 d->mMapUnits = Qgis::DistanceUnit::Unknown;
1727 if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
1730 QgsDebugMsgLevel(
"QgsCoordinateReferenceSystem::findMatchingProj will only "
1731 "work if prj acr ellipsoid acr and proj4string are set"
1732 " and the current projection is valid!", 4 );
1742 QString mySql = QString(
"select srs_id,parameters from tbl_srs where "
1743 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1750 myResult = openDatabase( myDatabaseFileName, database );
1751 if ( myResult != SQLITE_OK )
1756 statement = database.
prepare( mySql, myResult );
1757 if ( myResult == SQLITE_OK )
1760 while ( statement.
step() == SQLITE_ROW )
1764 if (
toProj() == myProj4String.trimmed() )
1766 return mySrsId.toLong();
1777 myResult = openDatabase( myDatabaseFileName, database );
1778 if ( myResult != SQLITE_OK )
1783 statement = database.
prepare( mySql, myResult );
1785 if ( myResult == SQLITE_OK )
1787 while ( statement.
step() == SQLITE_ROW )
1791 if (
toProj() == myProj4String.trimmed() )
1793 return mySrsId.toLong();
1807 if ( !d->mIsValid && !srs.d->mIsValid )
1810 if ( !d->mIsValid || !srs.d->mIsValid )
1818 if ( isUser != otherIsUser )
1822 if ( !isUser && ( !d->mAuthId.isEmpty() || !srs.d->mAuthId.isEmpty() ) )
1823 return d->mAuthId == srs.d->mAuthId;
1830 return !( *
this == srs );
1835 if (
PJ *obj = d->threadLocalProjObject() )
1837 const bool isDefaultPreferredFormat = variant ==
WKT_PREFERRED && !multiline;
1838 if ( isDefaultPreferredFormat && !d->mWktPreferred.isEmpty() )
1841 return d->mWktPreferred;
1844 PJ_WKT_TYPE type = PJ_WKT1_GDAL;
1848 type = PJ_WKT1_GDAL;
1851 type = PJ_WKT1_ESRI;
1854 type = PJ_WKT2_2015;
1857 type = PJ_WKT2_2015_SIMPLIFIED;
1860 type = PJ_WKT2_2019;
1863 type = PJ_WKT2_2019_SIMPLIFIED;
1867 const QByteArray multiLineOption = QStringLiteral(
"MULTILINE=%1" ).arg( multiline ? QStringLiteral(
"YES" ) : QStringLiteral(
"NO" ) ).toLocal8Bit();
1868 const QByteArray indentatationWidthOption = QStringLiteral(
"INDENTATION_WIDTH=%1" ).arg( multiline ? QString::number( indentationWidth ) : QStringLiteral(
"0" ) ).toLocal8Bit();
1869 const char *
const options[] = {multiLineOption.constData(), indentatationWidthOption.constData(),
nullptr};
1872 if ( isDefaultPreferredFormat )
1875 d->mWktPreferred = res;
1887 QDomNode srsNode = node.namedItem( QStringLiteral(
"spatialrefsys" ) );
1889 if ( ! srsNode.isNull() )
1891 bool initialized =
false;
1894 long srsid = srsNode.namedItem( QStringLiteral(
"srsid" ) ).toElement().text().toLong( &ok );
1900 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
1901 if ( !node.isNull() )
1912 node = srsNode.namedItem( QStringLiteral(
"epsg" ) );
1913 if ( !node.isNull() )
1931 const QString
description = srsNode.namedItem( QStringLiteral(
"description" ) ).toElement().text();
1933 const QString wkt = srsNode.namedItem( QStringLiteral(
"wkt" ) ).toElement().text();
1934 initialized = createFromWktInternal( wkt,
description );
1939 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
1940 const QString proj4 = node.toElement().text();
1947 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
1948 const QString proj4 = node.toElement().text();
1949 if ( !proj4.trimmed().isEmpty() )
1950 setProjString( node.toElement().text() );
1952 node = srsNode.namedItem( QStringLiteral(
"srsid" ) );
1953 d->mSrsId = node.toElement().text().toLong();
1955 node = srsNode.namedItem( QStringLiteral(
"srid" ) );
1956 d->mSRID = node.toElement().text().toLong();
1958 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
1959 d->mAuthId = node.toElement().text();
1961 node = srsNode.namedItem( QStringLiteral(
"description" ) );
1962 d->mDescription = node.toElement().text();
1964 node = srsNode.namedItem( QStringLiteral(
"projectionacronym" ) );
1965 d->mProjectionAcronym = node.toElement().text();
1967 node = srsNode.namedItem( QStringLiteral(
"ellipsoidacronym" ) );
1968 d->mEllipsoidAcronym = node.toElement().text();
1970 node = srsNode.namedItem( QStringLiteral(
"geographicflag" ) );
1971 d->mIsGeographic = node.toElement().text() == QLatin1String(
"true" );
1973 d->mWktPreferred.clear();
1979 const QString epoch = srsNode.toElement().attribute( QStringLiteral(
"coordinateEpoch" ) );
1980 if ( !epoch.isEmpty() )
1982 bool epochOk =
false;
1983 d->mCoordinateEpoch = epoch.toDouble( &epochOk );
1985 d->mCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
1989 d->mCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
1992 mNativeFormat = qgsEnumKeyToValue<Qgis::CrsDefinitionFormat>( srsNode.toElement().attribute( QStringLiteral(
"nativeFormat" ) ), Qgis::CrsDefinitionFormat::Wkt );
1997 d =
new QgsCoordinateReferenceSystemPrivate();
2005 QDomElement layerNode = node.toElement();
2006 QDomElement srsElement = doc.createElement( QStringLiteral(
"spatialrefsys" ) );
2008 srsElement.setAttribute( QStringLiteral(
"nativeFormat" ), qgsEnumValueToKey<Qgis::CrsDefinitionFormat>( mNativeFormat ) );
2010 if ( std::isfinite( d->mCoordinateEpoch ) )
2012 srsElement.setAttribute( QStringLiteral(
"coordinateEpoch" ), d->mCoordinateEpoch );
2015 QDomElement wktElement = doc.createElement( QStringLiteral(
"wkt" ) );
2017 srsElement.appendChild( wktElement );
2019 QDomElement proj4Element = doc.createElement( QStringLiteral(
"proj4" ) );
2020 proj4Element.appendChild( doc.createTextNode(
toProj() ) );
2021 srsElement.appendChild( proj4Element );
2023 QDomElement srsIdElement = doc.createElement( QStringLiteral(
"srsid" ) );
2024 srsIdElement.appendChild( doc.createTextNode( QString::number(
srsid() ) ) );
2025 srsElement.appendChild( srsIdElement );
2027 QDomElement sridElement = doc.createElement( QStringLiteral(
"srid" ) );
2028 sridElement.appendChild( doc.createTextNode( QString::number(
postgisSrid() ) ) );
2029 srsElement.appendChild( sridElement );
2031 QDomElement authidElement = doc.createElement( QStringLiteral(
"authid" ) );
2032 authidElement.appendChild( doc.createTextNode(
authid() ) );
2033 srsElement.appendChild( authidElement );
2035 QDomElement descriptionElement = doc.createElement( QStringLiteral(
"description" ) );
2036 descriptionElement.appendChild( doc.createTextNode(
description() ) );
2037 srsElement.appendChild( descriptionElement );
2039 QDomElement projectionAcronymElement = doc.createElement( QStringLiteral(
"projectionacronym" ) );
2040 projectionAcronymElement.appendChild( doc.createTextNode(
projectionAcronym() ) );
2041 srsElement.appendChild( projectionAcronymElement );
2043 QDomElement ellipsoidAcronymElement = doc.createElement( QStringLiteral(
"ellipsoidacronym" ) );
2044 ellipsoidAcronymElement.appendChild( doc.createTextNode(
ellipsoidAcronym() ) );
2045 srsElement.appendChild( ellipsoidAcronymElement );
2047 QDomElement geographicFlagElement = doc.createElement( QStringLiteral(
"geographicflag" ) );
2048 QString geoFlagText = QStringLiteral(
"false" );
2051 geoFlagText = QStringLiteral(
"true" );
2054 geographicFlagElement.appendChild( doc.createTextNode( geoFlagText ) );
2055 srsElement.appendChild( geographicFlagElement );
2057 layerNode.appendChild( srsElement );
2069QString QgsCoordinateReferenceSystem::projFromSrsId(
const int srsId )
2071 QString myDatabaseFileName;
2072 QString myProjString;
2073 QString mySql = QStringLiteral(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( srsId );
2082 QFileInfo myFileInfo;
2083 myFileInfo.setFile( myDatabaseFileName );
2084 if ( !myFileInfo.exists() )
2086 QgsDebugError( QStringLiteral(
"users qgis.db not found" ) );
2099 rc = openDatabase( myDatabaseFileName, database );
2105 statement = database.
prepare( mySql, rc );
2107 if ( rc == SQLITE_OK )
2109 if ( statement.
step() == SQLITE_ROW )
2115 return myProjString;
2122 myResult = database.
open_v2( path, SQLITE_OPEN_READONLY,
nullptr );
2124 myResult = database.
open( path );
2126 if ( myResult != SQLITE_OK )
2135 .arg( database.
errorMessage() ), QObject::tr(
"CRS" ) );
2142 sCustomSrsValidation = f;
2147 return sCustomSrsValidation;
2150void QgsCoordinateReferenceSystem::debugPrint()
2153 QgsDebugMsgLevel(
"* Valid : " + ( d->mIsValid ? QString(
"true" ) : QString(
"false" ) ), 1 );
2158 if (
mapUnits() == Qgis::DistanceUnit::Meters )
2162 else if (
mapUnits() == Qgis::DistanceUnit::Feet )
2166 else if (
mapUnits() == Qgis::DistanceUnit::Degrees )
2174 mValidationHint = html;
2179 return mValidationHint;
2189 mNativeFormat = format;
2194 return mNativeFormat;
2197long QgsCoordinateReferenceSystem::getRecordCount()
2202 long myRecordCount = 0;
2205 if ( myResult != SQLITE_OK )
2211 QString mySql = QStringLiteral(
"select count(*) from tbl_srs" );
2212 statement = database.
prepare( mySql, myResult );
2213 if ( myResult == SQLITE_OK )
2215 if ( statement.
step() == SQLITE_ROW )
2217 QString myRecordCountString = statement.
columnAsText( 0 );
2218 myRecordCount = myRecordCountString.toLong();
2221 return myRecordCount;
2227 bool isGeographic =
false;
2229 if ( coordinateSystem )
2231 const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
2232 if ( axisCount > 0 )
2234 const char *outUnitAuthName =
nullptr;
2235 const char *outUnitAuthCode =
nullptr;
2237 proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
2246 if ( outUnitAuthName && outUnitAuthCode )
2248 const char *unitCategory =
nullptr;
2249 if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode,
nullptr,
nullptr, &unitCategory ) )
2251 isGeographic = QString( unitCategory ).compare( QLatin1String(
"angular" ), Qt::CaseInsensitive ) == 0;
2256 return isGeographic;
2261 thread_local const QRegularExpression projRegExp( QStringLiteral(
"\\+proj=(\\S+)" ) );
2262 const QRegularExpressionMatch projMatch = projRegExp.match( proj );
2263 if ( !projMatch.hasMatch() )
2265 QgsDebugMsgLevel( QStringLiteral(
"no +proj argument found [%2]" ).arg( proj ), 2 );
2268 operation = projMatch.captured( 1 );
2270 const QRegularExpressionMatch ellipseMatch = projRegExp.match( proj );
2271 if ( ellipseMatch.hasMatch() )
2273 ellipsoid = ellipseMatch.captured( 1 );
2287bool QgsCoordinateReferenceSystem::loadFromAuthCode(
const QString &auth,
const QString &code )
2290 d->mIsValid =
false;
2291 d->mWktPreferred.clear();
2300 switch ( proj_get_type(
crs.get() ) )
2302 case PJ_TYPE_VERTICAL_CRS:
2312 proj4.replace( QLatin1String(
"+type=crs" ), QString() );
2313 proj4 = proj4.trimmed();
2317 d->mWktPreferred.clear();
2318 d->mDescription = QString( proj_get_name(
crs.get() ) );
2319 d->mAuthId = QStringLiteral(
"%1:%2" ).arg( auth, code );
2321 d->mAxisInvertedDirty =
true;
2326 d->mEllipsoidAcronym.clear();
2327 d->setPj( std::move(
crs ) );
2329 const QString dbVals =
sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( auth, code ).toUpper() );
2330 if ( !dbVals.isEmpty() )
2332 const QStringList parts = dbVals.split(
',' );
2333 d->mSrsId = parts.at( 0 ).toInt();
2334 d->mSRID = parts.at( 1 ).toInt();
2342QList<long> QgsCoordinateReferenceSystem::userSrsIds()
2344 QList<long> results;
2348 QFileInfo myInfo( db );
2349 if ( !myInfo.exists() )
2359 int result = openDatabase( db, database );
2360 if ( result != SQLITE_OK )
2362 QgsDebugError(
"failed : " + db +
" could not be opened!" );
2366 QString sql = QStringLiteral(
"select srs_id from tbl_srs where srs_id >= %1" ).arg(
USER_CRS_START_ID );
2368 statement = database.
prepare( sql, rc );
2371 int ret = statement.
step();
2373 if ( ret == SQLITE_DONE )
2379 if ( ret == SQLITE_ROW )
2385 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
2393long QgsCoordinateReferenceSystem::matchToUserCrs()
const
2395 PJ *obj = d->threadLocalProjObject();
2399 const QList< long > ids = userSrsIds();
2400 for (
long id : ids )
2403 if ( candidate.
projObject() && proj_is_equivalent_to( obj, candidate.
projObject(), PJ_COMP_EQUIVALENT ) )
2411static void sync_db_proj_logger(
void * ,
int level,
const char *message )
2416 if ( level == PJ_LOG_ERROR )
2420 else if ( level == PJ_LOG_DEBUG )
2428 setlocale( LC_ALL,
"C" );
2431 int inserted = 0, updated = 0, deleted = 0, errors = 0;
2436 if ( database.
open( dbFilePath ) != SQLITE_OK )
2442 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2450 char *errMsg =
nullptr;
2452 if ( sqlite3_exec( database.get(),
"create table tbl_info (proj_major INT, proj_minor INT, proj_patch INT)",
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
2454 QString sql = QStringLiteral(
"INSERT INTO tbl_info(proj_major, proj_minor, proj_patch) VALUES (%1, %2,%3)" )
2455 .arg( QString::number( PROJ_VERSION_MAJOR ),
2456 QString::number( PROJ_VERSION_MINOR ),
2457 QString::number( PROJ_VERSION_PATCH ) );
2458 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2460 QgsDebugError( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2463 errMsg ? errMsg :
"(unknown error)" ) );
2465 sqlite3_free( errMsg );
2472 QString sql = QStringLiteral(
"SELECT proj_major, proj_minor, proj_patch FROM tbl_info" );
2473 statement = database.
prepare( sql, result );
2474 if ( result != SQLITE_OK )
2479 if ( statement.
step() == SQLITE_ROW )
2484 if ( major == PROJ_VERSION_MAJOR && minor == PROJ_VERSION_MINOR && patch == PROJ_VERSION_PATCH )
2490 QgsDebugError( QStringLiteral(
"Could not retrieve previous CRS sync PROJ version number" ) );
2497 proj_log_func( pjContext,
nullptr, sync_db_proj_logger );
2499 PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
2501 int nextSrsId = 63561;
2502 int nextSrId = 520003561;
2503 for (
auto authIter = authorities; authIter && *authIter; ++authIter )
2505 const QString authority( *authIter );
2506 QgsDebugMsgLevel( QStringLiteral(
"Loading authority '%1'" ).arg( authority ), 2 );
2507 PROJ_STRING_LIST codes = proj_get_codes_from_database( pjContext, *authIter, PJ_TYPE_CRS,
true );
2509 QStringList allCodes;
2511 for (
auto codesIter = codes; codesIter && *codesIter; ++codesIter )
2513 const QString code( *codesIter );
2519 QgsDebugError( QStringLiteral(
"Could not load '%1:%2'" ).arg( authority, code ) );
2523 switch ( proj_get_type(
crs.get() ) )
2525 case PJ_TYPE_VERTICAL_CRS:
2535 proj4.replace( QLatin1String(
"+type=crs" ), QString() );
2536 proj4 = proj4.trimmed();
2538 if ( proj4.isEmpty() )
2540 QgsDebugMsgLevel( QStringLiteral(
"No proj4 for '%1:%2'" ).arg( authority, code ), 2 );
2545 const bool deprecated = proj_is_deprecated(
crs.get() );
2546 const QString name( proj_get_name(
crs.get() ) );
2548 QString sql = QStringLiteral(
"SELECT parameters,description,deprecated FROM tbl_srs WHERE auth_name='%1' AND auth_id='%2'" ).arg( authority, code );
2549 statement = database.
prepare( sql, result );
2550 if ( result != SQLITE_OK )
2558 bool srsDeprecated = deprecated;
2559 if ( statement.
step() == SQLITE_ROW )
2563 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2566 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
2568 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
2571 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name=%4 AND auth_id=%5" )
2574 .arg( deprecated ? 1 : 0 )
2577 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2579 QgsDebugError( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2582 errMsg ? errMsg :
"(unknown error)" ) );
2584 sqlite3_free( errMsg );
2602 const QString dbVals =
sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( authority, code ) );
2605 if ( !dbVals.isEmpty() )
2607 const QStringList parts = dbVals.split(
',' );
2608 srsId = parts.at( 0 );
2609 srId = parts.at( 1 );
2611 if ( srId.isEmpty() )
2613 srId = QString::number( nextSrId );
2616 if ( srsId.isEmpty() )
2618 srsId = QString::number( nextSrsId );
2622 if ( !srsId.isEmpty() )
2624 sql = QStringLiteral(
"INSERT INTO tbl_srs(srs_id, description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated) VALUES (%1, %2,%3,%4,%5,%6,%7,%8,%9,%10)" )
2634 .arg( deprecated ? 1 : 0 );
2638 sql = QStringLiteral(
"INSERT INTO tbl_srs(description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated) VALUES (%2,%3,%4,%5,%6,%7,%8,%9,%10)" )
2647 .arg( deprecated ? 1 : 0 );
2651 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2657 qCritical(
"Could not execute: %s [%s/%s]\n",
2658 sql.toLocal8Bit().constData(),
2659 sqlite3_errmsg( database.get() ),
2660 errMsg ? errMsg :
"(unknown error)" );
2664 sqlite3_free( errMsg );
2669 proj_string_list_destroy( codes );
2671 const QString sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='%1' AND NOT auth_id IN (%2)" ).arg( authority, allCodes.join(
',' ) );
2672 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
2674 deleted = sqlite3_changes( database.get() );
2679 qCritical(
"Could not execute: %s [%s]\n",
2680 sql.toLocal8Bit().constData(),
2681 sqlite3_errmsg( database.get() ) );
2685 proj_string_list_destroy( authorities );
2687 QString sql = QStringLiteral(
"UPDATE tbl_info set proj_major=%1,proj_minor=%2,proj_patch=%3" )
2688 .arg( QString::number( PROJ_VERSION_MAJOR ),
2689 QString::number( PROJ_VERSION_MINOR ),
2690 QString::number( PROJ_VERSION_PATCH ) );
2691 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2693 QgsDebugError( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2696 errMsg ? errMsg :
"(unknown error)" ) );
2698 sqlite3_free( errMsg );
2702 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2704 QgsDebugError( QStringLiteral(
"Could not commit transaction: %1 [%2]\n" ).arg(
2706 sqlite3_errmsg( database.get() ) )
2712 QgsDebugMsgLevel( QStringLiteral(
"CRS update (inserted:%1 updated:%2 deleted:%3 errors:%4)" ).arg( inserted ).arg( updated ).arg( deleted ).arg( errors ), 4 );
2720 return updated + inserted;
2723const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::stringCache()
2725 return *sStringCache();
2728const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::projCache()
2730 return *sProj4Cache();
2733const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::ogcCache()
2735 return *sOgcCache();
2738const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::wktCache()
2740 return *sWktCache();
2743const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srIdCache()
2745 return *sSrIdCache();
2748const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srsIdCache()
2750 return *sSrsIdCache();
2760 if (
PJ *obj = d->threadLocalProjObject() )
2788 else if (
PJ *obj = d->threadLocalProjObject() )
2791 return geoCrs ? QStringLiteral(
"%1:%2" ).arg( proj_get_id_auth_name( geoCrs.get(), 0 ), proj_get_id_code( geoCrs.get(), 0 ) ) : QString();
2801 return d->threadLocalProjObject();
2814 d->mIsValid =
false;
2816 d->mWktPreferred.clear();
2823 switch ( proj_get_type(
object ) )
2825 case PJ_TYPE_GEODETIC_CRS:
2826 case PJ_TYPE_GEOCENTRIC_CRS:
2827 case PJ_TYPE_GEOGRAPHIC_CRS:
2828 case PJ_TYPE_GEOGRAPHIC_2D_CRS:
2829 case PJ_TYPE_GEOGRAPHIC_3D_CRS:
2830 case PJ_TYPE_VERTICAL_CRS:
2831 case PJ_TYPE_PROJECTED_CRS:
2832 case PJ_TYPE_COMPOUND_CRS:
2833 case PJ_TYPE_TEMPORAL_CRS:
2834 case PJ_TYPE_ENGINEERING_CRS:
2835 case PJ_TYPE_BOUND_CRS:
2836 case PJ_TYPE_OTHER_CRS:
2852 const QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
2853 const QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
2854 if ( !authName.isEmpty() && !authCode.isEmpty() && loadFromAuthCode( authName, authCode ) )
2862 d->mDescription = QString( proj_get_name( d->threadLocalProjObject() ) );
2873 QStringList projections;
2875 projections.reserve( res.size() );
2878 projections << QString::number(
crs.
srsid() );
2885 QList<QgsCoordinateReferenceSystem> res;
2889 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
2890 QStringList projectionsWkt = settings.
value( QStringLiteral(
"UI/recentProjectionsWkt" ) ).toStringList();
2891 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
2892 int max = std::max( projectionsAuthId.size(), std::max( projectionsProj4.size(), projectionsWkt.size() ) );
2894 for (
int i = 0; i < max; ++i )
2896 const QString proj = projectionsProj4.value( i );
2897 const QString wkt = projectionsWkt.value( i );
2898 const QString
authid = projectionsAuthId.value( i );
2921 recent.removeAll(
crs );
2922 recent.insert( 0,
crs );
2925 recent = recent.mid( 0, 30 );
2926 QStringList authids;
2927 authids.reserve( recent.size() );
2929 proj.reserve( recent.size() );
2931 wkt.reserve( recent.size() );
2934 authids <<
c.authid();
2940 settings.
setValue( QStringLiteral(
"UI/recentProjectionsAuthId" ), authids );
2941 settings.
setValue( QStringLiteral(
"UI/recentProjectionsWkt" ), wkt );
2942 settings.
setValue( QStringLiteral(
"UI/recentProjectionsProj4" ), proj );
2952 recent.removeAll(
crs );
2953 QStringList authids;
2954 authids.reserve( recent.size() );
2956 proj.reserve( recent.size() );
2958 wkt.reserve( recent.size() );
2961 authids <<
c.authid();
2966 settings.
setValue( QStringLiteral(
"UI/recentProjectionsAuthId" ), authids );
2967 settings.
setValue( QStringLiteral(
"UI/recentProjectionsWkt" ), wkt );
2968 settings.
setValue( QStringLiteral(
"UI/recentProjectionsProj4" ), proj );
2974 settings.
remove( QStringLiteral(
"UI/recentProjectionsAuthId" ) );
2975 settings.
remove( QStringLiteral(
"UI/recentProjectionsWkt" ) );
2976 settings.
remove( QStringLiteral(
"UI/recentProjectionsProj4" ) );
2981 sSrIdCacheLock()->lockForWrite();
2982 if ( !sDisableSrIdCache )
2985 sDisableSrIdCache =
true;
2986 sSrIdCache()->clear();
2988 sSrIdCacheLock()->unlock();
2990 sOgcLock()->lockForWrite();
2991 if ( !sDisableOgcCache )
2994 sDisableOgcCache =
true;
2995 sOgcCache()->clear();
2997 sOgcLock()->unlock();
2999 sProj4CacheLock()->lockForWrite();
3000 if ( !sDisableProjCache )
3003 sDisableProjCache =
true;
3004 sProj4Cache()->clear();
3006 sProj4CacheLock()->unlock();
3008 sCRSWktLock()->lockForWrite();
3009 if ( !sDisableWktCache )
3012 sDisableWktCache =
true;
3013 sWktCache()->clear();
3015 sCRSWktLock()->unlock();
3017 sCRSSrsIdLock()->lockForWrite();
3018 if ( !sDisableSrsIdCache )
3021 sDisableSrsIdCache =
true;
3022 sSrsIdCache()->clear();
3024 sCRSSrsIdLock()->unlock();
3026 sCrsStringLock()->lockForWrite();
3027 if ( !sDisableStringCache )
3030 sDisableStringCache =
true;
3031 sStringCache()->clear();
3033 sCrsStringLock()->unlock();
3042 if ( !c1.d->mIsValid && !c2.d->mIsValid )
3045 if ( !c1.d->mIsValid && c2.d->mIsValid )
3048 if ( c1.d->mIsValid && !c2.d->mIsValid )
3054 if ( c1IsUser && !c2IsUser )
3057 if ( !c1IsUser && c2IsUser )
3060 if ( !c1IsUser && !c2IsUser )
3062 if ( c1.d->mAuthId != c2.d->mAuthId )
3063 return c1.d->mAuthId > c2.d->mAuthId;
3073 if ( c1.d->mCoordinateEpoch == c2.d->mCoordinateEpoch )
3076 if ( std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3079 if ( std::isnan( c1.d->mCoordinateEpoch ) && !std::isnan( c2.d->mCoordinateEpoch ) )
3082 if ( !std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3085 return c1.d->mCoordinateEpoch > c2.d->mCoordinateEpoch;
3093 if ( !c1.d->mIsValid && !c2.d->mIsValid )
3096 if ( c1.d->mIsValid && !c2.d->mIsValid )
3099 if ( !c1.d->mIsValid && c2.d->mIsValid )
3105 if ( !c1IsUser && c2IsUser )
3108 if ( c1IsUser && !c2IsUser )
3111 if ( !c1IsUser && !c2IsUser )
3113 if ( c1.d->mAuthId != c2.d->mAuthId )
3114 return c1.d->mAuthId < c2.d->mAuthId;
3124 if ( c1.d->mCoordinateEpoch == c2.d->mCoordinateEpoch )
3127 if ( std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3130 if ( !std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3133 if ( std::isnan( c1.d->mCoordinateEpoch ) && !std::isnan( c2.d->mCoordinateEpoch ) )
3136 return c1.d->mCoordinateEpoch < c2.d->mCoordinateEpoch;
3141 return !( c1 < c2 );
3145 return !( c1 > c2 );
DistanceUnit
Units of distance.
CrsDefinitionFormat
CRS definition formats.
CrsAxisDirection
Data provider flags.
@ 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)
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.
long addUserCrs(const QgsCoordinateReferenceSystem &crs, const QString &name, Qgis::CrsDefinitionFormat nativeFormat=Qgis::CrsDefinitionFormat::Wkt)
Adds a new crs definition as a custom ("USER") CRS.
QMap< QString, QgsProjOperation > projOperations() const
Returns a map of all valid PROJ operations.
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.
Q_GADGET Qgis::DistanceUnit mapUnits
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 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.
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.
QgsDatumEnsemble datumEnsemble() const SIP_THROW(QgsNotSupportedException)
Attempts to retrieve datum ensemble details from the CRS.
IdentifierType
Type of identifier string to create.
@ MediumString
A medium-length string, recommended for general purpose use.
@ ShortString
A heavily abbreviated string, for use when a compact representation is required.
static void removeRecentCoordinateReferenceSystem(const QgsCoordinateReferenceSystem &crs)
Removes a CRS from the list of recently used 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 QList< QgsCoordinateReferenceSystem > recentCoordinateReferenceSystems()
Returns a list of recently used CRS.
PJ * projObject() const
Returns the underlying PROJ PJ object corresponding to the CRS, or nullptr if the CRS is invalid.
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
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 void clearRecentCoordinateReferenceSystems()
Cleans the list of recently used CRS.
WktVariant
WKT formatting variants, only used for builds based on Proj >= 6.
@ WKT1_GDAL
WKT1 as traditionally output by GDAL, deriving from OGC 01-009. A notable departure from WKT1_GDAL wi...
@ WKT2_2019_SIMPLIFIED
WKT2_2019 with the simplification rule of WKT2_SIMPLIFIED.
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
@ WKT2_2015
Full WKT2 string, conforming to ISO 19162:2015(E) / OGC 12-063r5 with all possible nodes and new keyw...
@ WKT2_2019
Full WKT2 string, conforming to ISO 19162:2019 / OGC 18-010, with all possible nodes and new keyword ...
@ WKT1_ESRI
WKT1 as traditionally output by ESRI software, deriving from OGC 99-049.
@ WKT2_2015_SIMPLIFIED
Same as WKT2_2015 with the following exceptions: UNIT keyword used. ID node only on top element....
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.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
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.
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.
QString celestialBodyName() const SIP_THROW(QgsNotSupportedException)
Attempts to retrieve the name of the celestial body associated with the CRS (e.g.
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.
@ 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 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 crsToSingleCrs(const PJ *crs)
Given a PROJ crs (which may be a compound or bound crs, or some other type), extract a single crs fro...
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) SIP_HOLDGIL
Set the minimum y value.
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void remove(const QString &key, QgsSettings::Section section=QgsSettings::NoSection)
Removes the setting key and any sub-settings of key in a section.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to 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.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define Q_NOWARN_DEPRECATED_POP
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
#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