19#include "moc_qgscoordinatereferencesystem.cpp" 
   33#include <QRegularExpression> 
   53#include <proj_experimental.h> 
   56#include <ogr_srs_api.h> 
   68bool QgsCoordinateReferenceSystem::sDisableSrIdCache = 
false;
 
   72bool QgsCoordinateReferenceSystem::sDisableOgcCache = 
false;
 
   76bool QgsCoordinateReferenceSystem::sDisableProjCache = 
false;
 
   80bool QgsCoordinateReferenceSystem::sDisableWktCache = 
false;
 
   84bool QgsCoordinateReferenceSystem::sDisableSrsIdCache = 
false;
 
   88bool QgsCoordinateReferenceSystem::sDisableStringCache = 
false;
 
   97    if ( 
const char *proj4src = proj_as_proj_string( 
QgsProjContext::get(), boundCrs.get(), PJ_PROJ_4, 
nullptr ) )
 
   99      return QString( proj4src );
 
 
  116  d = 
new QgsCoordinateReferenceSystemPrivate();
 
 
  122  d = 
new QgsCoordinateReferenceSystemPrivate();
 
 
  130  , mValidationHint( srs.mValidationHint )
 
  131  , mNativeFormat( srs.mNativeFormat )
 
 
  138  mValidationHint = srs.mValidationHint;
 
  139  mNativeFormat = srs.mNativeFormat;
 
 
  149  const auto constDbs = dbs;
 
  150  for ( 
const QString &db : constDbs )
 
  152    QFileInfo myInfo( db );
 
  153    if ( !myInfo.exists() )
 
  163    int result = openDatabase( db, database );
 
  164    if ( result != SQLITE_OK )
 
  170    QString sql = QStringLiteral( 
"select srs_id from tbl_srs" );
 
  172    statement = database.
prepare( sql, rc );
 
  176      int ret = statement.
step();
 
  178      if ( ret == SQLITE_DONE )
 
  184      if ( ret == SQLITE_ROW )
 
  190        QgsMessageLog::logMessage( QObject::tr( 
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr( 
"SpatiaLite" ) );
 
  195  std::sort( results.begin(), results.end() );
 
 
  251  if ( horizontalObj && verticalObj )
 
  258    QStringList formattedErrorList;
 
  259    for ( 
const QString &rawError : std::as_const( errors ) )
 
  261      QString formattedError = rawError;
 
  262      formattedError.replace( QLatin1String( 
"proj_create_compound_crs: " ), QString() );
 
  263      formattedErrorList.append( formattedError );
 
  265    error = formattedErrorList.join( 
'\n' );
 
 
  273  if ( !ellipsoidParams.
valid )
 
 
  315      QgsDebugError( QStringLiteral( 
"Unexpected case reached!" ) );
 
 
  322  if ( definition.isEmpty() )
 
  326  if ( !sDisableStringCache )
 
  328    QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sStringCache()->constFind( definition );
 
  329    if ( crsIt != sStringCache()->constEnd() )
 
  332      *
this = crsIt.value();
 
  339  const thread_local QRegularExpression reCrsId( QStringLiteral( 
"^(epsg|esri|osgeo|ignf|ogc|nkg|zangi|iau_2015|iau2000|postgis|internal|user)\\:(\\w+)$" ), QRegularExpression::CaseInsensitiveOption );
 
  340  QRegularExpressionMatch match = reCrsId.match( definition );
 
  341  if ( match.capturedStart() == 0 )
 
  343    QString authName = match.captured( 1 ).toLower();
 
  344    if ( authName == QLatin1String( 
"epsg" ) )
 
  348    else if ( authName == QLatin1String( 
"postgis" ) )
 
  350      const long id = match.captured( 2 ).toLong();
 
  355    else if ( authName == QLatin1String( 
"esri" )
 
  356              || authName == QLatin1String( 
"osgeo" )
 
  357              || authName == QLatin1String( 
"ignf" )
 
  358              || authName == QLatin1String( 
"zangi" )
 
  359              || authName == QLatin1String( 
"iau2000" )
 
  360              || authName == QLatin1String( 
"ogc" )
 
  361              || authName == QLatin1String( 
"nkg" )
 
  362              || authName == QLatin1String( 
"iau_2015" )
 
  369      const long id = match.captured( 2 ).toLong();
 
  377    const thread_local QRegularExpression reCrsStr( QStringLiteral( 
"^(?:(wkt|proj4|proj)\\:)?(.+)$" ), QRegularExpression::CaseInsensitiveOption );
 
  378    match = reCrsStr.match( definition );
 
  379    if ( match.capturedStart() == 0 )
 
  381      if ( match.captured( 1 ).startsWith( QLatin1String( 
"proj" ), Qt::CaseInsensitive ) )
 
  393  if ( !sDisableStringCache )
 
  394    sStringCache()->insert( definition, *
this );
 
 
  400  if ( definition.isEmpty() )
 
  404  OGRSpatialReferenceH 
crs = OSRNewSpatialReference( 
nullptr );
 
  406  if ( OSRSetFromUserInput( 
crs, definition.toLocal8Bit().constData() ) == OGRERR_NONE )
 
  409    OSRDestroySpatialReference( 
crs );
 
 
  419  const char *configOld = CPLGetConfigOption( 
"GDAL_FIX_ESRI_WKT", 
"" );
 
  420  const char *configNew = 
"GEOGCS";
 
  422  if ( strcmp( configOld, 
"" ) == 0 )
 
  424    CPLSetConfigOption( 
"GDAL_FIX_ESRI_WKT", configNew );
 
  425    if ( strcmp( configNew, CPLGetConfigOption( 
"GDAL_FIX_ESRI_WKT", 
"" ) ) != 0 )
 
  427                          .arg( configNew, CPLGetConfigOption( 
"GDAL_FIX_ESRI_WKT", 
"" ) ) );
 
  428    QgsDebugMsgLevel( QStringLiteral( 
"set GDAL_FIX_ESRI_WKT : %1" ).arg( configNew ), 4 );
 
  432    QgsDebugMsgLevel( QStringLiteral( 
"GDAL_FIX_ESRI_WKT was already set : %1" ).arg( configNew ), 4 );
 
 
  442  if ( !sDisableOgcCache )
 
  444    QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sOgcCache()->constFind( 
crs );
 
  445    if ( crsIt != sOgcCache()->constEnd() )
 
  448      *
this = crsIt.value();
 
  454  QString wmsCrs = 
crs;
 
  459  const QString authorityLower = authority.toLower();
 
  461       ( authorityLower == QLatin1String( 
"user" ) ||
 
  462         authorityLower == QLatin1String( 
"custom" ) ||
 
  463         authorityLower == QLatin1String( 
"qgis" ) ) )
 
  468      if ( !sDisableOgcCache )
 
  469        sOgcCache()->insert( 
crs, *
this );
 
  475    wmsCrs = authority + 
':' + code;
 
  479  const QString legacyKey = wmsCrs.toLower();
 
  482    if ( it.key().compare( legacyKey, Qt::CaseInsensitive ) == 0 )
 
  484      const QStringList parts = it.key().split( 
':' );
 
  485      const QString auth = parts.at( 0 );
 
  486      const QString code = parts.at( 1 );
 
  487      if ( loadFromAuthCode( auth, code ) )
 
  490        if ( !sDisableOgcCache )
 
  491          sOgcCache()->insert( 
crs, *
this );
 
  500    if ( !sDisableOgcCache )
 
  501      sOgcCache()->insert( 
crs, *
this );
 
  506  if ( wmsCrs.compare( QLatin1String( 
"CRS:27" ), Qt::CaseInsensitive ) == 0 ||
 
  507       wmsCrs.compare( QLatin1String( 
"OGC:CRS27" ), Qt::CaseInsensitive ) == 0 )
 
  514  if ( wmsCrs.compare( QLatin1String( 
"CRS:83" ), Qt::CaseInsensitive ) == 0 ||
 
  515       wmsCrs.compare( QLatin1String( 
"OGC:CRS83" ), Qt::CaseInsensitive ) == 0 )
 
  522  if ( wmsCrs.compare( QLatin1String( 
"CRS:84" ), Qt::CaseInsensitive ) == 0 ||
 
  523       wmsCrs.compare( QLatin1String( 
"OGC:CRS84" ), Qt::CaseInsensitive ) == 0 )
 
  527      d->mAxisInverted = 
false;
 
  528      d->mAxisInvertedDirty = 
false;
 
  532    if ( !sDisableOgcCache )
 
  533      sOgcCache()->insert( 
crs, *
this );
 
  540  if ( !authority.isEmpty() && !code.isEmpty() && loadFromAuthCode( authority, code ) )
 
  543    if ( !sDisableOgcCache )
 
  544      sOgcCache()->insert( 
crs, *
this );
 
  549  if ( !sDisableOgcCache )
 
 
  559  if ( d->mIsValid || !sCustomSrsValidation )
 
  563  if ( sCustomSrsValidation )
 
  564    sCustomSrsValidation( *
this );
 
 
  570  if ( !sDisableSrIdCache )
 
  572    QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrIdCache()->constFind( 
id );
 
  573    if ( crsIt != sSrIdCache()->constEnd() )
 
  576      *
this = crsIt.value();
 
  585    if ( it.value().endsWith( QStringLiteral( 
",%1" ).arg( 
id ) ) )
 
  587      const QStringList parts = it.key().split( 
':' );
 
  588      const QString auth = parts.at( 0 );
 
  589      const QString code = parts.at( 1 );
 
  590      if ( loadFromAuthCode( auth, code ) )
 
  593        if ( !sDisableSrIdCache )
 
  594          sSrIdCache()->insert( 
id, *
this );
 
  604  if ( !sDisableSrIdCache )
 
  605    sSrIdCache()->insert( 
id, *
this );
 
 
  613  if ( !sDisableSrsIdCache )
 
  615    QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrsIdCache()->constFind( 
id );
 
  616    if ( crsIt != sSrsIdCache()->constEnd() )
 
  619      *
this = crsIt.value();
 
  628    if ( it.value().startsWith( QString::number( 
id ) + 
',' ) )
 
  630      const QStringList parts = it.key().split( 
':' );
 
  631      const QString auth = parts.at( 0 );
 
  632      const QString code = parts.at( 1 );
 
  633      if ( loadFromAuthCode( auth, code ) )
 
  636        if ( !sDisableSrsIdCache )
 
  637          sSrsIdCache()->insert( 
id, *
this );
 
  645                                  QStringLiteral( 
"srs_id" ), QString::number( 
id ) );
 
  648  if ( !sDisableSrsIdCache )
 
  649    sSrsIdCache()->insert( 
id, *
this );
 
 
  653bool QgsCoordinateReferenceSystem::loadFromDatabase( 
const QString &db, 
const QString &expression, 
const QString &value )
 
  657  QgsDebugMsgLevel( 
"load CRS from " + db + 
" where " + expression + 
" is " + value, 3 );
 
  659  d->mWktPreferred.clear();
 
  661  QFileInfo myInfo( db );
 
  662  if ( !myInfo.exists() )
 
  672  myResult = openDatabase( db, database );
 
  673  if ( myResult != SQLITE_OK )
 
  690  QString mySql = 
"select srs_id,description,projection_acronym," 
  691                  "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo,wkt " 
  693  statement = database.
prepare( mySql, myResult );
 
  696  if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
 
  701    d->mEllipsoidAcronym.clear();
 
  703    d->mWktPreferred.clear();
 
  706    d->mIsGeographic = statement.
columnAsText( 7 ).toInt() != 0;
 
  708    d->mAxisInvertedDirty = 
true;
 
  712      d->mAuthId = QStringLiteral( 
"USER:%1" ).arg( d->mSrsId );
 
  714    else if ( !d->mAuthId.startsWith( QLatin1String( 
"USER:" ), Qt::CaseInsensitive ) )
 
  716      QStringList parts = d->mAuthId.split( 
':' );
 
  717      QString auth = parts.at( 0 );
 
  718      QString code = parts.at( 1 );
 
  725      d->mIsValid = d->hasPj();
 
  731      if ( !wkt.isEmpty() )
 
  739        setProjString( d->mProj4 );
 
  749void QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread( 
PJ_CONTEXT *pj_context )
 
  756  if ( !sDisableSrIdCache )
 
  759    if ( !sDisableSrIdCache )
 
  761      for ( 
auto it = sSrIdCache()->begin(); it != sSrIdCache()->end(); )
 
  763        auto &v = it.value();
 
  764        if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
 
  765          it = sSrIdCache()->erase( it );
 
  771  if ( !sDisableOgcCache )
 
  774    if ( !sDisableOgcCache )
 
  776      for ( 
auto it = sOgcCache()->begin(); it != sOgcCache()->end(); )
 
  778        auto &v = it.value();
 
  779        if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
 
  780          it = sOgcCache()->erase( it );
 
  786  if ( !sDisableProjCache )
 
  789    if ( !sDisableProjCache )
 
  791      for ( 
auto it = sProj4Cache()->begin(); it != sProj4Cache()->end(); )
 
  793        auto &v = it.value();
 
  794        if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
 
  795          it = sProj4Cache()->erase( it );
 
  801  if ( !sDisableWktCache )
 
  804    if ( !sDisableWktCache )
 
  806      for ( 
auto it = sWktCache()->begin(); it != sWktCache()->end(); )
 
  808        auto &v = it.value();
 
  809        if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
 
  810          it = sWktCache()->erase( it );
 
  816  if ( !sDisableSrsIdCache )
 
  819    if ( !sDisableSrsIdCache )
 
  821      for ( 
auto it = sSrsIdCache()->begin(); it != sSrsIdCache()->end(); )
 
  823        auto &v = it.value();
 
  824        if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
 
  825          it = sSrsIdCache()->erase( it );
 
  831  if ( !sDisableStringCache )
 
  834    if ( !sDisableStringCache )
 
  836      for ( 
auto it = sStringCache()->begin(); it != sStringCache()->end(); )
 
  838        auto &v = it.value();
 
  839        if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
 
  840          it = sStringCache()->erase( it );
 
  850  if ( d->mAxisInvertedDirty )
 
  853    d->mAxisInvertedDirty = 
false;
 
  856  return d->mAxisInverted;
 
 
  873  const thread_local QMap< Qgis::CrsAxisDirection, QString > mapping =
 
  916  QList< Qgis::CrsAxisDirection > res;
 
  917  const int axisCount = proj_cs_get_axis_count( context, pjCs.get() );
 
  920    res.reserve( axisCount );
 
  922    for ( 
int i = 0; i < axisCount; ++i )
 
  924      const char *outDirection = 
nullptr;
 
  925      proj_cs_get_axis_info( context, pjCs.get(), i,
 
  935      const thread_local QRegularExpression rx( QStringLiteral( 
"([^\\s]+).*" ) );
 
  936      const QRegularExpressionMatch match = rx.match( QString( outDirection ) );
 
  937      if ( !match.hasMatch() )
 
  940      const QString direction = match.captured( 1 );
 
  942      for ( 
auto it = mapping.constBegin(); it != mapping.constEnd(); ++it )
 
  944        if ( it.value().compare( direction, Qt::CaseInsensitive ) == 0 )
 
 
  959  return createFromWktInternal( wkt, QString() );
 
 
  962bool QgsCoordinateReferenceSystem::createFromWktInternal( 
const QString &wkt, 
const QString &description )
 
  970  if ( !sDisableWktCache )
 
  972    QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sWktCache()->constFind( wkt );
 
  973    if ( crsIt != sWktCache()->constEnd() )
 
  976      *
this = crsIt.value();
 
  978      if ( !
description.isEmpty() && d->mDescription.isEmpty() )
 
  983        sWktCache()->insert( wkt, *
this );
 
  992  d->mWktPreferred.clear();
 
  995    QgsDebugMsgLevel( QStringLiteral( 
"theWkt is uninitialized, operation failed" ), 4 );
 
 1000  QgsCoordinateReferenceSystem::RecordMap record = getRecord( 
"select * from tbl_srs where wkt=" + 
QgsSqliteUtils::quotedString( wkt ) + 
" order by deprecated" );
 
 1001  if ( !record.empty() )
 
 1003    long srsId = record[QStringLiteral( 
"srs_id" )].toLong();
 
 1011    setWktString( wkt );
 
 1016    if ( d->mSrsId == 0 )
 
 1019      long id = matchToUserCrs();
 
 1028  if ( !sDisableWktCache )
 
 1029    sWktCache()->insert( wkt, *
this );
 
 1047  if ( projString.isEmpty() )
 
 1052  if ( projString.trimmed().isEmpty() )
 
 1054    d->mIsValid = 
false;
 
 1056    d->mWktPreferred.clear();
 
 1061  if ( !sDisableProjCache )
 
 1063    QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sProj4Cache()->constFind( projString );
 
 1064    if ( crsIt != sProj4Cache()->constEnd() )
 
 1067      *
this = crsIt.value();
 
 1081  QString myProj4String = projString.trimmed();
 
 1082  myProj4String.remove( QStringLiteral( 
"+type=crs" ) );
 
 1083  myProj4String = myProj4String.trimmed();
 
 1085  d->mIsValid = 
false;
 
 1086  d->mWktPreferred.clear();
 
 1091    const QString projCrsString = myProj4String + ( myProj4String.contains( QStringLiteral( 
"+type=crs" ) ) ? QString() : QStringLiteral( 
" +type=crs" ) );
 
 1099        const QString 
authid = QStringLiteral( 
"%1:%2" ).arg( authName, authCode );
 
 1103          if ( !sDisableProjCache )
 
 1104            sProj4Cache()->insert( projString, *
this );
 
 1111    QgsCoordinateReferenceSystem::RecordMap myRecord = getRecord( 
"select * from tbl_srs where parameters=" + 
QgsSqliteUtils::quotedString( myProj4String ) + 
" order by deprecated" );
 
 1113    if ( !myRecord.empty() )
 
 1115      id = myRecord[QStringLiteral( 
"srs_id" )].toLong();
 
 1124      setProjString( myProj4String );
 
 1127      id = matchToUserCrs();
 
 1136    setProjString( myProj4String );
 
 1140  if ( !sDisableProjCache )
 
 1141    sProj4Cache()->insert( projString, *
this );
 
 
 1147QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord( 
const QString &sql )
 
 1149  QString myDatabaseFileName;
 
 1150  QgsCoordinateReferenceSystem::RecordMap myMap;
 
 1151  QString myFieldName;
 
 1152  QString myFieldValue;
 
 1159  QFileInfo myInfo( myDatabaseFileName );
 
 1160  if ( !myInfo.exists() )
 
 1162    QgsDebugError( 
"failed : " + myDatabaseFileName + 
" does not exist!" );
 
 1167  myResult = openDatabase( myDatabaseFileName, database );
 
 1168  if ( myResult != SQLITE_OK )
 
 1173  statement = database.
prepare( sql, myResult );
 
 1175  if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
 
 1179    for ( 
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
 
 1181      myFieldName = statement.
columnName( myColNo );
 
 1183      myMap[myFieldName] = myFieldValue;
 
 1185    if ( statement.
step() != SQLITE_DONE )
 
 1187      QgsDebugMsgLevel( QStringLiteral( 
"Multiple records found in srs.db" ), 4 );
 
 1196  if ( myMap.empty() )
 
 1199    QFileInfo myFileInfo;
 
 1200    myFileInfo.setFile( myDatabaseFileName );
 
 1201    if ( !myFileInfo.exists() )
 
 1203      QgsDebugError( QStringLiteral( 
"user qgis.db not found" ) );
 
 1208    myResult = openDatabase( myDatabaseFileName, database );
 
 1209    if ( myResult != SQLITE_OK )
 
 1214    statement = database.
prepare( sql, myResult );
 
 1216    if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
 
 1220      for ( 
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
 
 1222        myFieldName = statement.
columnName( myColNo );
 
 1224        myMap[myFieldName] = myFieldValue;
 
 1227      if ( statement.
step() != SQLITE_DONE )
 
 1229        QgsDebugMsgLevel( QStringLiteral( 
"Multiple records found in srs.db" ), 4 );
 
 1260  if ( d->mDescription.isNull() )
 
 1266    return d->mDescription;
 
 
 1273  if ( !
authid().isEmpty() )
 
 1283    id = 
isValid() ? QObject::tr( 
"Custom CRS" ) : QObject::tr( 
"Unknown CRS" );
 
 1285    id = QObject::tr( 
"Custom CRS: %1" ).arg(
 
 1288  else if ( !
toProj().isEmpty() )
 
 1291  if ( !
id.isEmpty() && !std::isnan( d->mCoordinateEpoch ) )
 
 1292    id += QStringLiteral( 
" @ %1" ).arg( 
qgsDoubleToString( d->mCoordinateEpoch, 3 ) );
 
 
 1299  if ( d->mProjectionAcronym.isNull() )
 
 1305    return d->mProjectionAcronym;
 
 
 1311  if ( d->mEllipsoidAcronym.isNull() )
 
 1313    if ( 
PJ *obj = d->threadLocalProjObject() )
 
 1318        const QString ellipsoidAuthName( proj_get_id_auth_name( ellipsoid.get(), 0 ) );
 
 1319        const QString ellipsoidAuthCode( proj_get_id_code( ellipsoid.get(), 0 ) );
 
 1320        if ( !ellipsoidAuthName.isEmpty() && !ellipsoidAuthCode.isEmpty() )
 
 1321          d->mEllipsoidAcronym = QStringLiteral( 
"%1:%2" ).arg( ellipsoidAuthName, ellipsoidAuthCode );
 
 1324          double semiMajor, semiMinor, invFlattening;
 
 1325          int semiMinorComputed = 0;
 
 1326          if ( proj_ellipsoid_get_parameters( 
QgsProjContext::get(), ellipsoid.get(), &semiMajor, &semiMinor, &semiMinorComputed, &invFlattening ) )
 
 1328            d->mEllipsoidAcronym = QStringLiteral( 
"PARAMETER:%1:%2" ).arg( 
qgsDoubleToString( semiMajor ),
 
 1333            d->mEllipsoidAcronym.clear();
 
 1338    return d->mEllipsoidAcronym;
 
 1342    return d->mEllipsoidAcronym;
 
 1356  if ( d->mProj4.isEmpty() )
 
 1358    if ( 
PJ *obj = d->threadLocalProjObject() )
 
 1364  return d->mProj4.trimmed();
 
 
 1370  switch ( d->mProjType )
 
 1372    case PJ_TYPE_UNKNOWN:
 
 1375    case PJ_TYPE_ELLIPSOID:
 
 1376    case PJ_TYPE_PRIME_MERIDIAN:
 
 1377    case PJ_TYPE_GEODETIC_REFERENCE_FRAME:
 
 1378    case PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME:
 
 1379    case PJ_TYPE_VERTICAL_REFERENCE_FRAME:
 
 1380    case PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME:
 
 1381    case PJ_TYPE_DATUM_ENSEMBLE:
 
 1382    case PJ_TYPE_CONVERSION:
 
 1383    case PJ_TYPE_TRANSFORMATION:
 
 1384    case PJ_TYPE_CONCATENATED_OPERATION:
 
 1385    case PJ_TYPE_OTHER_COORDINATE_OPERATION:
 
 1386    case PJ_TYPE_TEMPORAL_DATUM:
 
 1387    case PJ_TYPE_ENGINEERING_DATUM:
 
 1388    case PJ_TYPE_PARAMETRIC_DATUM:
 
 1392    case PJ_TYPE_GEOGRAPHIC_CRS:
 
 1396    case PJ_TYPE_GEODETIC_CRS:
 
 1398    case PJ_TYPE_GEOCENTRIC_CRS:
 
 1400    case PJ_TYPE_GEOGRAPHIC_2D_CRS:
 
 1402    case PJ_TYPE_GEOGRAPHIC_3D_CRS:
 
 1404    case PJ_TYPE_VERTICAL_CRS:
 
 1406    case PJ_TYPE_PROJECTED_CRS:
 
 1408    case PJ_TYPE_COMPOUND_CRS:
 
 1410    case PJ_TYPE_TEMPORAL_CRS:
 
 1412    case PJ_TYPE_ENGINEERING_CRS:
 
 1414    case PJ_TYPE_BOUND_CRS:
 
 1416    case PJ_TYPE_OTHER_CRS:
 
 1418#if PROJ_VERSION_MAJOR>9 || (PROJ_VERSION_MAJOR==9 && PROJ_VERSION_MINOR>=2) 
 1419    case PJ_TYPE_DERIVED_PROJECTED_CRS:
 
 1421    case PJ_TYPE_COORDINATE_METADATA:
 
 
 1435  return proj_is_deprecated( pj );
 
 
 1440  return d->mIsGeographic;
 
 
 1460  return QString( proj_get_celestial_body_name( context, pj ) );
 
 
 1465  if ( d->mCoordinateEpoch == epoch )
 
 1471  d->mCoordinateEpoch = epoch;
 
 1472  d->setPj( std::move( clone ) );
 
 
 1477  return d->mCoordinateEpoch;
 
 
 1496  res.mName = QString( proj_get_name( ensemble.get() ) );
 
 1497  res.mAuthority = QString( proj_get_id_auth_name( ensemble.get(), 0 ) );
 
 1498  res.mCode = QString( proj_get_id_code( ensemble.get(), 0 ) );
 
 1499  res.mRemarks = QString( proj_get_remarks( ensemble.get() ) );
 
 1500  res.mScope = QString( proj_get_scope( ensemble.get() ) );
 
 1501  res.mAccuracy = proj_datum_ensemble_get_accuracy( context, ensemble.get() );
 
 1503  const int memberCount = proj_datum_ensemble_get_member_count( context, ensemble.get() );
 
 1504  for ( 
int i = 0; i < memberCount; ++i )
 
 1511    details.mName = QString( proj_get_name( member.get() ) );
 
 1512    details.mAuthority = QString( proj_get_id_auth_name( member.get(), 0 ) );
 
 1513    details.mCode = QString( proj_get_id_code( member.get(), 0 ) );
 
 1514    details.mRemarks = QString( proj_get_remarks( member.get() ) );
 
 1515    details.mScope = QString( proj_get_scope( member.get() ) );
 
 1517    res.mMembers << details;
 
 
 1527  QString projString = 
toProj();
 
 1528  projString.replace( QLatin1String( 
"+type=crs" ), QString() );
 
 1531  if ( !transformation )
 
 1534  PJ_COORD coord = proj_coord( 0, 0, 0, HUGE_VAL );
 
 1535  coord.uv.u = point.
x() * M_PI / 180.0;
 
 1536  coord.uv.v = point.
y() * M_PI / 180.0;
 
 1538  proj_errno_reset( transformation.get() );
 
 1539  const PJ_FACTORS pjFactors = proj_factors( transformation.get(), coord );
 
 1540  if ( proj_errno( transformation.get() ) )
 
 1545  res.mIsValid = 
true;
 
 1546  res.mMeridionalScale = pjFactors.meridional_scale;
 
 1547  res.mParallelScale = pjFactors.parallel_scale;
 
 1548  res.mArealScale = pjFactors.areal_scale;
 
 1549  res.mAngularDistortion = pjFactors.angular_distortion;
 
 1550  res.mMeridianParallelAngle = pjFactors.meridian_parallel_angle * 180 / M_PI;
 
 1551  res.mMeridianConvergence = pjFactors.meridian_convergence * 180 / M_PI;
 
 1552  res.mTissotSemimajor = pjFactors.tissot_semimajor;
 
 1553  res.mTissotSemiminor = pjFactors.tissot_semiminor;
 
 1554  res.mDxDlam = pjFactors.dx_dlam;
 
 1555  res.mDxDphi = pjFactors.dx_dphi;
 
 1556  res.mDyDlam = pjFactors.dy_dlam;
 
 1557  res.mDyDphi = pjFactors.dy_dphi;
 
 
 1569  QString projString = 
toProj();
 
 1570  projString.replace( QLatin1String( 
"+type=crs" ), QString() );
 
 1571  if ( projString.isEmpty() )
 
 1575  if ( !transformation )
 
 1578  PJ_PROJ_INFO info = proj_pj_info( transformation.get() );
 
 
 1593  return d->mMapUnits;
 
 
 1601  PJ *obj = d->threadLocalProjObject();
 
 1606  double southLat = 0;
 
 1608  double northLat = 0;
 
 1611                              &westLon, &southLat, &eastLon, &northLat, 
nullptr ) )
 
 
 1626  const auto parts { 
authid().split( 
':' ) };
 
 1627  if ( parts.length() == 2 )
 
 1629    if ( parts[0] == QLatin1String( 
"EPSG" ) )
 
 1630      return  QStringLiteral( 
"http://www.opengis.net/def/crs/EPSG/0/%1" ).arg( parts[1] ) ;
 
 1631    else if ( parts[0] == QLatin1String( 
"OGC" ) )
 
 1633      return  QStringLiteral( 
"http://www.opengis.net/def/crs/OGC/1.3/%1" ).arg( parts[1] ) ;
 
 
 1649  const auto parts { 
authid().split( 
':' ) };
 
 1650  if ( parts.length() == 2 )
 
 1652    if ( parts[0] == QLatin1String( 
"EPSG" ) )
 
 1653      return  QStringLiteral( 
"urn:ogc:def:crs:EPSG::%1" ).arg( parts[1] );
 
 1654    else if ( parts[0] == QLatin1String( 
"OGC" ) )
 
 1656      return  QStringLiteral( 
"urn:ogc:def:crs:OGC:1.3:%1" ).arg( parts[1] );
 
 
 1690void QgsCoordinateReferenceSystem::setProjString( 
const QString &proj4String )
 
 1693  d->mProj4 = proj4String;
 
 1694  d->mWktPreferred.clear();
 
 1697  QString trimmed = proj4String.trimmed();
 
 1699  trimmed += QLatin1String( 
" +type=crs" );
 
 1709    const int errNo = proj_context_errno( ctx );
 
 1710    QgsDebugError( QStringLiteral( 
"proj string rejected: %1" ).arg( proj_context_errno_string( ctx, errNo ) ) );
 
 1712    d->mIsValid = 
false;
 
 1716    d->mEllipsoidAcronym.clear();
 
 1723bool QgsCoordinateReferenceSystem::setWktString( 
const QString &wkt )
 
 1726  d->mIsValid = 
false;
 
 1727  d->mWktPreferred.clear();
 
 1729  PROJ_STRING_LIST warnings = 
nullptr;
 
 1730  PROJ_STRING_LIST grammarErrors = 
nullptr;
 
 1738    QgsDebugMsgLevel( QStringLiteral( 
"\n---------------------------------------------------------------" ), 2 );
 
 1739    QgsDebugMsgLevel( QStringLiteral( 
"This CRS could *** NOT *** be set from the supplied Wkt " ), 2 );
 
 1741    for ( 
auto iter = warnings; iter && *iter; ++iter )
 
 1745    for ( 
auto iter = grammarErrors; iter && *iter; ++iter )
 
 1749    QgsDebugMsgLevel( QStringLiteral( 
"---------------------------------------------------------------\n" ), 2 );
 
 1751  proj_string_list_destroy( warnings );
 
 1752  proj_string_list_destroy( grammarErrors );
 
 1758    if ( !sDisableWktCache )
 
 1759      sWktCache()->insert( wkt, *
this );
 
 1767    QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
 
 1768    QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
 
 1770    if ( authName.isEmpty() || authCode.isEmpty() )
 
 1776    if ( !authName.isEmpty() && !authCode.isEmpty() )
 
 1779      if ( fromAuthCode.loadFromAuthCode( authName, authCode ) )
 
 1781        *
this = fromAuthCode;
 
 1783        if ( !sDisableWktCache )
 
 1784          sWktCache()->insert( wkt, *
this );
 
 1791    d->mDescription = QString( proj_get_name( d->threadLocalProjObject() ) );
 
 1798void QgsCoordinateReferenceSystem::setMapUnits()
 
 1825  if ( !coordinateSystem )
 
 1831  const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
 
 1832  if ( axisCount > 0 )
 
 1834    const char *outUnitName = 
nullptr;
 
 1836    proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
 
 1845    const QString unitName( outUnitName );
 
 1849    if ( unitName.compare( QLatin1String( 
"degree" ), Qt::CaseInsensitive ) == 0 ||
 
 1850         unitName.compare( QLatin1String( 
"degree minute second" ), Qt::CaseInsensitive ) == 0 ||
 
 1851         unitName.compare( QLatin1String( 
"degree minute second hemisphere" ), Qt::CaseInsensitive ) == 0 ||
 
 1852         unitName.compare( QLatin1String( 
"degree minute" ), Qt::CaseInsensitive ) == 0 ||
 
 1853         unitName.compare( QLatin1String( 
"degree hemisphere" ), Qt::CaseInsensitive ) == 0 ||
 
 1854         unitName.compare( QLatin1String( 
"degree minute hemisphere" ), Qt::CaseInsensitive ) == 0 ||
 
 1855         unitName.compare( QLatin1String( 
"hemisphere degree" ), Qt::CaseInsensitive ) == 0 ||
 
 1856         unitName.compare( QLatin1String( 
"hemisphere degree minute" ), Qt::CaseInsensitive ) == 0 ||
 
 1857         unitName.compare( QLatin1String( 
"hemisphere degree minute second" ), Qt::CaseInsensitive ) == 0 ||
 
 1858         unitName.compare( QLatin1String( 
"degree (supplier to define representation)" ), Qt::CaseInsensitive ) == 0 )
 
 1860    else if ( unitName.compare( QLatin1String( 
"metre" ), Qt::CaseInsensitive ) == 0
 
 1861              || unitName.compare( QLatin1String( 
"m" ), Qt::CaseInsensitive ) == 0
 
 1862              || unitName.compare( QLatin1String( 
"meter" ), Qt::CaseInsensitive ) == 0 )
 
 1864    else if ( unitName.compare( QLatin1String( 
"US survey foot" ), Qt::CaseInsensitive ) == 0 )
 
 1866    else if ( unitName.compare( QLatin1String( 
"foot" ), Qt::CaseInsensitive ) == 0 )
 
 1868    else if ( unitName.compare( QLatin1String( 
"British yard (Sears 1922)" ), Qt::CaseInsensitive ) == 0 )
 
 1870    else if ( unitName.compare( QLatin1String( 
"British yard (Sears 1922 truncated)" ), Qt::CaseInsensitive ) == 0 )
 
 1872    else if ( unitName.compare( QLatin1String( 
"British foot (Sears 1922)" ), Qt::CaseInsensitive ) == 0 )
 
 1874    else if ( unitName.compare( QLatin1String( 
"British foot (Sears 1922 truncated)" ), Qt::CaseInsensitive ) == 0 )
 
 1876    else if ( unitName.compare( QLatin1String( 
"British chain (Sears 1922)" ), Qt::CaseInsensitive ) == 0 )
 
 1878    else if ( unitName.compare( QLatin1String( 
"British chain (Sears 1922 truncated)" ), Qt::CaseInsensitive ) == 0 )
 
 1880    else if ( unitName.compare( QLatin1String( 
"British link (Sears 1922)" ), Qt::CaseInsensitive ) == 0 )
 
 1882    else if ( unitName.compare( QLatin1String( 
"British link (Sears 1922 truncated)" ), Qt::CaseInsensitive ) == 0 )
 
 1884    else if ( unitName.compare( QLatin1String( 
"British yard (Benoit 1895 A)" ), Qt::CaseInsensitive ) == 0 )
 
 1886    else if ( unitName.compare( QLatin1String( 
"British foot (Benoit 1895 A)" ), Qt::CaseInsensitive ) == 0 )
 
 1888    else if ( unitName.compare( QLatin1String( 
"British chain (Benoit 1895 A)" ), Qt::CaseInsensitive ) == 0 )
 
 1890    else if ( unitName.compare( QLatin1String( 
"British link (Benoit 1895 A)" ), Qt::CaseInsensitive ) == 0 )
 
 1892    else if ( unitName.compare( QLatin1String( 
"British yard (Benoit 1895 B)" ), Qt::CaseInsensitive ) == 0 )
 
 1894    else if ( unitName.compare( QLatin1String( 
"British foot (Benoit 1895 B)" ), Qt::CaseInsensitive ) == 0 )
 
 1896    else if ( unitName.compare( QLatin1String( 
"British chain (Benoit 1895 B)" ), Qt::CaseInsensitive ) == 0 )
 
 1898    else if ( unitName.compare( QLatin1String( 
"British link (Benoit 1895 B)" ), Qt::CaseInsensitive ) == 0 )
 
 1900    else if ( unitName.compare( QLatin1String( 
"British foot (1865)" ), Qt::CaseInsensitive ) == 0 )
 
 1902    else if ( unitName.compare( QLatin1String( 
"British foot (1936)" ), Qt::CaseInsensitive ) == 0 )
 
 1904    else if ( unitName.compare( QLatin1String( 
"Indian foot" ), Qt::CaseInsensitive ) == 0 )
 
 1906    else if ( unitName.compare( QLatin1String( 
"Indian foot (1937)" ), Qt::CaseInsensitive ) == 0 )
 
 1908    else if ( unitName.compare( QLatin1String( 
"Indian foot (1962)" ), Qt::CaseInsensitive ) == 0 )
 
 1910    else if ( unitName.compare( QLatin1String( 
"Indian foot (1975)" ), Qt::CaseInsensitive ) == 0 )
 
 1912    else if ( unitName.compare( QLatin1String( 
"Indian yard" ), Qt::CaseInsensitive ) == 0 )
 
 1914    else if ( unitName.compare( QLatin1String( 
"Indian yard (1937)" ), Qt::CaseInsensitive ) == 0 )
 
 1916    else if ( unitName.compare( QLatin1String( 
"Indian yard (1962)" ), Qt::CaseInsensitive ) == 0 )
 
 1918    else if ( unitName.compare( QLatin1String( 
"Indian yard (1975)" ), Qt::CaseInsensitive ) == 0 )
 
 1920    else if ( unitName.compare( QLatin1String( 
"Gold Coast foot" ), Qt::CaseInsensitive ) == 0 )
 
 1922    else if ( unitName.compare( QLatin1String( 
"Clarke's foot" ), Qt::CaseInsensitive ) == 0 )
 
 1924    else if ( unitName.compare( QLatin1String( 
"Clarke's yard" ), Qt::CaseInsensitive ) == 0 )
 
 1926    else if ( unitName.compare( QLatin1String( 
"Clarke's chain" ), Qt::CaseInsensitive ) == 0 )
 
 1928    else if ( unitName.compare( QLatin1String( 
"Clarke's link" ), Qt::CaseInsensitive ) == 0 )
 
 1930    else if ( unitName.compare( QLatin1String( 
"kilometre" ), Qt::CaseInsensitive ) == 0 )  
 
 1932    else if ( unitName.compare( QLatin1String( 
"centimetre" ), Qt::CaseInsensitive ) == 0 )  
 
 1934    else if ( unitName.compare( QLatin1String( 
"millimetre" ), Qt::CaseInsensitive ) == 0 )  
 
 1936    else if ( unitName.compare( QLatin1String( 
"Statute mile" ), Qt::CaseInsensitive ) == 0 )
 
 1938    else if ( unitName.compare( QLatin1String( 
"nautical mile" ), Qt::CaseInsensitive ) == 0 )
 
 1940    else if ( unitName.compare( QLatin1String( 
"yard" ), Qt::CaseInsensitive ) == 0 )
 
 1942    else if ( unitName.compare( QLatin1String( 
"fathom" ), Qt::CaseInsensitive ) == 0 )
 
 1944    else if ( unitName.compare( QLatin1String( 
"US survey chain" ), Qt::CaseInsensitive ) == 0 )
 
 1946    else if ( unitName.compare( QLatin1String( 
"chain" ), Qt::CaseInsensitive ) == 0 )
 
 1948    else if ( unitName.compare( QLatin1String( 
"link" ), Qt::CaseInsensitive ) == 0 )
 
 1950    else if ( unitName.compare( QLatin1String( 
"US survey link" ), Qt::CaseInsensitive ) == 0 )
 
 1952    else if ( unitName.compare( QLatin1String( 
"US survey mile" ), Qt::CaseInsensitive ) == 0 )
 
 1954    else if ( unitName.compare( QLatin1String( 
"German legal metre" ), Qt::CaseInsensitive ) == 0 )
 
 1971  if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
 
 1974    QgsDebugMsgLevel( 
"QgsCoordinateReferenceSystem::findMatchingProj will only " 
 1975                      "work if prj acr ellipsoid acr and proj4string are set" 
 1976                      " and the current projection is valid!", 4 );
 
 1986  QString mySql = QString( 
"select srs_id,parameters from tbl_srs where " 
 1987                           "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
 
 1994  myResult = openDatabase( myDatabaseFileName, database );
 
 1995  if ( myResult != SQLITE_OK )
 
 2000  statement = database.
prepare( mySql, myResult );
 
 2001  if ( myResult == SQLITE_OK )
 
 2004    while ( statement.
step() == SQLITE_ROW )
 
 2008      if ( 
toProj() == myProj4String.trimmed() )
 
 2010        return mySrsId.toLong();
 
 2021  myResult = openDatabase( myDatabaseFileName, database );
 
 2022  if ( myResult != SQLITE_OK )
 
 2027  statement = database.
prepare( mySql, myResult );
 
 2029  if ( myResult == SQLITE_OK )
 
 2031    while ( statement.
step() == SQLITE_ROW )
 
 2035      if ( 
toProj() == myProj4String.trimmed() )
 
 2037        return mySrsId.toLong();
 
 
 2051  if ( !d->mIsValid && !srs.d->mIsValid )
 
 2054  if ( !d->mIsValid || !srs.d->mIsValid )
 
 2062  if ( isUser != otherIsUser )
 
 2066  if ( !isUser && ( !d->mAuthId.isEmpty() || !srs.d->mAuthId.isEmpty() ) )
 
 2067    return d->mAuthId == srs.d->mAuthId;
 
 
 2074  return  !( *
this == srs );
 
 
 2079  if ( 
PJ *obj = d->threadLocalProjObject() )
 
 2082    if ( isDefaultPreferredFormat && !d->mWktPreferred.isEmpty() )
 
 2085      return d->mWktPreferred;
 
 2088    PJ_WKT_TYPE 
type = PJ_WKT1_GDAL;
 
 2092        type = PJ_WKT1_GDAL;
 
 2095        type = PJ_WKT1_ESRI;
 
 2098        type = PJ_WKT2_2015;
 
 2101        type = PJ_WKT2_2015_SIMPLIFIED;
 
 2104        type = PJ_WKT2_2019;
 
 2107        type = PJ_WKT2_2019_SIMPLIFIED;
 
 2111    const QByteArray multiLineOption = QStringLiteral( 
"MULTILINE=%1" ).arg( multiline ? QStringLiteral( 
"YES" ) : QStringLiteral( 
"NO" ) ).toLocal8Bit();
 
 2112    const QByteArray indentatationWidthOption = QStringLiteral( 
"INDENTATION_WIDTH=%1" ).arg( multiline ? QString::number( indentationWidth ) : QStringLiteral( 
"0" ) ).toLocal8Bit();
 
 2113    const char *
const options[] = {multiLineOption.constData(), indentatationWidthOption.constData(), 
nullptr};
 
 2116    if ( isDefaultPreferredFormat )
 
 2119      d->mWktPreferred = res;
 
 
 2131  QDomNode srsNode = node.namedItem( QStringLiteral( 
"spatialrefsys" ) );
 
 2133  if ( ! srsNode.isNull() )
 
 2135    bool initialized = 
false;
 
 2138    long srsid = srsNode.namedItem( QStringLiteral( 
"srsid" ) ).toElement().text().toLong( &ok );
 
 2144      node = srsNode.namedItem( QStringLiteral( 
"authid" ) );
 
 2145      if ( !node.isNull() )
 
 2156        node = srsNode.namedItem( QStringLiteral( 
"epsg" ) );
 
 2157        if ( !node.isNull() )
 
 2175      const QString 
description = srsNode.namedItem( QStringLiteral( 
"description" ) ).toElement().text();
 
 2177      const QString wkt = srsNode.namedItem( QStringLiteral( 
"wkt" ) ).toElement().text();
 
 2178      initialized = createFromWktInternal( wkt, 
description );
 
 2183      node = srsNode.namedItem( QStringLiteral( 
"proj4" ) );
 
 2184      const QString proj4 = node.toElement().text();
 
 2191      node = srsNode.namedItem( QStringLiteral( 
"proj4" ) );
 
 2192      const QString proj4 = node.toElement().text();
 
 2193      if ( !proj4.trimmed().isEmpty() )
 
 2194        setProjString( node.toElement().text() );
 
 2196      node = srsNode.namedItem( QStringLiteral( 
"srsid" ) );
 
 2197      d->mSrsId = node.toElement().text().toLong();
 
 2199      node = srsNode.namedItem( QStringLiteral( 
"srid" ) );
 
 2200      d->mSRID = node.toElement().text().toLong();
 
 2202      node = srsNode.namedItem( QStringLiteral( 
"authid" ) );
 
 2203      d->mAuthId = node.toElement().text();
 
 2205      node = srsNode.namedItem( QStringLiteral( 
"description" ) );
 
 2206      d->mDescription = node.toElement().text();
 
 2208      node = srsNode.namedItem( QStringLiteral( 
"projectionacronym" ) );
 
 2209      d->mProjectionAcronym = node.toElement().text();
 
 2211      node = srsNode.namedItem( QStringLiteral( 
"ellipsoidacronym" ) );
 
 2212      d->mEllipsoidAcronym = node.toElement().text();
 
 2214      node = srsNode.namedItem( QStringLiteral( 
"geographicflag" ) );
 
 2215      d->mIsGeographic = node.toElement().text() == QLatin1String( 
"true" );
 
 2217      d->mWktPreferred.clear();
 
 2223    const QString epoch = srsNode.toElement().attribute( QStringLiteral( 
"coordinateEpoch" ) );
 
 2224    if ( !epoch.isEmpty() )
 
 2226      bool epochOk = 
false;
 
 2227      d->mCoordinateEpoch = epoch.toDouble( &epochOk );
 
 2229        d->mCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
 
 2233      d->mCoordinateEpoch = std::numeric_limits< double >::quiet_NaN();
 
 2236    mNativeFormat = qgsEnumKeyToValue<Qgis::CrsDefinitionFormat>( srsNode.toElement().attribute( QStringLiteral( 
"nativeFormat" ) ), 
Qgis::CrsDefinitionFormat::Wkt );
 
 2241    d = 
new QgsCoordinateReferenceSystemPrivate();
 
 
 2249  QDomElement layerNode = node.toElement();
 
 2250  QDomElement srsElement = doc.createElement( QStringLiteral( 
"spatialrefsys" ) );
 
 2252  srsElement.setAttribute( QStringLiteral( 
"nativeFormat" ), qgsEnumValueToKey<Qgis::CrsDefinitionFormat>( mNativeFormat ) );
 
 2254  if ( std::isfinite( d->mCoordinateEpoch ) )
 
 2256    srsElement.setAttribute( QStringLiteral( 
"coordinateEpoch" ), d->mCoordinateEpoch );
 
 2259  QDomElement wktElement = doc.createElement( QStringLiteral( 
"wkt" ) );
 
 2261  srsElement.appendChild( wktElement );
 
 2263  QDomElement proj4Element = doc.createElement( QStringLiteral( 
"proj4" ) );
 
 2264  proj4Element.appendChild( doc.createTextNode( 
toProj() ) );
 
 2265  srsElement.appendChild( proj4Element );
 
 2267  QDomElement srsIdElement = doc.createElement( QStringLiteral( 
"srsid" ) );
 
 2268  srsIdElement.appendChild( doc.createTextNode( QString::number( 
srsid() ) ) );
 
 2269  srsElement.appendChild( srsIdElement );
 
 2271  QDomElement sridElement = doc.createElement( QStringLiteral( 
"srid" ) );
 
 2272  sridElement.appendChild( doc.createTextNode( QString::number( 
postgisSrid() ) ) );
 
 2273  srsElement.appendChild( sridElement );
 
 2275  QDomElement authidElement = doc.createElement( QStringLiteral( 
"authid" ) );
 
 2276  authidElement.appendChild( doc.createTextNode( 
authid() ) );
 
 2277  srsElement.appendChild( authidElement );
 
 2279  QDomElement descriptionElement = doc.createElement( QStringLiteral( 
"description" ) );
 
 2280  descriptionElement.appendChild( doc.createTextNode( 
description() ) );
 
 2281  srsElement.appendChild( descriptionElement );
 
 2283  QDomElement projectionAcronymElement = doc.createElement( QStringLiteral( 
"projectionacronym" ) );
 
 2284  projectionAcronymElement.appendChild( doc.createTextNode( 
projectionAcronym() ) );
 
 2285  srsElement.appendChild( projectionAcronymElement );
 
 2287  QDomElement ellipsoidAcronymElement = doc.createElement( QStringLiteral( 
"ellipsoidacronym" ) );
 
 2288  ellipsoidAcronymElement.appendChild( doc.createTextNode( 
ellipsoidAcronym() ) );
 
 2289  srsElement.appendChild( ellipsoidAcronymElement );
 
 2291  QDomElement geographicFlagElement = doc.createElement( QStringLiteral( 
"geographicflag" ) );
 
 2292  QString geoFlagText = QStringLiteral( 
"false" );
 
 2295    geoFlagText = QStringLiteral( 
"true" );
 
 2298  geographicFlagElement.appendChild( doc.createTextNode( geoFlagText ) );
 
 2299  srsElement.appendChild( geographicFlagElement );
 
 2301  layerNode.appendChild( srsElement );
 
 
 2313QString QgsCoordinateReferenceSystem::projFromSrsId( 
const int srsId )
 
 2315  QString myDatabaseFileName;
 
 2316  QString myProjString;
 
 2317  QString mySql = QStringLiteral( 
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( srsId );
 
 2326    QFileInfo myFileInfo;
 
 2327    myFileInfo.setFile( myDatabaseFileName );
 
 2328    if ( !myFileInfo.exists() ) 
 
 2330      QgsDebugError( QStringLiteral( 
"users qgis.db not found" ) );
 
 2343  rc = openDatabase( myDatabaseFileName, database );
 
 2349  statement = database.
prepare( mySql, rc );
 
 2351  if ( rc == SQLITE_OK )
 
 2353    if ( statement.
step() == SQLITE_ROW )
 
 2359  return myProjString;
 
 2366    myResult = database.
open_v2( path, SQLITE_OPEN_READONLY, 
nullptr );
 
 2368    myResult = database.
open( path );
 
 2370  if ( myResult != SQLITE_OK )
 
 2379                               .arg( database.
errorMessage() ), QObject::tr( 
"CRS" ) );
 
 2386  sCustomSrsValidation = f;
 
 
 2391  return sCustomSrsValidation;
 
 
 2394void QgsCoordinateReferenceSystem::debugPrint()
 
 2397  QgsDebugMsgLevel( 
"* Valid : " + ( d->mIsValid ? QString( 
"true" ) : QString( 
"false" ) ), 1 );
 
 2418  mValidationHint = html;
 
 
 2423  return mValidationHint;
 
 
 2433  mNativeFormat = format;
 
 
 2438  return mNativeFormat;
 
 
 2441long QgsCoordinateReferenceSystem::getRecordCount()
 
 2446  long          myRecordCount = 0;
 
 2449  if ( myResult != SQLITE_OK )
 
 2455  QString mySql = QStringLiteral( 
"select count(*) from tbl_srs" );
 
 2456  statement = database.
prepare( mySql, myResult );
 
 2457  if ( myResult == SQLITE_OK )
 
 2459    if ( statement.
step() == SQLITE_ROW )
 
 2461      QString myRecordCountString = statement.
columnAsText( 0 );
 
 2462      myRecordCount = myRecordCountString.toLong();
 
 2465  return myRecordCount;
 
 2471  bool isGeographic = 
false;
 
 2475  if ( !horizontalCrs )
 
 2479  if ( coordinateSystem )
 
 2481    const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
 
 2482    if ( axisCount > 0 )
 
 2484      const char *outUnitAuthName = 
nullptr;
 
 2485      const char *outUnitAuthCode = 
nullptr;
 
 2487      proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
 
 2496      if ( outUnitAuthName && outUnitAuthCode )
 
 2498        const char *unitCategory = 
nullptr;
 
 2499        if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode, 
nullptr, 
nullptr, &unitCategory ) )
 
 2501          isGeographic = QString( unitCategory ).compare( QLatin1String( 
"angular" ), Qt::CaseInsensitive ) == 0;
 
 2506  return isGeographic;
 
 
 2511  thread_local const QRegularExpression projRegExp( QStringLiteral( 
"\\+proj=(\\S+)" ) );
 
 2512  const QRegularExpressionMatch projMatch = projRegExp.match( proj );
 
 2513  if ( !projMatch.hasMatch() )
 
 2515    QgsDebugMsgLevel( QStringLiteral( 
"no +proj argument found [%2]" ).arg( proj ), 2 );
 
 2518  operation = projMatch.captured( 1 );
 
 2520  const QRegularExpressionMatch ellipseMatch = projRegExp.match( proj );
 
 2521  if ( ellipseMatch.hasMatch() )
 
 2523    ellipsoid = ellipseMatch.captured( 1 );
 
 
 2537bool QgsCoordinateReferenceSystem::loadFromAuthCode( 
const QString &auth, 
const QString &code )
 
 2543  d->mIsValid = 
false;
 
 2544  d->mWktPreferred.clear();
 
 2556  proj4.replace( QLatin1String( 
"+type=crs" ), QString() );
 
 2557  proj4 = proj4.trimmed();
 
 2561  d->mWktPreferred.clear();
 
 2562  d->mDescription = QString( proj_get_name( 
crs.get() ) );
 
 2563  d->mAuthId = QStringLiteral( 
"%1:%2" ).arg( auth, code );
 
 2565  d->mAxisInvertedDirty = 
true;
 
 2570  d->mEllipsoidAcronym.clear();
 
 2571  d->setPj( std::move( 
crs ) );
 
 2573  const QString dbVals = 
sAuthIdToQgisSrsIdMap.value( QStringLiteral( 
"%1:%2" ).arg( auth, code ).toUpper() );
 
 2574  if ( !dbVals.isEmpty() )
 
 2576    const QStringList parts = dbVals.split( 
',' );
 
 2577    d->mSrsId = parts.at( 0 ).toInt();
 
 2578    d->mSRID = parts.at( 1 ).toInt();
 
 2586QList<long> QgsCoordinateReferenceSystem::userSrsIds()
 
 2588  QList<long> results;
 
 2592  QFileInfo myInfo( db );
 
 2593  if ( !myInfo.exists() )
 
 2603  int result = openDatabase( db, database );
 
 2604  if ( result != SQLITE_OK )
 
 2606    QgsDebugError( 
"failed : " + db + 
" could not be opened!" );
 
 2610  QString sql = QStringLiteral( 
"select srs_id from tbl_srs where srs_id >= %1" ).arg( 
Qgis::USER_CRS_START_ID );
 
 2612  statement = database.
prepare( sql, rc );
 
 2615    int ret = statement.
step();
 
 2617    if ( ret == SQLITE_DONE )
 
 2623    if ( ret == SQLITE_ROW )
 
 2629      QgsMessageLog::logMessage( QObject::tr( 
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr( 
"SpatiaLite" ) );
 
 2637long QgsCoordinateReferenceSystem::matchToUserCrs()
 const 
 2639  PJ *obj = d->threadLocalProjObject();
 
 2643  const QList< long > ids = userSrsIds();
 
 2644  for ( 
long id : ids )
 
 2647    if ( candidate.
projObject() && proj_is_equivalent_to( obj, candidate.
projObject(), PJ_COMP_EQUIVALENT ) )
 
 2655static void sync_db_proj_logger( 
void * , 
int level, 
const char *message )
 
 2660  if ( level == PJ_LOG_ERROR )
 
 2664  else if ( level == PJ_LOG_DEBUG )
 
 2672  setlocale( LC_ALL, 
"C" );
 
 2675  int inserted = 0, updated = 0, deleted = 0, errors = 0;
 
 2680  if ( database.
open( dbFilePath ) != SQLITE_OK )
 
 2686  if ( sqlite3_exec( database.get(), 
"BEGIN TRANSACTION", 
nullptr, 
nullptr, 
nullptr ) != SQLITE_OK )
 
 2694  char *errMsg = 
nullptr;
 
 2696  bool createdTypeColumn = 
false;
 
 2697  if ( sqlite3_exec( database.get(), 
"ALTER TABLE tbl_srs ADD COLUMN srs_type text", 
nullptr, 
nullptr, 
nullptr ) == SQLITE_OK )
 
 2699    createdTypeColumn = 
true;
 
 2700    if ( sqlite3_exec( database.get(), 
"CREATE INDEX srs_type ON tbl_srs(srs_type)", 
nullptr, 
nullptr, 
nullptr ) != SQLITE_OK )
 
 2702      QgsDebugError( QStringLiteral( 
"Could not create index for srs_type" ) );
 
 2707  if ( sqlite3_exec( database.get(), 
"create table tbl_info (proj_major INT, proj_minor INT, proj_patch INT)", 
nullptr, 
nullptr, 
nullptr ) == SQLITE_OK )
 
 2709    QString sql = QStringLiteral( 
"INSERT INTO tbl_info(proj_major, proj_minor, proj_patch) VALUES (%1, %2,%3)" )
 
 2710                  .arg( QString::number( PROJ_VERSION_MAJOR ),
 
 2711                        QString::number( PROJ_VERSION_MINOR ),
 
 2712                        QString::number( PROJ_VERSION_PATCH ) );
 
 2713    if ( sqlite3_exec( database.get(), sql.toUtf8(), 
nullptr, 
nullptr, &errMsg ) != SQLITE_OK )
 
 2715      QgsDebugError( QStringLiteral( 
"Could not execute: %1 [%2/%3]\n" ).arg(
 
 2718                       errMsg ? errMsg : 
"(unknown error)" ) );
 
 2720        sqlite3_free( errMsg );
 
 2727    QString sql = QStringLiteral( 
"SELECT proj_major, proj_minor, proj_patch FROM tbl_info" );
 
 2728    statement = database.
prepare( sql, result );
 
 2729    if ( result != SQLITE_OK )
 
 2734    if ( statement.
step() == SQLITE_ROW )
 
 2739      if ( !createdTypeColumn && major == PROJ_VERSION_MAJOR && minor == PROJ_VERSION_MINOR && patch == PROJ_VERSION_PATCH )
 
 2745      QgsDebugError( QStringLiteral( 
"Could not retrieve previous CRS sync PROJ version number" ) );
 
 2752  proj_log_func( pjContext, 
nullptr, sync_db_proj_logger );
 
 2754  PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
 
 2756  int nextSrsId = 67218;
 
 2757  int nextSrId = 520007218;
 
 2758  for ( 
auto authIter = authorities; authIter && *authIter; ++authIter )
 
 2760    const QString authority( *authIter );
 
 2761    QgsDebugMsgLevel( QStringLiteral( 
"Loading authority '%1'" ).arg( authority ), 2 );
 
 2762    PROJ_STRING_LIST codes = proj_get_codes_from_database( pjContext, *authIter, PJ_TYPE_CRS, 
true );
 
 2764    QStringList allCodes;
 
 2766    for ( 
auto codesIter = codes; codesIter && *codesIter; ++codesIter )
 
 2768      const QString code( *codesIter );
 
 2774        QgsDebugError( QStringLiteral( 
"Could not load '%1:%2'" ).arg( authority, code ) );
 
 2778      const PJ_TYPE pjType = proj_get_type( 
crs.get( ) );
 
 2780      QString srsTypeString;
 
 2785        case PJ_TYPE_ELLIPSOID:
 
 2786        case PJ_TYPE_PRIME_MERIDIAN:
 
 2787        case PJ_TYPE_GEODETIC_REFERENCE_FRAME:
 
 2788        case PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME:
 
 2789        case PJ_TYPE_VERTICAL_REFERENCE_FRAME:
 
 2790        case PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME:
 
 2791        case PJ_TYPE_DATUM_ENSEMBLE:
 
 2792        case PJ_TYPE_CONVERSION:
 
 2793        case PJ_TYPE_TRANSFORMATION:
 
 2794        case PJ_TYPE_CONCATENATED_OPERATION:
 
 2795        case PJ_TYPE_OTHER_COORDINATE_OPERATION:
 
 2796        case PJ_TYPE_TEMPORAL_DATUM:
 
 2797        case PJ_TYPE_ENGINEERING_DATUM:
 
 2798        case PJ_TYPE_PARAMETRIC_DATUM:
 
 2799        case PJ_TYPE_UNKNOWN:
 
 2803        case PJ_TYPE_GEOGRAPHIC_CRS:
 
 2806        case PJ_TYPE_GEODETIC_CRS:
 
 2810        case PJ_TYPE_GEOCENTRIC_CRS:
 
 2814        case PJ_TYPE_GEOGRAPHIC_2D_CRS:
 
 2818        case PJ_TYPE_GEOGRAPHIC_3D_CRS:
 
 2822        case PJ_TYPE_PROJECTED_CRS:
 
 2826        case PJ_TYPE_COMPOUND_CRS:
 
 2830        case PJ_TYPE_TEMPORAL_CRS:
 
 2834        case PJ_TYPE_ENGINEERING_CRS:
 
 2838        case PJ_TYPE_BOUND_CRS:
 
 2842        case PJ_TYPE_VERTICAL_CRS:
 
 2846#if PROJ_VERSION_MAJOR>9 || (PROJ_VERSION_MAJOR==9 && PROJ_VERSION_MINOR>=2) 
 2847        case PJ_TYPE_DERIVED_PROJECTED_CRS:
 
 2850        case PJ_TYPE_COORDINATE_METADATA:
 
 2853        case PJ_TYPE_OTHER_CRS:
 
 2862      proj4.replace( QLatin1String( 
"+type=crs" ), QString() );
 
 2863      proj4 = proj4.trimmed();
 
 2865      if ( proj4.isEmpty() )
 
 2867        QgsDebugMsgLevel( QStringLiteral( 
"No proj4 for '%1:%2'" ).arg( authority, code ), 2 );
 
 2878      if ( translatedOperation.isEmpty() && !
operation.isEmpty() )
 
 2880        std::cout << QStringLiteral( 
"Operation needs translation in QgsCoordinateReferenceSystemUtils::translateProjection: %1" ).arg( 
operation ).toLocal8Bit().constData() << std::endl;
 
 2881        qFatal( 
"aborted" );
 
 2884      const bool deprecated = proj_is_deprecated( 
crs.get() );
 
 2885      const QString name( proj_get_name( 
crs.get() ) );
 
 2887      QString sql = QStringLiteral( 
"SELECT parameters,description,deprecated,srs_type,projection_acronym FROM tbl_srs WHERE auth_name='%1' AND auth_id='%2'" ).arg( authority, code );
 
 2888      statement = database.
prepare( sql, result );
 
 2889      if ( result != SQLITE_OK )
 
 2898      QString dbOperation;
 
 2899      bool dbSrsDeprecated = deprecated;
 
 2900      if ( statement.
step() == SQLITE_ROW )
 
 2904        dbSrsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
 
 2909      if ( !dbSrsProj4.isEmpty() || !dbSrsDesc.isEmpty() )
 
 2911        if ( proj4 != dbSrsProj4 || name != dbSrsDesc || deprecated != dbSrsDeprecated || dbSrsType != srsTypeString || dbOperation != 
operation )
 
 2914          sql = QStringLiteral( 
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3, srs_type=%4,projection_acronym=%5 WHERE auth_name=%6 AND auth_id=%7" )
 
 2917                .arg( deprecated ? 1 : 0 )
 
 2922          if ( sqlite3_exec( database.get(), sql.toUtf8(), 
nullptr, 
nullptr, &errMsg ) != SQLITE_OK )
 
 2924            QgsDebugError( QStringLiteral( 
"Could not execute: %1 [%2/%3]\n" ).arg(
 
 2927                             errMsg ? errMsg : 
"(unknown error)" ) );
 
 2929              sqlite3_free( errMsg );
 
 2943        const QString dbVals = 
sAuthIdToQgisSrsIdMap.value( QStringLiteral( 
"%1:%2" ).arg( authority, code ) );
 
 2946        if ( !dbVals.isEmpty() )
 
 2948          const QStringList parts = dbVals.split( 
',' );
 
 2949          srsId = parts.at( 0 );
 
 2950          srId = parts.at( 1 );
 
 2952        if ( srId.isEmpty() )
 
 2954          srId = QString::number( nextSrId );
 
 2957        if ( srsId.isEmpty() )
 
 2959          srsId = QString::number( nextSrsId );
 
 2963        if ( !srsId.isEmpty() )
 
 2965          sql = QStringLiteral( 
"INSERT INTO tbl_srs(srs_id, description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated,srs_type) VALUES (%1, %2,%3,%4,%5,%6,%7,%8,%9,%10,%11)" )
 
 2975                .arg( deprecated ? 1 : 0 )
 
 2980          sql = QStringLiteral( 
"INSERT INTO tbl_srs(description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated,srs_type) VALUES (%1,%2,%3,%4,%5,%6,%7,%8,%9,%10)" )
 
 2989                .arg( deprecated ? 1 : 0 )
 
 2994        if ( sqlite3_exec( database.get(), sql.toUtf8(), 
nullptr, 
nullptr, &errMsg ) == SQLITE_OK )
 
 3000          qCritical( 
"Could not execute: %s [%s/%s]\n",
 
 3001                     sql.toLocal8Bit().constData(),
 
 3002                     sqlite3_errmsg( database.get() ),
 
 3003                     errMsg ? errMsg : 
"(unknown error)" );
 
 3007            sqlite3_free( errMsg );
 
 3012    proj_string_list_destroy( codes );
 
 3014    const QString sql = QStringLiteral( 
"DELETE FROM tbl_srs WHERE auth_name='%1' AND NOT auth_id IN (%2)" ).arg( authority, allCodes.join( 
',' ) );
 
 3015    if ( sqlite3_exec( database.get(), sql.toUtf8(), 
nullptr, 
nullptr, 
nullptr ) == SQLITE_OK )
 
 3017      deleted = sqlite3_changes( database.get() );
 
 3022      qCritical( 
"Could not execute: %s [%s]\n",
 
 3023                 sql.toLocal8Bit().constData(),
 
 3024                 sqlite3_errmsg( database.get() ) );
 
 3028  proj_string_list_destroy( authorities );
 
 3030  QString sql = QStringLiteral( 
"UPDATE tbl_info set proj_major=%1,proj_minor=%2,proj_patch=%3" )
 
 3031                .arg( QString::number( PROJ_VERSION_MAJOR ),
 
 3032                      QString::number( PROJ_VERSION_MINOR ),
 
 3033                      QString::number( PROJ_VERSION_PATCH ) );
 
 3034  if ( sqlite3_exec( database.get(), sql.toUtf8(), 
nullptr, 
nullptr, &errMsg ) != SQLITE_OK )
 
 3036    QgsDebugError( QStringLiteral( 
"Could not execute: %1 [%2/%3]\n" ).arg(
 
 3039                     errMsg ? errMsg : 
"(unknown error)" ) );
 
 3041      sqlite3_free( errMsg );
 
 3045  if ( sqlite3_exec( database.get(), 
"COMMIT", 
nullptr, 
nullptr, 
nullptr ) != SQLITE_OK )
 
 3047    QgsDebugError( QStringLiteral( 
"Could not commit transaction: %1 [%2]\n" ).arg(
 
 3049                     sqlite3_errmsg( database.get() ) )
 
 3055  QgsDebugMsgLevel( QStringLiteral( 
"CRS update (inserted:%1 updated:%2 deleted:%3 errors:%4)" ).arg( inserted ).arg( updated ).arg( deleted ).arg( errors ), 4 );
 
 3063    return updated + inserted;
 
 
 3066const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::stringCache()
 
 3068  return *sStringCache();
 
 3071const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::projCache()
 
 3073  return *sProj4Cache();
 
 3076const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::ogcCache()
 
 3078  return *sOgcCache();
 
 3081const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::wktCache()
 
 3083  return *sWktCache();
 
 3086const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srIdCache()
 
 3088  return *sSrIdCache();
 
 3091const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srsIdCache()
 
 3093  return *sSrsIdCache();
 
 3103  if ( 
PJ *obj = d->threadLocalProjObject() )
 
 3110    const PJ_TYPE pjType = proj_get_type( geoCrs.get( ) );
 
 3111    if ( pjType == PJ_TYPE_GEOCENTRIC_CRS )
 
 3117                                             pjContext, PJ_ELLPS2D_LONGITUDE_LATITUDE, 
"Degree", 1.0 ) );
 
 3121            pjContext, 
nullptr, datum ? datum.get() : 
datumEnsemble.get(),
 
 3124      if ( !geoGraphicCrs )
 
 
 3151  if ( 
PJ *obj = d->threadLocalProjObject() )
 
 
 3205  if ( 
PJ *obj = d->threadLocalProjObject() )
 
 
 3238  if ( 
PJ *obj = d->threadLocalProjObject() )
 
 
 3249  if ( 
PJ *obj = d->threadLocalProjObject() )
 
 
 3262  else if ( 
PJ *obj = d->threadLocalProjObject() )
 
 3265    return geoCrs ? QStringLiteral( 
"%1:%2" ).arg( proj_get_id_auth_name( geoCrs.get(), 0 ), proj_get_id_code( geoCrs.get(), 0 ) ) : QString();
 
 
 3275  return d->threadLocalProjObject();
 
 
 3288  d->mIsValid = 
false;
 
 3290  d->mWktPreferred.clear();
 
 3297  switch ( proj_get_type( 
object ) )
 
 3299    case PJ_TYPE_GEODETIC_CRS:
 
 3300    case PJ_TYPE_GEOCENTRIC_CRS:
 
 3301    case PJ_TYPE_GEOGRAPHIC_CRS:
 
 3302    case PJ_TYPE_GEOGRAPHIC_2D_CRS:
 
 3303    case PJ_TYPE_GEOGRAPHIC_3D_CRS:
 
 3304    case PJ_TYPE_VERTICAL_CRS:
 
 3305    case PJ_TYPE_PROJECTED_CRS:
 
 3306    case PJ_TYPE_COMPOUND_CRS:
 
 3307    case PJ_TYPE_TEMPORAL_CRS:
 
 3308    case PJ_TYPE_ENGINEERING_CRS:
 
 3309    case PJ_TYPE_BOUND_CRS:
 
 3310    case PJ_TYPE_OTHER_CRS:
 
 3326    const QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
 
 3327    const QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
 
 3328    if ( !authName.isEmpty() && !authCode.isEmpty() && 
createFromOgcWmsCrs( QStringLiteral( 
"%1:%2" ).arg( authName, authCode ) ) )
 
 3336      d->mDescription = QString( proj_get_name( d->threadLocalProjObject() ) );
 
 
 3347  QStringList projections;
 
 3349  projections.reserve( res.size() );
 
 3352    projections << QString::number( 
crs.
srsid() );
 
 
 3379  sSrIdCacheLock()->lockForWrite();
 
 3380  if ( !sDisableSrIdCache )
 
 3383      sDisableSrIdCache = 
true;
 
 3384    sSrIdCache()->clear();
 
 3386  sSrIdCacheLock()->unlock();
 
 3388  sOgcLock()->lockForWrite();
 
 3389  if ( !sDisableOgcCache )
 
 3392      sDisableOgcCache = 
true;
 
 3393    sOgcCache()->clear();
 
 3395  sOgcLock()->unlock();
 
 3397  sProj4CacheLock()->lockForWrite();
 
 3398  if ( !sDisableProjCache )
 
 3401      sDisableProjCache = 
true;
 
 3402    sProj4Cache()->clear();
 
 3404  sProj4CacheLock()->unlock();
 
 3406  sCRSWktLock()->lockForWrite();
 
 3407  if ( !sDisableWktCache )
 
 3410      sDisableWktCache = 
true;
 
 3411    sWktCache()->clear();
 
 3413  sCRSWktLock()->unlock();
 
 3415  sCRSSrsIdLock()->lockForWrite();
 
 3416  if ( !sDisableSrsIdCache )
 
 3419      sDisableSrsIdCache = 
true;
 
 3420    sSrsIdCache()->clear();
 
 3422  sCRSSrsIdLock()->unlock();
 
 3424  sCrsStringLock()->lockForWrite();
 
 3425  if ( !sDisableStringCache )
 
 3428      sDisableStringCache = 
true;
 
 3429    sStringCache()->clear();
 
 3431  sCrsStringLock()->unlock();
 
 
 3440  if ( !c1.d->mIsValid && !c2.d->mIsValid )
 
 3443  if ( !c1.d->mIsValid && c2.d->mIsValid )
 
 3446  if ( c1.d->mIsValid && !c2.d->mIsValid )
 
 3452  if ( c1IsUser && !c2IsUser )
 
 3455  if ( !c1IsUser && c2IsUser )
 
 3458  if ( !c1IsUser && !c2IsUser && !c1.d->mAuthId.isEmpty() && !c2.d->mAuthId.isEmpty() )
 
 3460    if ( c1.d->mAuthId != c2.d->mAuthId )
 
 3461      return c1.d->mAuthId > c2.d->mAuthId;
 
 3469  if ( c1.d->mCoordinateEpoch == c2.d->mCoordinateEpoch )
 
 3472  if ( std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
 
 3475  if ( std::isnan( c1.d->mCoordinateEpoch ) && !std::isnan( c2.d->mCoordinateEpoch ) )
 
 3478  if ( !std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
 
 3481  return c1.d->mCoordinateEpoch > c2.d->mCoordinateEpoch;
 
 
 3489  if ( !c1.d->mIsValid && !c2.d->mIsValid )
 
 3492  if ( c1.d->mIsValid && !c2.d->mIsValid )
 
 3495  if ( !c1.d->mIsValid && c2.d->mIsValid )
 
 3501  if ( !c1IsUser && c2IsUser )
 
 3504  if ( c1IsUser && !c2IsUser )
 
 3507  if ( !c1IsUser && !c2IsUser && !c1.d->mAuthId.isEmpty() && !c2.d->mAuthId.isEmpty() )
 
 3509    if ( c1.d->mAuthId != c2.d->mAuthId )
 
 3510      return c1.d->mAuthId < c2.d->mAuthId;
 
 3518  if ( c1.d->mCoordinateEpoch == c2.d->mCoordinateEpoch )
 
 3521  if ( std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
 
 3524  if ( !std::isnan( c1.d->mCoordinateEpoch ) && std::isnan( c2.d->mCoordinateEpoch ) )
 
 3527  if ( std::isnan( c1.d->mCoordinateEpoch ) && !std::isnan( c2.d->mCoordinateEpoch ) )
 
 3530  return c1.d->mCoordinateEpoch < c2.d->mCoordinateEpoch;
 
 
 3535  return !( c1 < c2 );
 
 
 3539  return !( c1 > c2 );
 
 
 
 
 
 
 
CrsIdentifierType
Available identifier string types for representing coordinate reference systems.
 
@ ShortString
A heavily abbreviated string, for use when a compact representation is required.
 
@ MediumString
A medium-length string, recommended for general purpose use.
 
DistanceUnit
Units of distance.
 
@ YardsBritishSears1922Truncated
British yards (Sears 1922 truncated)
 
@ MilesUSSurvey
US Survey miles.
 
@ LinksBritishSears1922
British links (Sears 1922)
 
@ YardsBritishBenoit1895A
British yards (Benoit 1895 A)
 
@ LinksBritishBenoit1895A
British links (Benoit 1895 A)
 
@ Centimeters
Centimeters.
 
@ YardsIndian1975
Indian yards (1975)
 
@ FeetUSSurvey
US Survey feet.
 
@ Millimeters
Millimeters.
 
@ FeetBritishSears1922
British feet (Sears 1922)
 
@ YardsClarkes
Clarke's yards.
 
@ YardsIndian
Indian yards.
 
@ FeetBritishBenoit1895B
British feet (Benoit 1895 B)
 
@ Miles
Terrestrial miles.
 
@ LinksUSSurvey
US Survey links.
 
@ ChainsUSSurvey
US Survey chains.
 
@ FeetClarkes
Clarke's feet.
 
@ Unknown
Unknown distance unit.
 
@ FeetBritish1936
British feet (1936)
 
@ FeetIndian1962
Indian feet (1962)
 
@ YardsBritishSears1922
British yards (Sears 1922)
 
@ FeetIndian1937
Indian feet (1937)
 
@ YardsIndian1937
Indian yards (1937)
 
@ Degrees
Degrees, for planar geographic CRS distance measurements.
 
@ ChainsBritishBenoit1895B
British chains (Benoit 1895 B)
 
@ LinksBritishSears1922Truncated
British links (Sears 1922 truncated)
 
@ ChainsBritishBenoit1895A
British chains (Benoit 1895 A)
 
@ YardsBritishBenoit1895B
British yards (Benoit 1895 B)
 
@ FeetBritish1865
British feet (1865)
 
@ YardsIndian1962
Indian yards (1962)
 
@ FeetBritishSears1922Truncated
British feet (Sears 1922 truncated)
 
@ MetersGermanLegal
German legal meter.
 
@ LinksBritishBenoit1895B
British links (Benoit 1895 B)
 
@ ChainsInternational
International chains.
 
@ LinksInternational
International links.
 
@ ChainsBritishSears1922Truncated
British chains (Sears 1922 truncated)
 
@ FeetIndian
Indian (geodetic) feet.
 
@ NauticalMiles
Nautical miles.
 
@ ChainsClarkes
Clarke's chains.
 
@ LinksClarkes
Clarke's links.
 
@ ChainsBritishSears1922
British chains (Sears 1922)
 
@ FeetIndian1975
Indian feet (1975)
 
@ FeetGoldCoast
Gold Coast feet.
 
@ FeetBritishBenoit1895A
British feet (Benoit 1895 A)
 
@ Critical
Critical/error message.
 
CrsType
Coordinate reference system types.
 
@ Compound
Compound (horizontal + vertical) CRS.
 
@ Projected
Projected CRS.
 
@ DerivedProjected
Derived projected CRS.
 
@ Engineering
Engineering CRS.
 
@ Geographic3d
3D geopraphic CRS
 
@ Geographic2d
2D geographic CRS
 
@ Geocentric
Geocentric CRS.
 
CrsDefinitionFormat
CRS definition formats.
 
@ Wkt
WKT format (always recommended over proj string format)
 
static const int USER_CRS_START_ID
Minimum ID number for a user-defined projection.
 
CrsAxisDirection
Coordinate reference system axis directions.
 
@ ColumnPositive
Column positive.
 
@ SouthSouthEast
South South East.
 
@ ColumnNegative
Column negative.
 
@ RowPositive
Row positive.
 
@ DisplayDown
Display down.
 
@ GeocentricZ
Geocentric (Z)
 
@ DisplayRight
Display right.
 
@ WestSouthWest
West South West.
 
@ RowNegative
Row negative.
 
@ NorthNorthEast
North North East.
 
@ EastNorthEast
East North East.
 
@ Unspecified
Unspecified.
 
@ NorthNorthWest
North North West.
 
@ GeocentricY
Geocentric (Y)
 
@ CounterClockwise
Counter clockwise.
 
@ SouthSouthWest
South South West.
 
@ DisplayLeft
Display left.
 
@ WestNorthWest
West North West.
 
@ EastSouthEast
East South East.
 
@ GeocentricX
Geocentric (X)
 
CrsWktVariant
Coordinate reference system WKT formatting variants.
 
@ Wkt2_2019Simplified
WKT2_2019 with the simplification rule of WKT2_SIMPLIFIED.
 
@ Wkt2_2015Simplified
Same as WKT2_2015 with the following exceptions: UNIT keyword used. ID node only on top element....
 
@ Wkt1Esri
WKT1 as traditionally output by ESRI software, deriving from OGC 99-049.
 
@ Preferred
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
 
@ Wkt2_2019
Full WKT2 string, conforming to ISO 19162:2019 / OGC 18-010, with all possible nodes and new keyword ...
 
@ Wkt2_2015
Full WKT2 string, conforming to ISO 19162:2015(E) / OGC 12-063r5 with all possible nodes and new keyw...
 
@ Wkt1Gdal
WKT1 as traditionally output by GDAL, deriving from OGC 01-009. A notable departure from WKT1_GDAL wi...
 
static QgsCoordinateReferenceSystemRegistry * coordinateReferenceSystemRegistry()
Returns the application's coordinate reference system (CRS) registry, which handles known CRS definit...
 
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
 
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
 
void removeRecent(const QgsCoordinateReferenceSystem &crs)
Removes a CRS from the list of recently used CRS.
 
long addUserCrs(const QgsCoordinateReferenceSystem &crs, const QString &name, Qgis::CrsDefinitionFormat nativeFormat=Qgis::CrsDefinitionFormat::Wkt)
Adds a new crs definition as a custom ("USER") CRS.
 
void clearRecent()
Cleans the list of recently used CRS.
 
QList< QgsCoordinateReferenceSystem > recentCrs()
Returns a list of recently used CRS.
 
void pushRecent(const QgsCoordinateReferenceSystem &crs)
Pushes a recently used CRS to the top of the recent CRS list.
 
QMap< QString, QgsProjOperation > projOperations() const
Returns a map of all valid PROJ operations.
 
static QString translateProjection(const QString &projection)
Returns a translated string for a projection method.
 
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.
 
bool hasVerticalAxis() const
Returns true if the CRS has a vertical axis.
 
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 QgsCoordinateReferenceSystem createCompoundCrs(const QgsCoordinateReferenceSystem &horizontalCrs, const QgsCoordinateReferenceSystem &verticalCrs, QString &error)
Given a horizontal and vertical CRS, attempts to create a compound CRS from them.
 
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...
 
QString toOgcUrn() const
Returns the crs as OGC URN (format: urn:ogc:def:crs:OGC:1.3:CRS84) Returns an empty string on failure...
 
static void setCustomCrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS.
 
static Q_DECL_DEPRECATED void pushRecentCoordinateReferenceSystem(const QgsCoordinateReferenceSystem &crs)
Pushes a recently used CRS to the top of the recent CRS list.
 
long postgisSrid() const
Returns PostGIS SRID for the CRS.
 
QgsCoordinateReferenceSystem horizontalCrs() const
Returns the horizontal CRS associated with this CRS object.
 
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
 
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
 
QString userFriendlyIdentifier(Qgis::CrsIdentifierType type=Qgis::CrsIdentifierType::MediumString) const
Returns a user friendly identifier for the CRS.
 
Qgis::CrsDefinitionFormat nativeFormat() const
Returns the native format for the CRS definition.
 
CrsType
Enumeration of types of IDs accepted in createFromId() method.
 
@ InternalCrsId
Internal ID used by QGIS in the local SQLite database.
 
@ PostgisCrsId
SRID used in PostGIS. DEPRECATED – DO NOT USE.
 
bool createFromUserInput(const QString &definition)
Set up this CRS from various text formats.
 
QgsCoordinateReferenceSystem()
Constructs an invalid CRS object.
 
static int syncDatabase()
Update proj.4 parameters in our database from proj.4.
 
bool operator!=(const QgsCoordinateReferenceSystem &srs) const
 
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.
 
QgsCoordinateReferenceSystem verticalCrs() const
Returns the vertical CRS associated with this CRS object.
 
static Q_DECL_DEPRECATED void removeRecentCoordinateReferenceSystem(const QgsCoordinateReferenceSystem &crs)
Removes a CRS from the list of recently used CRS.
 
QgsDatumEnsemble datumEnsemble() const
Attempts to retrieve datum ensemble details from the CRS.
 
QgsCoordinateReferenceSystem toGeographicCrs() const
Returns the geographic CRS associated with this CRS object.
 
bool isDynamic() const
Returns true if the CRS is a dynamic CRS.
 
bool createFromSrsId(long srsId)
Sets this CRS by lookup of internal QGIS CRS ID in the CRS database.
 
Q_DECL_DEPRECATED bool createFromId(long id, CrsType type=PostgisCrsId)
Sets this CRS by lookup of the given ID in the CRS database.
 
static QgsCoordinateReferenceSystem fromProjObject(PJ *object)
Constructs a QgsCoordinateReferenceSystem from a PROJ PJ object.
 
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
 
QgsCoordinateReferenceSystem & operator=(const QgsCoordinateReferenceSystem &srs)
 
void updateDefinition()
Updates the definition and parameters of the coordinate reference system to their latest values.
 
static QgsCoordinateReferenceSystem fromProj(const QString &proj)
Creates a CRS from a proj style formatted string.
 
static Q_DECL_DEPRECATED void setupESRIWktFix()
Make sure that ESRI WKT import is done properly.
 
static Q_DECL_DEPRECATED QList< QgsCoordinateReferenceSystem > recentCoordinateReferenceSystems()
Returns a list of recently used CRS.
 
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
 
PJ * projObject() const
Returns the underlying PROJ PJ object corresponding to the CRS, or nullptr if the CRS is invalid.
 
void setCoordinateEpoch(double epoch)
Sets the coordinate epoch, as a decimal year.
 
Q_DECL_DEPRECATED bool createFromSrid(long srid)
Sets this CRS by lookup of the given PostGIS SRID in the CRS database.
 
long saveAsUserCrs(const QString &name, Qgis::CrsDefinitionFormat nativeFormat=Qgis::CrsDefinitionFormat::Wkt)
Saves the CRS as a new custom ("USER") CRS.
 
static Q_DECL_DEPRECATED void clearRecentCoordinateReferenceSystems()
Cleans the list of recently used CRS.
 
QString celestialBodyName() const
Attempts to retrieve the name of the celestial body associated with the CRS (e.g.
 
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
 
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
 
static QgsCoordinateReferenceSystem createGeocentricCrs(const QString &ellipsoid)
Creates a geocentric CRS given an ellipsoid definition.
 
static QgsCoordinateReferenceSystem fromSrsId(long srsId)
Creates a CRS from a specified QGIS SRS ID.
 
double coordinateEpoch() const
Returns the coordinate epoch, as a decimal year.
 
QString geographicCrsAuthId() const
Returns auth id of related geographic CRS.
 
QString validationHint() const
Gets user hint for validation.
 
QgsProjOperation operation() const
Returns information about the PROJ operation associated with the coordinate reference system,...
 
QgsCoordinateReferenceSystem toGeocentricCrs() const
Returns a new geocentric CRS based on this CRS object.
 
QList< Qgis::CrsAxisDirection > axisOrdering() const
Returns an ordered list of the axis directions reflecting the native axis order for the CRS.
 
long srsid() const
Returns the internal CRS ID, if available.
 
Qgis::CrsType type() const
Returns the type of the CRS.
 
Qgis::DistanceUnit mapUnits
 
bool hasAxisInverted() const
Returns whether the axis order is inverted for the CRS compared to the order east/north (longitude/la...
 
bool createFromProjObject(PJ *object)
Sets this CRS by passing it a PROJ PJ object, corresponding to a PROJ CRS object.
 
bool isDeprecated() const
Returns true if the CRS is considered deprecated.
 
static Q_DECL_DEPRECATED QgsCoordinateReferenceSystem fromProj4(const QString &proj4)
Creates a CRS from a proj style formatted string.
 
Contains information about a member of a datum ensemble.
 
Contains information about a datum ensemble.
 
static EllipsoidParameters ellipsoidParameters(const QString &ellipsoid)
Returns the parameters for the specified ellipsoid.
 
Sets the current locale to the c locale for the lifetime of the object.
 
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, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
 
@ UNKNOWN
Unknown/unhandled flavor.
 
@ AUTH_CODE
E.g EPSG:4326.
 
static CRSFlavor parseCrsName(const QString &crsName, QString &authority, QString &code)
Parse a CRS name in one of the flavors of OGC services, and decompose it as authority and code.
 
static QString OGRSpatialReferenceToWkt(OGRSpatialReferenceH srs)
Returns a WKT string corresponding to the specified OGR srs object.
 
Point geometry type, with support for z-dimension and m-values.
 
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
 
Contains information about a PROJ operation.
 
static proj_pj_unique_ptr crsToHorizontalCrs(const PJ *crs)
Given a PROJ crs (which may be a compound or bound crs, or some other type), extract the horizontal c...
 
@ FlagMatchBoundCrsToUnderlyingSourceCrs
Allow matching a BoundCRS object to its underlying SourceCRS.
 
static proj_pj_unique_ptr createCompoundCrs(const PJ *horizontalCrs, const PJ *verticalCrs, QStringList *errors=nullptr)
Given a PROJ horizontal and vertical CRS, attempt to create a compound CRS from them.
 
static bool isDynamic(const PJ *crs)
Returns true if the given proj coordinate system is a dynamic CRS.
 
static proj_pj_unique_ptr unboundCrs(const PJ *crs)
Given a PROJ crs (which may be a compound or bound crs, or some other type), ensure that it is not a ...
 
static bool identifyCrs(const PJ *crs, QString &authName, QString &authCode, IdentifyFlags flags=IdentifyFlags())
Attempts to identify a crs, matching it to a known authority and code within an acceptable level of t...
 
static bool hasVerticalAxis(const PJ *crs)
Returns true if a PROJ crs has a vertical axis.
 
static proj_pj_unique_ptr crsToVerticalCrs(const PJ *crs)
Given a PROJ crs (which may be a compound crs, or some other type), extract the vertical crs from it.
 
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...
 
A convenience class that simplifies locking and unlocking QReadWriteLocks.
 
void unlock()
Unlocks the lock.
 
void changeMode(Mode mode)
Change the mode of the lock to mode.
 
A rectangle specified with double values.
 
void setYMinimum(double y)
Set the minimum y value.
 
void setXMinimum(double x)
Set the minimum x value.
 
void setYMaximum(double y)
Set the maximum y value.
 
void setXMaximum(double x)
Set the maximum x value.
 
static QString quotedString(const QString &value)
Returns a quoted string value, surround by ' characters and with special characters correctly escaped...
 
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
 
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
 
int open(const QString &path)
Opens the database at the specified file path.
 
QString errorMessage() const
Returns the most recent error message encountered by the database.
 
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
 
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
 
QString columnAsText(int column) const
Returns the column value from the current statement row as a string.
 
QString columnName(int column) const
Returns the name of column.
 
int step()
Steps to the next record in the statement, returning the sqlite3 result code.
 
qlonglong columnAsInt64(int column) const
Gets column value from the current statement row as a long long integer (64 bits).
 
int columnCount() const
Gets the number of columns that this statement returns.
 
#define Q_NOWARN_DEPRECATED_POP
 
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
 
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
 
#define Q_NOWARN_DEPRECATED_PUSH
 
bool qgsNanCompatibleEquals(double a, double b)
Compare two doubles, treating nan values as equal.
 
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(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
 
const QMap< QString, QString > sAuthIdToQgisSrsIdMap
 
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
 
#define QgsDebugMsgLevel(str, level)
 
#define QgsDebugError(str)
 
const QgsCoordinateReferenceSystem & crs
 
Contains parameters for an ellipsoid.
 
double semiMajor
Semi-major axis, in meters.
 
bool valid
Whether ellipsoid parameters are valid.
 
double inverseFlattening
Inverse flattening.