28 #include <QDomElement>
31 #include <QTextStream>
33 #include <QRegularExpression>
44 #if PROJ_VERSION_MAJOR>=6
47 #include <proj_experimental.h>
53 #include <ogr_srs_api.h>
54 #include <cpl_error.h>
59 #if PROJ_VERSION_MAJOR<6
71 bool QgsCoordinateReferenceSystem::sDisableSrIdCache =
false;
75 bool QgsCoordinateReferenceSystem::sDisableOgcCache =
false;
79 bool QgsCoordinateReferenceSystem::sDisableProjCache =
false;
83 bool QgsCoordinateReferenceSystem::sDisableWktCache =
false;
87 bool QgsCoordinateReferenceSystem::sDisableSrsIdCache =
false;
91 bool QgsCoordinateReferenceSystem::sDisableStringCache =
false;
93 #if PROJ_VERSION_MAJOR>=6
94 QString getFullProjString( PJ *obj )
98 QgsProjUtils::proj_pj_unique_ptr boundCrs( proj_crs_create_bound_crs_to_WGS84(
QgsProjContext::get(), obj,
nullptr ) );
101 if (
const char *proj4src = proj_as_proj_string(
QgsProjContext::get(), boundCrs.get(), PJ_PROJ_4,
nullptr ) )
103 return QString( proj4src );
114 d =
new QgsCoordinateReferenceSystemPrivate();
119 d =
new QgsCoordinateReferenceSystemPrivate();
125 d =
new QgsCoordinateReferenceSystemPrivate();
133 , mValidationHint( srs.mValidationHint )
140 mValidationHint = srs.mValidationHint;
150 const auto constDbs = dbs;
151 for (
const QString &db : constDbs )
153 QFileInfo myInfo( db );
154 if ( !myInfo.exists() )
156 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
164 int result = openDatabase( db, database );
165 if ( result != SQLITE_OK )
167 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
171 QString sql = QStringLiteral(
"select srs_id from tbl_srs" );
173 statement = database.
prepare( sql, rc );
177 int ret = statement.
step();
179 if ( ret == SQLITE_DONE )
185 if ( ret == SQLITE_ROW )
191 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
196 std::sort( results.begin(), results.end() );
260 result = createFromPostgisSrid(
id );
267 QgsDebugMsg( QStringLiteral(
"Unexpected case reached!" ) );
274 if ( definition.isEmpty() )
278 if ( !sDisableStringCache )
280 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sStringCache()->constFind( definition );
281 if ( crsIt != sStringCache()->constEnd() )
284 *
this = crsIt.value();
291 QRegularExpression reCrsId( QStringLiteral(
"^(epsg|esri|osgeo|ignf|zangi|iau2000|postgis|internal|user)\\:(\\w+)$" ), QRegularExpression::CaseInsensitiveOption );
292 QRegularExpressionMatch match = reCrsId.match( definition );
293 if ( match.capturedStart() == 0 )
295 QString authName = match.captured( 1 ).toLower();
296 if ( authName == QLatin1String(
"epsg" ) )
300 else if ( authName == QLatin1String(
"postgis" ) )
302 const long id = match.captured( 2 ).toLong();
303 result = createFromPostgisSrid(
id );
305 else if ( authName == QLatin1String(
"esri" ) || authName == QLatin1String(
"osgeo" ) || authName == QLatin1String(
"ignf" ) || authName == QLatin1String(
"zangi" ) || authName == QLatin1String(
"iau2000" ) )
311 const long id = match.captured( 2 ).toLong();
319 QRegularExpression reCrsStr(
"^(?:(wkt|proj4|proj)\\:)?(.+)$", QRegularExpression::CaseInsensitiveOption );
320 match = reCrsStr.match( definition );
321 if ( match.capturedStart() == 0 )
323 if ( match.captured( 1 ).startsWith( QLatin1String(
"proj" ), Qt::CaseInsensitive ) )
335 if ( !sDisableStringCache )
336 sStringCache()->insert( definition, *
this );
342 if ( definition.isEmpty() )
348 #if PROJ_VERSION_MAJOR<6
350 if ( definition.startsWith( QLatin1String(
"ESRI::" ) ) )
358 if ( OSRSetFromUserInput(
crs, definition.toLocal8Bit().constData() ) == OGRERR_NONE )
361 OSRDestroySpatialReference(
crs );
371 const char *configOld = CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" );
372 const char *configNew =
"GEOGCS";
374 if ( strcmp( configOld,
"" ) == 0 )
376 CPLSetConfigOption(
"GDAL_FIX_ESRI_WKT", configNew );
377 if ( strcmp( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) != 0 )
379 .arg( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) );
380 QgsDebugMsgLevel( QStringLiteral(
"set GDAL_FIX_ESRI_WKT : %1" ).arg( configNew ), 4 );
384 QgsDebugMsgLevel( QStringLiteral(
"GDAL_FIX_ESRI_WKT was already set : %1" ).arg( configNew ), 4 );
394 if ( !sDisableOgcCache )
396 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sOgcCache()->constFind(
crs );
397 if ( crsIt != sOgcCache()->constEnd() )
400 *
this = crsIt.value();
406 QString wmsCrs =
crs;
408 QRegExp re_uri(
"http://www\\.opengis\\.net/def/crs/([^/]+).+/([^/]+)", Qt::CaseInsensitive );
409 QRegExp re_urn(
"urn:ogc:def:crs:([^:]+).+([^:]+)", Qt::CaseInsensitive );
410 if ( re_uri.exactMatch( wmsCrs ) )
412 wmsCrs = re_uri.cap( 1 ) +
':' + re_uri.cap( 2 );
414 else if ( re_urn.exactMatch( wmsCrs ) )
416 wmsCrs = re_urn.cap( 1 ) +
':' + re_urn.cap( 2 );
420 re_urn.setPattern( QStringLiteral(
"(user|custom|qgis):(\\d+)" ) );
421 if ( re_urn.exactMatch( wmsCrs ) &&
createFromSrsId( re_urn.cap( 2 ).toInt() ) )
424 if ( !sDisableOgcCache )
425 sOgcCache()->insert(
crs, *
this );
430 #if PROJ_VERSION_MAJOR>=6
432 const QString legacyKey = wmsCrs.toLower();
433 for (
auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
435 if ( it.key().compare( legacyKey, Qt::CaseInsensitive ) == 0 )
437 const QStringList parts = it.key().split(
':' );
438 const QString auth = parts.at( 0 );
439 const QString code = parts.at( 1 );
440 if ( loadFromAuthCode( auth, code ) )
443 if ( !sDisableOgcCache )
444 sOgcCache()->insert(
crs, *
this );
454 if ( !sDisableOgcCache )
455 sOgcCache()->insert(
crs, *
this );
460 if ( wmsCrs.compare( QLatin1String(
"CRS:27" ), Qt::CaseInsensitive ) == 0 ||
461 wmsCrs.compare( QLatin1String(
"OGC:CRS27" ), Qt::CaseInsensitive ) == 0 )
468 if ( wmsCrs.compare( QLatin1String(
"CRS:83" ), Qt::CaseInsensitive ) == 0 ||
469 wmsCrs.compare( QLatin1String(
"OGC:CRS83" ), Qt::CaseInsensitive ) == 0 )
476 if ( wmsCrs.compare( QLatin1String(
"CRS:84" ), Qt::CaseInsensitive ) == 0 ||
477 wmsCrs.compare( QLatin1String(
"OGC:CRS84" ), Qt::CaseInsensitive ) == 0 )
481 d->mAxisInverted =
false;
482 d->mAxisInvertedDirty =
false;
486 if ( !sDisableOgcCache )
487 sOgcCache()->insert(
crs, *
this );
493 if ( !sDisableOgcCache )
503 if ( d->mIsValid || !sCustomSrsValidation )
507 if ( sCustomSrsValidation )
508 sCustomSrsValidation( *
this );
513 return createFromPostgisSrid(
id );
516 bool QgsCoordinateReferenceSystem::createFromPostgisSrid(
const long id )
519 if ( !sDisableSrIdCache )
521 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrIdCache()->constFind(
id );
522 if ( crsIt != sSrIdCache()->constEnd() )
525 *
this = crsIt.value();
531 #if PROJ_VERSION_MAJOR>=6
533 for (
auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
535 if ( it.value().endsWith( QStringLiteral(
",%1" ).arg(
id ) ) )
537 const QStringList parts = it.key().split(
':' );
538 const QString auth = parts.at( 0 );
539 const QString code = parts.at( 1 );
540 if ( loadFromAuthCode( auth, code ) )
543 if ( !sDisableSrIdCache )
544 sSrIdCache()->insert(
id, *
this );
555 if ( !sDisableSrIdCache )
556 sSrIdCache()->insert(
id, *
this );
564 if ( !sDisableSrsIdCache )
566 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrsIdCache()->constFind(
id );
567 if ( crsIt != sSrsIdCache()->constEnd() )
570 *
this = crsIt.value();
576 #if PROJ_VERSION_MAJOR>=6
578 for (
auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
580 if ( it.value().startsWith( QString::number(
id ) +
',' ) )
582 const QStringList parts = it.key().split(
':' );
583 const QString auth = parts.at( 0 );
584 const QString code = parts.at( 1 );
585 if ( loadFromAuthCode( auth, code ) )
588 if ( !sDisableSrsIdCache )
589 sSrsIdCache()->insert(
id, *
this );
598 QStringLiteral(
"srs_id" ), QString::number(
id ) );
601 if ( !sDisableSrsIdCache )
602 sSrsIdCache()->insert(
id, *
this );
606 bool QgsCoordinateReferenceSystem::loadFromDatabase(
const QString &db,
const QString &expression,
const QString &value )
610 QgsDebugMsgLevel(
"load CRS from " + db +
" where " + expression +
" is " + value, 3 );
612 d->mWktPreferred.clear();
614 QFileInfo myInfo( db );
615 if ( !myInfo.exists() )
617 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
625 myResult = openDatabase( db, database );
626 if ( myResult != SQLITE_OK )
643 QString mySql =
"select srs_id,description,projection_acronym,"
644 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo,wkt "
646 statement = database.
prepare( mySql, myResult );
649 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
654 #if PROJ_VERSION_MAJOR>=6
655 d->mEllipsoidAcronym.clear();
660 d->mWktPreferred.clear();
663 d->mIsGeographic = statement.
columnAsText( 7 ).toInt() != 0;
665 d->mAxisInvertedDirty =
true;
667 if ( d->mSrsId >=
USER_CRS_START_ID && ( d->mAuthId.isEmpty() || d->mAuthId == QChar(
':' ) ) )
669 d->mAuthId = QStringLiteral(
"USER:%1" ).arg( d->mSrsId );
671 else if ( !d->mAuthId.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive ) )
673 #if PROJ_VERSION_MAJOR>=6
674 QStringList parts = d->mAuthId.split(
':' );
675 QString auth = parts.at( 0 );
676 QString code = parts.at( 1 );
679 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database(
QgsProjContext::get(), auth.toLatin1(), code.toLatin1(), PJ_CATEGORY_CRS,
false,
nullptr ) );
680 d->setPj( QgsProjUtils::crsToSingleCrs(
crs.get() ) );
683 d->mIsValid = d->hasPj();
685 OSRDestroySpatialReference( d->mCRS );
686 d->mCRS = OSRNewSpatialReference(
nullptr );
687 d->mIsValid = OSRSetFromUserInput( d->mCRS, d->mAuthId.toLower().toLatin1() ) == OGRERR_NONE;
694 if ( !wkt.isEmpty() )
695 setWktString( wkt,
false );
697 setProjString( d->mProj4 );
707 #if PROJ_VERSION_MAJOR>=6
708 void QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread(
PJ_CONTEXT *pj_context )
715 if ( !sDisableSrIdCache )
718 if ( !sDisableSrIdCache )
720 for (
auto it = sSrIdCache()->begin(); it != sSrIdCache()->end(); )
722 auto &v = it.value();
723 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
724 it = sSrIdCache()->erase( it );
730 if ( !sDisableOgcCache )
733 if ( !sDisableOgcCache )
735 for (
auto it = sOgcCache()->begin(); it != sOgcCache()->end(); )
737 auto &v = it.value();
738 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
739 it = sOgcCache()->erase( it );
745 if ( !sDisableProjCache )
748 if ( !sDisableProjCache )
750 for (
auto it = sProj4Cache()->begin(); it != sProj4Cache()->end(); )
752 auto &v = it.value();
753 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
754 it = sProj4Cache()->erase( it );
760 if ( !sDisableWktCache )
763 if ( !sDisableWktCache )
765 for (
auto it = sWktCache()->begin(); it != sWktCache()->end(); )
767 auto &v = it.value();
768 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
769 it = sWktCache()->erase( it );
775 if ( !sDisableSrsIdCache )
778 if ( !sDisableSrsIdCache )
780 for (
auto it = sSrsIdCache()->begin(); it != sSrsIdCache()->end(); )
782 auto &v = it.value();
783 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
784 it = sSrsIdCache()->erase( it );
790 if ( !sDisableStringCache )
793 if ( !sDisableStringCache )
795 for (
auto it = sStringCache()->begin(); it != sStringCache()->end(); )
797 auto &v = it.value();
798 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
799 it = sStringCache()->erase( it );
810 if ( d->mAxisInvertedDirty )
812 #if PROJ_VERSION_MAJOR>=6
813 d->mAxisInverted = QgsProjUtils::axisOrderIsSwapped( d->threadLocalProjObject() );
815 OGRAxisOrientation orientation;
816 OSRGetAxis( d->mCRS, OSRIsGeographic( d->mCRS ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
819 if ( orientation == OAO_Other && d->mAuthId.startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
823 if ( OSRImportFromEPSGA(
crs, d->mAuthId.midRef( 5 ).toInt() ) == OGRERR_NONE )
825 OSRGetAxis(
crs, OSRIsGeographic(
crs ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
828 OSRDestroySpatialReference(
crs );
831 d->mAxisInverted = orientation == OAO_North;
833 d->mAxisInvertedDirty =
false;
836 return d->mAxisInverted;
847 if ( !sDisableWktCache )
849 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sWktCache()->constFind( wkt );
850 if ( crsIt != sWktCache()->constEnd() )
853 *
this = crsIt.value();
861 d->mWktPreferred.clear();
864 QgsDebugMsgLevel( QStringLiteral(
"theWkt is uninitialized, operation failed" ), 4 );
869 QgsCoordinateReferenceSystem::RecordMap record = getRecord(
"select * from tbl_srs where wkt=" +
QgsSqliteUtils::quotedString( wkt ) +
" order by deprecated" );
870 if ( !record.empty() )
872 long srsId = record[QStringLiteral(
"srs_id" )].toLong();
881 if ( d->mSrsId == 0 )
883 #if PROJ_VERSION_MAJOR>=6
885 long id = matchToUserCrs();
895 if ( !sDisableWktCache )
896 sWktCache()->insert( wkt, *
this );
914 if ( projString.isEmpty() )
919 if ( projString.trimmed().isEmpty() )
923 d->mWktPreferred.clear();
928 if ( !sDisableProjCache )
930 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sProj4Cache()->constFind( projString );
931 if ( crsIt != sProj4Cache()->constEnd() )
934 *
this = crsIt.value();
948 QString myProj4String = projString.trimmed();
949 myProj4String.remove( QStringLiteral(
"+type=crs" ) );
950 myProj4String = myProj4String.trimmed();
953 d->mWktPreferred.clear();
954 #if PROJ_VERSION_MAJOR>=6
958 const QString projCrsString = myProj4String + ( myProj4String.contains( QStringLiteral(
"+type=crs" ) ) ? QString() : QStringLiteral(
" +type=crs" ) );
959 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create(
QgsProjContext::get(), projCrsString.toLatin1().constData() ) );
966 const QString
authid = QStringLiteral(
"%1:%2" ).arg( authName, authCode );
970 if ( !sDisableProjCache )
971 sProj4Cache()->insert( projString, *
this );
978 QgsCoordinateReferenceSystem::RecordMap myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
980 if ( !myRecord.empty() )
982 id = myRecord[QStringLiteral(
"srs_id" )].toLong();
991 setProjString( myProj4String );
994 id = matchToUserCrs();
1003 setProjString( myProj4String );
1007 Q_UNUSED( identify )
1009 QRegExp myProjRegExp(
"\\+proj=(\\S+)" );
1010 int myStart = myProjRegExp.indexIn( myProj4String );
1011 if ( myStart == -1 )
1014 if ( !sDisableProjCache )
1015 sProj4Cache()->insert( projString, *
this );
1020 d->mProjectionAcronym = myProjRegExp.cap( 1 );
1022 QRegExp myEllipseRegExp(
"\\+ellps=(\\S+)" );
1023 myStart = myEllipseRegExp.indexIn( myProj4String );
1024 if ( myStart == -1 )
1026 d->mEllipsoidAcronym.clear();
1030 d->mEllipsoidAcronym = myEllipseRegExp.cap( 1 );
1033 QRegExp myAxisRegExp(
"\\+a=(\\S+)" );
1034 myStart = myAxisRegExp.indexIn( myProj4String );
1037 QgsCoordinateReferenceSystem::RecordMap myRecord;
1043 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
1044 if ( myRecord.empty() )
1049 QRegExp myLat1RegExp(
"\\+lat_1=\\S+" );
1050 QRegExp myLat2RegExp(
"\\+lat_2=\\S+" );
1057 myStart1 = myLat1RegExp.indexIn( myProj4String, myStart1 );
1058 myStart2 = myLat2RegExp.indexIn( myProj4String, myStart2 );
1059 if ( myStart1 != -1 && myStart2 != -1 )
1061 myLength1 = myLat1RegExp.matchedLength();
1062 myLength2 = myLat2RegExp.matchedLength();
1067 if ( !lat1Str.isEmpty() && !lat2Str.isEmpty() )
1070 QString proj4StringModified = myProj4String;
1075 myStart2 = myLat2RegExp.indexIn( projString, myStart2 );
1077 QgsDebugMsgLevel( QStringLiteral(
"trying proj4string match with swapped lat_1,lat_2" ), 4 );
1078 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( proj4StringModified.trimmed() ) +
" order by deprecated" );
1082 if ( myRecord.empty() )
1089 QString sql = QStringLiteral(
"SELECT * FROM tbl_srs WHERE " );
1096 QStringList myParams;
1097 const QRegExp regExp(
"\\s+(?=\\+)" );
1099 const auto constSplit = myProj4String.split( regExp, QString::SkipEmptyParts );
1100 for (
const QString ¶m : constSplit )
1102 QString arg = QStringLiteral(
"' '||parameters||' ' LIKE %1" ).arg(
QgsSqliteUtils::quotedString( QStringLiteral(
"% %1 %" ).arg( param.trimmed() ) ) );
1103 if ( param.startsWith( QLatin1String(
"+datum=" ) ) )
1110 delim = QStringLiteral(
" AND " );
1111 myParams << param.trimmed();
1116 if ( !datum.isEmpty() )
1118 myRecord = getRecord( sql + delim + datum +
" order by deprecated" );
1121 if ( myRecord.empty() )
1124 myRecord = getRecord( sql +
" order by deprecated" );
1127 if ( !myRecord.empty() )
1130 QStringList foundParams;
1131 const auto constSplit = myRecord[
"parameters"].split( regExp, QString::SkipEmptyParts );
1132 for (
const QString ¶m : constSplit )
1134 if ( !param.startsWith( QLatin1String(
"+datum=" ) ) )
1135 foundParams << param.trimmed();
1141 if ( myParams != foundParams )
1148 if ( !myRecord.empty() )
1150 mySrsId = myRecord[QStringLiteral(
"srs_id" )].toLong();
1159 setProjString( myProj4String );
1169 d->mIsValid =
false;
1176 QgsDebugMsgLevel( QStringLiteral(
"Projection is not found in databases." ), 4 );
1178 setProjString( myProj4String );
1183 if ( !sDisableProjCache )
1184 sProj4Cache()->insert( projString, *
this );
1190 QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord(
const QString &sql )
1192 QString myDatabaseFileName;
1193 QgsCoordinateReferenceSystem::RecordMap myMap;
1194 QString myFieldName;
1195 QString myFieldValue;
1202 QFileInfo myInfo( myDatabaseFileName );
1203 if ( !myInfo.exists() )
1205 QgsDebugMsg(
"failed : " + myDatabaseFileName +
" does not exist!" );
1210 myResult = openDatabase( myDatabaseFileName, database );
1211 if ( myResult != SQLITE_OK )
1216 statement = database.
prepare( sql, myResult );
1218 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1222 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1224 myFieldName = statement.
columnName( myColNo );
1226 myMap[myFieldName] = myFieldValue;
1228 if ( statement.
step() != SQLITE_DONE )
1230 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1232 #if PROJ_VERSION_MAJOR<6
1242 if ( myMap.empty() )
1245 QFileInfo myFileInfo;
1246 myFileInfo.setFile( myDatabaseFileName );
1247 if ( !myFileInfo.exists() )
1249 QgsDebugMsg( QStringLiteral(
"user qgis.db not found" ) );
1254 myResult = openDatabase( myDatabaseFileName, database );
1255 if ( myResult != SQLITE_OK )
1260 statement = database.
prepare( sql, myResult );
1262 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1266 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1268 myFieldName = statement.
columnName( myColNo );
1270 myMap[myFieldName] = myFieldValue;
1273 if ( statement.
step() != SQLITE_DONE )
1275 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1306 if ( d->mDescription.isNull() )
1312 return d->mDescription;
1318 if ( !
authid().isEmpty() )
1327 return QObject::tr(
"Unknown CRS" );
1329 return QObject::tr(
"Unknown CRS: %1" ).arg(
1332 else if ( !
toProj().isEmpty() )
1333 return QObject::tr(
"Unknown CRS: %1" ).arg( type ==
MediumString ? (
toProj().left( 50 ) + QString( QChar( 0x2026 ) ) )
1341 if ( d->mProjectionAcronym.isNull() )
1347 return d->mProjectionAcronym;
1353 if ( d->mEllipsoidAcronym.isNull() )
1355 #if PROJ_VERSION_MAJOR>=6
1356 if ( PJ *obj = d->threadLocalProjObject() )
1358 QgsProjUtils::proj_pj_unique_ptr ellipsoid( proj_get_ellipsoid(
QgsProjContext::get(), obj ) );
1361 const QString ellipsoidAuthName( proj_get_id_auth_name( ellipsoid.get(), 0 ) );
1362 const QString ellipsoidAuthCode( proj_get_id_code( ellipsoid.get(), 0 ) );
1363 if ( !ellipsoidAuthName.isEmpty() && !ellipsoidAuthCode.isEmpty() )
1364 d->mEllipsoidAcronym = QStringLiteral(
"%1:%2" ).arg( ellipsoidAuthName, ellipsoidAuthCode );
1367 double semiMajor, semiMinor, invFlattening;
1368 int semiMinorComputed = 0;
1369 if ( proj_ellipsoid_get_parameters(
QgsProjContext::get(), ellipsoid.get(), &semiMajor, &semiMinor, &semiMinorComputed, &invFlattening ) )
1371 d->mEllipsoidAcronym = QStringLiteral(
"PARAMETER:%1:%2" ).arg(
qgsDoubleToString( semiMajor ),
1376 d->mEllipsoidAcronym.clear();
1381 return d->mEllipsoidAcronym;
1389 return d->mEllipsoidAcronym;
1403 if ( d->mProj4.isEmpty() )
1405 #if PROJ_VERSION_MAJOR>=6
1406 if ( PJ *obj = d->threadLocalProjObject() )
1408 d->mProj4 = getFullProjString( obj );
1411 char *proj4src =
nullptr;
1412 OSRExportToProj4( d->mCRS, &proj4src );
1413 d->mProj4 = proj4src;
1414 CPLFree( proj4src );
1418 return d->mProj4.trimmed();
1423 return d->mIsGeographic;
1431 return d->mMapUnits;
1439 #if PROJ_VERSION_MAJOR>=6
1440 PJ *obj = d->threadLocalProjObject();
1445 double southLat = 0;
1447 double northLat = 0;
1450 &westLon, &southLat, &eastLon, &northLat,
nullptr ) )
1469 int result = openDatabase( databaseFileName, database );
1470 if ( result != SQLITE_OK )
1475 QString sql = QStringLiteral(
"select west_bound_lon, north_bound_lat, east_bound_lon, south_bound_lat from tbl_bounds "
1478 statement = database.
prepare( sql, result );
1481 if ( result == SQLITE_OK )
1483 if ( statement.
step() == SQLITE_ROW )
1500 void QgsCoordinateReferenceSystem::setProjString(
const QString &proj4String )
1503 d->mProj4 = proj4String;
1504 d->mWktPreferred.clear();
1507 QString trimmed = proj4String.trimmed();
1509 #if PROJ_VERSION_MAJOR>=6
1510 trimmed += QStringLiteral(
" +type=crs" );
1514 d->setPj( QgsProjUtils::proj_pj_unique_ptr( proj_create( ctx, trimmed.toLatin1().constData() ) ) );
1520 const int errNo = proj_context_errno( ctx );
1521 QgsDebugMsg( QStringLiteral(
"proj string rejected: %1" ).arg( proj_errno_string( errNo ) ) );
1523 d->mIsValid =
false;
1527 d->mEllipsoidAcronym.clear();
1531 OSRDestroySpatialReference( d->mCRS );
1532 d->mCRS = OSRNewSpatialReference(
nullptr );
1533 d->mIsValid = OSRImportFromProj4( d->mCRS, trimmed.toLatin1().constData() ) == OGRERR_NONE;
1539 projCtx pContext = pj_ctx_alloc();
1540 projPJ proj = pj_init_plus_ctx( pContext, proj4String.trimmed().toLatin1().constData() );
1543 QgsDebugMsgLevel( QStringLiteral(
"proj.4 string rejected by pj_init_plus_ctx()" ), 4 );
1544 d->mIsValid =
false;
1550 pj_ctx_free( pContext );
1556 bool QgsCoordinateReferenceSystem::setWktString(
const QString &wkt,
bool allowProjFallback )
1559 d->mIsValid =
false;
1560 d->mWktPreferred.clear();
1562 #if PROJ_VERSION_MAJOR>=6
1564 ( void )allowProjFallback;
1566 PROJ_STRING_LIST warnings =
nullptr;
1567 PROJ_STRING_LIST grammerErrors =
nullptr;
1569 d->setPj( QgsProjUtils::proj_pj_unique_ptr( proj_create_from_wkt(
QgsProjContext::get(), wkt.toLatin1().constData(),
nullptr, &warnings, &grammerErrors ) ) );
1575 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
1576 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
1578 for (
auto iter = warnings; iter && *iter; ++iter )
1580 for (
auto iter = grammerErrors; iter && *iter; ++iter )
1582 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
1584 proj_string_list_destroy( warnings );
1585 proj_string_list_destroy( grammerErrors );
1587 QByteArray ba = wkt.toLatin1();
1588 const char *pWkt = ba.data();
1590 OGRErr myInputResult = OSRImportFromWkt( d->mCRS,
const_cast< char **
>( & pWkt ) );
1591 res = myInputResult == OGRERR_NONE;
1594 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
1595 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
1597 QgsDebugMsg( QStringLiteral(
"UNUSED WKT: %1" ).arg( pWkt ) );
1598 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
1610 if ( !sDisableWktCache )
1611 sWktCache()->insert( wkt, *
this );
1615 #if PROJ_VERSION_MAJOR>=6
1619 QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
1620 QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
1622 if ( authName.isEmpty() || authCode.isEmpty() )
1625 QgsProjUtils::identifyCrs( d->threadLocalProjObject(), authName, authCode );
1628 if ( !authName.isEmpty() && !authCode.isEmpty() )
1630 if ( loadFromAuthCode( authName, authCode ) )
1633 if ( !sDisableWktCache )
1634 sWktCache()->insert( wkt, *
this );
1646 if ( OSRAutoIdentifyEPSG( d->mCRS ) == OGRERR_NONE )
1648 QString
authid = QStringLiteral(
"%1:%2" )
1649 .arg( OSRGetAuthorityName( d->mCRS,
nullptr ),
1650 OSRGetAuthorityCode( d->mCRS,
nullptr ) );
1653 if ( !sDisableWktCache )
1654 sWktCache()->insert( wkt, *
this );
1663 #if PROJ_VERSION_MAJOR<6
1664 if ( allowProjFallback )
1666 d->mIsValid =
false;
1668 char *proj4src =
nullptr;
1669 OSRExportToProj4( d->mCRS, &proj4src );
1676 CPLFree( proj4src );
1678 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0)
1680 OSRFixup( d->mCRS );
1683 OSRExportToProj4( d->mCRS, &proj4src );
1687 CPLFree( proj4src );
1689 else if ( d->mIsValid )
1697 void QgsCoordinateReferenceSystem::setMapUnits()
1705 #if PROJ_VERSION_MAJOR<6
1706 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0)
1709 OSRFixup( d->mCRS );
1713 #if PROJ_VERSION_MAJOR>=6
1721 QgsProjUtils::proj_pj_unique_ptr
crs( QgsProjUtils::crsToSingleCrs( d->threadLocalProjObject() ) );
1722 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( context,
crs.get() ) );
1723 if ( !coordinateSystem )
1729 const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
1730 if ( axisCount > 0 )
1732 const char *outUnitName =
nullptr;
1734 proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
1743 const QString unitName( outUnitName );
1747 if ( unitName.compare( QLatin1String(
"degree" ), Qt::CaseInsensitive ) == 0 ||
1748 unitName.compare( QLatin1String(
"degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1749 unitName.compare( QLatin1String(
"degree minute second hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1750 unitName.compare( QLatin1String(
"degree minute" ), Qt::CaseInsensitive ) == 0 ||
1751 unitName.compare( QLatin1String(
"degree hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1752 unitName.compare( QLatin1String(
"degree minute hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1753 unitName.compare( QLatin1String(
"hemisphere degree" ), Qt::CaseInsensitive ) == 0 ||
1754 unitName.compare( QLatin1String(
"hemisphere degree minute" ), Qt::CaseInsensitive ) == 0 ||
1755 unitName.compare( QLatin1String(
"hemisphere degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1756 unitName.compare( QLatin1String(
"degree (supplier to define representation)" ), Qt::CaseInsensitive ) == 0 )
1758 else if ( unitName.compare( QLatin1String(
"metre" ), Qt::CaseInsensitive ) == 0
1759 || unitName.compare( QLatin1String(
"m" ), Qt::CaseInsensitive ) == 0
1760 || unitName.compare( QLatin1String(
"meter" ), Qt::CaseInsensitive ) == 0 )
1763 else if ( unitName.compare( QLatin1String(
"US survey foot" ), Qt::CaseInsensitive ) == 0 ||
1764 unitName.compare( QLatin1String(
"foot" ), Qt::CaseInsensitive ) == 0 )
1766 else if ( unitName.compare( QLatin1String(
"kilometre" ), Qt::CaseInsensitive ) == 0 )
1768 else if ( unitName.compare( QLatin1String(
"centimetre" ), Qt::CaseInsensitive ) == 0 )
1770 else if ( unitName.compare( QLatin1String(
"millimetre" ), Qt::CaseInsensitive ) == 0 )
1772 else if ( unitName.compare( QLatin1String(
"Statute mile" ), Qt::CaseInsensitive ) == 0 )
1774 else if ( unitName.compare( QLatin1String(
"nautical mile" ), Qt::CaseInsensitive ) == 0 )
1776 else if ( unitName.compare( QLatin1String(
"yard" ), Qt::CaseInsensitive ) == 0 )
1790 char *unitName =
nullptr;
1792 if ( OSRIsProjected( d->mCRS ) )
1794 double toMeter = OSRGetLinearUnits( d->mCRS, &unitName );
1795 QString unit( unitName );
1803 static const double SMALL_NUM = 1e-3;
1806 unit = QStringLiteral(
"Foot" );
1810 else if ( unit == QLatin1String(
"Foot" ) )
1819 OSRGetAngularUnits( d->mCRS, &unitName );
1820 QString unit( unitName );
1821 if ( unit == QLatin1String(
"degree" ) )
1834 if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
1837 QgsDebugMsgLevel(
"QgsCoordinateReferenceSystem::findMatchingProj will only "
1838 "work if prj acr ellipsoid acr and proj4string are set"
1839 " and the current projection is valid!", 4 );
1849 QString mySql = QString(
"select srs_id,parameters from tbl_srs where "
1850 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1857 myResult = openDatabase( myDatabaseFileName, database );
1858 if ( myResult != SQLITE_OK )
1863 statement = database.
prepare( mySql, myResult );
1864 if ( myResult == SQLITE_OK )
1867 while ( statement.
step() == SQLITE_ROW )
1871 if (
toProj() == myProj4String.trimmed() )
1873 return mySrsId.toLong();
1884 myResult = openDatabase( myDatabaseFileName, database );
1885 if ( myResult != SQLITE_OK )
1890 statement = database.
prepare( mySql, myResult );
1892 if ( myResult == SQLITE_OK )
1894 while ( statement.
step() == SQLITE_ROW )
1898 if (
toProj() == myProj4String.trimmed() )
1900 return mySrsId.toLong();
1914 if ( !d->mIsValid && !srs.d->mIsValid )
1917 if ( !d->mIsValid || !srs.d->mIsValid )
1920 if ( ( !d->mAuthId.isEmpty() || !srs.d->mAuthId.isEmpty() ) )
1921 return d->mAuthId == srs.d->mAuthId;
1928 return !( *
this == srs );
1933 #if PROJ_VERSION_MAJOR>=6
1934 if ( PJ *obj = d->threadLocalProjObject() )
1936 const bool isDefaultPreferredFormat = variant ==
WKT_PREFERRED && !multiline;
1937 if ( isDefaultPreferredFormat && !d->mWktPreferred.isEmpty() )
1940 return d->mWktPreferred;
1943 PJ_WKT_TYPE type = PJ_WKT1_GDAL;
1947 type = PJ_WKT1_GDAL;
1950 type = PJ_WKT1_ESRI;
1953 type = PJ_WKT2_2015;
1956 type = PJ_WKT2_2015_SIMPLIFIED;
1959 type = PJ_WKT2_2019;
1962 type = PJ_WKT2_2019_SIMPLIFIED;
1966 const QByteArray multiLineOption = QStringLiteral(
"MULTILINE=%1" ).arg( multiline ? QStringLiteral(
"YES" ) : QStringLiteral(
"NO" ) ).toLocal8Bit();
1967 const QByteArray indentatationWidthOption = QStringLiteral(
"INDENTATION_WIDTH=%1" ).arg( multiline ? QString::number( indentationWidth ) : QStringLiteral(
"0" ) ).toLocal8Bit();
1968 const char *
const options[] = {multiLineOption.constData(), indentatationWidthOption.constData(),
nullptr};
1971 if ( isDefaultPreferredFormat )
1974 d->mWktPreferred = res;
1982 Q_UNUSED( multiline )
1983 Q_UNUSED( indentationWidth )
1984 char *wkt =
nullptr;
1986 if ( OSRExportToWkt( d->mCRS, &wkt ) == OGRERR_NONE )
1999 QDomNode srsNode = node.namedItem( QStringLiteral(
"spatialrefsys" ) );
2001 if ( ! srsNode.isNull() )
2003 bool initialized =
false;
2006 long srsid = srsNode.namedItem( QStringLiteral(
"srsid" ) ).toElement().text().toLong( &ok );
2012 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
2013 if ( !node.isNull() )
2024 node = srsNode.namedItem( QStringLiteral(
"epsg" ) );
2025 if ( !node.isNull() )
2039 const QString wkt = srsNode.namedItem( QStringLiteral(
"wkt" ) ).toElement().text();
2045 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
2046 const QString proj4 = node.toElement().text();
2053 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
2054 const QString proj4 = node.toElement().text();
2055 if ( !proj4.trimmed().isEmpty() )
2056 setProjString( node.toElement().text() );
2058 node = srsNode.namedItem( QStringLiteral(
"srsid" ) );
2059 d->mSrsId = node.toElement().text().toLong();
2061 node = srsNode.namedItem( QStringLiteral(
"srid" ) );
2062 d->mSRID = node.toElement().text().toLong();
2064 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
2065 d->mAuthId = node.toElement().text();
2067 node = srsNode.namedItem( QStringLiteral(
"description" ) );
2068 d->mDescription = node.toElement().text();
2070 node = srsNode.namedItem( QStringLiteral(
"projectionacronym" ) );
2071 d->mProjectionAcronym = node.toElement().text();
2073 node = srsNode.namedItem( QStringLiteral(
"ellipsoidacronym" ) );
2074 d->mEllipsoidAcronym = node.toElement().text();
2076 node = srsNode.namedItem( QStringLiteral(
"geographicflag" ) );
2077 d->mIsGeographic = node.toElement().text().compare( QLatin1String(
"true" ) );
2079 d->mWktPreferred.clear();
2088 d =
new QgsCoordinateReferenceSystemPrivate();
2096 QDomElement layerNode = node.toElement();
2097 QDomElement srsElement = doc.createElement( QStringLiteral(
"spatialrefsys" ) );
2099 QDomElement wktElement = doc.createElement( QStringLiteral(
"wkt" ) );
2101 srsElement.appendChild( wktElement );
2103 QDomElement proj4Element = doc.createElement( QStringLiteral(
"proj4" ) );
2104 proj4Element.appendChild( doc.createTextNode(
toProj() ) );
2105 srsElement.appendChild( proj4Element );
2107 QDomElement srsIdElement = doc.createElement( QStringLiteral(
"srsid" ) );
2108 srsIdElement.appendChild( doc.createTextNode( QString::number(
srsid() ) ) );
2109 srsElement.appendChild( srsIdElement );
2111 QDomElement sridElement = doc.createElement( QStringLiteral(
"srid" ) );
2112 sridElement.appendChild( doc.createTextNode( QString::number(
postgisSrid() ) ) );
2113 srsElement.appendChild( sridElement );
2115 QDomElement authidElement = doc.createElement( QStringLiteral(
"authid" ) );
2116 authidElement.appendChild( doc.createTextNode(
authid() ) );
2117 srsElement.appendChild( authidElement );
2119 QDomElement descriptionElement = doc.createElement( QStringLiteral(
"description" ) );
2120 descriptionElement.appendChild( doc.createTextNode(
description() ) );
2121 srsElement.appendChild( descriptionElement );
2123 QDomElement projectionAcronymElement = doc.createElement( QStringLiteral(
"projectionacronym" ) );
2124 projectionAcronymElement.appendChild( doc.createTextNode(
projectionAcronym() ) );
2125 srsElement.appendChild( projectionAcronymElement );
2127 QDomElement ellipsoidAcronymElement = doc.createElement( QStringLiteral(
"ellipsoidacronym" ) );
2128 ellipsoidAcronymElement.appendChild( doc.createTextNode(
ellipsoidAcronym() ) );
2129 srsElement.appendChild( ellipsoidAcronymElement );
2131 QDomElement geographicFlagElement = doc.createElement( QStringLiteral(
"geographicflag" ) );
2132 QString geoFlagText = QStringLiteral(
"false" );
2135 geoFlagText = QStringLiteral(
"true" );
2138 geographicFlagElement.appendChild( doc.createTextNode( geoFlagText ) );
2139 srsElement.appendChild( geographicFlagElement );
2141 layerNode.appendChild( srsElement );
2153 QString QgsCoordinateReferenceSystem::projFromSrsId(
const int srsId )
2155 QString myDatabaseFileName;
2156 QString myProjString;
2157 QString mySql = QStringLiteral(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( srsId );
2166 QFileInfo myFileInfo;
2167 myFileInfo.setFile( myDatabaseFileName );
2168 if ( !myFileInfo.exists() )
2170 QgsDebugMsg( QStringLiteral(
"users qgis.db not found" ) );
2183 rc = openDatabase( myDatabaseFileName, database );
2189 statement = database.
prepare( mySql, rc );
2191 if ( rc == SQLITE_OK )
2193 if ( statement.
step() == SQLITE_ROW )
2199 return myProjString;
2206 myResult = database.
open_v2( path, SQLITE_OPEN_READONLY,
nullptr );
2208 myResult = database.
open( path );
2210 if ( myResult != SQLITE_OK )
2219 .arg( database.
errorMessage() ), QObject::tr(
"CRS" ) );
2226 sCustomSrsValidation = f;
2231 return sCustomSrsValidation;
2234 void QgsCoordinateReferenceSystem::debugPrint()
2236 QgsDebugMsg( QStringLiteral(
"***SpatialRefSystem***" ) );
2237 QgsDebugMsg(
"* Valid : " + ( d->mIsValid ? QString(
"true" ) : QString(
"false" ) ) );
2238 QgsDebugMsg(
"* SrsId : " + QString::number( d->mSrsId ) );
2244 QgsDebugMsg( QStringLiteral(
"* Units : meters" ) );
2248 QgsDebugMsg( QStringLiteral(
"* Units : feet" ) );
2252 QgsDebugMsg( QStringLiteral(
"* Units : degrees" ) );
2258 mValidationHint = html;
2263 return mValidationHint;
2279 QString proj4String = d->mProj4;
2280 if ( proj4String.isEmpty() )
2294 if ( getRecordCount() == 0 )
2296 mySql =
"insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo,wkt) values ("
2300 +
',' + quotedEllipsoidString
2308 mySql =
"insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo,wkt) values ("
2311 +
',' + quotedEllipsoidString
2321 if ( myResult != SQLITE_OK )
2323 QgsDebugMsg( QStringLiteral(
"Can't open or create database %1: %2" )
2328 statement = database.
prepare( mySql, myResult );
2330 qint64 returnId = -1;
2331 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_DONE )
2335 returnId = sqlite3_last_insert_rowid( database.get() );
2336 d->mSrsId = returnId;
2337 if (
authid().isEmpty() )
2338 d->mAuthId = QStringLiteral(
"USER:%1" ).arg( returnId );
2339 d->mDescription = name;
2346 long QgsCoordinateReferenceSystem::getRecordCount()
2351 long myRecordCount = 0;
2354 if ( myResult != SQLITE_OK )
2360 QString mySql = QStringLiteral(
"select count(*) from tbl_srs" );
2361 statement = database.
prepare( mySql, myResult );
2362 if ( myResult == SQLITE_OK )
2364 if ( statement.
step() == SQLITE_ROW )
2366 QString myRecordCountString = statement.
columnAsText( 0 );
2367 myRecordCount = myRecordCountString.toLong();
2370 return myRecordCount;
2373 #if PROJ_VERSION_MAJOR>=6
2374 bool testIsGeographic( PJ *
crs )
2377 bool isGeographic =
false;
2378 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( pjContext,
crs ) );
2379 if ( coordinateSystem )
2381 const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
2382 if ( axisCount > 0 )
2384 const char *outUnitAuthName =
nullptr;
2385 const char *outUnitAuthCode =
nullptr;
2387 proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
2396 if ( outUnitAuthName && outUnitAuthCode )
2398 const char *unitCategory =
nullptr;
2399 if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode,
nullptr,
nullptr, &unitCategory ) )
2401 isGeographic = QString( unitCategory ).compare( QLatin1String(
"angular" ), Qt::CaseInsensitive ) == 0;
2406 return isGeographic;
2409 void getOperationAndEllipsoidFromProjString(
const QString &proj, QString &operation, QString &ellipsoid )
2411 QRegExp projRegExp(
"\\+proj=(\\S+)" );
2412 if ( projRegExp.indexIn( proj ) < 0 )
2414 QgsDebugMsgLevel( QStringLiteral(
"no +proj argument found [%2]" ).arg( proj ), 2 );
2417 operation = projRegExp.cap( 1 );
2419 QRegExp ellipseRegExp(
"\\+(?:ellps|datum)=(\\S+)" );
2421 if ( ellipseRegExp.indexIn( proj ) >= 0 )
2423 ellipsoid = ellipseRegExp.cap( 1 );
2437 bool QgsCoordinateReferenceSystem::loadFromAuthCode(
const QString &auth,
const QString &code )
2440 d->mIsValid =
false;
2441 d->mWktPreferred.clear();
2444 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database( pjContext, auth.toUtf8().constData(), code.toUtf8().constData(), PJ_CATEGORY_CRS,
false,
nullptr ) );
2450 switch ( proj_get_type(
crs.get() ) )
2452 case PJ_TYPE_VERTICAL_CRS:
2459 crs = QgsProjUtils::crsToSingleCrs(
crs.get() );
2461 QString proj4 = getFullProjString(
crs.get() );
2462 proj4.replace( QStringLiteral(
"+type=crs" ), QString() );
2463 proj4 = proj4.trimmed();
2467 d->mWktPreferred.clear();
2468 d->mDescription = QString( proj_get_name(
crs.get() ) );
2469 d->mAuthId = QStringLiteral(
"%1:%2" ).arg( auth, code );
2470 d->mIsGeographic = testIsGeographic(
crs.get() );
2471 d->mAxisInvertedDirty =
true;
2474 getOperationAndEllipsoidFromProjString( proj4, operation, ellipsoid );
2475 d->mProjectionAcronym = operation;
2476 d->mEllipsoidAcronym.clear();
2477 d->setPj( std::move(
crs ) );
2479 const QString dbVals = sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( auth, code ).toUpper() );
2482 if ( !dbVals.isEmpty() )
2484 const QStringList parts = dbVals.split(
',' );
2485 d->mSrsId = parts.at( 0 ).toInt();
2486 d->mSRID = parts.at( 1 ).toInt();
2494 QList<long> QgsCoordinateReferenceSystem::userSrsIds()
2496 QList<long> results;
2500 QFileInfo myInfo( db );
2501 if ( !myInfo.exists() )
2503 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
2511 int result = openDatabase( db, database );
2512 if ( result != SQLITE_OK )
2514 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
2518 QString sql = QStringLiteral(
"select srs_id from tbl_srs where srs_id >= %1" ).arg(
USER_CRS_START_ID );
2520 statement = database.
prepare( sql, rc );
2523 int ret = statement.
step();
2525 if ( ret == SQLITE_DONE )
2531 if ( ret == SQLITE_ROW )
2537 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
2545 long QgsCoordinateReferenceSystem::matchToUserCrs()
const
2547 PJ *obj = d->threadLocalProjObject();
2551 const QList< long > ids = userSrsIds();
2552 for (
long id : ids )
2555 if ( candidate.projObject() && proj_is_equivalent_to( obj, candidate.projObject(), PJ_COMP_EQUIVALENT ) )
2564 #if PROJ_VERSION_MAJOR<6
2566 bool QgsCoordinateReferenceSystem::loadWkts( QHash<int, QString> &wkts,
const char *filename )
2569 const char *pszFilename = CPLFindFile(
"gdal", filename );
2573 QFile csv( pszFilename );
2574 if ( !csv.open( QIODevice::ReadOnly ) )
2577 QTextStream lines( &csv );
2581 QString line = lines.readLine();
2582 if ( line.isNull() )
2585 if ( line.trimmed().isEmpty() || line.startsWith(
'#' ) )
2589 else if ( line.startsWith( QLatin1String(
"include " ) ) )
2591 if ( !loadWkts( wkts, line.mid( 8 ).toUtf8() ) )
2596 int pos = line.indexOf(
',' );
2601 int epsg = line.leftRef( pos ).toInt( &ok );
2605 wkts.insert( epsg, line.mid( pos + 1 ) );
2614 bool QgsCoordinateReferenceSystem::loadIds( QHash<int, QString> &wkts )
2618 static const QStringList csvs { QStringList() << QStringLiteral(
"gcs.csv" ) << QStringLiteral(
"pcs.csv" ) << QStringLiteral(
"vertcs.csv" ) << QStringLiteral(
"compdcs.csv" ) << QStringLiteral(
"geoccs.csv" ) };
2619 for (
const QString &csv : csvs )
2621 QString filename = CPLFindFile(
"gdal", csv.toUtf8() );
2623 QFile f( filename );
2624 if ( !f.open( QIODevice::ReadOnly ) )
2627 QTextStream lines( &f );
2634 QString line = lines.readLine();
2635 if ( line.isNull() )
2638 if ( line.trimmed().isEmpty() )
2641 int pos = line.indexOf(
',' );
2644 qWarning(
"No id found in: %s", qPrintable( line ) );
2649 int epsg = line.leftRef( pos ).toInt( &ok );
2652 qWarning(
"No valid id found in: %s", qPrintable( line ) );
2657 if ( epsg == 2218 || epsg == 2221 || epsg == 2296 || epsg == 2297 || epsg == 2298 || epsg == 2299 || epsg == 2300 || epsg == 2301 || epsg == 2302 ||
2658 epsg == 2303 || epsg == 2304 || epsg == 2305 || epsg == 2306 || epsg == 2307 || epsg == 2963 || epsg == 2985 || epsg == 2986 || epsg == 3052 ||
2659 epsg == 3053 || epsg == 3139 || epsg == 3144 || epsg == 3145 || epsg == 3173 || epsg == 3295 || epsg == 3993 || epsg == 4087 || epsg == 4088 ||
2660 epsg == 5017 || epsg == 5221 || epsg == 5224 || epsg == 5225 || epsg == 5514 || epsg == 5515 || epsg == 5516 || epsg == 5819 || epsg == 5820 ||
2661 epsg == 5821 || epsg == 6200 || epsg == 6201 || epsg == 6202 || epsg == 6244 || epsg == 6245 || epsg == 6246 || epsg == 6247 || epsg == 6248 ||
2662 epsg == 6249 || epsg == 6250 || epsg == 6251 || epsg == 6252 || epsg == 6253 || epsg == 6254 || epsg == 6255 || epsg == 6256 || epsg == 6257 ||
2663 epsg == 6258 || epsg == 6259 || epsg == 6260 || epsg == 6261 || epsg == 6262 || epsg == 6263 || epsg == 6264 || epsg == 6265 || epsg == 6266 ||
2664 epsg == 6267 || epsg == 6268 || epsg == 6269 || epsg == 6270 || epsg == 6271 || epsg == 6272 || epsg == 6273 || epsg == 6274 || epsg == 6275 ||
2665 epsg == 6966 || epsg == 7082 || epsg == 32600 || epsg == 32663 || epsg == 32700 )
2668 if ( OSRImportFromEPSG(
crs, epsg ) != OGRERR_NONE )
2670 qDebug(
"EPSG %d: not imported", epsg );
2674 char *wkt =
nullptr;
2675 if ( OSRExportToWkt(
crs, &wkt ) != OGRERR_NONE )
2677 qWarning(
"EPSG %d: not exported to WKT", epsg );
2681 wkts.insert( epsg, wkt );
2689 QgsDebugMsgLevel( QStringLiteral(
"Loaded %1/%2 from %3" ).arg( QString::number( n ), QString::number( l ), filename.toUtf8().constData() ), 4 );
2692 OSRDestroySpatialReference(
crs );
2698 #if PROJ_VERSION_MAJOR>=6
2699 static void sync_db_proj_logger(
void * ,
int level,
const char *message )
2704 if ( level == PJ_LOG_ERROR )
2708 else if ( level == PJ_LOG_DEBUG )
2717 setlocale( LC_ALL,
"C" );
2720 #if PROJ_VERSION_MAJOR<6
2721 syncDatumTransform( dbFilePath );
2724 int inserted = 0, updated = 0, deleted = 0, errors = 0;
2729 if ( database.
open( dbFilePath ) != SQLITE_OK )
2735 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2743 char *errMsg =
nullptr;
2745 #if PROJ_VERSION_MAJOR<6
2747 if ( sqlite3_exec( database.get(),
"alter table tbl_srs add noupdate boolean",
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
2748 ( 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 );
2750 ( 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 );
2752 if ( sqlite3_exec( database.get(),
"create table tbl_info (proj_major INT, proj_minor INT, proj_patch INT)",
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2754 QString sql = QStringLiteral(
"INSERT INTO tbl_info(proj_major, proj_minor, proj_patch) VALUES (%1, %2,%3)" )
2755 .arg( QString::number( PROJ_VERSION_MAJOR ),
2756 QString::number( PROJ_VERSION_MINOR ),
2757 QString::number( PROJ_VERSION_PATCH ) );
2758 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2760 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2763 errMsg ? errMsg :
"(unknown error)" ) );
2765 sqlite3_free( errMsg );
2772 QString sql = QStringLiteral(
"SELECT proj_major, proj_minor, proj_patch FROM tbl_info" );
2773 statement = database.
prepare( sql, result );
2774 if ( result != SQLITE_OK )
2779 if ( statement.
step() == SQLITE_ROW )
2784 if ( major == PROJ_VERSION_MAJOR && minor == PROJ_VERSION_MINOR && patch == PROJ_VERSION_PATCH )
2790 QgsDebugMsg( QStringLiteral(
"Could not retrieve previous CRS sync PROJ version number" ) );
2797 #if PROJ_VERSION_MAJOR>=6
2800 proj_log_func( pjContext,
nullptr, sync_db_proj_logger );
2802 PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
2804 int nextSrsId = 63321;
2805 int nextSrId = 520003321;
2806 for (
auto authIter = authorities; authIter && *authIter; ++authIter )
2808 const QString authority( *authIter );
2809 QgsDebugMsgLevel( QStringLiteral(
"Loading authority '%1'" ).arg( authority ), 2 );
2810 PROJ_STRING_LIST codes = proj_get_codes_from_database( pjContext, *authIter, PJ_TYPE_CRS,
true );
2812 QStringList allCodes;
2814 for (
auto codesIter = codes; codesIter && *codesIter; ++codesIter )
2816 const QString code( *codesIter );
2819 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database( pjContext, *authIter, *codesIter, PJ_CATEGORY_CRS,
false,
nullptr ) );
2822 QgsDebugMsg( QStringLiteral(
"Could not load '%1:%2'" ).arg( authority, code ) );
2826 switch ( proj_get_type(
crs.get() ) )
2828 case PJ_TYPE_VERTICAL_CRS:
2835 crs = QgsProjUtils::crsToSingleCrs(
crs.get() );
2837 QString proj4 = getFullProjString(
crs.get() );
2838 proj4.replace( QStringLiteral(
"+type=crs" ), QString() );
2839 proj4 = proj4.trimmed();
2841 if ( proj4.isEmpty() )
2843 QgsDebugMsgLevel( QStringLiteral(
"No proj4 for '%1:%2'" ).arg( authority, code ), 2 );
2848 const bool deprecated = proj_is_deprecated(
crs.get() );
2849 const QString name( proj_get_name(
crs.get() ) );
2851 QString sql = QStringLiteral(
"SELECT parameters,description,deprecated FROM tbl_srs WHERE auth_name='%1' AND auth_id='%2'" ).arg( authority, code );
2852 statement = database.
prepare( sql, result );
2853 if ( result != SQLITE_OK )
2861 bool srsDeprecated = deprecated;
2862 if ( statement.
step() == SQLITE_ROW )
2866 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2869 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
2871 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
2874 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name=%4 AND auth_id=%5" )
2877 .arg( deprecated ? 1 : 0 )
2880 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2882 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2885 errMsg ? errMsg :
"(unknown error)" ) );
2887 sqlite3_free( errMsg );
2899 QString operation =
"";
2901 getOperationAndEllipsoidFromProjString( proj4, operation, ellps );
2905 const QString dbVals = sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( authority, code ) );
2908 if ( !dbVals.isEmpty() )
2910 const QStringList parts = dbVals.split(
',' );
2911 srsId = parts.at( 0 );
2912 srId = parts.at( 1 );
2914 if ( srId.isEmpty() )
2916 srId = QString::number( nextSrId );
2919 if ( srsId.isEmpty() )
2921 srsId = QString::number( nextSrsId );
2925 if ( !srsId.isEmpty() )
2927 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)" )
2937 .arg( deprecated ? 1 : 0 );
2941 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)" )
2950 .arg( deprecated ? 1 : 0 );
2954 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2960 qCritical(
"Could not execute: %s [%s/%s]\n",
2961 sql.toLocal8Bit().constData(),
2962 sqlite3_errmsg( database.get() ),
2963 errMsg ? errMsg :
"(unknown error)" );
2967 sqlite3_free( errMsg );
2972 proj_string_list_destroy( codes );
2974 const QString sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='%1' AND NOT auth_id IN (%2)" ).arg( authority, allCodes.join(
',' ) );
2975 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
2977 deleted = sqlite3_changes( database.get() );
2982 qCritical(
"Could not execute: %s [%s]\n",
2983 sql.toLocal8Bit().constData(),
2984 sqlite3_errmsg( database.get() ) );
2988 proj_string_list_destroy( authorities );
2996 QHash<int, QString> wkts;
2998 loadWkts( wkts,
"epsg.wkt" );
3000 QgsDebugMsgLevel( QStringLiteral(
"%1 WKTs loaded" ).arg( wkts.count() ), 4 );
3002 for ( QHash<int, QString>::const_iterator it = wkts.constBegin(); it != wkts.constEnd(); ++it )
3004 QByteArray ba( it.value().toUtf8() );
3005 char *psz = ba.data();
3008 OSRDestroySpatialReference(
crs );
3010 crs = OSRNewSpatialReference(
nullptr );
3012 OGRErr ogrErr = OSRImportFromWkt(
crs, &psz );
3013 if ( ogrErr != OGRERR_NONE )
3016 if ( OSRExportToProj4(
crs, &psz ) != OGRERR_NONE )
3023 proj4 = proj4.trimmed();
3027 if ( proj4.isEmpty() )
3030 QString name( OSRIsGeographic(
crs ) ? OSRGetAttrValue(
crs,
"GEOGCS", 0 ) :
3031 OSRIsGeocentric(
crs ) ? OSRGetAttrValue(
crs,
"GEOCCS", 0 ) :
3032 OSRGetAttrValue(
crs,
"PROJCS", 0 ) );
3033 if ( name.isEmpty() )
3034 name = QObject::tr(
"Imported from GDAL" );
3036 bool deprecated = name.contains( QLatin1String(
"(deprecated)" ) );
3038 sql = QStringLiteral(
"SELECT parameters,description,deprecated,noupdate FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).arg( it.key() );
3039 statement = database.
prepare( sql, result );
3040 if ( result != SQLITE_OK )
3048 bool srsDeprecated = deprecated;
3049 if ( statement.
step() == SQLITE_ROW )
3053 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
3061 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
3063 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
3066 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name='EPSG' AND auth_id=%4" )
3069 .arg( deprecated ? 1 : 0 )
3072 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
3074 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
3077 errMsg ? errMsg :
"(unknown error)" ) );
3079 sqlite3_free( errMsg );
3090 QRegExp projRegExp(
"\\+proj=(\\S+)" );
3091 if ( projRegExp.indexIn( proj4 ) < 0 )
3093 QgsDebugMsgLevel( QStringLiteral(
"EPSG %1: no +proj argument found [%2]" ).arg( it.key() ).arg( proj4 ), 4 );
3097 QRegExp ellipseRegExp(
"\\+ellps=(\\S+)" );
3099 if ( ellipseRegExp.indexIn( proj4 ) >= 0 )
3101 ellps = ellipseRegExp.cap( 1 );
3113 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)" )
3119 .arg( OSRIsGeographic(
crs ) )
3120 .arg( deprecated ? 1 : 0 );
3123 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
3129 qCritical(
"Could not execute: %s [%s/%s]\n",
3130 sql.toLocal8Bit().constData(),
3131 sqlite3_errmsg( database.get() ),
3132 errMsg ? errMsg :
"(unknown error)" );
3136 sqlite3_free( errMsg );
3142 OSRDestroySpatialReference(
crs );
3145 sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN (" );
3147 QHash<int, QString>::const_iterator it = wkts.constBegin();
3148 for ( ; it != wkts.constEnd(); ++it )
3150 sql += delim + QString::number( it.key() );
3153 sql += QLatin1String(
") AND NOT noupdate" );
3155 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
3157 deleted = sqlite3_changes( database.get() );
3162 qCritical(
"Could not execute: %s [%s]\n",
3163 sql.toLocal8Bit().constData(),
3164 sqlite3_errmsg( database.get() ) );
3167 projCtx pContext = pj_ctx_alloc();
3169 #if !defined(PJ_VERSION) || PJ_VERSION!=470
3170 sql = QStringLiteral(
"select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated AND NOT noupdate" );
3171 statement = database.
prepare( sql, result );
3172 if ( result == SQLITE_OK )
3174 while ( statement.
step() == SQLITE_ROW )
3180 QString input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toLower(), auth_id );
3181 projPJ pj = pj_init_plus_ctx( pContext, input.toLatin1() );
3184 input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toUpper(), auth_id );
3185 pj = pj_init_plus_ctx( pContext, input.toLatin1() );
3190 char *def = pj_get_def( pj, 0 );
3196 input.prepend(
' ' ).append(
' ' );
3197 if ( proj4.startsWith( input ) )
3199 proj4 = proj4.mid( input.size() );
3200 proj4 = proj4.trimmed();
3203 if ( proj4 != params )
3205 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
3210 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
3216 qCritical(
"Could not execute: %s [%s/%s]\n",
3217 sql.toLocal8Bit().constData(),
3218 sqlite3_errmsg( database.get() ),
3219 errMsg ? errMsg :
"(unknown error)" );
3221 sqlite3_free( errMsg );
3228 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve proj string for %1 from PROJ" ).arg( input ), 4 );
3233 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve crs for %1 from PROJ" ).arg( input ), 3 );
3242 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2]\n" ).arg(
3244 sqlite3_errmsg( database.get() ) ) );
3248 pj_ctx_free( pContext );
3252 #if PROJ_VERSION_MAJOR>=6
3253 QString sql = QStringLiteral(
"UPDATE tbl_info set proj_major=%1,proj_minor=%2,proj_patch=%3" )
3254 .arg( QString::number( PROJ_VERSION_MAJOR ),
3255 QString::number( PROJ_VERSION_MINOR ),
3256 QString::number( PROJ_VERSION_PATCH ) );
3257 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
3259 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
3262 errMsg ? errMsg :
"(unknown error)" ) );
3264 sqlite3_free( errMsg );
3269 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
3271 QgsDebugMsg( QStringLiteral(
"Could not commit transaction: %1 [%2]\n" ).arg(
3273 sqlite3_errmsg( database.get() ) )
3279 QgsDebugMsgLevel( QStringLiteral(
"CRS update (inserted:%1 updated:%2 deleted:%3 errors:%4)" ).arg( inserted ).arg( updated ).arg( deleted ).arg( errors ), 4 );
3287 return updated + inserted;
3290 #if PROJ_VERSION_MAJOR<6
3291 bool QgsCoordinateReferenceSystem::syncDatumTransform(
const QString &dbPath )
3293 const char *filename = CSVFilename(
"datum_shift.csv" );
3294 FILE *fp = VSIFOpen( filename,
"rb" );
3300 char **fieldnames = CSVReadParseLine( fp );
3312 {
"SOURCE_CRS_CODE",
"source_crs_code", -1 },
3313 {
"TARGET_CRS_CODE",
"target_crs_code", -1 },
3314 {
"REMARKS",
"remarks", -1 },
3315 {
"COORD_OP_SCOPE",
"scope", -1 },
3316 {
"AREA_OF_USE_CODE",
"area_of_use_code", -1 },
3322 {
"DEPRECATED",
"deprecated", -1 },
3323 {
"COORD_OP_METHOD_CODE",
"coord_op_method_code", -1 },
3331 {
"PREFERRED",
"preferred", -1 },
3332 {
"COORD_OP_CODE",
"coord_op_code", -1 },
3335 QString update = QStringLiteral(
"UPDATE tbl_datum_transform SET " );
3337 const int n = CSLCount( fieldnames );
3338 int idxid = -1, idxrx = -1, idxry = -1, idxrz = -1, idxmcode = -1;
3343 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
3345 bool last = i ==
sizeof( map ) /
sizeof( *map ) - 1;
3347 map[i].idx = CSLFindString( fieldnames, map[i].src );
3348 if ( map[i].idx < 0 )
3350 qWarning(
"field %s not found", map[i].src );
3351 CSLDestroy( fieldnames );
3356 if ( strcmp( map[i].src,
"COORD_OP_CODE" ) == 0 )
3358 if ( strcmp( map[i].src,
"RX" ) == 0 )
3360 if ( strcmp( map[i].src,
"RY" ) == 0 )
3362 if ( strcmp( map[i].src,
"RZ" ) == 0 )
3364 if ( strcmp( map[i].src,
"COORD_OP_METHOD_CODE" ) == 0 )
3374 update += QLatin1String(
" WHERE " );
3382 update += QStringLiteral(
"%1=%%2" ).arg( map[i].dst ).arg( i + 1 );
3384 insert += map[i].dst;
3385 values += QStringLiteral(
"%%1" ).arg( i + 1 );
3388 insert =
"INSERT INTO tbl_datum_transform(" + insert +
") VALUES (" + values +
')';
3390 Q_ASSERT( idxid >= 0 );
3391 Q_ASSERT( idxrx >= 0 );
3392 Q_ASSERT( idxry >= 0 );
3393 Q_ASSERT( idxrz >= 0 );
3396 CSLDestroy( fieldnames );
3399 int openResult = database.
open( dbPath );
3400 if ( openResult != SQLITE_OK )
3406 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
3414 v.reserve(
sizeof( map ) /
sizeof( *map ) );
3418 char **values = CSVReadParseLine( fp );
3424 if ( CSLCount( values ) == 0 )
3426 CSLDestroy( values );
3430 if ( CSLCount( values ) < n )
3432 qWarning(
"Only %d columns", CSLCount( values ) );
3433 CSLDestroy( values );
3437 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
3439 int idx = map[i].idx;
3440 Q_ASSERT( idx != -1 );
3441 Q_ASSERT( idx < n );
3444 CSLDestroy( values );
3447 if ( v.at( idxmcode ).compare( QLatin1String(
"'9607'" ) ) == 0 )
3449 v[ idxmcode ] = QStringLiteral(
"'9606'" );
3450 v[ idxrx ] =
'\'' +
qgsDoubleToString( -( v[ idxrx ].remove(
'\'' ).toDouble() ) ) +
'\'';
3451 v[ idxry ] =
'\'' +
qgsDoubleToString( -( v[ idxry ].remove(
'\'' ).toDouble() ) ) +
'\'';
3452 v[ idxrz ] =
'\'' +
qgsDoubleToString( -( v[ idxrz ].remove(
'\'' ).toDouble() ) ) +
'\'';
3458 QString sql = QStringLiteral(
"SELECT coord_op_code FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( v[ idxid ] );
3460 statement = database.
prepare( sql, prepareRes );
3461 if ( prepareRes != SQLITE_OK )
3464 if ( statement.
step() == SQLITE_ROW )
3469 sql = cOpCode.isEmpty() ? insert : update;
3470 for (
int i = 0; i < v.size(); i++ )
3472 sql = sql.arg( v[i] );
3475 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
3477 qCritical(
"SQL: %s", sql.toUtf8().constData() );
3478 qCritical(
"Error: %s", sqlite3_errmsg( database.get() ) );
3482 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
3492 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::stringCache()
3494 return *sStringCache();
3497 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::projCache()
3499 return *sProj4Cache();
3502 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::ogcCache()
3504 return *sOgcCache();
3507 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::wktCache()
3509 return *sWktCache();
3512 const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srIdCache()
3514 return *sSrIdCache();
3517 const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srsIdCache()
3519 return *sSrsIdCache();
3528 #if PROJ_VERSION_MAJOR>=6
3529 else if ( PJ *obj = d->threadLocalProjObject() )
3531 QgsProjUtils::proj_pj_unique_ptr geoCrs( proj_crs_get_geodetic_crs(
QgsProjContext::get(), obj ) );
3532 return geoCrs ? QStringLiteral(
"%1:%2" ).arg( proj_get_id_auth_name( geoCrs.get(), 0 ), proj_get_id_code( geoCrs.get(), 0 ) ) : QString();
3537 return OSRGetAuthorityName( d->mCRS,
"GEOGCS" ) + QStringLiteral(
":" ) + OSRGetAuthorityCode( d->mCRS,
"GEOGCS" );
3546 #if PROJ_VERSION_MAJOR>=6
3547 PJ *QgsCoordinateReferenceSystem::projObject()
const
3549 return d->threadLocalProjObject();
3555 QStringList projections;
3557 projections.reserve( res.size() );
3560 projections << QString::number(
crs.
srsid() );
3567 QList<QgsCoordinateReferenceSystem> res;
3571 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
3572 QStringList projectionsWkt = settings.
value( QStringLiteral(
"UI/recentProjectionsWkt" ) ).toStringList();
3573 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
3574 int max = std::max( projectionsAuthId.size(), std::max( projectionsProj4.size(), projectionsWkt.size() ) );
3576 for (
int i = 0; i < max; ++i )
3578 const QString proj = projectionsProj4.value( i );
3579 const QString wkt = projectionsWkt.value( i );
3580 const QString
authid = projectionsAuthId.value( i );
3603 recent.removeAll(
crs );
3604 recent.insert( 0,
crs );
3607 recent = recent.mid( 0, 10 );
3608 QStringList authids;
3609 authids.reserve( recent.size() );
3611 proj.reserve( recent.size() );
3613 wkt.reserve( recent.size() );
3616 authids <<
c.authid();
3622 settings.
setValue( QStringLiteral(
"UI/recentProjectionsAuthId" ), authids );
3623 settings.
setValue( QStringLiteral(
"UI/recentProjectionsWkt" ), wkt );
3624 settings.
setValue( QStringLiteral(
"UI/recentProjectionsProj4" ), proj );
3629 sSrIdCacheLock()->lockForWrite();
3630 if ( !sDisableSrIdCache )
3633 sDisableSrIdCache =
true;
3634 sSrIdCache()->clear();
3636 sSrIdCacheLock()->unlock();
3638 sOgcLock()->lockForWrite();
3639 if ( !sDisableOgcCache )
3642 sDisableOgcCache =
true;
3643 sOgcCache()->clear();
3645 sOgcLock()->unlock();
3647 sProj4CacheLock()->lockForWrite();
3648 if ( !sDisableProjCache )
3651 sDisableProjCache =
true;
3652 sProj4Cache()->clear();
3654 sProj4CacheLock()->unlock();
3656 sCRSWktLock()->lockForWrite();
3657 if ( !sDisableWktCache )
3660 sDisableWktCache =
true;
3661 sWktCache()->clear();
3663 sCRSWktLock()->unlock();
3665 sCRSSrsIdLock()->lockForWrite();
3666 if ( !sDisableSrsIdCache )
3669 sDisableSrsIdCache =
true;
3670 sSrsIdCache()->clear();
3672 sCRSSrsIdLock()->unlock();
3674 sCrsStringLock()->lockForWrite();
3675 if ( !sDisableStringCache )
3678 sDisableStringCache =
true;
3679 sStringCache()->clear();
3681 sCrsStringLock()->unlock();