27 #include <QDomElement> 30 #include <QTextStream> 32 #include <QRegularExpression> 42 #if PROJ_VERSION_MAJOR>=6 45 #include <proj_experimental.h> 51 #include <ogr_srs_api.h> 52 #include <cpl_error.h> 63 QReadWriteLock QgsCoordinateReferenceSystem::sSrIdCacheLock;
64 QHash< long, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sSrIdCache;
65 QReadWriteLock QgsCoordinateReferenceSystem::sOgcLock;
66 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sOgcCache;
67 QReadWriteLock QgsCoordinateReferenceSystem::sProj4CacheLock;
68 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sProj4Cache;
69 QReadWriteLock QgsCoordinateReferenceSystem::sCRSWktLock;
70 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sWktCache;
71 QReadWriteLock QgsCoordinateReferenceSystem::sCRSSrsIdLock;
72 QHash< long, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sSrsIdCache;
73 QReadWriteLock QgsCoordinateReferenceSystem::sCrsStringLock;
74 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sStringCache;
77 #if PROJ_VERSION_MAJOR>=6 78 QString getFullProjString( PJ *obj )
82 QgsProjUtils::proj_pj_unique_ptr boundCrs( proj_crs_create_bound_crs_to_WGS84(
QgsProjContext::get(), obj,
nullptr ) );
85 if (
const char *proj4src = proj_as_proj_string(
QgsProjContext::get(), boundCrs.get(), PJ_PROJ_4, nullptr ) )
87 return QString( proj4src );
98 d =
new QgsCoordinateReferenceSystemPrivate();
103 d =
new QgsCoordinateReferenceSystemPrivate();
109 d =
new QgsCoordinateReferenceSystemPrivate();
130 const auto constDbs = dbs;
131 for (
const QString &db : constDbs )
133 QFileInfo myInfo( db );
134 if ( !myInfo.exists() )
136 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
144 int result = openDatabase( db, database );
145 if ( result != SQLITE_OK )
147 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
151 QString sql = QStringLiteral(
"select srs_id from tbl_srs" );
153 statement = database.
prepare( sql, rc );
157 int ret = statement.
step();
159 if ( ret == SQLITE_DONE )
165 if ( ret == SQLITE_ROW )
171 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
176 std::sort( results.begin(), results.end() );
242 QgsDebugMsg( QStringLiteral(
"Unexpected case reached!" ) );
249 sCrsStringLock.lockForRead();
250 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sStringCache.constFind( definition );
251 if ( crsIt != sStringCache.constEnd() )
254 *
this = crsIt.value();
255 sCrsStringLock.unlock();
258 sCrsStringLock.unlock();
261 QRegularExpression reCrsId(
"^(epsg|postgis|internal|user)\\:(\\d+)$", QRegularExpression::CaseInsensitiveOption );
262 QRegularExpressionMatch match = reCrsId.match( definition );
263 if ( match.capturedStart() == 0 )
265 QString authName = match.captured( 1 ).toLower();
267 if ( authName == QLatin1String(
"epsg" ) )
269 if ( authName == QLatin1String(
"postgis" ) )
271 long id = match.captured( 2 ).toLong();
276 QRegularExpression reCrsStr(
"^(?:(wkt|proj4)\\:)?(.+)$", QRegularExpression::CaseInsensitiveOption );
277 match = reCrsStr.match( definition );
278 if ( match.capturedStart() == 0 )
280 if ( match.captured( 1 ).compare( QLatin1String(
"proj4" ), Qt::CaseInsensitive ) == 0 )
289 QString myName = QStringLiteral(
" * %1 (%2)" )
290 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
302 sCrsStringLock.lockForWrite();
303 sStringCache.insert( definition, *
this );
304 sCrsStringLock.unlock();
315 if ( definition.startsWith( QLatin1String(
"ESRI::" ) ) )
320 if ( OSRSetFromUserInput( crs, definition.toLocal8Bit().constData() ) == OGRERR_NONE )
322 if ( OSRExportToWkt( crs, &wkt ) == OGRERR_NONE )
327 OSRDestroySpatialReference( crs );
337 const char *configOld = CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" );
338 const char *configNew =
"GEOGCS";
340 if ( strcmp( configOld,
"" ) == 0 )
342 CPLSetConfigOption(
"GDAL_FIX_ESRI_WKT", configNew );
343 if ( strcmp( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) != 0 )
345 .arg( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) );
346 QgsDebugMsgLevel( QStringLiteral(
"set GDAL_FIX_ESRI_WKT : %1" ).arg( configNew ), 4 );
350 QgsDebugMsgLevel( QStringLiteral(
"GDAL_FIX_ESRI_WKT was already set : %1" ).arg( configNew ), 4 );
356 sOgcLock.lockForRead();
357 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sOgcCache.constFind( crs );
358 if ( crsIt != sOgcCache.constEnd() )
361 *
this = crsIt.value();
367 QString wmsCrs =
crs;
369 QRegExp re(
"urn:ogc:def:crs:([^:]+).+([^:]+)", Qt::CaseInsensitive );
370 if ( re.exactMatch( wmsCrs ) )
372 wmsCrs = re.cap( 1 ) +
':' + re.cap( 2 );
376 re.setPattern( QStringLiteral(
"(user|custom|qgis):(\\d+)" ) );
377 if ( re.exactMatch( wmsCrs ) &&
createFromSrsId( re.cap( 2 ).toInt() ) )
379 sOgcLock.lockForWrite();
380 sOgcCache.insert( crs, *
this );
386 #if PROJ_VERSION_MAJOR>=6 388 const QString legacyKey = wmsCrs.toLower();
391 if ( it.key().compare( legacyKey, Qt::CaseInsensitive ) == 0 )
393 const QStringList parts = it.key().split(
':' );
394 const QString auth = parts.at( 0 );
395 const QString code = parts.at( 1 );
396 if ( loadFromAuthCode( auth, code ) )
398 sOgcLock.lockForWrite();
399 sOgcCache.insert( crs, *
this );
409 sOgcLock.lockForWrite();
410 sOgcCache.insert( crs, *
this );
416 if ( wmsCrs.compare( QLatin1String(
"CRS:27" ), Qt::CaseInsensitive ) == 0 ||
417 wmsCrs.compare( QLatin1String(
"OGC:CRS27" ), Qt::CaseInsensitive ) == 0 )
424 if ( wmsCrs.compare( QLatin1String(
"CRS:83" ), Qt::CaseInsensitive ) == 0 ||
425 wmsCrs.compare( QLatin1String(
"OGC:CRS83" ), Qt::CaseInsensitive ) == 0 )
432 if ( wmsCrs.compare( QLatin1String(
"CRS:84" ), Qt::CaseInsensitive ) == 0 ||
433 wmsCrs.compare( QLatin1String(
"OGC:CRS84" ), Qt::CaseInsensitive ) == 0 )
438 d->mAxisInverted =
false;
439 d->mAxisInvertedDirty =
false;
441 sOgcLock.lockForWrite();
442 sOgcCache.insert( crs, *
this );
448 sOgcLock.lockForWrite();
465 if ( mCustomSrsValidation )
466 mCustomSrsValidation( *
this );
476 sSrIdCacheLock.lockForRead();
477 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrIdCache.constFind(
id );
478 if ( crsIt != sSrIdCache.constEnd() )
481 *
this = crsIt.value();
482 sSrIdCacheLock.unlock();
485 sSrIdCacheLock.unlock();
487 #if PROJ_VERSION_MAJOR>=6 491 if ( it.value().endsWith( QStringLiteral(
",%1" ).arg(
id ) ) )
493 const QStringList parts = it.key().split(
':' );
494 const QString auth = parts.at( 0 );
495 const QString code = parts.at( 1 );
496 if ( loadFromAuthCode( auth, code ) )
498 sSrIdCacheLock.lockForWrite();
499 sSrIdCache.insert(
id, *
this );
500 sSrIdCacheLock.unlock();
510 sSrIdCacheLock.lockForWrite();
511 sSrIdCache.insert(
id, *
this );
512 sSrIdCacheLock.unlock();
519 sCRSSrsIdLock.lockForRead();
520 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrsIdCache.constFind(
id );
521 if ( crsIt != sSrsIdCache.constEnd() )
524 *
this = crsIt.value();
525 sCRSSrsIdLock.unlock();
528 sCRSSrsIdLock.unlock();
530 #if PROJ_VERSION_MAJOR>=6 534 if ( it.value().startsWith( QString::number(
id ) +
',' ) )
536 const QStringList parts = it.key().split(
':' );
537 const QString auth = parts.at( 0 );
538 const QString code = parts.at( 1 );
539 if ( loadFromAuthCode( auth, code ) )
541 sCRSSrsIdLock.lockForWrite();
542 sSrsIdCache.insert(
id, *
this );
543 sCRSSrsIdLock.unlock();
553 QStringLiteral(
"srs_id" ), QString::number(
id ) );
555 sCRSSrsIdLock.lockForWrite();
556 sSrsIdCache.insert(
id, *
this );
557 sCRSSrsIdLock.unlock();
562 bool QgsCoordinateReferenceSystem::loadFromDatabase(
const QString &db,
const QString &expression,
const QString &value )
566 QgsDebugMsgLevel(
"load CRS from " + db +
" where " + expression +
" is " + value, 3 );
570 QFileInfo myInfo( db );
571 if ( !myInfo.exists() )
573 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
581 myResult = openDatabase( db, database );
582 if ( myResult != SQLITE_OK )
599 QString mySql =
"select srs_id,description,projection_acronym," 600 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo " 602 statement = database.
prepare( mySql, myResult );
604 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
613 d->mIsGeographic = statement.
columnAsText( 7 ).toInt() != 0;
614 d->mAxisInvertedDirty =
true;
618 d->mAuthId = QStringLiteral(
"USER:%1" ).arg( d->mSrsId );
620 else if ( !d->mAuthId.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive ) )
622 #if PROJ_VERSION_MAJOR>=6 623 QStringList parts = d->mAuthId.split(
':' );
624 QString auth = parts.at( 0 );
625 QString code = parts.at( 1 );
628 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database(
QgsProjContext::get(), auth.toLatin1(), code.toLatin1(), PJ_CATEGORY_CRS,
false, nullptr ) );
629 d->mPj = QgsProjUtils::crsToSingleCrs( crs.get() );
632 d->mIsValid =
static_cast< bool >( d->mPj );
634 OSRDestroySpatialReference( d->mCRS );
635 d->mCRS = OSRNewSpatialReference(
nullptr );
636 d->mIsValid = OSRSetFromUserInput( d->mCRS, d->mAuthId.toLower().toLatin1() ) == OGRERR_NONE;
643 setProj4String( d->mProj4 );
655 if ( d->mAxisInvertedDirty )
657 #if PROJ_VERSION_MAJOR>=6 658 d->mAxisInverted = QgsProjUtils::axisOrderIsSwapped( d->mPj.get() );
660 OGRAxisOrientation orientation;
661 OSRGetAxis( d->mCRS, OSRIsGeographic( d->mCRS ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
664 if ( orientation == OAO_Other && d->mAuthId.startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
668 if ( OSRImportFromEPSGA( crs, d->mAuthId.midRef( 5 ).toInt() ) == OGRERR_NONE )
670 OSRGetAxis( crs, OSRIsGeographic( crs ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
673 OSRDestroySpatialReference( crs );
676 d->mAxisInverted = orientation == OAO_North;
678 d->mAxisInvertedDirty =
false;
681 return d->mAxisInverted;
688 sCRSWktLock.lockForRead();
689 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sWktCache.constFind( wkt );
690 if ( crsIt != sWktCache.constEnd() )
693 *
this = crsIt.value();
694 sCRSWktLock.unlock();
697 sCRSWktLock.unlock();
704 QgsDebugMsgLevel( QStringLiteral(
"theWkt is uninitialized, operation failed" ), 4 );
709 #if PROJ_VERSION_MAJOR>=6 710 PROJ_STRING_LIST warnings =
nullptr;
711 PROJ_STRING_LIST grammerErrors =
nullptr;
714 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_wkt(
QgsProjContext::get(), wkt.toLatin1().constData(),
nullptr, &warnings, &grammerErrors ) );
715 d->mPj = QgsProjUtils::crsToSingleCrs( crs.get() );
718 res =
static_cast< bool >( d->mPj );
721 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
722 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
724 for (
auto iter = warnings; iter && *iter; ++iter )
726 for (
auto iter = grammerErrors; iter && *iter; ++iter )
728 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
730 proj_string_list_destroy( warnings );
731 proj_string_list_destroy( grammerErrors );
733 QByteArray ba = wkt.toLatin1();
734 const char *pWkt = ba.data();
736 OGRErr myInputResult = OSRImportFromWkt( d->mCRS, const_cast< char ** >( & pWkt ) );
737 res = myInputResult == OGRERR_NONE;
740 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
741 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
743 QgsDebugMsg( QStringLiteral(
"UNUSED WKT: %1" ).arg( pWkt ) );
744 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
749 sCRSWktLock.lockForWrite();
750 sWktCache.insert( wkt, *
this );
751 sCRSWktLock.unlock();
755 #if PROJ_VERSION_MAJOR>=6 758 const QString authName( proj_get_id_auth_name( d->mPj.get(), 0 ) );
759 const QString authCode( proj_get_id_code( d->mPj.get(), 0 ) );
760 if ( !authName.isEmpty() && !authCode.isEmpty() )
762 if ( loadFromAuthCode( authName, authCode ) )
764 sCRSWktLock.lockForWrite();
765 sWktCache.insert( wkt, *
this );
766 sCRSWktLock.unlock();
772 if ( OSRAutoIdentifyEPSG( d->mCRS ) == OGRERR_NONE )
774 QString
authid = QStringLiteral(
"%1:%2" )
775 .arg( OSRGetAuthorityName( d->mCRS,
nullptr ),
776 OSRGetAuthorityCode( d->mCRS,
nullptr ) );
778 sCRSWktLock.lockForWrite();
779 sWktCache.insert( wkt, *
this );
780 sCRSWktLock.unlock();
794 #if PROJ_VERSION_MAJOR>=6 798 const QString proj4String = getFullProjString( d->mPj.get() );
799 if ( !proj4String.isEmpty() )
809 char *proj4src =
nullptr;
810 OSRExportToProj4( d->mCRS, &proj4src );
819 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0) 824 OSRExportToProj4( d->mCRS, &proj4src );
834 if ( d->mSrsId == 0 )
836 QString myName = QStringLiteral(
" * %1 (%2)" )
837 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
842 #if PROJ_VERSION_MAJOR<6 846 sCRSWktLock.lockForWrite();
847 sWktCache.insert( wkt, *
this );
848 sCRSWktLock.unlock();
863 if ( proj4String.trimmed().isEmpty() )
871 sProj4CacheLock.lockForRead();
872 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sProj4Cache.constFind( proj4String );
873 if ( crsIt != sProj4Cache.constEnd() )
876 *
this = crsIt.value();
877 sProj4CacheLock.unlock();
880 sProj4CacheLock.unlock();
890 QString myProj4String = proj4String.trimmed();
891 myProj4String.remove( QStringLiteral(
"+type=crs" ) );
892 myProj4String = myProj4String.trimmed();
895 #if PROJ_VERSION_MAJOR>=6 896 myProj4String.remove( QStringLiteral(
"+towgs84=0,0,0,0,0,0,0" ) );
897 myProj4String = myProj4String.trimmed();
904 #if PROJ_VERSION_MAJOR>=6 906 const QString projCrsString = myProj4String + ( myProj4String.contains( QStringLiteral(
"+type=crs" ) ) ? QString() : QStringLiteral(
" +type=crs" ) );
907 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create(
QgsProjContext::get(), projCrsString.toLatin1().constData() ) );
911 int *confidence =
nullptr;
912 if ( PJ_OBJ_LIST *crsList = proj_identify(
QgsProjContext::get(), crs.get(),
nullptr,
nullptr, &confidence ) )
914 const int count = proj_list_get_count( crsList );
915 int bestConfidence = 0;
916 QgsProjUtils::proj_pj_unique_ptr matchedCrs;
917 for (
int i = 0; i < count; ++i )
919 if ( confidence[i] >= bestConfidence )
922 QgsProjUtils::proj_pj_unique_ptr candidateCrs( proj_list_get(
QgsProjContext::get(), crsList, i ) );
923 candidateCrs = QgsProjUtils::crsToSingleCrs( candidateCrs.get() );
924 const QString authName( proj_get_id_auth_name( candidateCrs.get(), 0 ) );
925 if ( confidence[i] > bestConfidence || authName == QLatin1String(
"EPSG" ) )
927 bestConfidence = confidence[i];
928 matchedCrs = std::move( candidateCrs );
932 proj_list_destroy( crsList );
933 proj_int_list_destroy( confidence );
934 if ( matchedCrs && bestConfidence >= 70 )
936 const QString authName( proj_get_id_auth_name( matchedCrs.get(), 0 ) );
937 const QString authCode( proj_get_id_code( matchedCrs.get(), 0 ) );
938 if ( !authName.isEmpty() && !authCode.isEmpty() )
940 const QString
authid = QStringLiteral(
"%1:%2" ).arg( authName, authCode );
943 sProj4CacheLock.lockForWrite();
944 sProj4Cache.insert( proj4String, *
this );
945 sProj4CacheLock.unlock();
960 QRegExp myProjRegExp(
"\\+proj=(\\S+)" );
961 int myStart = myProjRegExp.indexIn( myProj4String );
964 sProj4CacheLock.lockForWrite();
965 sProj4Cache.insert( proj4String, *
this );
966 sProj4CacheLock.unlock();
971 d->mProjectionAcronym = myProjRegExp.cap( 1 );
973 QRegExp myEllipseRegExp(
"\\+ellps=(\\S+)" );
974 myStart = myEllipseRegExp.indexIn( myProj4String );
977 d->mEllipsoidAcronym.clear();
981 d->mEllipsoidAcronym = myEllipseRegExp.cap( 1 );
984 QRegExp myAxisRegExp(
"\\+a=(\\S+)" );
985 myStart = myAxisRegExp.indexIn( myProj4String );
988 QgsCoordinateReferenceSystem::RecordMap myRecord;
994 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
995 if ( myRecord.empty() )
1000 QRegExp myLat1RegExp(
"\\+lat_1=\\S+" );
1001 QRegExp myLat2RegExp(
"\\+lat_2=\\S+" );
1008 myStart1 = myLat1RegExp.indexIn( myProj4String, myStart1 );
1009 myStart2 = myLat2RegExp.indexIn( myProj4String, myStart2 );
1010 if ( myStart1 != -1 && myStart2 != -1 )
1012 myLength1 = myLat1RegExp.matchedLength();
1013 myLength2 = myLat2RegExp.matchedLength();
1018 if ( !lat1Str.isEmpty() && !lat2Str.isEmpty() )
1021 QString proj4StringModified = myProj4String;
1026 myStart2 = myLat2RegExp.indexIn( proj4String, myStart2 );
1028 QgsDebugMsgLevel( QStringLiteral(
"trying proj4string match with swapped lat_1,lat_2" ), 4 );
1029 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( proj4StringModified.trimmed() ) +
" order by deprecated" );
1033 if ( myRecord.empty() )
1040 QString sql = QStringLiteral(
"SELECT * FROM tbl_srs WHERE " );
1047 QStringList myParams;
1048 const auto constSplit = myProj4String.split( QRegExp(
"\\s+(?=\\+)" ), QString::SkipEmptyParts );
1049 for (
const QString ¶m : constSplit )
1051 QString arg = QStringLiteral(
"' '||parameters||' ' LIKE %1" ).arg(
QgsSqliteUtils::quotedString( QStringLiteral(
"% %1 %" ).arg( param.trimmed() ) ) );
1052 if ( param.startsWith( QLatin1String(
"+datum=" ) ) )
1059 delim = QStringLiteral(
" AND " );
1060 myParams << param.trimmed();
1064 if ( !datum.isEmpty() )
1066 myRecord = getRecord( sql + delim + datum +
" order by deprecated" );
1069 if ( myRecord.empty() )
1072 myRecord = getRecord( sql +
" order by deprecated" );
1075 if ( !myRecord.empty() )
1078 QStringList foundParams;
1079 const auto constSplit = myRecord[
"parameters"].split( QRegExp(
"\\s+(?=\\+)" ), QString::SkipEmptyParts );
1080 for (
const QString ¶m : constSplit )
1082 if ( !param.startsWith( QLatin1String(
"+datum=" ) ) )
1083 foundParams << param.trimmed();
1089 if ( myParams != foundParams )
1096 if ( !myRecord.empty() )
1098 mySrsId = myRecord[QStringLiteral(
"srs_id" )].toLong();
1107 setProj4String( myProj4String );
1115 d->mIsValid =
false;
1123 QgsDebugMsgLevel( QStringLiteral(
"Projection is not found in databases." ), 4 );
1125 setProj4String( myProj4String );
1128 sProj4CacheLock.lockForWrite();
1129 sProj4Cache.insert( proj4String, *
this );
1130 sProj4CacheLock.unlock();
1136 QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord(
const QString &sql )
1138 QString myDatabaseFileName;
1139 QgsCoordinateReferenceSystem::RecordMap myMap;
1140 QString myFieldName;
1141 QString myFieldValue;
1148 QFileInfo myInfo( myDatabaseFileName );
1149 if ( !myInfo.exists() )
1151 QgsDebugMsg(
"failed : " + myDatabaseFileName +
" does not exist!" );
1156 myResult = openDatabase( myDatabaseFileName, database );
1157 if ( myResult != SQLITE_OK )
1162 statement = database.
prepare( sql, myResult );
1164 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1168 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1170 myFieldName = statement.
columnName( myColNo );
1172 myMap[myFieldName] = myFieldValue;
1174 if ( statement.
step() != SQLITE_DONE )
1176 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1178 #if PROJ_VERSION_MAJOR<6 1188 if ( myMap.empty() )
1191 QFileInfo myFileInfo;
1192 myFileInfo.setFile( myDatabaseFileName );
1193 if ( !myFileInfo.exists() )
1195 QgsDebugMsg( QStringLiteral(
"user qgis.db not found" ) );
1200 myResult = openDatabase( myDatabaseFileName, database );
1201 if ( myResult != SQLITE_OK )
1206 statement = database.
prepare( sql, myResult );
1208 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1212 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1214 myFieldName = statement.
columnName( myColNo );
1216 myMap[myFieldName] = myFieldValue;
1219 if ( statement.
step() != SQLITE_DONE )
1221 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1252 if ( d->mDescription.isNull() )
1258 return d->mDescription;
1264 if ( d->mProjectionAcronym.isNull() )
1270 return d->mProjectionAcronym;
1276 if ( d->mEllipsoidAcronym.isNull() )
1282 return d->mEllipsoidAcronym;
1291 if ( d->mProj4.isEmpty() )
1293 #if PROJ_VERSION_MAJOR>=6 1296 d->mProj4 = getFullProjString( d->mPj.get() );
1299 char *proj4src =
nullptr;
1300 OSRExportToProj4( d->mCRS, &proj4src );
1301 d->mProj4 = proj4src;
1302 CPLFree( proj4src );
1306 return d->mProj4.trimmed();
1311 return d->mIsGeographic;
1319 return d->mMapUnits;
1327 #if PROJ_VERSION_MAJOR>=6 1332 double southLat = 0;
1334 double northLat = 0;
1337 &westLon, &southLat, &eastLon, &northLat, nullptr ) )
1356 int result = openDatabase( databaseFileName, database );
1357 if ( result != SQLITE_OK )
1362 QString sql = QStringLiteral(
"select west_bound_lon, north_bound_lat, east_bound_lon, south_bound_lat from tbl_bounds " 1365 statement = database.
prepare( sql, result );
1368 if ( result == SQLITE_OK )
1370 if ( statement.
step() == SQLITE_ROW )
1391 void QgsCoordinateReferenceSystem::setInternalId(
long srsId )
1396 void QgsCoordinateReferenceSystem::setAuthId(
const QString &authId )
1399 d->mAuthId = authId;
1401 void QgsCoordinateReferenceSystem::setSrid(
long srid )
1406 void QgsCoordinateReferenceSystem::setDescription(
const QString &
description )
1411 void QgsCoordinateReferenceSystem::setProj4String(
const QString &proj4String )
1414 d->mProj4 = proj4String;
1417 QString trimmed = proj4String.trimmed();
1419 #if PROJ_VERSION_MAJOR>=6 1420 trimmed += QStringLiteral(
" +type=crs" );
1424 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create( ctx, trimmed.toLatin1().constData() ) );
1425 d->mPj = QgsProjUtils::crsToSingleCrs( crs.get() );
1430 const int errNo = proj_context_errno( ctx );
1431 QgsDebugMsg( QStringLiteral(
"proj string rejected: %1" ).arg( proj_errno_string( errNo ) ) );
1432 d->mIsValid =
false;
1436 QgsProjUtils::proj_pj_unique_ptr ellipsoid( proj_get_ellipsoid( ctx, d->mPj.get() ) );
1439 const QString ellipsoidAuthName( proj_get_id_auth_name( ellipsoid.get(), 0 ) );
1440 const QString ellipsoidAuthCode( proj_get_id_code( ellipsoid.get(), 0 ) );
1441 d->mEllipsoidAcronym = QStringLiteral(
"%1:%2" ).arg( ellipsoidAuthName, ellipsoidAuthCode );
1447 OSRDestroySpatialReference( d->mCRS );
1448 d->mCRS = OSRNewSpatialReference(
nullptr );
1449 d->mIsValid = OSRImportFromProj4( d->mCRS, trimmed.toLatin1().constData() ) == OGRERR_NONE;
1455 projCtx pContext = pj_ctx_alloc();
1456 projPJ proj = pj_init_plus_ctx( pContext, proj4String.trimmed().toLatin1().constData() );
1459 QgsDebugMsgLevel( QStringLiteral(
"proj.4 string rejected by pj_init_plus_ctx()" ), 4 );
1460 d->mIsValid =
false;
1466 pj_ctx_free( pContext );
1473 void QgsCoordinateReferenceSystem::setGeographicFlag(
bool geoFlag )
1476 d->mIsGeographic = geoFlag;
1478 void QgsCoordinateReferenceSystem::setEpsg(
long epsg )
1481 d->mAuthId = QStringLiteral(
"EPSG:%1" ).arg( epsg );
1483 void QgsCoordinateReferenceSystem::setProjectionAcronym(
const QString &
projectionAcronym )
1488 void QgsCoordinateReferenceSystem::setEllipsoidAcronym(
const QString &
ellipsoidAcronym )
1494 void QgsCoordinateReferenceSystem::setMapUnits()
1503 #if PROJ_VERSION_MAJOR<6 1504 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0) 1507 OSRFixup( d->mCRS );
1511 #if PROJ_VERSION_MAJOR>=6 1519 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( context, d->mPj.get() ) );
1520 if ( !coordinateSystem )
1526 const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
1527 if ( axisCount > 0 )
1529 const char *outUnitName =
nullptr;
1531 proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
1540 const QString unitName( outUnitName );
1544 if ( unitName.compare( QLatin1String(
"degree" ), Qt::CaseInsensitive ) == 0 ||
1545 unitName.compare( QLatin1String(
"degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1546 unitName.compare( QLatin1String(
"degree minute second hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1547 unitName.compare( QLatin1String(
"degree minute" ), Qt::CaseInsensitive ) == 0 ||
1548 unitName.compare( QLatin1String(
"degree hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1549 unitName.compare( QLatin1String(
"degree minute hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1550 unitName.compare( QLatin1String(
"hemisphere degree" ), Qt::CaseInsensitive ) == 0 ||
1551 unitName.compare( QLatin1String(
"hemisphere degree minute" ), Qt::CaseInsensitive ) == 0 ||
1552 unitName.compare( QLatin1String(
"hemisphere degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1553 unitName.compare( QLatin1String(
"degree (supplier to define representation)" ), Qt::CaseInsensitive ) == 0 )
1555 else if ( unitName.compare( QLatin1String(
"metre" ), Qt::CaseInsensitive ) == 0 )
1558 else if ( unitName.compare( QLatin1String(
"US survey foot" ), Qt::CaseInsensitive ) == 0 ||
1559 unitName.compare( QLatin1String(
"foot" ), Qt::CaseInsensitive ) == 0 )
1561 else if ( unitName.compare( QLatin1String(
"kilometre" ), Qt::CaseInsensitive ) == 0 )
1563 else if ( unitName.compare( QLatin1String(
"centimetre" ), Qt::CaseInsensitive ) == 0 )
1565 else if ( unitName.compare( QLatin1String(
"millimetre" ), Qt::CaseInsensitive ) == 0 )
1567 else if ( unitName.compare( QLatin1String(
"Statute mile" ), Qt::CaseInsensitive ) == 0 )
1569 else if ( unitName.compare( QLatin1String(
"nautical mile" ), Qt::CaseInsensitive ) == 0 )
1571 else if ( unitName.compare( QLatin1String(
"yard" ), Qt::CaseInsensitive ) == 0 )
1585 char *unitName =
nullptr;
1587 if ( OSRIsProjected( d->mCRS ) )
1589 double toMeter = OSRGetLinearUnits( d->mCRS, &unitName );
1590 QString unit( unitName );
1598 static const double SMALL_NUM = 1e-3;
1600 if ( std::fabs( toMeter - FEET_TO_METER ) < SMALL_NUM )
1601 unit = QStringLiteral(
"Foot" );
1605 else if ( unit == QLatin1String(
"Foot" ) )
1614 OSRGetAngularUnits( d->mCRS, &unitName );
1615 QString unit( unitName );
1616 if ( unit == QLatin1String(
"degree" ) )
1629 if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
1632 QgsDebugMsgLevel(
"QgsCoordinateReferenceSystem::findMatchingProj will only " 1633 "work if prj acr ellipsoid acr and proj4string are set" 1634 " and the current projection is valid!", 4 );
1644 QString mySql = QString(
"select srs_id,parameters from tbl_srs where " 1645 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1652 myResult = openDatabase( myDatabaseFileName, database );
1653 if ( myResult != SQLITE_OK )
1658 statement = database.
prepare( mySql, myResult );
1659 if ( myResult == SQLITE_OK )
1662 while ( statement.
step() == SQLITE_ROW )
1666 if (
toProj4() == myProj4String.trimmed() )
1668 return mySrsId.toLong();
1679 myResult = openDatabase( myDatabaseFileName, database );
1680 if ( myResult != SQLITE_OK )
1685 statement = database.
prepare( mySql, myResult );
1687 if ( myResult == SQLITE_OK )
1689 while ( statement.
step() == SQLITE_ROW )
1693 if (
toProj4() == myProj4String.trimmed() )
1695 return mySrsId.toLong();
1705 return ( !d->mIsValid && !srs.d->mIsValid ) ||
1706 ( d->mIsValid && srs.d->mIsValid && srs.
authid() ==
authid() );
1711 return !( *
this == srs );
1716 if ( d->mWkt.isEmpty() )
1718 #if PROJ_VERSION_MAJOR>=6 1722 const char *
const options[] = {
"MULTILINE=NO",
"INDENTATION_WIDTH=0",
nullptr};
1723 d->mWkt = QString( proj_as_wkt(
QgsProjContext::get(), d->mPj.get(), PJ_WKT1_GDAL, options ) );
1726 char *wkt =
nullptr;
1727 if ( OSRExportToWkt( d->mCRS, &wkt ) == OGRERR_NONE )
1741 QDomNode srsNode = node.namedItem( QStringLiteral(
"spatialrefsys" ) );
1743 if ( ! srsNode.isNull() )
1745 bool initialized =
false;
1748 long srsid = srsNode.namedItem( QStringLiteral(
"srsid" ) ).toElement().text().toLong( &ok );
1754 myNode = srsNode.namedItem( QStringLiteral(
"authid" ) );
1755 if ( !myNode.isNull() )
1766 myNode = srsNode.namedItem( QStringLiteral(
"epsg" ) );
1767 if ( !myNode.isNull() )
1780 myNode = srsNode.namedItem( QStringLiteral(
"proj4" ) );
1781 const QString proj4 = myNode.toElement().text();
1786 if ( !proj4.trimmed().isEmpty() )
1787 setProj4String( myNode.toElement().text() );
1789 myNode = srsNode.namedItem( QStringLiteral(
"srsid" ) );
1790 setInternalId( myNode.toElement().text().toLong() );
1792 myNode = srsNode.namedItem( QStringLiteral(
"srid" ) );
1793 setSrid( myNode.toElement().text().toLong() );
1795 myNode = srsNode.namedItem( QStringLiteral(
"authid" ) );
1796 setAuthId( myNode.toElement().text() );
1798 myNode = srsNode.namedItem( QStringLiteral(
"description" ) );
1799 setDescription( myNode.toElement().text() );
1801 myNode = srsNode.namedItem( QStringLiteral(
"projectionacronym" ) );
1802 setProjectionAcronym( myNode.toElement().text() );
1804 myNode = srsNode.namedItem( QStringLiteral(
"ellipsoidacronym" ) );
1805 setEllipsoidAcronym( myNode.toElement().text() );
1807 myNode = srsNode.namedItem( QStringLiteral(
"geographicflag" ) );
1808 if ( myNode.toElement().text().compare( QLatin1String(
"true" ) ) )
1810 setGeographicFlag(
true );
1814 setGeographicFlag(
false );
1824 if (
isValid() && d->mSrsId == 0 )
1826 QString myName = QStringLiteral(
" * %1 (%2)" )
1827 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
1837 d =
new QgsCoordinateReferenceSystemPrivate();
1846 QDomElement myLayerNode = node.toElement();
1847 QDomElement mySrsElement = doc.createElement( QStringLiteral(
"spatialrefsys" ) );
1849 QDomElement myProj4Element = doc.createElement( QStringLiteral(
"proj4" ) );
1850 myProj4Element.appendChild( doc.createTextNode(
toProj4() ) );
1851 mySrsElement.appendChild( myProj4Element );
1853 QDomElement mySrsIdElement = doc.createElement( QStringLiteral(
"srsid" ) );
1854 mySrsIdElement.appendChild( doc.createTextNode( QString::number(
srsid() ) ) );
1855 mySrsElement.appendChild( mySrsIdElement );
1857 QDomElement mySridElement = doc.createElement( QStringLiteral(
"srid" ) );
1858 mySridElement.appendChild( doc.createTextNode( QString::number(
postgisSrid() ) ) );
1859 mySrsElement.appendChild( mySridElement );
1861 QDomElement myEpsgElement = doc.createElement( QStringLiteral(
"authid" ) );
1862 myEpsgElement.appendChild( doc.createTextNode(
authid() ) );
1863 mySrsElement.appendChild( myEpsgElement );
1865 QDomElement myDescriptionElement = doc.createElement( QStringLiteral(
"description" ) );
1866 myDescriptionElement.appendChild( doc.createTextNode(
description() ) );
1867 mySrsElement.appendChild( myDescriptionElement );
1869 QDomElement myProjectionAcronymElement = doc.createElement( QStringLiteral(
"projectionacronym" ) );
1870 myProjectionAcronymElement.appendChild( doc.createTextNode(
projectionAcronym() ) );
1871 mySrsElement.appendChild( myProjectionAcronymElement );
1873 QDomElement myEllipsoidAcronymElement = doc.createElement( QStringLiteral(
"ellipsoidacronym" ) );
1874 myEllipsoidAcronymElement.appendChild( doc.createTextNode(
ellipsoidAcronym() ) );
1875 mySrsElement.appendChild( myEllipsoidAcronymElement );
1877 QDomElement myGeographicFlagElement = doc.createElement( QStringLiteral(
"geographicflag" ) );
1878 QString myGeoFlagText = QStringLiteral(
"false" );
1881 myGeoFlagText = QStringLiteral(
"true" );
1884 myGeographicFlagElement.appendChild( doc.createTextNode( myGeoFlagText ) );
1885 mySrsElement.appendChild( myGeographicFlagElement );
1887 myLayerNode.appendChild( mySrsElement );
1901 QString QgsCoordinateReferenceSystem::proj4FromSrsId(
const int srsId )
1903 QString myDatabaseFileName;
1904 QString myProjString;
1905 QString mySql = QStringLiteral(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( srsId );
1914 QFileInfo myFileInfo;
1915 myFileInfo.setFile( myDatabaseFileName );
1916 if ( !myFileInfo.exists() )
1918 QgsDebugMsg( QStringLiteral(
"users qgis.db not found" ) );
1931 rc = openDatabase( myDatabaseFileName, database );
1937 statement = database.
prepare( mySql, rc );
1939 if ( rc == SQLITE_OK )
1941 if ( statement.
step() == SQLITE_ROW )
1947 return myProjString;
1954 myResult = database.
open_v2( path, SQLITE_OPEN_READONLY,
nullptr );
1956 myResult = database.
open( path );
1958 if ( myResult != SQLITE_OK )
1967 .arg( database.
errorMessage() ), QObject::tr(
"CRS" ) );
1974 mCustomSrsValidation = f;
1979 return mCustomSrsValidation;
1982 void QgsCoordinateReferenceSystem::debugPrint()
1984 QgsDebugMsg( QStringLiteral(
"***SpatialRefSystem***" ) );
1985 QgsDebugMsg(
"* Valid : " + ( d->mIsValid ? QString(
"true" ) : QString(
"false" ) ) );
1986 QgsDebugMsg(
"* SrsId : " + QString::number( d->mSrsId ) );
1992 QgsDebugMsg( QStringLiteral(
"* Units : meters" ) );
1996 QgsDebugMsg( QStringLiteral(
"* Units : feet" ) );
2000 QgsDebugMsg( QStringLiteral(
"* Units : degrees" ) );
2007 d->mValidationHint = html;
2012 return d->mValidationHint;
2028 QString proj4String = d->mProj4;
2029 if ( proj4String.isEmpty() )
2042 if ( getRecordCount() == 0 )
2044 mySql =
"insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 2048 +
',' + quotedEllipsoidString
2054 mySql =
"insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 2057 +
',' + quotedEllipsoidString
2066 if ( myResult != SQLITE_OK )
2068 QgsDebugMsg( QStringLiteral(
"Can't open or create database %1: %2" )
2073 statement = database.
prepare( mySql, myResult );
2076 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_DONE )
2080 returnId = sqlite3_last_insert_rowid( database.get() );
2081 setInternalId( returnId );
2082 if (
authid().isEmpty() )
2083 setAuthId( QStringLiteral(
"USER:%1" ).arg( returnId ) );
2084 setDescription( name );
2089 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
2090 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
2093 projectionsProj4.append(
toProj4() );
2094 projectionsAuthId.append(
authid() );
2095 settings.
setValue( QStringLiteral(
"UI/recentProjectionsProj4" ), projectionsProj4 );
2096 settings.
setValue( QStringLiteral(
"UI/recentProjectionsAuthId" ), projectionsAuthId );
2106 long QgsCoordinateReferenceSystem::getRecordCount()
2111 long myRecordCount = 0;
2114 if ( myResult != SQLITE_OK )
2120 QString mySql = QStringLiteral(
"select count(*) from tbl_srs" );
2121 statement = database.
prepare( mySql, myResult );
2122 if ( myResult == SQLITE_OK )
2124 if ( statement.
step() == SQLITE_ROW )
2126 QString myRecordCountString = statement.
columnAsText( 0 );
2127 myRecordCount = myRecordCountString.toLong();
2130 return myRecordCount;
2133 #if PROJ_VERSION_MAJOR>=6 2134 bool testIsGeographic( PJ *
crs )
2138 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( pjContext, crs ) );
2139 if ( coordinateSystem )
2141 const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
2142 if ( axisCount > 0 )
2144 const char *outUnitAuthName =
nullptr;
2145 const char *outUnitAuthCode =
nullptr;
2147 proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
2156 if ( outUnitAuthName && outUnitAuthCode )
2158 const char *unitCategory =
nullptr;
2159 if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode,
nullptr,
nullptr, &unitCategory ) )
2161 isGeographic = QString( unitCategory ).compare( QLatin1String(
"angular" ), Qt::CaseInsensitive ) == 0;
2169 void getOperationAndEllipsoidFromProjString(
const QString &proj, QString &operation, QString &ellipsoid )
2171 QRegExp projRegExp(
"\\+proj=(\\S+)" );
2172 if ( projRegExp.indexIn( proj ) < 0 )
2174 QgsDebugMsgLevel( QStringLiteral(
"no +proj argument found [%2]" ).arg( proj ), 2 );
2177 operation = projRegExp.cap( 1 );
2179 QRegExp ellipseRegExp(
"\\+(?:ellps|datum)=(\\S+)" );
2181 if ( ellipseRegExp.indexIn( proj ) >= 0 )
2183 ellipsoid = ellipseRegExp.cap( 1 );
2197 bool QgsCoordinateReferenceSystem::loadFromAuthCode(
const QString &auth,
const QString &code )
2200 d->mIsValid =
false;
2204 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database( pjContext, auth.toUtf8().constData(), code.toUtf8().constData(), PJ_CATEGORY_CRS,
false, nullptr ) );
2210 switch ( proj_get_type( crs.get() ) )
2212 case PJ_TYPE_VERTICAL_CRS:
2219 crs = QgsProjUtils::crsToSingleCrs( crs.get() );
2221 QString proj4 = getFullProjString( crs.get() );
2222 proj4.replace( QStringLiteral(
"+type=crs" ), QString() );
2223 proj4 = proj4.trimmed();
2227 d->mDescription = QString( proj_get_name( crs.get() ) );
2228 d->mAuthId = QStringLiteral(
"%1:%2" ).arg( auth, code );
2229 d->mIsGeographic = testIsGeographic( crs.get() );
2230 d->mAxisInvertedDirty =
true;
2233 getOperationAndEllipsoidFromProjString( proj4, operation, ellipsoid );
2234 d->mProjectionAcronym = operation;
2235 d->mEllipsoidAcronym = ellipsoid;
2236 d->mPj = std::move( crs );
2238 const QString dbVals =
sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( auth, code ).toUpper() );
2241 if ( !dbVals.isEmpty() )
2243 const QStringList parts = dbVals.split(
',' );
2244 d->mSrsId = parts.at( 0 ).toInt();
2245 d->mSRID = parts.at( 1 ).toInt();
2254 #if PROJ_VERSION_MAJOR<6 2256 bool QgsCoordinateReferenceSystem::loadWkts( QHash<int, QString> &wkts,
const char *filename )
2259 const char *pszFilename = CPLFindFile(
"gdal", filename );
2263 QFile csv( pszFilename );
2264 if ( !csv.open( QIODevice::ReadOnly ) )
2267 QTextStream lines( &csv );
2271 QString line = lines.readLine();
2272 if ( line.isNull() )
2275 if ( line.trimmed().isEmpty() || line.startsWith(
'#' ) )
2279 else if ( line.startsWith( QLatin1String(
"include " ) ) )
2281 if ( !loadWkts( wkts, line.mid( 8 ).toUtf8() ) )
2286 int pos = line.indexOf(
',' );
2291 int epsg = line.leftRef( pos ).toInt( &ok );
2295 wkts.insert( epsg, line.mid( pos + 1 ) );
2304 bool QgsCoordinateReferenceSystem::loadIds( QHash<int, QString> &wkts )
2308 static const QStringList csvs { QStringList() << QStringLiteral(
"gcs.csv" ) << QStringLiteral(
"pcs.csv" ) << QStringLiteral(
"vertcs.csv" ) << QStringLiteral(
"compdcs.csv" ) << QStringLiteral(
"geoccs.csv" ) };
2309 for (
const QString &csv : csvs )
2311 QString filename = CPLFindFile(
"gdal", csv.toUtf8() );
2313 QFile f( filename );
2314 if ( !f.open( QIODevice::ReadOnly ) )
2317 QTextStream lines( &f );
2324 QString line = lines.readLine();
2325 if ( line.isNull() )
2328 if ( line.trimmed().isEmpty() )
2331 int pos = line.indexOf(
',' );
2334 qWarning(
"No id found in: %s", qPrintable( line ) );
2339 int epsg = line.leftRef( pos ).toInt( &ok );
2342 qWarning(
"No valid id found in: %s", qPrintable( line ) );
2347 if ( epsg == 2218 || epsg == 2221 || epsg == 2296 || epsg == 2297 || epsg == 2298 || epsg == 2299 || epsg == 2300 || epsg == 2301 || epsg == 2302 ||
2348 epsg == 2303 || epsg == 2304 || epsg == 2305 || epsg == 2306 || epsg == 2307 || epsg == 2963 || epsg == 2985 || epsg == 2986 || epsg == 3052 ||
2349 epsg == 3053 || epsg == 3139 || epsg == 3144 || epsg == 3145 || epsg == 3173 || epsg == 3295 || epsg == 3993 || epsg == 4087 || epsg == 4088 ||
2350 epsg == 5017 || epsg == 5221 || epsg == 5224 || epsg == 5225 || epsg == 5514 || epsg == 5515 || epsg == 5516 || epsg == 5819 || epsg == 5820 ||
2351 epsg == 5821 || epsg == 6200 || epsg == 6201 || epsg == 6202 || epsg == 6244 || epsg == 6245 || epsg == 6246 || epsg == 6247 || epsg == 6248 ||
2352 epsg == 6249 || epsg == 6250 || epsg == 6251 || epsg == 6252 || epsg == 6253 || epsg == 6254 || epsg == 6255 || epsg == 6256 || epsg == 6257 ||
2353 epsg == 6258 || epsg == 6259 || epsg == 6260 || epsg == 6261 || epsg == 6262 || epsg == 6263 || epsg == 6264 || epsg == 6265 || epsg == 6266 ||
2354 epsg == 6267 || epsg == 6268 || epsg == 6269 || epsg == 6270 || epsg == 6271 || epsg == 6272 || epsg == 6273 || epsg == 6274 || epsg == 6275 ||
2355 epsg == 6966 || epsg == 7082 || epsg == 32600 || epsg == 32663 || epsg == 32700 )
2358 if ( OSRImportFromEPSG( crs, epsg ) != OGRERR_NONE )
2360 qDebug(
"EPSG %d: not imported", epsg );
2364 char *wkt =
nullptr;
2365 if ( OSRExportToWkt( crs, &wkt ) != OGRERR_NONE )
2367 qWarning(
"EPSG %d: not exported to WKT", epsg );
2371 wkts.insert( epsg, wkt );
2379 QgsDebugMsgLevel( QStringLiteral(
"Loaded %1/%2 from %3" ).arg( QString::number( n ), QString::number( l ), filename.toUtf8().constData() ), 4 );
2382 OSRDestroySpatialReference( crs );
2388 #if PROJ_VERSION_MAJOR>=6 2389 static void sync_db_proj_logger(
void * ,
int level,
const char *message )
2391 if ( level == PJ_LOG_ERROR )
2395 else if ( level == PJ_LOG_DEBUG )
2404 setlocale( LC_ALL,
"C" );
2407 #if PROJ_VERSION_MAJOR<6 2408 syncDatumTransform( dbFilePath );
2411 int inserted = 0, updated = 0, deleted = 0, errors = 0;
2416 if ( database.
open( dbFilePath ) != SQLITE_OK )
2422 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2428 #if PROJ_VERSION_MAJOR<6 2430 if ( sqlite3_exec( database.get(),
"alter table tbl_srs add noupdate boolean",
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2431 ( void )sqlite3_exec( database.get(),
"update tbl_srs set noupdate=(auth_name='EPSG' and auth_id in (5513,5514,5221,2065,102067,4156,4818))",
nullptr,
nullptr, nullptr );
2433 ( void )sqlite3_exec( database.get(),
"UPDATE tbl_srs SET srid=141001 WHERE srid=41001 AND auth_name='OSGEO' AND auth_id='41001'",
nullptr,
nullptr, nullptr );
2438 char *errMsg =
nullptr;
2440 #if PROJ_VERSION_MAJOR>=6 2443 proj_log_func( pjContext,
nullptr, sync_db_proj_logger );
2445 PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
2447 int nextSrsId = 60000;
2448 int nextSrId = 520000000;
2449 for (
auto authIter = authorities; authIter && *authIter; ++authIter )
2451 const QString authority( *authIter );
2452 QgsDebugMsgLevel( QStringLiteral(
"Loading authority '%1'" ).arg( authority ), 2 );
2453 PROJ_STRING_LIST codes = proj_get_codes_from_database( pjContext, *authIter, PJ_TYPE_CRS,
true );
2455 QStringList allCodes;
2457 for (
auto codesIter = codes; codesIter && *codesIter; ++codesIter )
2459 const QString code( *codesIter );
2462 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database( pjContext, *authIter, *codesIter, PJ_CATEGORY_CRS,
false,
nullptr ) );
2465 QgsDebugMsg( QStringLiteral(
"Could not load '%1:%2'" ).arg( authority, code ) );
2469 switch ( proj_get_type( crs.get() ) )
2471 case PJ_TYPE_VERTICAL_CRS:
2478 crs = QgsProjUtils::crsToSingleCrs( crs.get() );
2480 QString proj4 = getFullProjString( crs.get() );
2481 proj4.replace( QStringLiteral(
"+type=crs" ), QString() );
2482 proj4 = proj4.trimmed();
2484 if ( proj4.isEmpty() )
2486 QgsDebugMsgLevel( QStringLiteral(
"No proj4 for '%1:%2'" ).arg( authority, code ), 2 );
2491 const bool deprecated = proj_is_deprecated( crs.get() );
2492 const QString name( proj_get_name( crs.get() ) );
2494 QString sql = QStringLiteral(
"SELECT parameters,description,deprecated FROM tbl_srs WHERE auth_name='%1' AND auth_id='%2'" ).arg( authority, code );
2495 statement = database.
prepare( sql, result );
2496 if ( result != SQLITE_OK )
2504 bool srsDeprecated = deprecated;
2505 if ( statement.
step() == SQLITE_ROW )
2509 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2512 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
2514 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
2517 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name=%4 AND auth_id=%5" )
2518 .arg( QgsSqliteUtils::quotedString( proj4 ) )
2519 .arg( QgsSqliteUtils::quotedString( name ) )
2520 .arg( deprecated ? 1 : 0 )
2521 .arg( QgsSqliteUtils::quotedString( authority ), QgsSqliteUtils::quotedString( code ) );
2523 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2525 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2528 errMsg ? errMsg :
"(unknown error)" ) );
2530 sqlite3_free( errMsg );
2542 QString operation =
"";
2544 getOperationAndEllipsoidFromProjString( proj4, operation, ellps );
2545 const bool isGeographic = testIsGeographic( crs.get() );
2548 const QString dbVals =
sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( authority, code ) );
2551 if ( !dbVals.isEmpty() )
2553 const QStringList parts = dbVals.split(
',' );
2554 srsId = parts.at( 0 );
2555 srId = parts.at( 1 );
2557 if ( srId.isEmpty() )
2559 srId = QString::number( nextSrId );
2562 if ( srsId.isEmpty() )
2564 srsId = QString::number( nextSrsId );
2568 if ( !srsId.isEmpty() )
2570 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)" )
2572 .arg( QgsSqliteUtils::quotedString( name ),
2573 QgsSqliteUtils::quotedString( operation ),
2574 QgsSqliteUtils::quotedString( ellps ),
2575 QgsSqliteUtils::quotedString( proj4 ) )
2577 .arg( QgsSqliteUtils::quotedString( authority ) )
2578 .arg( QgsSqliteUtils::quotedString( code ) )
2579 .arg( isGeographic ? 1 : 0 )
2580 .arg( deprecated ? 1 : 0 );
2584 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)" )
2585 .arg( QgsSqliteUtils::quotedString( name ),
2586 QgsSqliteUtils::quotedString( operation ),
2587 QgsSqliteUtils::quotedString( ellps ),
2588 QgsSqliteUtils::quotedString( proj4 ) )
2590 .arg( QgsSqliteUtils::quotedString( authority ) )
2591 .arg( QgsSqliteUtils::quotedString( code ) )
2592 .arg( isGeographic ? 1 : 0 )
2593 .arg( deprecated ? 1 : 0 );
2597 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2603 qCritical(
"Could not execute: %s [%s/%s]\n",
2604 sql.toLocal8Bit().constData(),
2605 sqlite3_errmsg( database.get() ),
2606 errMsg ? errMsg :
"(unknown error)" );
2610 sqlite3_free( errMsg );
2615 proj_string_list_destroy( codes );
2617 const QString sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='%1' AND NOT auth_id IN (%2)" ).arg( authority, allCodes.join(
',' ) );
2618 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2620 deleted = sqlite3_changes( database.get() );
2625 qCritical(
"Could not execute: %s [%s]\n",
2626 sql.toLocal8Bit().constData(),
2627 sqlite3_errmsg( database.get() ) );
2631 proj_string_list_destroy( authorities );
2639 QHash<int, QString> wkts;
2641 loadWkts( wkts,
"epsg.wkt" );
2643 QgsDebugMsgLevel( QStringLiteral(
"%1 WKTs loaded" ).arg( wkts.count() ), 4 );
2645 for ( QHash<int, QString>::const_iterator it = wkts.constBegin(); it != wkts.constEnd(); ++it )
2647 QByteArray ba( it.value().toUtf8() );
2648 char *psz = ba.data();
2651 OSRDestroySpatialReference( crs );
2653 crs = OSRNewSpatialReference(
nullptr );
2655 OGRErr ogrErr = OSRImportFromWkt( crs, &psz );
2656 if ( ogrErr != OGRERR_NONE )
2659 if ( OSRExportToProj4( crs, &psz ) != OGRERR_NONE )
2666 proj4 = proj4.trimmed();
2670 if ( proj4.isEmpty() )
2673 QString name( OSRIsGeographic( crs ) ? OSRGetAttrValue( crs,
"GEOGCS", 0 ) :
2674 OSRIsGeocentric( crs ) ? OSRGetAttrValue( crs,
"GEOCCS", 0 ) :
2675 OSRGetAttrValue( crs,
"PROJCS", 0 ) );
2676 if ( name.isEmpty() )
2677 name = QObject::tr(
"Imported from GDAL" );
2679 bool deprecated = name.contains( QLatin1Literal(
"(deprecated)" ) );
2681 sql = QStringLiteral(
"SELECT parameters,description,deprecated,noupdate FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).arg( it.key() );
2682 statement = database.
prepare( sql, result );
2683 if ( result != SQLITE_OK )
2691 bool srsDeprecated = deprecated;
2692 if ( statement.
step() == SQLITE_ROW )
2696 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2704 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
2706 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
2709 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name='EPSG' AND auth_id=%4" )
2712 .arg( deprecated ? 1 : 0 )
2715 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2717 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2720 errMsg ? errMsg :
"(unknown error)" ) );
2722 sqlite3_free( errMsg );
2733 QRegExp projRegExp(
"\\+proj=(\\S+)" );
2734 if ( projRegExp.indexIn( proj4 ) < 0 )
2736 QgsDebugMsgLevel( QStringLiteral(
"EPSG %1: no +proj argument found [%2]" ).arg( it.key() ).arg( proj4 ), 4 );
2740 QRegExp ellipseRegExp(
"\\+ellps=(\\S+)" );
2742 if ( ellipseRegExp.indexIn( proj4 ) >= 0 )
2744 ellps = ellipseRegExp.cap( 1 );
2756 sql = QStringLiteral(
"INSERT INTO tbl_srs(description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated) VALUES (%1,%2,%3,%4,%5,'EPSG',%5,%6,%7)" )
2762 .arg( OSRIsGeographic( crs ) )
2763 .arg( deprecated ? 1 : 0 );
2766 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2772 qCritical(
"Could not execute: %s [%s/%s]\n",
2773 sql.toLocal8Bit().constData(),
2774 sqlite3_errmsg( database.get() ),
2775 errMsg ? errMsg :
"(unknown error)" );
2779 sqlite3_free( errMsg );
2785 OSRDestroySpatialReference( crs );
2788 sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN (" );
2790 QHash<int, QString>::const_iterator it = wkts.constBegin();
2791 for ( ; it != wkts.constEnd(); ++it )
2793 sql += delim + QString::number( it.key() );
2796 sql += QLatin1String(
") AND NOT noupdate" );
2798 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2800 deleted = sqlite3_changes( database.get() );
2805 qCritical(
"Could not execute: %s [%s]\n",
2806 sql.toLocal8Bit().constData(),
2807 sqlite3_errmsg( database.get() ) );
2810 projCtx pContext = pj_ctx_alloc();
2812 #if !defined(PJ_VERSION) || PJ_VERSION!=470 2813 sql = QStringLiteral(
"select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated AND NOT noupdate" );
2814 statement = database.
prepare( sql, result );
2815 if ( result == SQLITE_OK )
2817 while ( statement.
step() == SQLITE_ROW )
2823 QString input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toLower(), auth_id );
2824 projPJ pj = pj_init_plus_ctx( pContext, input.toLatin1() );
2827 input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toUpper(), auth_id );
2828 pj = pj_init_plus_ctx( pContext, input.toLatin1() );
2833 char *def = pj_get_def( pj, 0 );
2839 input.prepend(
' ' ).append(
' ' );
2840 if ( proj4.startsWith( input ) )
2842 proj4 = proj4.mid( input.size() );
2843 proj4 = proj4.trimmed();
2846 if ( proj4 != params )
2848 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
2853 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2859 qCritical(
"Could not execute: %s [%s/%s]\n",
2860 sql.toLocal8Bit().constData(),
2861 sqlite3_errmsg( database.get() ),
2862 errMsg ? errMsg :
"(unknown error)" );
2864 sqlite3_free( errMsg );
2871 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve proj string for %1 from PROJ" ).arg( input ), 4 );
2876 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve crs for %1 from PROJ" ).arg( input ), 3 );
2885 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2]\n" ).arg(
2887 sqlite3_errmsg( database.get() ) ) );
2891 pj_ctx_free( pContext );
2895 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2897 QgsDebugMsg( QStringLiteral(
"Could not commit transaction: %1 [%2]\n" ).arg(
2899 sqlite3_errmsg( database.get() ) )
2904 QgsDebugMsgLevel( QStringLiteral(
"CRS update (inserted:%1 updated:%2 deleted:%3 errors:%4)" ).arg( QString::number( inserted ), QString::number( updated ), QString::number( deleted ), QString::number( errors ) ), 4 );
2909 return updated + inserted;
2912 #if PROJ_VERSION_MAJOR<6 2913 bool QgsCoordinateReferenceSystem::syncDatumTransform(
const QString &dbPath )
2915 const char *filename = CSVFilename(
"datum_shift.csv" );
2916 FILE *fp = VSIFOpen( filename,
"rb" );
2922 char **fieldnames = CSVReadParseLine( fp );
2934 {
"SOURCE_CRS_CODE",
"source_crs_code", -1 },
2935 {
"TARGET_CRS_CODE",
"target_crs_code", -1 },
2936 {
"REMARKS",
"remarks", -1 },
2937 {
"COORD_OP_SCOPE",
"scope", -1 },
2938 {
"AREA_OF_USE_CODE",
"area_of_use_code", -1 },
2944 {
"DEPRECATED",
"deprecated", -1 },
2945 {
"COORD_OP_METHOD_CODE",
"coord_op_method_code", -1 },
2953 {
"PREFERRED",
"preferred", -1 },
2954 {
"COORD_OP_CODE",
"coord_op_code", -1 },
2957 QString update = QStringLiteral(
"UPDATE tbl_datum_transform SET " );
2958 QString insert, values;
2960 int n = CSLCount( fieldnames );
2962 int idxid = -1, idxrx = -1, idxry = -1, idxrz = -1, idxmcode = -1;
2963 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
2965 bool last = i ==
sizeof( map ) /
sizeof( *map ) - 1;
2967 map[i].idx = CSLFindString( fieldnames, map[i].src );
2968 if ( map[i].idx < 0 )
2970 qWarning(
"field %s not found", map[i].src );
2971 CSLDestroy( fieldnames );
2976 if ( strcmp( map[i].src,
"COORD_OP_CODE" ) == 0 )
2978 if ( strcmp( map[i].src,
"RX" ) == 0 )
2980 if ( strcmp( map[i].src,
"RY" ) == 0 )
2982 if ( strcmp( map[i].src,
"RZ" ) == 0 )
2984 if ( strcmp( map[i].src,
"COORD_OP_METHOD_CODE" ) == 0 )
2994 update += QLatin1String(
" WHERE " );
3002 update += QStringLiteral(
"%1=%%2" ).arg( map[i].dst ).arg( i + 1 );
3004 insert += map[i].dst;
3005 values += QStringLiteral(
"%%1" ).arg( i + 1 );
3008 insert =
"INSERT INTO tbl_datum_transform(" + insert +
") VALUES (" + values +
')';
3010 CSLDestroy( fieldnames );
3012 Q_ASSERT( idxid >= 0 );
3013 Q_ASSERT( idxrx >= 0 );
3014 Q_ASSERT( idxry >= 0 );
3015 Q_ASSERT( idxrz >= 0 );
3018 int openResult = database.
open( dbPath );
3019 if ( openResult != SQLITE_OK )
3025 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
3033 v.reserve(
sizeof( map ) /
sizeof( *map ) );
3037 char **values = CSVReadParseLine( fp );
3043 if ( CSLCount( values ) == 0 )
3045 CSLDestroy( values );
3049 if ( CSLCount( values ) < n )
3051 qWarning(
"Only %d columns", CSLCount( values ) );
3052 CSLDestroy( values );
3056 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
3058 int idx = map[i].idx;
3059 Q_ASSERT( idx != -1 );
3060 Q_ASSERT( idx < n );
3063 CSLDestroy( values );
3066 if ( v.at( idxmcode ).compare( QLatin1String(
"'9607'" ) ) == 0 )
3068 v[ idxmcode ] = QStringLiteral(
"'9606'" );
3069 v[ idxrx ] =
'\'' +
qgsDoubleToString( -( v[ idxrx ].
remove(
'\'' ).toDouble() ) ) +
'\'';
3070 v[ idxry ] =
'\'' +
qgsDoubleToString( -( v[ idxry ].
remove(
'\'' ).toDouble() ) ) +
'\'';
3071 v[ idxrz ] =
'\'' +
qgsDoubleToString( -( v[ idxrz ].
remove(
'\'' ).toDouble() ) ) +
'\'';
3077 QString sql = QStringLiteral(
"SELECT coord_op_code FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( v[ idxid ] );
3079 statement = database.
prepare( sql, prepareRes );
3080 if ( prepareRes != SQLITE_OK )
3083 if ( statement.
step() == SQLITE_ROW )
3088 sql = cOpCode.isEmpty() ? insert : update;
3089 for (
int i = 0; i < v.size(); i++ )
3091 sql = sql.arg( v[i] );
3094 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) != SQLITE_OK )
3096 qCritical(
"SQL: %s", sql.toUtf8().constData() );
3097 qCritical(
"Error: %s", sqlite3_errmsg( database.get() ) );
3101 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
3117 #if PROJ_VERSION_MAJOR>=6 3120 QgsProjUtils::proj_pj_unique_ptr geoCrs( proj_crs_get_geodetic_crs(
QgsProjContext::get(), d->mPj.get() ) );
3121 return geoCrs ? QStringLiteral(
"%1:%2" ).arg( proj_get_id_auth_name( geoCrs.get(), 0 ), proj_get_id_code( geoCrs.get(), 0 ) ) : QString();
3126 return OSRGetAuthorityName( d->mCRS,
"GEOGCS" ) + QStringLiteral(
":" ) + OSRGetAuthorityCode( d->mCRS,
"GEOGCS" );
3135 #if PROJ_VERSION_MAJOR>=6 3136 PJ *QgsCoordinateReferenceSystem::projObject()
const 3138 return d->mPj.get();
3144 QStringList projections;
3148 projections = settings.
value( QStringLiteral(
"UI/recentProjections" ) ).toStringList();
3152 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
3153 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
3154 if ( projectionsAuthId.size() >= projections.size() )
3158 projections.clear();
3159 for (
int i = 0; i < projectionsAuthId.size(); i++ )
3167 if ( i >= projectionsProj4.size() || !crs.
createFromProj4( projectionsProj4.at( i ) ) )
3173 if ( crs.
srsid() == 0 )
3178 projections << QString::number( crs.
srsid() );
3186 sSrIdCacheLock.lockForWrite();
3188 sSrIdCacheLock.unlock();
3189 sOgcLock.lockForWrite();
3192 sProj4CacheLock.lockForWrite();
3193 sProj4Cache.clear();
3194 sProj4CacheLock.unlock();
3195 sCRSWktLock.lockForWrite();
3197 sCRSWktLock.unlock();
3198 sCRSSrsIdLock.lockForWrite();
3199 sSrsIdCache.clear();
3200 sCRSSrsIdLock.unlock();
3201 sCrsStringLock.lockForWrite();
3202 sStringCache.clear();
3203 sCrsStringLock.unlock();
QString geographicCrsAuthId() const
Returns auth id of related geographic CRS.
QgsCoordinateReferenceSystem()
Constructs an invalid CRS object.
bool createFromId(long id, CrsType type=PostgisCrsId)
Sets this CRS by lookup of the given ID in the CRS database.
bool operator!=(const QgsCoordinateReferenceSystem &srs) const
Overloaded != operator used to compare to CRS's.
A rectangle specified with double values.
static QgsCoordinateReferenceSystem fromProj4(const QString &proj4)
Creates a CRS from a proj4 style formatted string.
bool createFromString(const QString &definition)
Set up this CRS from a string definition.
static QList< long > validSrsIds()
Returns a list of all valid SRS IDs present in the CRS database.
void setXMaximum(double x)
Set the maximum x value.
This class is a composition of two QSettings instances:
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void validate()
Perform some validation on this CRS.
static void warning(const QString &msg)
Goes to qWarning.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
static void setCustomCrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS.
QString toProj4() const
Returns a Proj4 string representation of this CRS.
const int LAT_PREFIX_LEN
The length of the string "+lat_1=".
const QMap< QString, QString > sAuthIdToQgisSrsIdMap
const QgsCoordinateReferenceSystem & crs
Internal ID used by QGIS in the local SQLite database.
long saveAsUserCrs(const QString &name)
Save the proj4-string as a custom CRS.
bool createFromOgcWmsCrs(const QString &crs)
Sets this CRS to the given OGC WMS-format Coordinate Reference Systems.
QString errorMessage() const
Returns the most recent error message encountered by the database.
static Q_INVOKABLE QgsCoordinateReferenceSystem fromEpsgId(long epsg)
Creates a CRS from a given EPSG ID.
void setValidationHint(const QString &html)
Set user hint for validation.
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
#define QgsDebugMsgLevel(str, level)
bool createFromSrid(long srid)
Sets this CRS by lookup of the given PostGIS SRID in the CRS database.
static QStringList recentProjections()
Returns a list of recently used projections.
int step()
Steps to the next record in the statement, returning the sqlite3 result code.
QString validationHint()
Gets user hint for validation.
long postgisSrid() const
Returns PostGIS SRID for the CRS.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
long findMatchingProj()
Walks the CRS databases (both system and user database) trying to match stored PROJ string to a datab...
void setYMinimum(double y)
Set the minimum y value.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
int columnCount() const
Gets the number of columns that this statement returns.
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
Degrees, for planar geographic CRS distance measurements.
QgsCoordinateReferenceSystem & operator=(const QgsCoordinateReferenceSystem &srs)
Assignment operator.
QString columnAsText(int column) const
Returns the column value from the current statement row as a string.
const QString GEO_EPSG_CRS_AUTHID
Geographic coord sys from EPSG authority.
bool isGeographic() const
Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
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.
bool createFromWkt(const QString &wkt)
Sets this CRS using a WKT definition.
~QgsCoordinateReferenceSystem()
CrsType
Enumeration of types of IDs accepted in createFromId() method.
static CUSTOM_CRS_VALIDATION customCrsValidation()
Gets custom function.
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
DistanceUnit
Units of distance.
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
const int USER_CRS_START_ID
Magick number that determines whether a projection crsid is a system (srs.db) or user (~/...
bool createFromSrsId(long srsId)
Sets this CRS by lookup of internal QGIS CRS ID in the CRS database.
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool createFromUserInput(const QString &definition)
Set up this CRS from various text formats.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void setYMaximum(double y)
Set the maximum y value.
bool hasAxisInverted() const
Returns whether axis is inverted (e.g., for WMS 1.3) for the CRS.
This class represents a coordinate reference system (CRS).
QString toWkt() const
Returns a WKT representation of this CRS.
bool createFromProj4(const QString &projString)
Sets this CRS by passing it a PROJ style formatted string.
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
QgsUnitTypes::DistanceUnit mapUnits() const
Returns the units for the projection used by the CRS.
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
static void invalidateCache()
Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
QgsRectangle bounds() const
Returns the approximate bounds for the region the CRS is usable within.
long srsid() const
Returns the internal CRS ID, if available.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
bool operator==(const QgsCoordinateReferenceSystem &srs) const
Overloaded == operator used to compare to CRS's.
QString columnName(int column) const
Returns the name of column.
double columnAsDouble(int column) const
Gets column value from the current statement row as a double.
qlonglong columnAsInt64(int column) const
Gets column value from the current statement row as a long long integer (64 bits).
static int syncDatabase()
Update proj.4 parameters in our database from proj.4.
QString authid() const
Returns the authority identifier for the CRS.
static void setupESRIWktFix()
Make sure that ESRI WKT import is done properly.
void setXMinimum(double x)
Set the minimum x value.
static QgsCoordinateReferenceSystem fromSrsId(long srsId)
Creates a CRS from a specified QGIS SRS ID.
void * OGRSpatialReferenceH
static QString quotedString(const QString &value)
Returns a quoted string value, surround by ' characters and with special characters correctly escaped...
bool isValid() const
Returns whether this CRS is correctly initialized and usable.