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() )
152 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
160 int result = openDatabase( db, database );
161 if ( result != SQLITE_OK )
163 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
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 QgsDebugMsg( 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() )
604 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
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 QgsDebugMsg(
"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 QgsDebugMsg( 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() );
1467 return d->mMapUnits;
1475 PJ *obj = d->threadLocalProjObject();
1480 double southLat = 0;
1482 double northLat = 0;
1485 &westLon, &southLat, &eastLon, &northLat,
nullptr ) )
1514void QgsCoordinateReferenceSystem::setProjString(
const QString &proj4String )
1517 d->mProj4 = proj4String;
1518 d->mWktPreferred.clear();
1521 QString trimmed = proj4String.trimmed();
1523 trimmed += QLatin1String(
" +type=crs" );
1533 const int errNo = proj_context_errno( ctx );
1534 QgsDebugMsg( QStringLiteral(
"proj string rejected: %1" ).arg( proj_errno_string( errNo ) ) );
1536 d->mIsValid =
false;
1540 d->mEllipsoidAcronym.clear();
1547bool QgsCoordinateReferenceSystem::setWktString(
const QString &wkt )
1550 d->mIsValid =
false;
1551 d->mWktPreferred.clear();
1553 PROJ_STRING_LIST warnings =
nullptr;
1554 PROJ_STRING_LIST grammerErrors =
nullptr;
1562 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
1563 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
1565 for (
auto iter = warnings; iter && *iter; ++iter )
1567 for (
auto iter = grammerErrors; iter && *iter; ++iter )
1569 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
1571 proj_string_list_destroy( warnings );
1572 proj_string_list_destroy( grammerErrors );
1578 if ( !sDisableWktCache )
1579 sWktCache()->insert( wkt, *
this );
1586 QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
1587 QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
1589 if ( authName.isEmpty() || authCode.isEmpty() )
1595 if ( !authName.isEmpty() && !authCode.isEmpty() )
1597 if ( loadFromAuthCode( authName, authCode ) )
1600 if ( !sDisableWktCache )
1601 sWktCache()->insert( wkt, *
this );
1609 d->mDescription = QString( proj_get_name( d->threadLocalProjObject() ) );
1617void QgsCoordinateReferenceSystem::setMapUnits()
1634 if ( !coordinateSystem )
1640 const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
1641 if ( axisCount > 0 )
1643 const char *outUnitName =
nullptr;
1645 proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
1654 const QString unitName( outUnitName );
1658 if ( unitName.compare( QLatin1String(
"degree" ), Qt::CaseInsensitive ) == 0 ||
1659 unitName.compare( QLatin1String(
"degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1660 unitName.compare( QLatin1String(
"degree minute second hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1661 unitName.compare( QLatin1String(
"degree minute" ), Qt::CaseInsensitive ) == 0 ||
1662 unitName.compare( QLatin1String(
"degree hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1663 unitName.compare( QLatin1String(
"degree minute hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1664 unitName.compare( QLatin1String(
"hemisphere degree" ), Qt::CaseInsensitive ) == 0 ||
1665 unitName.compare( QLatin1String(
"hemisphere degree minute" ), Qt::CaseInsensitive ) == 0 ||
1666 unitName.compare( QLatin1String(
"hemisphere degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1667 unitName.compare( QLatin1String(
"degree (supplier to define representation)" ), Qt::CaseInsensitive ) == 0 )
1669 else if ( unitName.compare( QLatin1String(
"metre" ), Qt::CaseInsensitive ) == 0
1670 || unitName.compare( QLatin1String(
"m" ), Qt::CaseInsensitive ) == 0
1671 || unitName.compare( QLatin1String(
"meter" ), Qt::CaseInsensitive ) == 0 )
1674 else if ( unitName.compare( QLatin1String(
"US survey foot" ), Qt::CaseInsensitive ) == 0 ||
1675 unitName.compare( QLatin1String(
"foot" ), Qt::CaseInsensitive ) == 0 )
1677 else if ( unitName.compare( QLatin1String(
"kilometre" ), Qt::CaseInsensitive ) == 0 )
1679 else if ( unitName.compare( QLatin1String(
"centimetre" ), Qt::CaseInsensitive ) == 0 )
1681 else if ( unitName.compare( QLatin1String(
"millimetre" ), Qt::CaseInsensitive ) == 0 )
1683 else if ( unitName.compare( QLatin1String(
"Statute mile" ), Qt::CaseInsensitive ) == 0 )
1685 else if ( unitName.compare( QLatin1String(
"nautical mile" ), Qt::CaseInsensitive ) == 0 )
1687 else if ( unitName.compare( QLatin1String(
"yard" ), Qt::CaseInsensitive ) == 0 )
1704 if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
1707 QgsDebugMsgLevel(
"QgsCoordinateReferenceSystem::findMatchingProj will only "
1708 "work if prj acr ellipsoid acr and proj4string are set"
1709 " and the current projection is valid!", 4 );
1719 QString mySql = QString(
"select srs_id,parameters from tbl_srs where "
1720 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1727 myResult = openDatabase( myDatabaseFileName, database );
1728 if ( myResult != SQLITE_OK )
1733 statement = database.
prepare( mySql, myResult );
1734 if ( myResult == SQLITE_OK )
1737 while ( statement.
step() == SQLITE_ROW )
1741 if (
toProj() == myProj4String.trimmed() )
1743 return mySrsId.toLong();
1754 myResult = openDatabase( myDatabaseFileName, database );
1755 if ( myResult != SQLITE_OK )
1760 statement = database.
prepare( mySql, myResult );
1762 if ( myResult == SQLITE_OK )
1764 while ( statement.
step() == SQLITE_ROW )
1768 if (
toProj() == myProj4String.trimmed() )
1770 return mySrsId.toLong();
1784 if ( !d->mIsValid && !srs.d->mIsValid )
1787 if ( !d->mIsValid || !srs.d->mIsValid )
1795 if ( isUser != otherIsUser )
1799 if ( !isUser && ( !d->mAuthId.isEmpty() || !srs.d->mAuthId.isEmpty() ) )
1800 return d->mAuthId == srs.d->mAuthId;
1807 return !( *
this == srs );
1812 if (
PJ *obj = d->threadLocalProjObject() )
1814 const bool isDefaultPreferredFormat = variant ==
WKT_PREFERRED && !multiline;
1815 if ( isDefaultPreferredFormat && !d->mWktPreferred.isEmpty() )
1818 return d->mWktPreferred;
1821 PJ_WKT_TYPE type = PJ_WKT1_GDAL;
1825 type = PJ_WKT1_GDAL;
1828 type = PJ_WKT1_ESRI;
1831 type = PJ_WKT2_2015;
1834 type = PJ_WKT2_2015_SIMPLIFIED;
1837 type = PJ_WKT2_2019;
1840 type = PJ_WKT2_2019_SIMPLIFIED;
1844 const QByteArray multiLineOption = QStringLiteral(
"MULTILINE=%1" ).arg( multiline ? QStringLiteral(
"YES" ) : QStringLiteral(
"NO" ) ).toLocal8Bit();
1845 const QByteArray indentatationWidthOption = QStringLiteral(
"INDENTATION_WIDTH=%1" ).arg( multiline ? QString::number( indentationWidth ) : QStringLiteral(
"0" ) ).toLocal8Bit();
1846 const char *
const options[] = {multiLineOption.constData(), indentatationWidthOption.constData(),
nullptr};
1849 if ( isDefaultPreferredFormat )
1852 d->mWktPreferred = res;
1864 QDomNode srsNode = node.namedItem( QStringLiteral(
"spatialrefsys" ) );
1866 if ( ! srsNode.isNull() )
1868 bool initialized =
false;
1871 long srsid = srsNode.namedItem( QStringLiteral(
"srsid" ) ).toElement().text().toLong( &ok );
1877 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
1878 if ( !node.isNull() )
1889 node = srsNode.namedItem( QStringLiteral(
"epsg" ) );
1890 if ( !node.isNull() )
1908 const QString
description = srsNode.namedItem( QStringLiteral(
"description" ) ).toElement().text();
1910 const QString wkt = srsNode.namedItem( QStringLiteral(
"wkt" ) ).toElement().text();
1911 initialized = createFromWktInternal( wkt,
description );
1916 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
1917 const QString proj4 = node.toElement().text();
1924 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
1925 const QString proj4 = node.toElement().text();
1926 if ( !proj4.trimmed().isEmpty() )
1927 setProjString( node.toElement().text() );
1929 node = srsNode.namedItem( QStringLiteral(
"srsid" ) );
1930 d->mSrsId = node.toElement().text().toLong();
1932 node = srsNode.namedItem( QStringLiteral(
"srid" ) );
1933 d->mSRID = node.toElement().text().toLong();
1935 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
1936 d->mAuthId = node.toElement().text();
1938 node = srsNode.namedItem( QStringLiteral(
"description" ) );
1939 d->mDescription = node.toElement().text();
1941 node = srsNode.namedItem( QStringLiteral(
"projectionacronym" ) );
1942 d->mProjectionAcronym = node.toElement().text();
1944 node = srsNode.namedItem( QStringLiteral(
"ellipsoidacronym" ) );
1945 d->mEllipsoidAcronym = node.toElement().text();
1947 node = srsNode.namedItem( QStringLiteral(
"geographicflag" ) );
1948 d->mIsGeographic = node.toElement().text() == QLatin1String(
"true" );
1950 d->mWktPreferred.clear();
1956 const QString epoch = srsNode.toElement().attribute( QStringLiteral(
"coordinateEpoch" ) );
1957 if ( !epoch.isEmpty() )
1959 bool epochOk =
false;
1960 d->mCoordinateEpoch = epoch.toDouble( &epochOk );
1962 d->mCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
1966 d->mCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
1969 mNativeFormat = qgsEnumKeyToValue<Qgis::CrsDefinitionFormat>( srsNode.toElement().attribute( QStringLiteral(
"nativeFormat" ) ), Qgis::CrsDefinitionFormat::Wkt );
1974 d =
new QgsCoordinateReferenceSystemPrivate();
1982 QDomElement layerNode = node.toElement();
1983 QDomElement srsElement = doc.createElement( QStringLiteral(
"spatialrefsys" ) );
1985 srsElement.setAttribute( QStringLiteral(
"nativeFormat" ), qgsEnumValueToKey<Qgis::CrsDefinitionFormat>( mNativeFormat ) );
1987 if ( std::isfinite( d->mCoordinateEpoch ) )
1989 srsElement.setAttribute( QStringLiteral(
"coordinateEpoch" ), d->mCoordinateEpoch );
1992 QDomElement wktElement = doc.createElement( QStringLiteral(
"wkt" ) );
1994 srsElement.appendChild( wktElement );
1996 QDomElement proj4Element = doc.createElement( QStringLiteral(
"proj4" ) );
1997 proj4Element.appendChild( doc.createTextNode(
toProj() ) );
1998 srsElement.appendChild( proj4Element );
2000 QDomElement srsIdElement = doc.createElement( QStringLiteral(
"srsid" ) );
2001 srsIdElement.appendChild( doc.createTextNode( QString::number(
srsid() ) ) );
2002 srsElement.appendChild( srsIdElement );
2004 QDomElement sridElement = doc.createElement( QStringLiteral(
"srid" ) );
2005 sridElement.appendChild( doc.createTextNode( QString::number(
postgisSrid() ) ) );
2006 srsElement.appendChild( sridElement );
2008 QDomElement authidElement = doc.createElement( QStringLiteral(
"authid" ) );
2009 authidElement.appendChild( doc.createTextNode(
authid() ) );
2010 srsElement.appendChild( authidElement );
2012 QDomElement descriptionElement = doc.createElement( QStringLiteral(
"description" ) );
2013 descriptionElement.appendChild( doc.createTextNode(
description() ) );
2014 srsElement.appendChild( descriptionElement );
2016 QDomElement projectionAcronymElement = doc.createElement( QStringLiteral(
"projectionacronym" ) );
2017 projectionAcronymElement.appendChild( doc.createTextNode(
projectionAcronym() ) );
2018 srsElement.appendChild( projectionAcronymElement );
2020 QDomElement ellipsoidAcronymElement = doc.createElement( QStringLiteral(
"ellipsoidacronym" ) );
2021 ellipsoidAcronymElement.appendChild( doc.createTextNode(
ellipsoidAcronym() ) );
2022 srsElement.appendChild( ellipsoidAcronymElement );
2024 QDomElement geographicFlagElement = doc.createElement( QStringLiteral(
"geographicflag" ) );
2025 QString geoFlagText = QStringLiteral(
"false" );
2028 geoFlagText = QStringLiteral(
"true" );
2031 geographicFlagElement.appendChild( doc.createTextNode( geoFlagText ) );
2032 srsElement.appendChild( geographicFlagElement );
2034 layerNode.appendChild( srsElement );
2046QString QgsCoordinateReferenceSystem::projFromSrsId(
const int srsId )
2048 QString myDatabaseFileName;
2049 QString myProjString;
2050 QString mySql = QStringLiteral(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( srsId );
2059 QFileInfo myFileInfo;
2060 myFileInfo.setFile( myDatabaseFileName );
2061 if ( !myFileInfo.exists() )
2063 QgsDebugMsg( QStringLiteral(
"users qgis.db not found" ) );
2076 rc = openDatabase( myDatabaseFileName, database );
2082 statement = database.
prepare( mySql, rc );
2084 if ( rc == SQLITE_OK )
2086 if ( statement.
step() == SQLITE_ROW )
2092 return myProjString;
2099 myResult = database.
open_v2( path, SQLITE_OPEN_READONLY,
nullptr );
2101 myResult = database.
open( path );
2103 if ( myResult != SQLITE_OK )
2112 .arg( database.
errorMessage() ), QObject::tr(
"CRS" ) );
2119 sCustomSrsValidation = f;
2124 return sCustomSrsValidation;
2127void QgsCoordinateReferenceSystem::debugPrint()
2129 QgsDebugMsg( QStringLiteral(
"***SpatialRefSystem***" ) );
2130 QgsDebugMsg(
"* Valid : " + ( d->mIsValid ? QString(
"true" ) : QString(
"false" ) ) );
2131 QgsDebugMsg(
"* SrsId : " + QString::number( d->mSrsId ) );
2137 QgsDebugMsg( QStringLiteral(
"* Units : meters" ) );
2141 QgsDebugMsg( QStringLiteral(
"* Units : feet" ) );
2145 QgsDebugMsg( QStringLiteral(
"* Units : degrees" ) );
2151 mValidationHint = html;
2156 return mValidationHint;
2166 mNativeFormat = format;
2171 return mNativeFormat;
2174long QgsCoordinateReferenceSystem::getRecordCount()
2179 long myRecordCount = 0;
2182 if ( myResult != SQLITE_OK )
2188 QString mySql = QStringLiteral(
"select count(*) from tbl_srs" );
2189 statement = database.
prepare( mySql, myResult );
2190 if ( myResult == SQLITE_OK )
2192 if ( statement.
step() == SQLITE_ROW )
2194 QString myRecordCountString = statement.
columnAsText( 0 );
2195 myRecordCount = myRecordCountString.toLong();
2198 return myRecordCount;
2204 bool isGeographic =
false;
2206 if ( coordinateSystem )
2208 const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
2209 if ( axisCount > 0 )
2211 const char *outUnitAuthName =
nullptr;
2212 const char *outUnitAuthCode =
nullptr;
2214 proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
2223 if ( outUnitAuthName && outUnitAuthCode )
2225 const char *unitCategory =
nullptr;
2226 if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode,
nullptr,
nullptr, &unitCategory ) )
2228 isGeographic = QString( unitCategory ).compare( QLatin1String(
"angular" ), Qt::CaseInsensitive ) == 0;
2233 return isGeographic;
2238 thread_local const QRegularExpression projRegExp( QStringLiteral(
"\\+proj=(\\S+)" ) );
2239 const QRegularExpressionMatch projMatch = projRegExp.match( proj );
2240 if ( !projMatch.hasMatch() )
2242 QgsDebugMsgLevel( QStringLiteral(
"no +proj argument found [%2]" ).arg( proj ), 2 );
2245 operation = projMatch.captured( 1 );
2247 const QRegularExpressionMatch ellipseMatch = projRegExp.match( proj );
2248 if ( ellipseMatch.hasMatch() )
2250 ellipsoid = ellipseMatch.captured( 1 );
2264bool QgsCoordinateReferenceSystem::loadFromAuthCode(
const QString &auth,
const QString &code )
2267 d->mIsValid =
false;
2268 d->mWktPreferred.clear();
2277 switch ( proj_get_type(
crs.get() ) )
2279 case PJ_TYPE_VERTICAL_CRS:
2289 proj4.replace( QLatin1String(
"+type=crs" ), QString() );
2290 proj4 = proj4.trimmed();
2294 d->mWktPreferred.clear();
2295 d->mDescription = QString( proj_get_name(
crs.get() ) );
2296 d->mAuthId = QStringLiteral(
"%1:%2" ).arg( auth, code );
2298 d->mAxisInvertedDirty =
true;
2303 d->mEllipsoidAcronym.clear();
2304 d->setPj( std::move(
crs ) );
2306 const QString dbVals =
sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( auth, code ).toUpper() );
2307 if ( !dbVals.isEmpty() )
2309 const QStringList parts = dbVals.split(
',' );
2310 d->mSrsId = parts.at( 0 ).toInt();
2311 d->mSRID = parts.at( 1 ).toInt();
2319QList<long> QgsCoordinateReferenceSystem::userSrsIds()
2321 QList<long> results;
2325 QFileInfo myInfo( db );
2326 if ( !myInfo.exists() )
2328 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
2336 int result = openDatabase( db, database );
2337 if ( result != SQLITE_OK )
2339 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
2343 QString sql = QStringLiteral(
"select srs_id from tbl_srs where srs_id >= %1" ).arg(
USER_CRS_START_ID );
2345 statement = database.
prepare( sql, rc );
2348 int ret = statement.
step();
2350 if ( ret == SQLITE_DONE )
2356 if ( ret == SQLITE_ROW )
2362 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
2370long QgsCoordinateReferenceSystem::matchToUserCrs()
const
2372 PJ *obj = d->threadLocalProjObject();
2376 const QList< long > ids = userSrsIds();
2377 for (
long id : ids )
2380 if ( candidate.
projObject() && proj_is_equivalent_to( obj, candidate.
projObject(), PJ_COMP_EQUIVALENT ) )
2388static void sync_db_proj_logger(
void * ,
int level,
const char *message )
2393 if ( level == PJ_LOG_ERROR )
2397 else if ( level == PJ_LOG_DEBUG )
2405 setlocale( LC_ALL,
"C" );
2408 int inserted = 0, updated = 0, deleted = 0, errors = 0;
2413 if ( database.
open( dbFilePath ) != SQLITE_OK )
2419 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2427 char *errMsg =
nullptr;
2429 if ( sqlite3_exec( database.get(),
"create table tbl_info (proj_major INT, proj_minor INT, proj_patch INT)",
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
2431 QString sql = QStringLiteral(
"INSERT INTO tbl_info(proj_major, proj_minor, proj_patch) VALUES (%1, %2,%3)" )
2432 .arg( QString::number( PROJ_VERSION_MAJOR ),
2433 QString::number( PROJ_VERSION_MINOR ),
2434 QString::number( PROJ_VERSION_PATCH ) );
2435 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2437 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2440 errMsg ? errMsg :
"(unknown error)" ) );
2442 sqlite3_free( errMsg );
2449 QString sql = QStringLiteral(
"SELECT proj_major, proj_minor, proj_patch FROM tbl_info" );
2450 statement = database.
prepare( sql, result );
2451 if ( result != SQLITE_OK )
2456 if ( statement.
step() == SQLITE_ROW )
2461 if ( major == PROJ_VERSION_MAJOR && minor == PROJ_VERSION_MINOR && patch == PROJ_VERSION_PATCH )
2467 QgsDebugMsg( QStringLiteral(
"Could not retrieve previous CRS sync PROJ version number" ) );
2474 proj_log_func( pjContext,
nullptr, sync_db_proj_logger );
2476 PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
2478 int nextSrsId = 63561;
2479 int nextSrId = 520003561;
2480 for (
auto authIter = authorities; authIter && *authIter; ++authIter )
2482 const QString authority( *authIter );
2483 QgsDebugMsgLevel( QStringLiteral(
"Loading authority '%1'" ).arg( authority ), 2 );
2484 PROJ_STRING_LIST codes = proj_get_codes_from_database( pjContext, *authIter, PJ_TYPE_CRS,
true );
2486 QStringList allCodes;
2488 for (
auto codesIter = codes; codesIter && *codesIter; ++codesIter )
2490 const QString code( *codesIter );
2496 QgsDebugMsg( QStringLiteral(
"Could not load '%1:%2'" ).arg( authority, code ) );
2500 switch ( proj_get_type(
crs.get() ) )
2502 case PJ_TYPE_VERTICAL_CRS:
2512 proj4.replace( QLatin1String(
"+type=crs" ), QString() );
2513 proj4 = proj4.trimmed();
2515 if ( proj4.isEmpty() )
2517 QgsDebugMsgLevel( QStringLiteral(
"No proj4 for '%1:%2'" ).arg( authority, code ), 2 );
2522 const bool deprecated = proj_is_deprecated(
crs.get() );
2523 const QString name( proj_get_name(
crs.get() ) );
2525 QString sql = QStringLiteral(
"SELECT parameters,description,deprecated FROM tbl_srs WHERE auth_name='%1' AND auth_id='%2'" ).arg( authority, code );
2526 statement = database.
prepare( sql, result );
2527 if ( result != SQLITE_OK )
2535 bool srsDeprecated = deprecated;
2536 if ( statement.
step() == SQLITE_ROW )
2540 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2543 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
2545 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
2548 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name=%4 AND auth_id=%5" )
2551 .arg( deprecated ? 1 : 0 )
2554 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2556 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2559 errMsg ? errMsg :
"(unknown error)" ) );
2561 sqlite3_free( errMsg );
2579 const QString dbVals =
sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( authority, code ) );
2582 if ( !dbVals.isEmpty() )
2584 const QStringList parts = dbVals.split(
',' );
2585 srsId = parts.at( 0 );
2586 srId = parts.at( 1 );
2588 if ( srId.isEmpty() )
2590 srId = QString::number( nextSrId );
2593 if ( srsId.isEmpty() )
2595 srsId = QString::number( nextSrsId );
2599 if ( !srsId.isEmpty() )
2601 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)" )
2611 .arg( deprecated ? 1 : 0 );
2615 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)" )
2624 .arg( deprecated ? 1 : 0 );
2628 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2634 qCritical(
"Could not execute: %s [%s/%s]\n",
2635 sql.toLocal8Bit().constData(),
2636 sqlite3_errmsg( database.get() ),
2637 errMsg ? errMsg :
"(unknown error)" );
2641 sqlite3_free( errMsg );
2646 proj_string_list_destroy( codes );
2648 const QString sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='%1' AND NOT auth_id IN (%2)" ).arg( authority, allCodes.join(
',' ) );
2649 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
2651 deleted = sqlite3_changes( database.get() );
2656 qCritical(
"Could not execute: %s [%s]\n",
2657 sql.toLocal8Bit().constData(),
2658 sqlite3_errmsg( database.get() ) );
2662 proj_string_list_destroy( authorities );
2664 QString sql = QStringLiteral(
"UPDATE tbl_info set proj_major=%1,proj_minor=%2,proj_patch=%3" )
2665 .arg( QString::number( PROJ_VERSION_MAJOR ),
2666 QString::number( PROJ_VERSION_MINOR ),
2667 QString::number( PROJ_VERSION_PATCH ) );
2668 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2670 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2673 errMsg ? errMsg :
"(unknown error)" ) );
2675 sqlite3_free( errMsg );
2679 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2681 QgsDebugMsg( QStringLiteral(
"Could not commit transaction: %1 [%2]\n" ).arg(
2683 sqlite3_errmsg( database.get() ) )
2689 QgsDebugMsgLevel( QStringLiteral(
"CRS update (inserted:%1 updated:%2 deleted:%3 errors:%4)" ).arg( inserted ).arg( updated ).arg( deleted ).arg( errors ), 4 );
2697 return updated + inserted;
2700const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::stringCache()
2702 return *sStringCache();
2705const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::projCache()
2707 return *sProj4Cache();
2710const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::ogcCache()
2712 return *sOgcCache();
2715const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::wktCache()
2717 return *sWktCache();
2720const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srIdCache()
2722 return *sSrIdCache();
2725const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srsIdCache()
2727 return *sSrsIdCache();
2737 if (
PJ *obj = d->threadLocalProjObject() )
2765 else if (
PJ *obj = d->threadLocalProjObject() )
2768 return geoCrs ? QStringLiteral(
"%1:%2" ).arg( proj_get_id_auth_name( geoCrs.get(), 0 ), proj_get_id_code( geoCrs.get(), 0 ) ) : QString();
2778 return d->threadLocalProjObject();
2791 d->mIsValid =
false;
2793 d->mWktPreferred.clear();
2800 switch ( proj_get_type(
object ) )
2802 case PJ_TYPE_GEODETIC_CRS:
2803 case PJ_TYPE_GEOCENTRIC_CRS:
2804 case PJ_TYPE_GEOGRAPHIC_CRS:
2805 case PJ_TYPE_GEOGRAPHIC_2D_CRS:
2806 case PJ_TYPE_GEOGRAPHIC_3D_CRS:
2807 case PJ_TYPE_VERTICAL_CRS:
2808 case PJ_TYPE_PROJECTED_CRS:
2809 case PJ_TYPE_COMPOUND_CRS:
2810 case PJ_TYPE_TEMPORAL_CRS:
2811 case PJ_TYPE_ENGINEERING_CRS:
2812 case PJ_TYPE_BOUND_CRS:
2813 case PJ_TYPE_OTHER_CRS:
2829 const QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
2830 const QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
2831 if ( !authName.isEmpty() && !authCode.isEmpty() && loadFromAuthCode( authName, authCode ) )
2839 d->mDescription = QString( proj_get_name( d->threadLocalProjObject() ) );
2849 QStringList projections;
2851 projections.reserve( res.size() );
2854 projections << QString::number(
crs.
srsid() );
2861 QList<QgsCoordinateReferenceSystem> res;
2865 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
2866 QStringList projectionsWkt = settings.
value( QStringLiteral(
"UI/recentProjectionsWkt" ) ).toStringList();
2867 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
2868 int max = std::max( projectionsAuthId.size(), std::max( projectionsProj4.size(), projectionsWkt.size() ) );
2870 for (
int i = 0; i < max; ++i )
2872 const QString proj = projectionsProj4.value( i );
2873 const QString wkt = projectionsWkt.value( i );
2874 const QString
authid = projectionsAuthId.value( i );
2897 recent.removeAll(
crs );
2898 recent.insert( 0,
crs );
2901 recent = recent.mid( 0, 30 );
2902 QStringList authids;
2903 authids.reserve( recent.size() );
2905 proj.reserve( recent.size() );
2907 wkt.reserve( recent.size() );
2910 authids <<
c.authid();
2916 settings.
setValue( QStringLiteral(
"UI/recentProjectionsAuthId" ), authids );
2917 settings.
setValue( QStringLiteral(
"UI/recentProjectionsWkt" ), wkt );
2918 settings.
setValue( QStringLiteral(
"UI/recentProjectionsProj4" ), proj );
2923 sSrIdCacheLock()->lockForWrite();
2924 if ( !sDisableSrIdCache )
2927 sDisableSrIdCache =
true;
2928 sSrIdCache()->clear();
2930 sSrIdCacheLock()->unlock();
2932 sOgcLock()->lockForWrite();
2933 if ( !sDisableOgcCache )
2936 sDisableOgcCache =
true;
2937 sOgcCache()->clear();
2939 sOgcLock()->unlock();
2941 sProj4CacheLock()->lockForWrite();
2942 if ( !sDisableProjCache )
2945 sDisableProjCache =
true;
2946 sProj4Cache()->clear();
2948 sProj4CacheLock()->unlock();
2950 sCRSWktLock()->lockForWrite();
2951 if ( !sDisableWktCache )
2954 sDisableWktCache =
true;
2955 sWktCache()->clear();
2957 sCRSWktLock()->unlock();
2959 sCRSSrsIdLock()->lockForWrite();
2960 if ( !sDisableSrsIdCache )
2963 sDisableSrsIdCache =
true;
2964 sSrsIdCache()->clear();
2966 sCRSSrsIdLock()->unlock();
2968 sCrsStringLock()->lockForWrite();
2969 if ( !sDisableStringCache )
2972 sDisableStringCache =
true;
2973 sStringCache()->clear();
2975 sCrsStringLock()->unlock();
2984 if ( !c1.d->mIsValid && !c2.d->mIsValid )
2987 if ( !c1.d->mIsValid && c2.d->mIsValid )
2990 if ( c1.d->mIsValid && !c2.d->mIsValid )
2996 if ( c1IsUser && !c2IsUser )
2999 if ( !c1IsUser && c2IsUser )
3002 if ( !c1IsUser && !c2IsUser )
3004 if ( c1.d->mAuthId != c2.d->mAuthId )
3005 return c1.d->mAuthId > c2.d->mAuthId;
3015 if ( c1.d->mCoordinateEpoch == c2.d->mCoordinateEpoch )
3018 if ( std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3021 if ( std::isnan( c1.d->mCoordinateEpoch ) && !std::isnan( c2.d->mCoordinateEpoch ) )
3024 if ( !std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3027 return c1.d->mCoordinateEpoch > c2.d->mCoordinateEpoch;
3035 if ( !c1.d->mIsValid && !c2.d->mIsValid )
3038 if ( c1.d->mIsValid && !c2.d->mIsValid )
3041 if ( !c1.d->mIsValid && c2.d->mIsValid )
3047 if ( !c1IsUser && c2IsUser )
3050 if ( c1IsUser && !c2IsUser )
3053 if ( !c1IsUser && !c2IsUser )
3055 if ( c1.d->mAuthId != c2.d->mAuthId )
3056 return c1.d->mAuthId < c2.d->mAuthId;
3066 if ( c1.d->mCoordinateEpoch == c2.d->mCoordinateEpoch )
3069 if ( std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3072 if ( !std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
3075 if ( std::isnan( c1.d->mCoordinateEpoch ) && !std::isnan( c2.d->mCoordinateEpoch ) )
3078 return c1.d->mCoordinateEpoch < c2.d->mCoordinateEpoch;
3083 return !( c1 < c2 );
3087 return !( c1 > c2 );
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.
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.
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.
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.
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,...
Q_GADGET QgsUnitTypes::DistanceUnit mapUnits
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 axis is inverted (e.g., for WMS 1.3) for the CRS.
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 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...
DistanceUnit
Units of distance.
@ DistanceDegrees
Degrees, for planar geographic CRS distance measurements.
@ DistanceKilometers
Kilometers.
@ DistanceMiles
Terrestrial miles.
@ DistanceUnknownUnit
Unknown distance unit.
@ DistanceMillimeters
Millimeters.
@ DistanceYards
Imperial yards.
@ DistanceFeet
Imperial feet.
@ DistanceNauticalMiles
Nautical miles.
@ DistanceCentimeters
Centimeters.
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)
const QgsCoordinateReferenceSystem & crs