28 #include <QDomElement> 31 #include <QTextStream> 33 #include <QRegularExpression> 43 #if PROJ_VERSION_MAJOR>=6 46 #include <proj_experimental.h> 52 #include <ogr_srs_api.h> 53 #include <cpl_error.h> 64 QReadWriteLock QgsCoordinateReferenceSystem::sSrIdCacheLock;
65 QHash< long, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sSrIdCache;
66 bool QgsCoordinateReferenceSystem::sDisableSrIdCache =
false;
68 QReadWriteLock QgsCoordinateReferenceSystem::sOgcLock;
69 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sOgcCache;
70 bool QgsCoordinateReferenceSystem::sDisableOgcCache =
false;
72 QReadWriteLock QgsCoordinateReferenceSystem::sProj4CacheLock;
73 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sProj4Cache;
74 bool QgsCoordinateReferenceSystem::sDisableProj4Cache =
false;
76 QReadWriteLock QgsCoordinateReferenceSystem::sCRSWktLock;
77 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sWktCache;
78 bool QgsCoordinateReferenceSystem::sDisableWktCache =
false;
80 QReadWriteLock QgsCoordinateReferenceSystem::sCRSSrsIdLock;
81 QHash< long, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sSrsIdCache;
82 bool QgsCoordinateReferenceSystem::sDisableSrsIdCache =
false;
84 QReadWriteLock QgsCoordinateReferenceSystem::sCrsStringLock;
85 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sStringCache;
86 bool QgsCoordinateReferenceSystem::sDisableStringCache =
false;
88 #if PROJ_VERSION_MAJOR>=6 89 QString getFullProjString( PJ *obj )
93 QgsProjUtils::proj_pj_unique_ptr boundCrs( proj_crs_create_bound_crs_to_WGS84(
QgsProjContext::get(), obj,
nullptr ) );
96 if (
const char *proj4src = proj_as_proj_string(
QgsProjContext::get(), boundCrs.get(), PJ_PROJ_4, nullptr ) )
98 return QString( proj4src );
109 d =
new QgsCoordinateReferenceSystemPrivate();
114 d =
new QgsCoordinateReferenceSystemPrivate();
120 d =
new QgsCoordinateReferenceSystemPrivate();
141 const auto constDbs = dbs;
142 for (
const QString &db : constDbs )
144 QFileInfo myInfo( db );
145 if ( !myInfo.exists() )
147 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
155 int result = openDatabase( db, database );
156 if ( result != SQLITE_OK )
158 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
162 QString sql = QStringLiteral(
"select srs_id from tbl_srs" );
164 statement = database.
prepare( sql, rc );
168 int ret = statement.
step();
170 if ( ret == SQLITE_DONE )
176 if ( ret == SQLITE_ROW )
182 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
187 std::sort( results.begin(), results.end() );
253 QgsDebugMsg( QStringLiteral(
"Unexpected case reached!" ) );
261 if ( !sDisableStringCache )
263 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sStringCache.constFind( definition );
264 if ( crsIt != sStringCache.constEnd() )
267 *
this = crsIt.value();
274 QRegularExpression reCrsId( QStringLiteral(
"^(epsg|esri|osgeo|ignf|zangi|iau2000|postgis|internal|user)\\:(\\w+)$" ), QRegularExpression::CaseInsensitiveOption );
275 QRegularExpressionMatch match = reCrsId.match( definition );
276 if ( match.capturedStart() == 0 )
278 QString authName = match.captured( 1 ).toLower();
279 if ( authName == QLatin1String(
"epsg" ) )
283 else if ( authName == QLatin1String(
"postgis" ) )
285 const long id = match.captured( 2 ).toLong();
288 else if ( authName == QLatin1String(
"esri" ) || authName == QLatin1String(
"osgeo" ) || authName == QLatin1String(
"ignf" ) || authName == QLatin1String(
"zangi" ) || authName == QLatin1String(
"iau2000" ) )
294 const long id = match.captured( 2 ).toLong();
300 QRegularExpression reCrsStr(
"^(?:(wkt|proj4)\\:)?(.+)$", QRegularExpression::CaseInsensitiveOption );
301 match = reCrsStr.match( definition );
302 if ( match.capturedStart() == 0 )
304 if ( match.captured( 1 ).compare( QLatin1String(
"proj4" ), Qt::CaseInsensitive ) == 0 )
313 QString myName = QStringLiteral(
" * %1 (%2)" )
314 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
327 if ( !sDisableStringCache )
328 sStringCache.insert( definition, *
this );
339 if ( definition.startsWith( QLatin1String(
"ESRI::" ) ) )
344 if ( OSRSetFromUserInput( crs, definition.toLocal8Bit().constData() ) == OGRERR_NONE )
346 if ( OSRExportToWkt( crs, &wkt ) == OGRERR_NONE )
351 OSRDestroySpatialReference( crs );
361 const char *configOld = CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" );
362 const char *configNew =
"GEOGCS";
364 if ( strcmp( configOld,
"" ) == 0 )
366 CPLSetConfigOption(
"GDAL_FIX_ESRI_WKT", configNew );
367 if ( strcmp( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) != 0 )
369 .arg( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) );
370 QgsDebugMsgLevel( QStringLiteral(
"set GDAL_FIX_ESRI_WKT : %1" ).arg( configNew ), 4 );
374 QgsDebugMsgLevel( QStringLiteral(
"GDAL_FIX_ESRI_WKT was already set : %1" ).arg( configNew ), 4 );
381 if ( !sDisableOgcCache )
383 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sOgcCache.constFind( crs );
384 if ( crsIt != sOgcCache.constEnd() )
387 *
this = crsIt.value();
393 QString wmsCrs =
crs;
395 QRegExp re_uri(
"http://www\\.opengis\\.net/def/crs/([^/]+).+/(\\d+)", Qt::CaseInsensitive );
396 QRegExp re_urn(
"urn:ogc:def:crs:([^:]+).+([^:]+)", Qt::CaseInsensitive );
397 if ( re_uri.exactMatch( wmsCrs ) )
399 wmsCrs = re_uri.cap( 1 ) +
':' + re_uri.cap( 2 );
401 else if ( re_urn.exactMatch( wmsCrs ) )
403 wmsCrs = re_urn.cap( 1 ) +
':' + re_urn.cap( 2 );
407 re_urn.setPattern( QStringLiteral(
"(user|custom|qgis):(\\d+)" ) );
408 if ( re_urn.exactMatch( wmsCrs ) &&
createFromSrsId( re_urn.cap( 2 ).toInt() ) )
411 if ( !sDisableOgcCache )
412 sOgcCache.insert( crs, *
this );
417 #if PROJ_VERSION_MAJOR>=6 419 const QString legacyKey = wmsCrs.toLower();
420 for (
auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
422 if ( it.key().compare( legacyKey, Qt::CaseInsensitive ) == 0 )
424 const QStringList parts = it.key().split(
':' );
425 const QString auth = parts.at( 0 );
426 const QString code = parts.at( 1 );
427 if ( loadFromAuthCode( auth, code ) )
430 if ( !sDisableOgcCache )
431 sOgcCache.insert( crs, *
this );
441 if ( !sDisableOgcCache )
442 sOgcCache.insert( crs, *
this );
447 if ( wmsCrs.compare( QLatin1String(
"CRS:27" ), Qt::CaseInsensitive ) == 0 ||
448 wmsCrs.compare( QLatin1String(
"OGC:CRS27" ), Qt::CaseInsensitive ) == 0 )
455 if ( wmsCrs.compare( QLatin1String(
"CRS:83" ), Qt::CaseInsensitive ) == 0 ||
456 wmsCrs.compare( QLatin1String(
"OGC:CRS83" ), Qt::CaseInsensitive ) == 0 )
463 if ( wmsCrs.compare( QLatin1String(
"CRS:84" ), Qt::CaseInsensitive ) == 0 ||
464 wmsCrs.compare( QLatin1String(
"OGC:CRS84" ), Qt::CaseInsensitive ) == 0 )
469 d->mAxisInverted =
false;
470 d->mAxisInvertedDirty =
false;
473 if ( !sDisableOgcCache )
474 sOgcCache.insert( crs, *
this );
480 if ( !sDisableOgcCache )
490 if ( d->mIsValid || !sCustomSrsValidation )
496 if ( sCustomSrsValidation )
497 sCustomSrsValidation( *
this );
503 if ( !sDisableSrIdCache )
505 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrIdCache.constFind(
id );
506 if ( crsIt != sSrIdCache.constEnd() )
509 *
this = crsIt.value();
515 #if PROJ_VERSION_MAJOR>=6 517 for (
auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
519 if ( it.value().endsWith( QStringLiteral(
",%1" ).arg(
id ) ) )
521 const QStringList parts = it.key().split(
':' );
522 const QString auth = parts.at( 0 );
523 const QString code = parts.at( 1 );
524 if ( loadFromAuthCode( auth, code ) )
527 if ( !sDisableSrIdCache )
528 sSrIdCache.insert(
id, *
this );
539 if ( !sDisableSrIdCache )
540 sSrIdCache.insert(
id, *
this );
548 if ( !sDisableSrsIdCache )
550 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrsIdCache.constFind(
id );
551 if ( crsIt != sSrsIdCache.constEnd() )
554 *
this = crsIt.value();
560 #if PROJ_VERSION_MAJOR>=6 562 for (
auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
564 if ( it.value().startsWith( QString::number(
id ) +
',' ) )
566 const QStringList parts = it.key().split(
':' );
567 const QString auth = parts.at( 0 );
568 const QString code = parts.at( 1 );
569 if ( loadFromAuthCode( auth, code ) )
572 if ( !sDisableSrsIdCache )
573 sSrsIdCache.insert(
id, *
this );
582 QStringLiteral(
"srs_id" ), QString::number(
id ) );
585 if ( !sDisableSrsIdCache )
586 sSrsIdCache.insert(
id, *
this );
590 bool QgsCoordinateReferenceSystem::loadFromDatabase(
const QString &db,
const QString &expression,
const QString &value )
594 QgsDebugMsgLevel(
"load CRS from " + db +
" where " + expression +
" is " + value, 3 );
598 QFileInfo myInfo( db );
599 if ( !myInfo.exists() )
601 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
609 myResult = openDatabase( db, database );
610 if ( myResult != SQLITE_OK )
627 QString mySql =
"select srs_id,description,projection_acronym," 628 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo " 630 statement = database.
prepare( mySql, myResult );
632 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
641 d->mIsGeographic = statement.
columnAsText( 7 ).toInt() != 0;
642 d->mAxisInvertedDirty =
true;
646 d->mAuthId = QStringLiteral(
"USER:%1" ).arg( d->mSrsId );
648 else if ( !d->mAuthId.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive ) )
650 #if PROJ_VERSION_MAJOR>=6 651 QStringList parts = d->mAuthId.split(
':' );
652 QString auth = parts.at( 0 );
653 QString code = parts.at( 1 );
656 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database(
QgsProjContext::get(), auth.toLatin1(), code.toLatin1(), PJ_CATEGORY_CRS,
false, nullptr ) );
657 d->mPj = QgsProjUtils::crsToSingleCrs( crs.get() );
660 d->mIsValid =
static_cast< bool >( d->mPj );
662 OSRDestroySpatialReference( d->mCRS );
663 d->mCRS = OSRNewSpatialReference(
nullptr );
664 d->mIsValid = OSRSetFromUserInput( d->mCRS, d->mAuthId.toLower().toLatin1() ) == OGRERR_NONE;
671 setProj4String( d->mProj4 );
683 if ( d->mAxisInvertedDirty )
685 #if PROJ_VERSION_MAJOR>=6 686 d->mAxisInverted = QgsProjUtils::axisOrderIsSwapped( d->mPj.get() );
688 OGRAxisOrientation orientation;
689 OSRGetAxis( d->mCRS, OSRIsGeographic( d->mCRS ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
692 if ( orientation == OAO_Other && d->mAuthId.startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
696 if ( OSRImportFromEPSGA( crs, d->mAuthId.midRef( 5 ).toInt() ) == OGRERR_NONE )
698 OSRGetAxis( crs, OSRIsGeographic( crs ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
701 OSRDestroySpatialReference( crs );
704 d->mAxisInverted = orientation == OAO_North;
706 d->mAxisInvertedDirty =
false;
709 return d->mAxisInverted;
717 if ( !sDisableWktCache )
719 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sWktCache.constFind( wkt );
720 if ( crsIt != sWktCache.constEnd() )
723 *
this = crsIt.value();
734 QgsDebugMsgLevel( QStringLiteral(
"theWkt is uninitialized, operation failed" ), 4 );
739 #if PROJ_VERSION_MAJOR>=6 740 PROJ_STRING_LIST warnings =
nullptr;
741 PROJ_STRING_LIST grammerErrors =
nullptr;
744 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_wkt(
QgsProjContext::get(), wkt.toLatin1().constData(),
nullptr, &warnings, &grammerErrors ) );
745 d->mPj = QgsProjUtils::crsToSingleCrs( crs.get() );
748 res =
static_cast< bool >( d->mPj );
751 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
752 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
754 for (
auto iter = warnings; iter && *iter; ++iter )
756 for (
auto iter = grammerErrors; iter && *iter; ++iter )
758 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
760 proj_string_list_destroy( warnings );
761 proj_string_list_destroy( grammerErrors );
763 QByteArray ba = wkt.toLatin1();
764 const char *pWkt = ba.data();
766 OGRErr myInputResult = OSRImportFromWkt( d->mCRS, const_cast< char ** >( & pWkt ) );
767 res = myInputResult == OGRERR_NONE;
770 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
771 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
773 QgsDebugMsg( QStringLiteral(
"UNUSED WKT: %1" ).arg( pWkt ) );
774 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
780 if ( !sDisableWktCache )
781 sWktCache.insert( wkt, *
this );
785 #if PROJ_VERSION_MAJOR>=6 788 const QString authName( proj_get_id_auth_name( d->mPj.get(), 0 ) );
789 const QString authCode( proj_get_id_code( d->mPj.get(), 0 ) );
790 if ( !authName.isEmpty() && !authCode.isEmpty() )
792 if ( loadFromAuthCode( authName, authCode ) )
795 if ( !sDisableWktCache )
796 sWktCache.insert( wkt, *
this );
802 if ( OSRAutoIdentifyEPSG( d->mCRS ) == OGRERR_NONE )
804 QString
authid = QStringLiteral(
"%1:%2" )
805 .arg( OSRGetAuthorityName( d->mCRS,
nullptr ),
806 OSRGetAuthorityCode( d->mCRS,
nullptr ) );
809 if ( !sDisableWktCache )
810 sWktCache.insert( wkt, *
this );
824 #if PROJ_VERSION_MAJOR>=6 828 const QString proj4String = getFullProjString( d->mPj.get() );
829 if ( !proj4String.isEmpty() )
839 char *proj4src =
nullptr;
840 OSRExportToProj4( d->mCRS, &proj4src );
849 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0) 854 OSRExportToProj4( d->mCRS, &proj4src );
864 if ( d->mSrsId == 0 )
866 QString myName = QStringLiteral(
" * %1 (%2)" )
867 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
872 #if PROJ_VERSION_MAJOR<6 877 if ( !sDisableWktCache )
878 sWktCache.insert( wkt, *
this );
893 if ( proj4String.trimmed().isEmpty() )
902 if ( !sDisableProj4Cache )
904 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sProj4Cache.constFind( proj4String );
905 if ( crsIt != sProj4Cache.constEnd() )
908 *
this = crsIt.value();
922 QString myProj4String = proj4String.trimmed();
923 myProj4String.remove( QStringLiteral(
"+type=crs" ) );
924 myProj4String = myProj4String.trimmed();
927 #if PROJ_VERSION_MAJOR>=6 928 myProj4String.remove( QStringLiteral(
"+towgs84=0,0,0,0,0,0,0" ) );
929 myProj4String = myProj4String.trimmed();
936 #if PROJ_VERSION_MAJOR>=6 938 const QString projCrsString = myProj4String + ( myProj4String.contains( QStringLiteral(
"+type=crs" ) ) ? QString() : QStringLiteral(
" +type=crs" ) );
939 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create(
QgsProjContext::get(), projCrsString.toLatin1().constData() ) );
943 int *confidence =
nullptr;
944 if ( PJ_OBJ_LIST *crsList = proj_identify(
QgsProjContext::get(), crs.get(),
nullptr,
nullptr, &confidence ) )
946 const int count = proj_list_get_count( crsList );
947 int bestConfidence = 0;
948 QgsProjUtils::proj_pj_unique_ptr matchedCrs;
949 for (
int i = 0; i < count; ++i )
951 if ( confidence[i] >= bestConfidence )
954 QgsProjUtils::proj_pj_unique_ptr candidateCrs( proj_list_get(
QgsProjContext::get(), crsList, i ) );
955 candidateCrs = QgsProjUtils::crsToSingleCrs( candidateCrs.get() );
956 const QString authName( proj_get_id_auth_name( candidateCrs.get(), 0 ) );
957 if ( confidence[i] > bestConfidence || authName == QLatin1String(
"EPSG" ) )
959 bestConfidence = confidence[i];
960 matchedCrs = std::move( candidateCrs );
964 proj_list_destroy( crsList );
965 proj_int_list_destroy( confidence );
966 if ( matchedCrs && bestConfidence >= 70 )
968 const QString authName( proj_get_id_auth_name( matchedCrs.get(), 0 ) );
969 const QString authCode( proj_get_id_code( matchedCrs.get(), 0 ) );
970 if ( !authName.isEmpty() && !authCode.isEmpty() )
972 const QString
authid = QStringLiteral(
"%1:%2" ).arg( authName, authCode );
976 if ( !sDisableProj4Cache )
977 sProj4Cache.insert( proj4String, *
this );
992 QRegExp myProjRegExp(
"\\+proj=(\\S+)" );
993 int myStart = myProjRegExp.indexIn( myProj4String );
997 if ( !sDisableProj4Cache )
998 sProj4Cache.insert( proj4String, *
this );
1003 d->mProjectionAcronym = myProjRegExp.cap( 1 );
1005 QRegExp myEllipseRegExp(
"\\+ellps=(\\S+)" );
1006 myStart = myEllipseRegExp.indexIn( myProj4String );
1007 if ( myStart == -1 )
1009 d->mEllipsoidAcronym.clear();
1013 d->mEllipsoidAcronym = myEllipseRegExp.cap( 1 );
1016 QRegExp myAxisRegExp(
"\\+a=(\\S+)" );
1017 myStart = myAxisRegExp.indexIn( myProj4String );
1020 QgsCoordinateReferenceSystem::RecordMap myRecord;
1026 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
1027 if ( myRecord.empty() )
1032 QRegExp myLat1RegExp(
"\\+lat_1=\\S+" );
1033 QRegExp myLat2RegExp(
"\\+lat_2=\\S+" );
1040 myStart1 = myLat1RegExp.indexIn( myProj4String, myStart1 );
1041 myStart2 = myLat2RegExp.indexIn( myProj4String, myStart2 );
1042 if ( myStart1 != -1 && myStart2 != -1 )
1044 myLength1 = myLat1RegExp.matchedLength();
1045 myLength2 = myLat2RegExp.matchedLength();
1050 if ( !lat1Str.isEmpty() && !lat2Str.isEmpty() )
1053 QString proj4StringModified = myProj4String;
1058 myStart2 = myLat2RegExp.indexIn( proj4String, myStart2 );
1060 QgsDebugMsgLevel( QStringLiteral(
"trying proj4string match with swapped lat_1,lat_2" ), 4 );
1061 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( proj4StringModified.trimmed() ) +
" order by deprecated" );
1065 if ( myRecord.empty() )
1072 QString sql = QStringLiteral(
"SELECT * FROM tbl_srs WHERE " );
1079 QStringList myParams;
1080 const auto constSplit = myProj4String.split( QRegExp(
"\\s+(?=\\+)" ), QString::SkipEmptyParts );
1081 for (
const QString ¶m : constSplit )
1083 QString arg = QStringLiteral(
"' '||parameters||' ' LIKE %1" ).arg(
QgsSqliteUtils::quotedString( QStringLiteral(
"% %1 %" ).arg( param.trimmed() ) ) );
1084 if ( param.startsWith( QLatin1String(
"+datum=" ) ) )
1091 delim = QStringLiteral(
" AND " );
1092 myParams << param.trimmed();
1096 if ( !datum.isEmpty() )
1098 myRecord = getRecord( sql + delim + datum +
" order by deprecated" );
1101 if ( myRecord.empty() )
1104 myRecord = getRecord( sql +
" order by deprecated" );
1107 if ( !myRecord.empty() )
1110 QStringList foundParams;
1111 const auto constSplit = myRecord[
"parameters"].split( QRegExp(
"\\s+(?=\\+)" ), QString::SkipEmptyParts );
1112 for (
const QString ¶m : constSplit )
1114 if ( !param.startsWith( QLatin1String(
"+datum=" ) ) )
1115 foundParams << param.trimmed();
1121 if ( myParams != foundParams )
1128 if ( !myRecord.empty() )
1130 mySrsId = myRecord[QStringLiteral(
"srs_id" )].toLong();
1139 setProj4String( myProj4String );
1147 d->mIsValid =
false;
1155 QgsDebugMsgLevel( QStringLiteral(
"Projection is not found in databases." ), 4 );
1157 setProj4String( myProj4String );
1161 if ( !sDisableProj4Cache )
1162 sProj4Cache.insert( proj4String, *
this );
1168 QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord(
const QString &sql )
1170 QString myDatabaseFileName;
1171 QgsCoordinateReferenceSystem::RecordMap myMap;
1172 QString myFieldName;
1173 QString myFieldValue;
1180 QFileInfo myInfo( myDatabaseFileName );
1181 if ( !myInfo.exists() )
1183 QgsDebugMsg(
"failed : " + myDatabaseFileName +
" does not exist!" );
1188 myResult = openDatabase( myDatabaseFileName, database );
1189 if ( myResult != SQLITE_OK )
1194 statement = database.
prepare( sql, myResult );
1196 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1200 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1202 myFieldName = statement.
columnName( myColNo );
1204 myMap[myFieldName] = myFieldValue;
1206 if ( statement.
step() != SQLITE_DONE )
1208 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1210 #if PROJ_VERSION_MAJOR<6 1220 if ( myMap.empty() )
1223 QFileInfo myFileInfo;
1224 myFileInfo.setFile( myDatabaseFileName );
1225 if ( !myFileInfo.exists() )
1227 QgsDebugMsg( QStringLiteral(
"user qgis.db not found" ) );
1232 myResult = openDatabase( myDatabaseFileName, database );
1233 if ( myResult != SQLITE_OK )
1238 statement = database.
prepare( sql, myResult );
1240 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1244 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1246 myFieldName = statement.
columnName( myColNo );
1248 myMap[myFieldName] = myFieldValue;
1251 if ( statement.
step() != SQLITE_DONE )
1253 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1284 if ( d->mDescription.isNull() )
1290 return d->mDescription;
1296 if ( d->mProjectionAcronym.isNull() )
1302 return d->mProjectionAcronym;
1308 if ( d->mEllipsoidAcronym.isNull() )
1314 return d->mEllipsoidAcronym;
1323 if ( d->mProj4.isEmpty() )
1325 #if PROJ_VERSION_MAJOR>=6 1328 d->mProj4 = getFullProjString( d->mPj.get() );
1331 char *proj4src =
nullptr;
1332 OSRExportToProj4( d->mCRS, &proj4src );
1333 d->mProj4 = proj4src;
1334 CPLFree( proj4src );
1338 return d->mProj4.trimmed();
1343 return d->mIsGeographic;
1351 return d->mMapUnits;
1359 #if PROJ_VERSION_MAJOR>=6 1364 double southLat = 0;
1366 double northLat = 0;
1369 &westLon, &southLat, &eastLon, &northLat, nullptr ) )
1388 int result = openDatabase( databaseFileName, database );
1389 if ( result != SQLITE_OK )
1394 QString sql = QStringLiteral(
"select west_bound_lon, north_bound_lat, east_bound_lon, south_bound_lat from tbl_bounds " 1397 statement = database.
prepare( sql, result );
1400 if ( result == SQLITE_OK )
1402 if ( statement.
step() == SQLITE_ROW )
1423 void QgsCoordinateReferenceSystem::setInternalId(
long srsId )
1428 void QgsCoordinateReferenceSystem::setAuthId(
const QString &authId )
1431 d->mAuthId = authId;
1433 void QgsCoordinateReferenceSystem::setSrid(
long srid )
1438 void QgsCoordinateReferenceSystem::setDescription(
const QString &
description )
1443 void QgsCoordinateReferenceSystem::setProj4String(
const QString &proj4String )
1446 d->mProj4 = proj4String;
1449 QString trimmed = proj4String.trimmed();
1451 #if PROJ_VERSION_MAJOR>=6 1452 trimmed += QStringLiteral(
" +type=crs" );
1456 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create( ctx, trimmed.toLatin1().constData() ) );
1457 d->mPj = QgsProjUtils::crsToSingleCrs( crs.get() );
1463 const int errNo = proj_context_errno( ctx );
1464 QgsDebugMsg( QStringLiteral(
"proj string rejected: %1" ).arg( proj_errno_string( errNo ) ) );
1466 d->mIsValid =
false;
1470 QgsProjUtils::proj_pj_unique_ptr ellipsoid( proj_get_ellipsoid( ctx, d->mPj.get() ) );
1473 const QString ellipsoidAuthName( proj_get_id_auth_name( ellipsoid.get(), 0 ) );
1474 const QString ellipsoidAuthCode( proj_get_id_code( ellipsoid.get(), 0 ) );
1475 d->mEllipsoidAcronym = QStringLiteral(
"%1:%2" ).arg( ellipsoidAuthName, ellipsoidAuthCode );
1481 OSRDestroySpatialReference( d->mCRS );
1482 d->mCRS = OSRNewSpatialReference(
nullptr );
1483 d->mIsValid = OSRImportFromProj4( d->mCRS, trimmed.toLatin1().constData() ) == OGRERR_NONE;
1489 projCtx pContext = pj_ctx_alloc();
1490 projPJ proj = pj_init_plus_ctx( pContext, proj4String.trimmed().toLatin1().constData() );
1493 QgsDebugMsgLevel( QStringLiteral(
"proj.4 string rejected by pj_init_plus_ctx()" ), 4 );
1494 d->mIsValid =
false;
1500 pj_ctx_free( pContext );
1507 void QgsCoordinateReferenceSystem::setGeographicFlag(
bool geoFlag )
1510 d->mIsGeographic = geoFlag;
1512 void QgsCoordinateReferenceSystem::setEpsg(
long epsg )
1515 d->mAuthId = QStringLiteral(
"EPSG:%1" ).arg( epsg );
1517 void QgsCoordinateReferenceSystem::setProjectionAcronym(
const QString &
projectionAcronym )
1522 void QgsCoordinateReferenceSystem::setEllipsoidAcronym(
const QString &
ellipsoidAcronym )
1528 void QgsCoordinateReferenceSystem::setMapUnits()
1537 #if PROJ_VERSION_MAJOR<6 1538 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0) 1541 OSRFixup( d->mCRS );
1545 #if PROJ_VERSION_MAJOR>=6 1553 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( context, d->mPj.get() ) );
1554 if ( !coordinateSystem )
1560 const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
1561 if ( axisCount > 0 )
1563 const char *outUnitName =
nullptr;
1565 proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
1574 const QString unitName( outUnitName );
1578 if ( unitName.compare( QLatin1String(
"degree" ), Qt::CaseInsensitive ) == 0 ||
1579 unitName.compare( QLatin1String(
"degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1580 unitName.compare( QLatin1String(
"degree minute second hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1581 unitName.compare( QLatin1String(
"degree minute" ), Qt::CaseInsensitive ) == 0 ||
1582 unitName.compare( QLatin1String(
"degree hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1583 unitName.compare( QLatin1String(
"degree minute hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1584 unitName.compare( QLatin1String(
"hemisphere degree" ), Qt::CaseInsensitive ) == 0 ||
1585 unitName.compare( QLatin1String(
"hemisphere degree minute" ), Qt::CaseInsensitive ) == 0 ||
1586 unitName.compare( QLatin1String(
"hemisphere degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1587 unitName.compare( QLatin1String(
"degree (supplier to define representation)" ), Qt::CaseInsensitive ) == 0 )
1589 else if ( unitName.compare( QLatin1String(
"metre" ), Qt::CaseInsensitive ) == 0 )
1592 else if ( unitName.compare( QLatin1String(
"US survey foot" ), Qt::CaseInsensitive ) == 0 ||
1593 unitName.compare( QLatin1String(
"foot" ), Qt::CaseInsensitive ) == 0 )
1595 else if ( unitName.compare( QLatin1String(
"kilometre" ), Qt::CaseInsensitive ) == 0 )
1597 else if ( unitName.compare( QLatin1String(
"centimetre" ), Qt::CaseInsensitive ) == 0 )
1599 else if ( unitName.compare( QLatin1String(
"millimetre" ), Qt::CaseInsensitive ) == 0 )
1601 else if ( unitName.compare( QLatin1String(
"Statute mile" ), Qt::CaseInsensitive ) == 0 )
1603 else if ( unitName.compare( QLatin1String(
"nautical mile" ), Qt::CaseInsensitive ) == 0 )
1605 else if ( unitName.compare( QLatin1String(
"yard" ), Qt::CaseInsensitive ) == 0 )
1619 char *unitName =
nullptr;
1621 if ( OSRIsProjected( d->mCRS ) )
1623 double toMeter = OSRGetLinearUnits( d->mCRS, &unitName );
1624 QString unit( unitName );
1632 static const double SMALL_NUM = 1e-3;
1634 if ( std::fabs( toMeter - FEET_TO_METER ) < SMALL_NUM )
1635 unit = QStringLiteral(
"Foot" );
1639 else if ( unit == QLatin1String(
"Foot" ) )
1648 OSRGetAngularUnits( d->mCRS, &unitName );
1649 QString unit( unitName );
1650 if ( unit == QLatin1String(
"degree" ) )
1663 if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
1666 QgsDebugMsgLevel(
"QgsCoordinateReferenceSystem::findMatchingProj will only " 1667 "work if prj acr ellipsoid acr and proj4string are set" 1668 " and the current projection is valid!", 4 );
1678 QString mySql = QString(
"select srs_id,parameters from tbl_srs where " 1679 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1686 myResult = openDatabase( myDatabaseFileName, database );
1687 if ( myResult != SQLITE_OK )
1692 statement = database.
prepare( mySql, myResult );
1693 if ( myResult == SQLITE_OK )
1696 while ( statement.
step() == SQLITE_ROW )
1700 if (
toProj4() == myProj4String.trimmed() )
1702 return mySrsId.toLong();
1713 myResult = openDatabase( myDatabaseFileName, database );
1714 if ( myResult != SQLITE_OK )
1719 statement = database.
prepare( mySql, myResult );
1721 if ( myResult == SQLITE_OK )
1723 while ( statement.
step() == SQLITE_ROW )
1727 if (
toProj4() == myProj4String.trimmed() )
1729 return mySrsId.toLong();
1739 return ( !d->mIsValid && !srs.d->mIsValid ) ||
1740 ( d->mIsValid && srs.d->mIsValid && srs.
authid() ==
authid() );
1745 return !( *
this == srs );
1750 if ( d->mWkt.isEmpty() )
1752 #if PROJ_VERSION_MAJOR>=6 1759 type = PJ_WKT1_GDAL;
1762 type = PJ_WKT1_ESRI;
1765 type = PJ_WKT2_2015;
1768 type = PJ_WKT2_2015_SIMPLIFIED;
1771 type = PJ_WKT2_2018;
1774 type = PJ_WKT2_2018_SIMPLIFIED;
1778 const QByteArray multiLineOption = QStringLiteral(
"MULTILINE=%1" ).arg( multiline ? QStringLiteral(
"YES" ) : QStringLiteral(
"NO" ) ).toLocal8Bit();
1779 const QByteArray indentatationWidthOption = QStringLiteral(
"INDENTATION_WIDTH=%1" ).arg( multiline ? QString::number( indentationWidth ) : QStringLiteral(
"0" ) ).toLocal8Bit();
1780 const char *
const options[] = {multiLineOption.constData(), indentatationWidthOption.constData(),
nullptr};
1785 Q_UNUSED( multiline )
1786 Q_UNUSED( indentationWidth )
1787 char *wkt =
nullptr;
1788 if ( OSRExportToWkt( d->mCRS, &wkt ) == OGRERR_NONE )
1802 QDomNode srsNode = node.namedItem( QStringLiteral(
"spatialrefsys" ) );
1804 if ( ! srsNode.isNull() )
1806 bool initialized =
false;
1809 long srsid = srsNode.namedItem( QStringLiteral(
"srsid" ) ).toElement().text().toLong( &ok );
1815 myNode = srsNode.namedItem( QStringLiteral(
"authid" ) );
1816 if ( !myNode.isNull() )
1827 myNode = srsNode.namedItem( QStringLiteral(
"epsg" ) );
1828 if ( !myNode.isNull() )
1841 myNode = srsNode.namedItem( QStringLiteral(
"proj4" ) );
1842 const QString proj4 = myNode.toElement().text();
1847 if ( !proj4.trimmed().isEmpty() )
1848 setProj4String( myNode.toElement().text() );
1850 myNode = srsNode.namedItem( QStringLiteral(
"srsid" ) );
1851 setInternalId( myNode.toElement().text().toLong() );
1853 myNode = srsNode.namedItem( QStringLiteral(
"srid" ) );
1854 setSrid( myNode.toElement().text().toLong() );
1856 myNode = srsNode.namedItem( QStringLiteral(
"authid" ) );
1857 setAuthId( myNode.toElement().text() );
1859 myNode = srsNode.namedItem( QStringLiteral(
"description" ) );
1860 setDescription( myNode.toElement().text() );
1862 myNode = srsNode.namedItem( QStringLiteral(
"projectionacronym" ) );
1863 setProjectionAcronym( myNode.toElement().text() );
1865 myNode = srsNode.namedItem( QStringLiteral(
"ellipsoidacronym" ) );
1866 setEllipsoidAcronym( myNode.toElement().text() );
1868 myNode = srsNode.namedItem( QStringLiteral(
"geographicflag" ) );
1869 if ( myNode.toElement().text().compare( QLatin1String(
"true" ) ) )
1871 setGeographicFlag(
true );
1875 setGeographicFlag(
false );
1885 if (
isValid() && d->mSrsId == 0 )
1887 QString myName = QStringLiteral(
" * %1 (%2)" )
1888 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
1898 d =
new QgsCoordinateReferenceSystemPrivate();
1907 QDomElement myLayerNode = node.toElement();
1908 QDomElement mySrsElement = doc.createElement( QStringLiteral(
"spatialrefsys" ) );
1910 QDomElement myProj4Element = doc.createElement( QStringLiteral(
"proj4" ) );
1911 myProj4Element.appendChild( doc.createTextNode(
toProj4() ) );
1912 mySrsElement.appendChild( myProj4Element );
1914 QDomElement mySrsIdElement = doc.createElement( QStringLiteral(
"srsid" ) );
1915 mySrsIdElement.appendChild( doc.createTextNode( QString::number(
srsid() ) ) );
1916 mySrsElement.appendChild( mySrsIdElement );
1918 QDomElement mySridElement = doc.createElement( QStringLiteral(
"srid" ) );
1919 mySridElement.appendChild( doc.createTextNode( QString::number(
postgisSrid() ) ) );
1920 mySrsElement.appendChild( mySridElement );
1922 QDomElement myEpsgElement = doc.createElement( QStringLiteral(
"authid" ) );
1923 myEpsgElement.appendChild( doc.createTextNode(
authid() ) );
1924 mySrsElement.appendChild( myEpsgElement );
1926 QDomElement myDescriptionElement = doc.createElement( QStringLiteral(
"description" ) );
1927 myDescriptionElement.appendChild( doc.createTextNode(
description() ) );
1928 mySrsElement.appendChild( myDescriptionElement );
1930 QDomElement myProjectionAcronymElement = doc.createElement( QStringLiteral(
"projectionacronym" ) );
1931 myProjectionAcronymElement.appendChild( doc.createTextNode(
projectionAcronym() ) );
1932 mySrsElement.appendChild( myProjectionAcronymElement );
1934 QDomElement myEllipsoidAcronymElement = doc.createElement( QStringLiteral(
"ellipsoidacronym" ) );
1935 myEllipsoidAcronymElement.appendChild( doc.createTextNode(
ellipsoidAcronym() ) );
1936 mySrsElement.appendChild( myEllipsoidAcronymElement );
1938 QDomElement myGeographicFlagElement = doc.createElement( QStringLiteral(
"geographicflag" ) );
1939 QString myGeoFlagText = QStringLiteral(
"false" );
1942 myGeoFlagText = QStringLiteral(
"true" );
1945 myGeographicFlagElement.appendChild( doc.createTextNode( myGeoFlagText ) );
1946 mySrsElement.appendChild( myGeographicFlagElement );
1948 myLayerNode.appendChild( mySrsElement );
1962 QString QgsCoordinateReferenceSystem::proj4FromSrsId(
const int srsId )
1964 QString myDatabaseFileName;
1965 QString myProjString;
1966 QString mySql = QStringLiteral(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( srsId );
1975 QFileInfo myFileInfo;
1976 myFileInfo.setFile( myDatabaseFileName );
1977 if ( !myFileInfo.exists() )
1979 QgsDebugMsg( QStringLiteral(
"users qgis.db not found" ) );
1992 rc = openDatabase( myDatabaseFileName, database );
1998 statement = database.
prepare( mySql, rc );
2000 if ( rc == SQLITE_OK )
2002 if ( statement.
step() == SQLITE_ROW )
2008 return myProjString;
2015 myResult = database.
open_v2( path, SQLITE_OPEN_READONLY,
nullptr );
2017 myResult = database.
open( path );
2019 if ( myResult != SQLITE_OK )
2028 .arg( database.
errorMessage() ), QObject::tr(
"CRS" ) );
2035 sCustomSrsValidation = f;
2040 return sCustomSrsValidation;
2043 void QgsCoordinateReferenceSystem::debugPrint()
2045 QgsDebugMsg( QStringLiteral(
"***SpatialRefSystem***" ) );
2046 QgsDebugMsg(
"* Valid : " + ( d->mIsValid ? QString(
"true" ) : QString(
"false" ) ) );
2047 QgsDebugMsg(
"* SrsId : " + QString::number( d->mSrsId ) );
2053 QgsDebugMsg( QStringLiteral(
"* Units : meters" ) );
2057 QgsDebugMsg( QStringLiteral(
"* Units : feet" ) );
2061 QgsDebugMsg( QStringLiteral(
"* Units : degrees" ) );
2068 d->mValidationHint = html;
2073 return d->mValidationHint;
2089 QString proj4String = d->mProj4;
2090 if ( proj4String.isEmpty() )
2103 if ( getRecordCount() == 0 )
2105 mySql =
"insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 2109 +
',' + quotedEllipsoidString
2115 mySql =
"insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 2118 +
',' + quotedEllipsoidString
2127 if ( myResult != SQLITE_OK )
2129 QgsDebugMsg( QStringLiteral(
"Can't open or create database %1: %2" )
2134 statement = database.
prepare( mySql, myResult );
2137 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_DONE )
2141 returnId = sqlite3_last_insert_rowid( database.get() );
2142 setInternalId( returnId );
2143 if (
authid().isEmpty() )
2144 setAuthId( QStringLiteral(
"USER:%1" ).arg( returnId ) );
2145 setDescription( name );
2150 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
2151 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
2154 projectionsProj4.append(
toProj4() );
2155 projectionsAuthId.append(
authid() );
2156 settings.
setValue( QStringLiteral(
"UI/recentProjectionsProj4" ), projectionsProj4 );
2157 settings.
setValue( QStringLiteral(
"UI/recentProjectionsAuthId" ), projectionsAuthId );
2167 long QgsCoordinateReferenceSystem::getRecordCount()
2172 long myRecordCount = 0;
2175 if ( myResult != SQLITE_OK )
2181 QString mySql = QStringLiteral(
"select count(*) from tbl_srs" );
2182 statement = database.
prepare( mySql, myResult );
2183 if ( myResult == SQLITE_OK )
2185 if ( statement.
step() == SQLITE_ROW )
2187 QString myRecordCountString = statement.
columnAsText( 0 );
2188 myRecordCount = myRecordCountString.toLong();
2191 return myRecordCount;
2194 #if PROJ_VERSION_MAJOR>=6 2195 bool testIsGeographic( PJ *
crs )
2199 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( pjContext, crs ) );
2200 if ( coordinateSystem )
2202 const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
2203 if ( axisCount > 0 )
2205 const char *outUnitAuthName =
nullptr;
2206 const char *outUnitAuthCode =
nullptr;
2208 proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
2217 if ( outUnitAuthName && outUnitAuthCode )
2219 const char *unitCategory =
nullptr;
2220 if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode,
nullptr,
nullptr, &unitCategory ) )
2222 isGeographic = QString( unitCategory ).compare( QLatin1String(
"angular" ), Qt::CaseInsensitive ) == 0;
2230 void getOperationAndEllipsoidFromProjString(
const QString &proj, QString &operation, QString &ellipsoid )
2232 QRegExp projRegExp(
"\\+proj=(\\S+)" );
2233 if ( projRegExp.indexIn( proj ) < 0 )
2235 QgsDebugMsgLevel( QStringLiteral(
"no +proj argument found [%2]" ).arg( proj ), 2 );
2238 operation = projRegExp.cap( 1 );
2240 QRegExp ellipseRegExp(
"\\+(?:ellps|datum)=(\\S+)" );
2242 if ( ellipseRegExp.indexIn( proj ) >= 0 )
2244 ellipsoid = ellipseRegExp.cap( 1 );
2258 bool QgsCoordinateReferenceSystem::loadFromAuthCode(
const QString &auth,
const QString &code )
2261 d->mIsValid =
false;
2265 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database( pjContext, auth.toUtf8().constData(), code.toUtf8().constData(), PJ_CATEGORY_CRS,
false, nullptr ) );
2271 switch ( proj_get_type( crs.get() ) )
2273 case PJ_TYPE_VERTICAL_CRS:
2280 crs = QgsProjUtils::crsToSingleCrs( crs.get() );
2282 QString proj4 = getFullProjString( crs.get() );
2283 proj4.replace( QStringLiteral(
"+type=crs" ), QString() );
2284 proj4 = proj4.trimmed();
2288 d->mDescription = QString( proj_get_name( crs.get() ) );
2289 d->mAuthId = QStringLiteral(
"%1:%2" ).arg( auth, code );
2290 d->mIsGeographic = testIsGeographic( crs.get() );
2291 d->mAxisInvertedDirty =
true;
2294 getOperationAndEllipsoidFromProjString( proj4, operation, ellipsoid );
2295 d->mProjectionAcronym = operation;
2296 d->mEllipsoidAcronym = ellipsoid;
2297 d->mPj = std::move( crs );
2299 const QString dbVals = sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( auth, code ).toUpper() );
2302 if ( !dbVals.isEmpty() )
2304 const QStringList parts = dbVals.split(
',' );
2305 d->mSrsId = parts.at( 0 ).toInt();
2306 d->mSRID = parts.at( 1 ).toInt();
2315 #if PROJ_VERSION_MAJOR<6 2317 bool QgsCoordinateReferenceSystem::loadWkts( QHash<int, QString> &wkts,
const char *filename )
2320 const char *pszFilename = CPLFindFile(
"gdal", filename );
2324 QFile csv( pszFilename );
2325 if ( !csv.open( QIODevice::ReadOnly ) )
2328 QTextStream lines( &csv );
2332 QString line = lines.readLine();
2333 if ( line.isNull() )
2336 if ( line.trimmed().isEmpty() || line.startsWith(
'#' ) )
2340 else if ( line.startsWith( QLatin1String(
"include " ) ) )
2342 if ( !loadWkts( wkts, line.mid( 8 ).toUtf8() ) )
2347 int pos = line.indexOf(
',' );
2352 int epsg = line.leftRef( pos ).toInt( &ok );
2356 wkts.insert( epsg, line.mid( pos + 1 ) );
2365 bool QgsCoordinateReferenceSystem::loadIds( QHash<int, QString> &wkts )
2369 static const QStringList csvs { QStringList() << QStringLiteral(
"gcs.csv" ) << QStringLiteral(
"pcs.csv" ) << QStringLiteral(
"vertcs.csv" ) << QStringLiteral(
"compdcs.csv" ) << QStringLiteral(
"geoccs.csv" ) };
2370 for (
const QString &csv : csvs )
2372 QString filename = CPLFindFile(
"gdal", csv.toUtf8() );
2374 QFile f( filename );
2375 if ( !f.open( QIODevice::ReadOnly ) )
2378 QTextStream lines( &f );
2385 QString line = lines.readLine();
2386 if ( line.isNull() )
2389 if ( line.trimmed().isEmpty() )
2392 int pos = line.indexOf(
',' );
2395 qWarning(
"No id found in: %s", qPrintable( line ) );
2400 int epsg = line.leftRef( pos ).toInt( &ok );
2403 qWarning(
"No valid id found in: %s", qPrintable( line ) );
2408 if ( epsg == 2218 || epsg == 2221 || epsg == 2296 || epsg == 2297 || epsg == 2298 || epsg == 2299 || epsg == 2300 || epsg == 2301 || epsg == 2302 ||
2409 epsg == 2303 || epsg == 2304 || epsg == 2305 || epsg == 2306 || epsg == 2307 || epsg == 2963 || epsg == 2985 || epsg == 2986 || epsg == 3052 ||
2410 epsg == 3053 || epsg == 3139 || epsg == 3144 || epsg == 3145 || epsg == 3173 || epsg == 3295 || epsg == 3993 || epsg == 4087 || epsg == 4088 ||
2411 epsg == 5017 || epsg == 5221 || epsg == 5224 || epsg == 5225 || epsg == 5514 || epsg == 5515 || epsg == 5516 || epsg == 5819 || epsg == 5820 ||
2412 epsg == 5821 || epsg == 6200 || epsg == 6201 || epsg == 6202 || epsg == 6244 || epsg == 6245 || epsg == 6246 || epsg == 6247 || epsg == 6248 ||
2413 epsg == 6249 || epsg == 6250 || epsg == 6251 || epsg == 6252 || epsg == 6253 || epsg == 6254 || epsg == 6255 || epsg == 6256 || epsg == 6257 ||
2414 epsg == 6258 || epsg == 6259 || epsg == 6260 || epsg == 6261 || epsg == 6262 || epsg == 6263 || epsg == 6264 || epsg == 6265 || epsg == 6266 ||
2415 epsg == 6267 || epsg == 6268 || epsg == 6269 || epsg == 6270 || epsg == 6271 || epsg == 6272 || epsg == 6273 || epsg == 6274 || epsg == 6275 ||
2416 epsg == 6966 || epsg == 7082 || epsg == 32600 || epsg == 32663 || epsg == 32700 )
2419 if ( OSRImportFromEPSG( crs, epsg ) != OGRERR_NONE )
2421 qDebug(
"EPSG %d: not imported", epsg );
2425 char *wkt =
nullptr;
2426 if ( OSRExportToWkt( crs, &wkt ) != OGRERR_NONE )
2428 qWarning(
"EPSG %d: not exported to WKT", epsg );
2432 wkts.insert( epsg, wkt );
2440 QgsDebugMsgLevel( QStringLiteral(
"Loaded %1/%2 from %3" ).arg( QString::number( n ), QString::number( l ), filename.toUtf8().constData() ), 4 );
2443 OSRDestroySpatialReference( crs );
2449 #if PROJ_VERSION_MAJOR>=6 2450 static void sync_db_proj_logger(
void * ,
int level,
const char *message )
2455 if ( level == PJ_LOG_ERROR )
2459 else if ( level == PJ_LOG_DEBUG )
2468 setlocale( LC_ALL,
"C" );
2471 #if PROJ_VERSION_MAJOR<6 2472 syncDatumTransform( dbFilePath );
2475 int inserted = 0, updated = 0, deleted = 0, errors = 0;
2480 if ( database.
open( dbFilePath ) != SQLITE_OK )
2486 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2492 #if PROJ_VERSION_MAJOR<6 2494 if ( sqlite3_exec( database.get(),
"alter table tbl_srs add noupdate boolean",
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2495 ( 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 );
2497 ( 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 );
2502 char *errMsg =
nullptr;
2504 #if PROJ_VERSION_MAJOR>=6 2507 proj_log_func( pjContext,
nullptr, sync_db_proj_logger );
2509 PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
2511 int nextSrsId = 60000;
2512 int nextSrId = 520000000;
2513 for (
auto authIter = authorities; authIter && *authIter; ++authIter )
2515 const QString authority( *authIter );
2516 QgsDebugMsgLevel( QStringLiteral(
"Loading authority '%1'" ).arg( authority ), 2 );
2517 PROJ_STRING_LIST codes = proj_get_codes_from_database( pjContext, *authIter, PJ_TYPE_CRS,
true );
2519 QStringList allCodes;
2521 for (
auto codesIter = codes; codesIter && *codesIter; ++codesIter )
2523 const QString code( *codesIter );
2526 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database( pjContext, *authIter, *codesIter, PJ_CATEGORY_CRS,
false,
nullptr ) );
2529 QgsDebugMsg( QStringLiteral(
"Could not load '%1:%2'" ).arg( authority, code ) );
2533 switch ( proj_get_type( crs.get() ) )
2535 case PJ_TYPE_VERTICAL_CRS:
2542 crs = QgsProjUtils::crsToSingleCrs( crs.get() );
2544 QString proj4 = getFullProjString( crs.get() );
2545 proj4.replace( QStringLiteral(
"+type=crs" ), QString() );
2546 proj4 = proj4.trimmed();
2548 if ( proj4.isEmpty() )
2550 QgsDebugMsgLevel( QStringLiteral(
"No proj4 for '%1:%2'" ).arg( authority, code ), 2 );
2555 const bool deprecated = proj_is_deprecated( crs.get() );
2556 const QString name( proj_get_name( crs.get() ) );
2558 QString sql = QStringLiteral(
"SELECT parameters,description,deprecated FROM tbl_srs WHERE auth_name='%1' AND auth_id='%2'" ).arg( authority, code );
2559 statement = database.
prepare( sql, result );
2560 if ( result != SQLITE_OK )
2568 bool srsDeprecated = deprecated;
2569 if ( statement.
step() == SQLITE_ROW )
2573 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2576 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
2578 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
2581 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name=%4 AND auth_id=%5" )
2582 .arg( QgsSqliteUtils::quotedString( proj4 ) )
2583 .arg( QgsSqliteUtils::quotedString( name ) )
2584 .arg( deprecated ? 1 : 0 )
2585 .arg( QgsSqliteUtils::quotedString( authority ), QgsSqliteUtils::quotedString( code ) );
2587 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2589 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2592 errMsg ? errMsg :
"(unknown error)" ) );
2594 sqlite3_free( errMsg );
2606 QString operation =
"";
2608 getOperationAndEllipsoidFromProjString( proj4, operation, ellps );
2609 const bool isGeographic = testIsGeographic( crs.get() );
2612 const QString dbVals = sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( authority, code ) );
2615 if ( !dbVals.isEmpty() )
2617 const QStringList parts = dbVals.split(
',' );
2618 srsId = parts.at( 0 );
2619 srId = parts.at( 1 );
2621 if ( srId.isEmpty() )
2623 srId = QString::number( nextSrId );
2626 if ( srsId.isEmpty() )
2628 srsId = QString::number( nextSrsId );
2632 if ( !srsId.isEmpty() )
2634 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)" )
2636 .arg( QgsSqliteUtils::quotedString( name ),
2637 QgsSqliteUtils::quotedString( operation ),
2638 QgsSqliteUtils::quotedString( ellps ),
2639 QgsSqliteUtils::quotedString( proj4 ) )
2641 .arg( QgsSqliteUtils::quotedString( authority ) )
2642 .arg( QgsSqliteUtils::quotedString( code ) )
2643 .arg( isGeographic ? 1 : 0 )
2644 .arg( deprecated ? 1 : 0 );
2648 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)" )
2649 .arg( QgsSqliteUtils::quotedString( name ),
2650 QgsSqliteUtils::quotedString( operation ),
2651 QgsSqliteUtils::quotedString( ellps ),
2652 QgsSqliteUtils::quotedString( proj4 ) )
2654 .arg( QgsSqliteUtils::quotedString( authority ) )
2655 .arg( QgsSqliteUtils::quotedString( code ) )
2656 .arg( isGeographic ? 1 : 0 )
2657 .arg( deprecated ? 1 : 0 );
2661 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2667 qCritical(
"Could not execute: %s [%s/%s]\n",
2668 sql.toLocal8Bit().constData(),
2669 sqlite3_errmsg( database.get() ),
2670 errMsg ? errMsg :
"(unknown error)" );
2674 sqlite3_free( errMsg );
2679 proj_string_list_destroy( codes );
2681 const QString sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='%1' AND NOT auth_id IN (%2)" ).arg( authority, allCodes.join(
',' ) );
2682 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2684 deleted = sqlite3_changes( database.get() );
2689 qCritical(
"Could not execute: %s [%s]\n",
2690 sql.toLocal8Bit().constData(),
2691 sqlite3_errmsg( database.get() ) );
2695 proj_string_list_destroy( authorities );
2703 QHash<int, QString> wkts;
2705 loadWkts( wkts,
"epsg.wkt" );
2707 QgsDebugMsgLevel( QStringLiteral(
"%1 WKTs loaded" ).arg( wkts.count() ), 4 );
2709 for ( QHash<int, QString>::const_iterator it = wkts.constBegin(); it != wkts.constEnd(); ++it )
2711 QByteArray ba( it.value().toUtf8() );
2712 char *psz = ba.data();
2715 OSRDestroySpatialReference( crs );
2717 crs = OSRNewSpatialReference(
nullptr );
2719 OGRErr ogrErr = OSRImportFromWkt( crs, &psz );
2720 if ( ogrErr != OGRERR_NONE )
2723 if ( OSRExportToProj4( crs, &psz ) != OGRERR_NONE )
2730 proj4 = proj4.trimmed();
2734 if ( proj4.isEmpty() )
2737 QString name( OSRIsGeographic( crs ) ? OSRGetAttrValue( crs,
"GEOGCS", 0 ) :
2738 OSRIsGeocentric( crs ) ? OSRGetAttrValue( crs,
"GEOCCS", 0 ) :
2739 OSRGetAttrValue( crs,
"PROJCS", 0 ) );
2740 if ( name.isEmpty() )
2741 name = QObject::tr(
"Imported from GDAL" );
2743 bool deprecated = name.contains( QLatin1Literal(
"(deprecated)" ) );
2745 sql = QStringLiteral(
"SELECT parameters,description,deprecated,noupdate FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).arg( it.key() );
2746 statement = database.
prepare( sql, result );
2747 if ( result != SQLITE_OK )
2755 bool srsDeprecated = deprecated;
2756 if ( statement.
step() == SQLITE_ROW )
2760 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2768 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
2770 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
2773 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name='EPSG' AND auth_id=%4" )
2776 .arg( deprecated ? 1 : 0 )
2779 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2781 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2784 errMsg ? errMsg :
"(unknown error)" ) );
2786 sqlite3_free( errMsg );
2797 QRegExp projRegExp(
"\\+proj=(\\S+)" );
2798 if ( projRegExp.indexIn( proj4 ) < 0 )
2800 QgsDebugMsgLevel( QStringLiteral(
"EPSG %1: no +proj argument found [%2]" ).arg( it.key() ).arg( proj4 ), 4 );
2804 QRegExp ellipseRegExp(
"\\+ellps=(\\S+)" );
2806 if ( ellipseRegExp.indexIn( proj4 ) >= 0 )
2808 ellps = ellipseRegExp.cap( 1 );
2820 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)" )
2826 .arg( OSRIsGeographic( crs ) )
2827 .arg( deprecated ? 1 : 0 );
2830 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2836 qCritical(
"Could not execute: %s [%s/%s]\n",
2837 sql.toLocal8Bit().constData(),
2838 sqlite3_errmsg( database.get() ),
2839 errMsg ? errMsg :
"(unknown error)" );
2843 sqlite3_free( errMsg );
2849 OSRDestroySpatialReference( crs );
2852 sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN (" );
2854 QHash<int, QString>::const_iterator it = wkts.constBegin();
2855 for ( ; it != wkts.constEnd(); ++it )
2857 sql += delim + QString::number( it.key() );
2860 sql += QLatin1String(
") AND NOT noupdate" );
2862 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2864 deleted = sqlite3_changes( database.get() );
2869 qCritical(
"Could not execute: %s [%s]\n",
2870 sql.toLocal8Bit().constData(),
2871 sqlite3_errmsg( database.get() ) );
2874 projCtx pContext = pj_ctx_alloc();
2876 #if !defined(PJ_VERSION) || PJ_VERSION!=470 2877 sql = QStringLiteral(
"select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated AND NOT noupdate" );
2878 statement = database.
prepare( sql, result );
2879 if ( result == SQLITE_OK )
2881 while ( statement.
step() == SQLITE_ROW )
2887 QString input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toLower(), auth_id );
2888 projPJ pj = pj_init_plus_ctx( pContext, input.toLatin1() );
2891 input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toUpper(), auth_id );
2892 pj = pj_init_plus_ctx( pContext, input.toLatin1() );
2897 char *def = pj_get_def( pj, 0 );
2903 input.prepend(
' ' ).append(
' ' );
2904 if ( proj4.startsWith( input ) )
2906 proj4 = proj4.mid( input.size() );
2907 proj4 = proj4.trimmed();
2910 if ( proj4 != params )
2912 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
2917 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2923 qCritical(
"Could not execute: %s [%s/%s]\n",
2924 sql.toLocal8Bit().constData(),
2925 sqlite3_errmsg( database.get() ),
2926 errMsg ? errMsg :
"(unknown error)" );
2928 sqlite3_free( errMsg );
2935 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve proj string for %1 from PROJ" ).arg( input ), 4 );
2940 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve crs for %1 from PROJ" ).arg( input ), 3 );
2949 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2]\n" ).arg(
2951 sqlite3_errmsg( database.get() ) ) );
2955 pj_ctx_free( pContext );
2959 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2961 QgsDebugMsg( QStringLiteral(
"Could not commit transaction: %1 [%2]\n" ).arg(
2963 sqlite3_errmsg( database.get() ) )
2968 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 );
2973 return updated + inserted;
2976 #if PROJ_VERSION_MAJOR<6 2977 bool QgsCoordinateReferenceSystem::syncDatumTransform(
const QString &dbPath )
2979 const char *filename = CSVFilename(
"datum_shift.csv" );
2980 FILE *fp = VSIFOpen( filename,
"rb" );
2986 char **fieldnames = CSVReadParseLine( fp );
2998 {
"SOURCE_CRS_CODE",
"source_crs_code", -1 },
2999 {
"TARGET_CRS_CODE",
"target_crs_code", -1 },
3000 {
"REMARKS",
"remarks", -1 },
3001 {
"COORD_OP_SCOPE",
"scope", -1 },
3002 {
"AREA_OF_USE_CODE",
"area_of_use_code", -1 },
3008 {
"DEPRECATED",
"deprecated", -1 },
3009 {
"COORD_OP_METHOD_CODE",
"coord_op_method_code", -1 },
3017 {
"PREFERRED",
"preferred", -1 },
3018 {
"COORD_OP_CODE",
"coord_op_code", -1 },
3021 QString update = QStringLiteral(
"UPDATE tbl_datum_transform SET " );
3022 QString insert, values;
3024 int n = CSLCount( fieldnames );
3026 int idxid = -1, idxrx = -1, idxry = -1, idxrz = -1, idxmcode = -1;
3027 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
3029 bool last = i ==
sizeof( map ) /
sizeof( *map ) - 1;
3031 map[i].idx = CSLFindString( fieldnames, map[i].src );
3032 if ( map[i].idx < 0 )
3034 qWarning(
"field %s not found", map[i].src );
3035 CSLDestroy( fieldnames );
3040 if ( strcmp( map[i].src,
"COORD_OP_CODE" ) == 0 )
3042 if ( strcmp( map[i].src,
"RX" ) == 0 )
3044 if ( strcmp( map[i].src,
"RY" ) == 0 )
3046 if ( strcmp( map[i].src,
"RZ" ) == 0 )
3048 if ( strcmp( map[i].src,
"COORD_OP_METHOD_CODE" ) == 0 )
3058 update += QLatin1String(
" WHERE " );
3066 update += QStringLiteral(
"%1=%%2" ).arg( map[i].dst ).arg( i + 1 );
3068 insert += map[i].dst;
3069 values += QStringLiteral(
"%%1" ).arg( i + 1 );
3072 insert =
"INSERT INTO tbl_datum_transform(" + insert +
") VALUES (" + values +
')';
3074 CSLDestroy( fieldnames );
3076 Q_ASSERT( idxid >= 0 );
3077 Q_ASSERT( idxrx >= 0 );
3078 Q_ASSERT( idxry >= 0 );
3079 Q_ASSERT( idxrz >= 0 );
3082 int openResult = database.
open( dbPath );
3083 if ( openResult != SQLITE_OK )
3089 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
3097 v.reserve(
sizeof( map ) /
sizeof( *map ) );
3101 char **values = CSVReadParseLine( fp );
3107 if ( CSLCount( values ) == 0 )
3109 CSLDestroy( values );
3113 if ( CSLCount( values ) < n )
3115 qWarning(
"Only %d columns", CSLCount( values ) );
3116 CSLDestroy( values );
3120 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
3122 int idx = map[i].idx;
3123 Q_ASSERT( idx != -1 );
3124 Q_ASSERT( idx < n );
3127 CSLDestroy( values );
3130 if ( v.at( idxmcode ).compare( QLatin1String(
"'9607'" ) ) == 0 )
3132 v[ idxmcode ] = QStringLiteral(
"'9606'" );
3133 v[ idxrx ] =
'\'' +
qgsDoubleToString( -( v[ idxrx ].
remove(
'\'' ).toDouble() ) ) +
'\'';
3134 v[ idxry ] =
'\'' +
qgsDoubleToString( -( v[ idxry ].
remove(
'\'' ).toDouble() ) ) +
'\'';
3135 v[ idxrz ] =
'\'' +
qgsDoubleToString( -( v[ idxrz ].
remove(
'\'' ).toDouble() ) ) +
'\'';
3141 QString sql = QStringLiteral(
"SELECT coord_op_code FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( v[ idxid ] );
3143 statement = database.
prepare( sql, prepareRes );
3144 if ( prepareRes != SQLITE_OK )
3147 if ( statement.
step() == SQLITE_ROW )
3152 sql = cOpCode.isEmpty() ? insert : update;
3153 for (
int i = 0; i < v.size(); i++ )
3155 sql = sql.arg( v[i] );
3158 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) != SQLITE_OK )
3160 qCritical(
"SQL: %s", sql.toUtf8().constData() );
3161 qCritical(
"Error: %s", sqlite3_errmsg( database.get() ) );
3165 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
3181 #if PROJ_VERSION_MAJOR>=6 3184 QgsProjUtils::proj_pj_unique_ptr geoCrs( proj_crs_get_geodetic_crs(
QgsProjContext::get(), d->mPj.get() ) );
3185 return geoCrs ? QStringLiteral(
"%1:%2" ).arg( proj_get_id_auth_name( geoCrs.get(), 0 ), proj_get_id_code( geoCrs.get(), 0 ) ) : QString();
3190 return OSRGetAuthorityName( d->mCRS,
"GEOGCS" ) + QStringLiteral(
":" ) + OSRGetAuthorityCode( d->mCRS,
"GEOGCS" );
3199 #if PROJ_VERSION_MAJOR>=6 3200 PJ *QgsCoordinateReferenceSystem::projObject()
const 3202 return d->mPj.get();
3208 QStringList projections;
3212 projections = settings.
value( QStringLiteral(
"UI/recentProjections" ) ).toStringList();
3216 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
3217 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
3218 if ( projectionsAuthId.size() >= projections.size() )
3222 projections.clear();
3223 for (
int i = 0; i < projectionsAuthId.size(); i++ )
3231 if ( i >= projectionsProj4.size() || !crs.
createFromProj4( projectionsProj4.at( i ) ) )
3237 if ( crs.
srsid() == 0 )
3242 projections << QString::number( crs.
srsid() );
3250 sSrIdCacheLock.lockForWrite();
3251 if ( !sDisableSrIdCache )
3254 sDisableSrIdCache =
true;
3257 sSrIdCacheLock.unlock();
3259 sOgcLock.lockForWrite();
3260 if ( !sDisableOgcCache )
3263 sDisableOgcCache =
true;
3268 sProj4CacheLock.lockForWrite();
3269 if ( !sDisableProj4Cache )
3272 sDisableProj4Cache =
true;
3273 sProj4Cache.clear();
3275 sProj4CacheLock.unlock();
3277 sCRSWktLock.lockForWrite();
3278 if ( !sDisableWktCache )
3281 sDisableWktCache =
true;
3284 sCRSWktLock.unlock();
3286 sCRSSrsIdLock.lockForWrite();
3287 if ( !sDisableSrsIdCache )
3290 sDisableSrsIdCache =
true;
3291 sSrsIdCache.clear();
3293 sCRSSrsIdLock.unlock();
3295 sCrsStringLock.lockForWrite();
3296 if ( !sDisableStringCache )
3299 sDisableStringCache =
true;
3300 sStringCache.clear();
3302 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.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
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=".
Full WKT2 string, conforming to ISO 19162:2015(E) / OGC 12-063r5 with all possible nodes and new keyw...
const QgsCoordinateReferenceSystem & crs
WKT2_2018 with the simplification rule of WKT2_SIMPLIFIED.
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.
Same as WKT2_2015 with the following exceptions: UNIT keyword used. ID node only on top element...
QString errorMessage() const
Returns the most recent error message encountered by the database.
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
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.
WKT1 as traditionally output by GDAL, deriving from OGC 01-009. A notable departure from WKT1_GDAL wi...
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.
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.
Full WKT2 string, conforming to ISO 19162:2018 / OGC 18-010, with all possible nodes and new keyword ...
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...
void unlock()
Unlocks the lock.
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).
bool createFromProj4(const QString &projString)
Sets this CRS by passing it a PROJ style formatted string.
void changeMode(Mode mode)
Change the mode of the lock to mode.
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.
WktVariant
WKT formatting variants, only used for builds based on Proj >= 6.
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
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.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
void * OGRSpatialReferenceH
WKT1 as traditionally output by ESRI software, deriving from OGC 99-049.
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.