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() )
696 setWktString( wkt,
false );
702 setProjString( d->mProj4 );
712 #if PROJ_VERSION_MAJOR>=6
713 void QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread(
PJ_CONTEXT *pj_context )
720 if ( !sDisableSrIdCache )
723 if ( !sDisableSrIdCache )
725 for (
auto it = sSrIdCache()->begin(); it != sSrIdCache()->end(); )
727 auto &v = it.value();
728 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
729 it = sSrIdCache()->erase( it );
735 if ( !sDisableOgcCache )
738 if ( !sDisableOgcCache )
740 for (
auto it = sOgcCache()->begin(); it != sOgcCache()->end(); )
742 auto &v = it.value();
743 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
744 it = sOgcCache()->erase( it );
750 if ( !sDisableProjCache )
753 if ( !sDisableProjCache )
755 for (
auto it = sProj4Cache()->begin(); it != sProj4Cache()->end(); )
757 auto &v = it.value();
758 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
759 it = sProj4Cache()->erase( it );
765 if ( !sDisableWktCache )
768 if ( !sDisableWktCache )
770 for (
auto it = sWktCache()->begin(); it != sWktCache()->end(); )
772 auto &v = it.value();
773 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
774 it = sWktCache()->erase( it );
780 if ( !sDisableSrsIdCache )
783 if ( !sDisableSrsIdCache )
785 for (
auto it = sSrsIdCache()->begin(); it != sSrsIdCache()->end(); )
787 auto &v = it.value();
788 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
789 it = sSrsIdCache()->erase( it );
795 if ( !sDisableStringCache )
798 if ( !sDisableStringCache )
800 for (
auto it = sStringCache()->begin(); it != sStringCache()->end(); )
802 auto &v = it.value();
803 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
804 it = sStringCache()->erase( it );
815 if ( d->mAxisInvertedDirty )
817 #if PROJ_VERSION_MAJOR>=6
818 d->mAxisInverted = QgsProjUtils::axisOrderIsSwapped( d->threadLocalProjObject() );
820 OGRAxisOrientation orientation;
821 OSRGetAxis( d->mCRS, OSRIsGeographic( d->mCRS ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
824 if ( orientation == OAO_Other && d->mAuthId.startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
828 if ( OSRImportFromEPSGA(
crs, d->mAuthId.midRef( 5 ).toInt() ) == OGRERR_NONE )
830 OSRGetAxis(
crs, OSRIsGeographic(
crs ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
833 OSRDestroySpatialReference(
crs );
836 d->mAxisInverted = orientation == OAO_North;
838 d->mAxisInvertedDirty =
false;
841 return d->mAxisInverted;
846 return createFromWktInternal( wkt, QString() );
849 bool QgsCoordinateReferenceSystem::createFromWktInternal(
const QString &wkt,
const QString &description )
857 if ( !sDisableWktCache )
859 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sWktCache()->constFind( wkt );
860 if ( crsIt != sWktCache()->constEnd() )
863 *
this = crsIt.value();
865 if ( !
description.isEmpty() && d->mDescription.isEmpty() )
870 sWktCache()->insert( wkt, *
this );
879 d->mWktPreferred.clear();
882 QgsDebugMsgLevel( QStringLiteral(
"theWkt is uninitialized, operation failed" ), 4 );
887 QgsCoordinateReferenceSystem::RecordMap record = getRecord(
"select * from tbl_srs where wkt=" +
QgsSqliteUtils::quotedString( wkt ) +
" order by deprecated" );
888 if ( !record.empty() )
890 long srsId = record[QStringLiteral(
"srs_id" )].toLong();
903 if ( d->mSrsId == 0 )
905 #if PROJ_VERSION_MAJOR>=6
907 long id = matchToUserCrs();
917 if ( !sDisableWktCache )
918 sWktCache()->insert( wkt, *
this );
936 if ( projString.isEmpty() )
941 if ( projString.trimmed().isEmpty() )
945 d->mWktPreferred.clear();
950 if ( !sDisableProjCache )
952 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sProj4Cache()->constFind( projString );
953 if ( crsIt != sProj4Cache()->constEnd() )
956 *
this = crsIt.value();
970 QString myProj4String = projString.trimmed();
971 myProj4String.remove( QStringLiteral(
"+type=crs" ) );
972 myProj4String = myProj4String.trimmed();
975 d->mWktPreferred.clear();
976 #if PROJ_VERSION_MAJOR>=6
980 const QString projCrsString = myProj4String + ( myProj4String.contains( QStringLiteral(
"+type=crs" ) ) ? QString() : QStringLiteral(
" +type=crs" ) );
981 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create(
QgsProjContext::get(), projCrsString.toLatin1().constData() ) );
988 const QString
authid = QStringLiteral(
"%1:%2" ).arg( authName, authCode );
992 if ( !sDisableProjCache )
993 sProj4Cache()->insert( projString, *
this );
1000 QgsCoordinateReferenceSystem::RecordMap myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
1002 if ( !myRecord.empty() )
1004 id = myRecord[QStringLiteral(
"srs_id" )].toLong();
1013 setProjString( myProj4String );
1016 id = matchToUserCrs();
1025 setProjString( myProj4String );
1029 Q_UNUSED( identify )
1031 QRegExp myProjRegExp(
"\\+proj=(\\S+)" );
1032 int myStart = myProjRegExp.indexIn( myProj4String );
1033 if ( myStart == -1 )
1036 if ( !sDisableProjCache )
1037 sProj4Cache()->insert( projString, *
this );
1042 d->mProjectionAcronym = myProjRegExp.cap( 1 );
1044 QRegExp myEllipseRegExp(
"\\+ellps=(\\S+)" );
1045 myStart = myEllipseRegExp.indexIn( myProj4String );
1046 if ( myStart == -1 )
1048 d->mEllipsoidAcronym.clear();
1052 d->mEllipsoidAcronym = myEllipseRegExp.cap( 1 );
1055 QRegExp myAxisRegExp(
"\\+a=(\\S+)" );
1056 myStart = myAxisRegExp.indexIn( myProj4String );
1059 QgsCoordinateReferenceSystem::RecordMap myRecord;
1065 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
1066 if ( myRecord.empty() )
1071 QRegExp myLat1RegExp(
"\\+lat_1=\\S+" );
1072 QRegExp myLat2RegExp(
"\\+lat_2=\\S+" );
1079 myStart1 = myLat1RegExp.indexIn( myProj4String, myStart1 );
1080 myStart2 = myLat2RegExp.indexIn( myProj4String, myStart2 );
1081 if ( myStart1 != -1 && myStart2 != -1 )
1083 myLength1 = myLat1RegExp.matchedLength();
1084 myLength2 = myLat2RegExp.matchedLength();
1089 if ( !lat1Str.isEmpty() && !lat2Str.isEmpty() )
1092 QString proj4StringModified = myProj4String;
1097 myStart2 = myLat2RegExp.indexIn( projString, myStart2 );
1099 QgsDebugMsgLevel( QStringLiteral(
"trying proj4string match with swapped lat_1,lat_2" ), 4 );
1100 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( proj4StringModified.trimmed() ) +
" order by deprecated" );
1104 if ( myRecord.empty() )
1111 QString sql = QStringLiteral(
"SELECT * FROM tbl_srs WHERE " );
1118 QStringList myParams;
1119 const QRegExp regExp(
"\\s+(?=\\+)" );
1121 const auto constSplit = myProj4String.split( regExp, QString::SkipEmptyParts );
1122 for (
const QString ¶m : constSplit )
1124 QString arg = QStringLiteral(
"' '||parameters||' ' LIKE %1" ).arg(
QgsSqliteUtils::quotedString( QStringLiteral(
"% %1 %" ).arg( param.trimmed() ) ) );
1125 if ( param.startsWith( QLatin1String(
"+datum=" ) ) )
1132 delim = QStringLiteral(
" AND " );
1133 myParams << param.trimmed();
1138 if ( !datum.isEmpty() )
1140 myRecord = getRecord( sql + delim + datum +
" order by deprecated" );
1143 if ( myRecord.empty() )
1146 myRecord = getRecord( sql +
" order by deprecated" );
1149 if ( !myRecord.empty() )
1152 QStringList foundParams;
1153 const auto constSplit = myRecord[
"parameters"].split( regExp, QString::SkipEmptyParts );
1154 for (
const QString ¶m : constSplit )
1156 if ( !param.startsWith( QLatin1String(
"+datum=" ) ) )
1157 foundParams << param.trimmed();
1163 if ( myParams != foundParams )
1170 if ( !myRecord.empty() )
1172 mySrsId = myRecord[QStringLiteral(
"srs_id" )].toLong();
1181 setProjString( myProj4String );
1191 d->mIsValid =
false;
1198 QgsDebugMsgLevel( QStringLiteral(
"Projection is not found in databases." ), 4 );
1200 setProjString( myProj4String );
1205 if ( !sDisableProjCache )
1206 sProj4Cache()->insert( projString, *
this );
1212 QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord(
const QString &sql )
1214 QString myDatabaseFileName;
1215 QgsCoordinateReferenceSystem::RecordMap myMap;
1216 QString myFieldName;
1217 QString myFieldValue;
1224 QFileInfo myInfo( myDatabaseFileName );
1225 if ( !myInfo.exists() )
1227 QgsDebugMsg(
"failed : " + myDatabaseFileName +
" does not exist!" );
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;
1250 if ( statement.
step() != SQLITE_DONE )
1252 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1254 #if PROJ_VERSION_MAJOR<6
1264 if ( myMap.empty() )
1267 QFileInfo myFileInfo;
1268 myFileInfo.setFile( myDatabaseFileName );
1269 if ( !myFileInfo.exists() )
1271 QgsDebugMsg( QStringLiteral(
"user qgis.db not found" ) );
1276 myResult = openDatabase( myDatabaseFileName, database );
1277 if ( myResult != SQLITE_OK )
1282 statement = database.
prepare( sql, myResult );
1284 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1288 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1290 myFieldName = statement.
columnName( myColNo );
1292 myMap[myFieldName] = myFieldValue;
1295 if ( statement.
step() != SQLITE_DONE )
1297 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1328 if ( d->mDescription.isNull() )
1334 return d->mDescription;
1340 if ( !
authid().isEmpty() )
1349 return isValid() ? QObject::tr(
"Custom CRS" ) : QObject::tr(
"Unknown CRS" );
1351 return QObject::tr(
"Custom CRS: %1" ).arg(
1354 else if ( !
toProj().isEmpty() )
1355 return QObject::tr(
"Custom CRS: %1" ).arg( type ==
MediumString ? (
toProj().left( 50 ) + QString( QChar( 0x2026 ) ) )
1363 if ( d->mProjectionAcronym.isNull() )
1369 return d->mProjectionAcronym;
1375 if ( d->mEllipsoidAcronym.isNull() )
1377 #if PROJ_VERSION_MAJOR>=6
1378 if ( PJ *obj = d->threadLocalProjObject() )
1380 QgsProjUtils::proj_pj_unique_ptr ellipsoid( proj_get_ellipsoid(
QgsProjContext::get(), obj ) );
1383 const QString ellipsoidAuthName( proj_get_id_auth_name( ellipsoid.get(), 0 ) );
1384 const QString ellipsoidAuthCode( proj_get_id_code( ellipsoid.get(), 0 ) );
1385 if ( !ellipsoidAuthName.isEmpty() && !ellipsoidAuthCode.isEmpty() )
1386 d->mEllipsoidAcronym = QStringLiteral(
"%1:%2" ).arg( ellipsoidAuthName, ellipsoidAuthCode );
1389 double semiMajor, semiMinor, invFlattening;
1390 int semiMinorComputed = 0;
1391 if ( proj_ellipsoid_get_parameters(
QgsProjContext::get(), ellipsoid.get(), &semiMajor, &semiMinor, &semiMinorComputed, &invFlattening ) )
1393 d->mEllipsoidAcronym = QStringLiteral(
"PARAMETER:%1:%2" ).arg(
qgsDoubleToString( semiMajor ),
1398 d->mEllipsoidAcronym.clear();
1403 return d->mEllipsoidAcronym;
1411 return d->mEllipsoidAcronym;
1425 if ( d->mProj4.isEmpty() )
1427 #if PROJ_VERSION_MAJOR>=6
1428 if ( PJ *obj = d->threadLocalProjObject() )
1430 d->mProj4 = getFullProjString( obj );
1433 char *proj4src =
nullptr;
1434 OSRExportToProj4( d->mCRS, &proj4src );
1435 d->mProj4 = proj4src;
1436 CPLFree( proj4src );
1440 return d->mProj4.trimmed();
1445 return d->mIsGeographic;
1453 return d->mMapUnits;
1461 #if PROJ_VERSION_MAJOR>=6
1462 PJ *obj = d->threadLocalProjObject();
1467 double southLat = 0;
1469 double northLat = 0;
1472 &westLon, &southLat, &eastLon, &northLat,
nullptr ) )
1491 int result = openDatabase( databaseFileName, database );
1492 if ( result != SQLITE_OK )
1497 QString sql = QStringLiteral(
"select west_bound_lon, north_bound_lat, east_bound_lon, south_bound_lat from tbl_bounds "
1500 statement = database.
prepare( sql, result );
1503 if ( result == SQLITE_OK )
1505 if ( statement.
step() == SQLITE_ROW )
1522 void QgsCoordinateReferenceSystem::setProjString(
const QString &proj4String )
1525 d->mProj4 = proj4String;
1526 d->mWktPreferred.clear();
1529 QString trimmed = proj4String.trimmed();
1531 #if PROJ_VERSION_MAJOR>=6
1532 trimmed += QLatin1String(
" +type=crs" );
1536 d->setPj( QgsProjUtils::proj_pj_unique_ptr( proj_create( ctx, trimmed.toLatin1().constData() ) ) );
1542 const int errNo = proj_context_errno( ctx );
1543 QgsDebugMsg( QStringLiteral(
"proj string rejected: %1" ).arg( proj_errno_string( errNo ) ) );
1545 d->mIsValid =
false;
1549 d->mEllipsoidAcronym.clear();
1553 OSRDestroySpatialReference( d->mCRS );
1554 d->mCRS = OSRNewSpatialReference(
nullptr );
1555 d->mIsValid = OSRImportFromProj4( d->mCRS, trimmed.toLatin1().constData() ) == OGRERR_NONE;
1561 projCtx pContext = pj_ctx_alloc();
1562 projPJ proj = pj_init_plus_ctx( pContext, proj4String.trimmed().toLatin1().constData() );
1565 QgsDebugMsgLevel( QStringLiteral(
"proj.4 string rejected by pj_init_plus_ctx()" ), 4 );
1566 d->mIsValid =
false;
1572 pj_ctx_free( pContext );
1578 bool QgsCoordinateReferenceSystem::setWktString(
const QString &wkt,
bool allowProjFallback )
1581 d->mIsValid =
false;
1582 d->mWktPreferred.clear();
1584 #if PROJ_VERSION_MAJOR>=6
1586 ( void )allowProjFallback;
1588 PROJ_STRING_LIST warnings =
nullptr;
1589 PROJ_STRING_LIST grammerErrors =
nullptr;
1591 d->setPj( QgsProjUtils::proj_pj_unique_ptr( proj_create_from_wkt(
QgsProjContext::get(), wkt.toLatin1().constData(),
nullptr, &warnings, &grammerErrors ) ) );
1597 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
1598 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
1600 for (
auto iter = warnings; iter && *iter; ++iter )
1602 for (
auto iter = grammerErrors; iter && *iter; ++iter )
1604 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
1606 proj_string_list_destroy( warnings );
1607 proj_string_list_destroy( grammerErrors );
1609 QByteArray ba = wkt.toLatin1();
1610 const char *pWkt = ba.data();
1612 OGRErr myInputResult = OSRImportFromWkt( d->mCRS,
const_cast< char **
>( & pWkt ) );
1613 res = myInputResult == OGRERR_NONE;
1616 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
1617 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
1619 QgsDebugMsg( QStringLiteral(
"UNUSED WKT: %1" ).arg( pWkt ) );
1620 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
1632 if ( !sDisableWktCache )
1633 sWktCache()->insert( wkt, *
this );
1637 #if PROJ_VERSION_MAJOR>=6
1641 QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
1642 QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
1644 if ( authName.isEmpty() || authCode.isEmpty() )
1647 QgsProjUtils::identifyCrs( d->threadLocalProjObject(), authName, authCode );
1650 if ( !authName.isEmpty() && !authCode.isEmpty() )
1652 if ( loadFromAuthCode( authName, authCode ) )
1655 if ( !sDisableWktCache )
1656 sWktCache()->insert( wkt, *
this );
1664 d->mDescription = QString( proj_get_name( d->threadLocalProjObject() ) );
1669 if ( OSRAutoIdentifyEPSG( d->mCRS ) == OGRERR_NONE )
1671 QString
authid = QStringLiteral(
"%1:%2" )
1672 .arg( OSRGetAuthorityName( d->mCRS,
nullptr ),
1673 OSRGetAuthorityCode( d->mCRS,
nullptr ) );
1676 if ( !sDisableWktCache )
1677 sWktCache()->insert( wkt, *
this );
1686 #if PROJ_VERSION_MAJOR<6
1687 if ( allowProjFallback )
1689 d->mIsValid =
false;
1691 char *proj4src =
nullptr;
1692 OSRExportToProj4( d->mCRS, &proj4src );
1699 CPLFree( proj4src );
1701 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0)
1703 OSRFixup( d->mCRS );
1706 OSRExportToProj4( d->mCRS, &proj4src );
1710 CPLFree( proj4src );
1712 else if ( d->mIsValid )
1720 void QgsCoordinateReferenceSystem::setMapUnits()
1728 #if PROJ_VERSION_MAJOR<6
1729 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0)
1732 OSRFixup( d->mCRS );
1736 #if PROJ_VERSION_MAJOR>=6
1744 QgsProjUtils::proj_pj_unique_ptr
crs( QgsProjUtils::crsToSingleCrs( d->threadLocalProjObject() ) );
1745 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( context,
crs.get() ) );
1746 if ( !coordinateSystem )
1752 const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
1753 if ( axisCount > 0 )
1755 const char *outUnitName =
nullptr;
1757 proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
1766 const QString unitName( outUnitName );
1770 if ( unitName.compare( QLatin1String(
"degree" ), Qt::CaseInsensitive ) == 0 ||
1771 unitName.compare( QLatin1String(
"degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1772 unitName.compare( QLatin1String(
"degree minute second hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1773 unitName.compare( QLatin1String(
"degree minute" ), Qt::CaseInsensitive ) == 0 ||
1774 unitName.compare( QLatin1String(
"degree hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1775 unitName.compare( QLatin1String(
"degree minute hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1776 unitName.compare( QLatin1String(
"hemisphere degree" ), Qt::CaseInsensitive ) == 0 ||
1777 unitName.compare( QLatin1String(
"hemisphere degree minute" ), Qt::CaseInsensitive ) == 0 ||
1778 unitName.compare( QLatin1String(
"hemisphere degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1779 unitName.compare( QLatin1String(
"degree (supplier to define representation)" ), Qt::CaseInsensitive ) == 0 )
1781 else if ( unitName.compare( QLatin1String(
"metre" ), Qt::CaseInsensitive ) == 0
1782 || unitName.compare( QLatin1String(
"m" ), Qt::CaseInsensitive ) == 0
1783 || unitName.compare( QLatin1String(
"meter" ), Qt::CaseInsensitive ) == 0 )
1786 else if ( unitName.compare( QLatin1String(
"US survey foot" ), Qt::CaseInsensitive ) == 0 ||
1787 unitName.compare( QLatin1String(
"foot" ), Qt::CaseInsensitive ) == 0 )
1789 else if ( unitName.compare( QLatin1String(
"kilometre" ), Qt::CaseInsensitive ) == 0 )
1791 else if ( unitName.compare( QLatin1String(
"centimetre" ), Qt::CaseInsensitive ) == 0 )
1793 else if ( unitName.compare( QLatin1String(
"millimetre" ), Qt::CaseInsensitive ) == 0 )
1795 else if ( unitName.compare( QLatin1String(
"Statute mile" ), Qt::CaseInsensitive ) == 0 )
1797 else if ( unitName.compare( QLatin1String(
"nautical mile" ), Qt::CaseInsensitive ) == 0 )
1799 else if ( unitName.compare( QLatin1String(
"yard" ), Qt::CaseInsensitive ) == 0 )
1813 char *unitName =
nullptr;
1815 if ( OSRIsProjected( d->mCRS ) )
1817 double toMeter = OSRGetLinearUnits( d->mCRS, &unitName );
1818 QString unit( unitName );
1826 static const double SMALL_NUM = 1e-3;
1829 unit = QStringLiteral(
"Foot" );
1833 else if ( unit == QLatin1String(
"Foot" ) )
1842 OSRGetAngularUnits( d->mCRS, &unitName );
1843 QString unit( unitName );
1844 if ( unit == QLatin1String(
"degree" ) )
1857 if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
1860 QgsDebugMsgLevel(
"QgsCoordinateReferenceSystem::findMatchingProj will only "
1861 "work if prj acr ellipsoid acr and proj4string are set"
1862 " and the current projection is valid!", 4 );
1872 QString mySql = QString(
"select srs_id,parameters from tbl_srs where "
1873 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1880 myResult = openDatabase( myDatabaseFileName, database );
1881 if ( myResult != SQLITE_OK )
1886 statement = database.
prepare( mySql, myResult );
1887 if ( myResult == SQLITE_OK )
1890 while ( statement.
step() == SQLITE_ROW )
1894 if (
toProj() == myProj4String.trimmed() )
1896 return mySrsId.toLong();
1907 myResult = openDatabase( myDatabaseFileName, database );
1908 if ( myResult != SQLITE_OK )
1913 statement = database.
prepare( mySql, myResult );
1915 if ( myResult == SQLITE_OK )
1917 while ( statement.
step() == SQLITE_ROW )
1921 if (
toProj() == myProj4String.trimmed() )
1923 return mySrsId.toLong();
1937 if ( !d->mIsValid && !srs.d->mIsValid )
1940 if ( !d->mIsValid || !srs.d->mIsValid )
1943 if ( ( !d->mAuthId.isEmpty() || !srs.d->mAuthId.isEmpty() ) )
1944 return d->mAuthId == srs.d->mAuthId;
1951 return !( *
this == srs );
1956 #if PROJ_VERSION_MAJOR>=6
1957 if ( PJ *obj = d->threadLocalProjObject() )
1959 const bool isDefaultPreferredFormat = variant ==
WKT_PREFERRED && !multiline;
1960 if ( isDefaultPreferredFormat && !d->mWktPreferred.isEmpty() )
1963 return d->mWktPreferred;
1966 PJ_WKT_TYPE type = PJ_WKT1_GDAL;
1970 type = PJ_WKT1_GDAL;
1973 type = PJ_WKT1_ESRI;
1976 type = PJ_WKT2_2015;
1979 type = PJ_WKT2_2015_SIMPLIFIED;
1982 type = PJ_WKT2_2019;
1985 type = PJ_WKT2_2019_SIMPLIFIED;
1989 const QByteArray multiLineOption = QStringLiteral(
"MULTILINE=%1" ).arg( multiline ? QStringLiteral(
"YES" ) : QStringLiteral(
"NO" ) ).toLocal8Bit();
1990 const QByteArray indentatationWidthOption = QStringLiteral(
"INDENTATION_WIDTH=%1" ).arg( multiline ? QString::number( indentationWidth ) : QStringLiteral(
"0" ) ).toLocal8Bit();
1991 const char *
const options[] = {multiLineOption.constData(), indentatationWidthOption.constData(),
nullptr};
1994 if ( isDefaultPreferredFormat )
1997 d->mWktPreferred = res;
2005 Q_UNUSED( multiline )
2006 Q_UNUSED( indentationWidth )
2007 char *wkt =
nullptr;
2009 if ( OSRExportToWkt( d->mCRS, &wkt ) == OGRERR_NONE )
2022 QDomNode srsNode = node.namedItem( QStringLiteral(
"spatialrefsys" ) );
2024 if ( ! srsNode.isNull() )
2026 bool initialized =
false;
2029 long srsid = srsNode.namedItem( QStringLiteral(
"srsid" ) ).toElement().text().toLong( &ok );
2035 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
2036 if ( !node.isNull() )
2047 node = srsNode.namedItem( QStringLiteral(
"epsg" ) );
2048 if ( !node.isNull() )
2066 const QString
description = srsNode.namedItem( QStringLiteral(
"description" ) ).toElement().text();
2068 const QString wkt = srsNode.namedItem( QStringLiteral(
"wkt" ) ).toElement().text();
2069 initialized = createFromWktInternal( wkt,
description );
2074 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
2075 const QString proj4 = node.toElement().text();
2082 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
2083 const QString proj4 = node.toElement().text();
2084 if ( !proj4.trimmed().isEmpty() )
2085 setProjString( node.toElement().text() );
2087 node = srsNode.namedItem( QStringLiteral(
"srsid" ) );
2088 d->mSrsId = node.toElement().text().toLong();
2090 node = srsNode.namedItem( QStringLiteral(
"srid" ) );
2091 d->mSRID = node.toElement().text().toLong();
2093 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
2094 d->mAuthId = node.toElement().text();
2096 node = srsNode.namedItem( QStringLiteral(
"description" ) );
2097 d->mDescription = node.toElement().text();
2099 node = srsNode.namedItem( QStringLiteral(
"projectionacronym" ) );
2100 d->mProjectionAcronym = node.toElement().text();
2102 node = srsNode.namedItem( QStringLiteral(
"ellipsoidacronym" ) );
2103 d->mEllipsoidAcronym = node.toElement().text();
2105 node = srsNode.namedItem( QStringLiteral(
"geographicflag" ) );
2106 d->mIsGeographic = node.toElement().text().compare( QLatin1String(
"true" ) );
2108 d->mWktPreferred.clear();
2117 d =
new QgsCoordinateReferenceSystemPrivate();
2125 QDomElement layerNode = node.toElement();
2126 QDomElement srsElement = doc.createElement( QStringLiteral(
"spatialrefsys" ) );
2128 QDomElement wktElement = doc.createElement( QStringLiteral(
"wkt" ) );
2130 srsElement.appendChild( wktElement );
2132 QDomElement proj4Element = doc.createElement( QStringLiteral(
"proj4" ) );
2133 proj4Element.appendChild( doc.createTextNode(
toProj() ) );
2134 srsElement.appendChild( proj4Element );
2136 QDomElement srsIdElement = doc.createElement( QStringLiteral(
"srsid" ) );
2137 srsIdElement.appendChild( doc.createTextNode( QString::number(
srsid() ) ) );
2138 srsElement.appendChild( srsIdElement );
2140 QDomElement sridElement = doc.createElement( QStringLiteral(
"srid" ) );
2141 sridElement.appendChild( doc.createTextNode( QString::number(
postgisSrid() ) ) );
2142 srsElement.appendChild( sridElement );
2144 QDomElement authidElement = doc.createElement( QStringLiteral(
"authid" ) );
2145 authidElement.appendChild( doc.createTextNode(
authid() ) );
2146 srsElement.appendChild( authidElement );
2148 QDomElement descriptionElement = doc.createElement( QStringLiteral(
"description" ) );
2149 descriptionElement.appendChild( doc.createTextNode(
description() ) );
2150 srsElement.appendChild( descriptionElement );
2152 QDomElement projectionAcronymElement = doc.createElement( QStringLiteral(
"projectionacronym" ) );
2153 projectionAcronymElement.appendChild( doc.createTextNode(
projectionAcronym() ) );
2154 srsElement.appendChild( projectionAcronymElement );
2156 QDomElement ellipsoidAcronymElement = doc.createElement( QStringLiteral(
"ellipsoidacronym" ) );
2157 ellipsoidAcronymElement.appendChild( doc.createTextNode(
ellipsoidAcronym() ) );
2158 srsElement.appendChild( ellipsoidAcronymElement );
2160 QDomElement geographicFlagElement = doc.createElement( QStringLiteral(
"geographicflag" ) );
2161 QString geoFlagText = QStringLiteral(
"false" );
2164 geoFlagText = QStringLiteral(
"true" );
2167 geographicFlagElement.appendChild( doc.createTextNode( geoFlagText ) );
2168 srsElement.appendChild( geographicFlagElement );
2170 layerNode.appendChild( srsElement );
2182 QString QgsCoordinateReferenceSystem::projFromSrsId(
const int srsId )
2184 QString myDatabaseFileName;
2185 QString myProjString;
2186 QString mySql = QStringLiteral(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( srsId );
2195 QFileInfo myFileInfo;
2196 myFileInfo.setFile( myDatabaseFileName );
2197 if ( !myFileInfo.exists() )
2199 QgsDebugMsg( QStringLiteral(
"users qgis.db not found" ) );
2212 rc = openDatabase( myDatabaseFileName, database );
2218 statement = database.
prepare( mySql, rc );
2220 if ( rc == SQLITE_OK )
2222 if ( statement.
step() == SQLITE_ROW )
2228 return myProjString;
2235 myResult = database.
open_v2( path, SQLITE_OPEN_READONLY,
nullptr );
2237 myResult = database.
open( path );
2239 if ( myResult != SQLITE_OK )
2248 .arg( database.
errorMessage() ), QObject::tr(
"CRS" ) );
2255 sCustomSrsValidation = f;
2260 return sCustomSrsValidation;
2263 void QgsCoordinateReferenceSystem::debugPrint()
2265 QgsDebugMsg( QStringLiteral(
"***SpatialRefSystem***" ) );
2266 QgsDebugMsg(
"* Valid : " + ( d->mIsValid ? QString(
"true" ) : QString(
"false" ) ) );
2267 QgsDebugMsg(
"* SrsId : " + QString::number( d->mSrsId ) );
2273 QgsDebugMsg( QStringLiteral(
"* Units : meters" ) );
2277 QgsDebugMsg( QStringLiteral(
"* Units : feet" ) );
2281 QgsDebugMsg( QStringLiteral(
"* Units : degrees" ) );
2287 mValidationHint = html;
2292 return mValidationHint;
2308 QString proj4String = d->mProj4;
2309 if ( proj4String.isEmpty() )
2323 if ( getRecordCount() == 0 )
2325 mySql =
"insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo,wkt) values ("
2329 +
',' + quotedEllipsoidString
2337 mySql =
"insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo,wkt) values ("
2340 +
',' + quotedEllipsoidString
2350 if ( myResult != SQLITE_OK )
2352 QgsDebugMsg( QStringLiteral(
"Can't open or create database %1: %2" )
2357 statement = database.
prepare( mySql, myResult );
2359 qint64 returnId = -1;
2360 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_DONE )
2364 returnId = sqlite3_last_insert_rowid( database.get() );
2365 d->mSrsId = returnId;
2366 if (
authid().isEmpty() )
2367 d->mAuthId = QStringLiteral(
"USER:%1" ).arg( returnId );
2368 d->mDescription = name;
2375 long QgsCoordinateReferenceSystem::getRecordCount()
2380 long myRecordCount = 0;
2383 if ( myResult != SQLITE_OK )
2389 QString mySql = QStringLiteral(
"select count(*) from tbl_srs" );
2390 statement = database.
prepare( mySql, myResult );
2391 if ( myResult == SQLITE_OK )
2393 if ( statement.
step() == SQLITE_ROW )
2395 QString myRecordCountString = statement.
columnAsText( 0 );
2396 myRecordCount = myRecordCountString.toLong();
2399 return myRecordCount;
2402 #if PROJ_VERSION_MAJOR>=6
2403 bool testIsGeographic( PJ *
crs )
2406 bool isGeographic =
false;
2407 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( pjContext,
crs ) );
2408 if ( coordinateSystem )
2410 const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
2411 if ( axisCount > 0 )
2413 const char *outUnitAuthName =
nullptr;
2414 const char *outUnitAuthCode =
nullptr;
2416 proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
2425 if ( outUnitAuthName && outUnitAuthCode )
2427 const char *unitCategory =
nullptr;
2428 if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode,
nullptr,
nullptr, &unitCategory ) )
2430 isGeographic = QString( unitCategory ).compare( QLatin1String(
"angular" ), Qt::CaseInsensitive ) == 0;
2435 return isGeographic;
2438 void getOperationAndEllipsoidFromProjString(
const QString &proj, QString &operation, QString &ellipsoid )
2440 QRegExp projRegExp(
"\\+proj=(\\S+)" );
2441 if ( projRegExp.indexIn( proj ) < 0 )
2443 QgsDebugMsgLevel( QStringLiteral(
"no +proj argument found [%2]" ).arg( proj ), 2 );
2446 operation = projRegExp.cap( 1 );
2448 QRegExp ellipseRegExp(
"\\+(?:ellps|datum)=(\\S+)" );
2450 if ( ellipseRegExp.indexIn( proj ) >= 0 )
2452 ellipsoid = ellipseRegExp.cap( 1 );
2466 bool QgsCoordinateReferenceSystem::loadFromAuthCode(
const QString &auth,
const QString &code )
2469 d->mIsValid =
false;
2470 d->mWktPreferred.clear();
2473 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database( pjContext, auth.toUtf8().constData(), code.toUtf8().constData(), PJ_CATEGORY_CRS,
false,
nullptr ) );
2479 switch ( proj_get_type(
crs.get() ) )
2481 case PJ_TYPE_VERTICAL_CRS:
2488 crs = QgsProjUtils::crsToSingleCrs(
crs.get() );
2490 QString proj4 = getFullProjString(
crs.get() );
2491 proj4.replace( QLatin1String(
"+type=crs" ), QString() );
2492 proj4 = proj4.trimmed();
2496 d->mWktPreferred.clear();
2497 d->mDescription = QString( proj_get_name(
crs.get() ) );
2498 d->mAuthId = QStringLiteral(
"%1:%2" ).arg( auth, code );
2499 d->mIsGeographic = testIsGeographic(
crs.get() );
2500 d->mAxisInvertedDirty =
true;
2503 getOperationAndEllipsoidFromProjString( proj4, operation, ellipsoid );
2504 d->mProjectionAcronym = operation;
2505 d->mEllipsoidAcronym.clear();
2506 d->setPj( std::move(
crs ) );
2508 const QString dbVals = sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( auth, code ).toUpper() );
2511 if ( !dbVals.isEmpty() )
2513 const QStringList parts = dbVals.split(
',' );
2514 d->mSrsId = parts.at( 0 ).toInt();
2515 d->mSRID = parts.at( 1 ).toInt();
2523 QList<long> QgsCoordinateReferenceSystem::userSrsIds()
2525 QList<long> results;
2529 QFileInfo myInfo( db );
2530 if ( !myInfo.exists() )
2532 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
2540 int result = openDatabase( db, database );
2541 if ( result != SQLITE_OK )
2543 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
2547 QString sql = QStringLiteral(
"select srs_id from tbl_srs where srs_id >= %1" ).arg(
USER_CRS_START_ID );
2549 statement = database.
prepare( sql, rc );
2552 int ret = statement.
step();
2554 if ( ret == SQLITE_DONE )
2560 if ( ret == SQLITE_ROW )
2566 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
2574 long QgsCoordinateReferenceSystem::matchToUserCrs()
const
2576 PJ *obj = d->threadLocalProjObject();
2580 const QList< long > ids = userSrsIds();
2581 for (
long id : ids )
2584 if ( candidate.projObject() && proj_is_equivalent_to( obj, candidate.projObject(), PJ_COMP_EQUIVALENT ) )
2593 #if PROJ_VERSION_MAJOR<6
2595 bool QgsCoordinateReferenceSystem::loadWkts( QHash<int, QString> &wkts,
const char *filename )
2598 const char *pszFilename = CPLFindFile(
"gdal", filename );
2602 QFile csv( pszFilename );
2603 if ( !csv.open( QIODevice::ReadOnly ) )
2606 QTextStream lines( &csv );
2610 QString line = lines.readLine();
2611 if ( line.isNull() )
2614 if ( line.trimmed().isEmpty() || line.startsWith(
'#' ) )
2618 else if ( line.startsWith( QLatin1String(
"include " ) ) )
2620 if ( !loadWkts( wkts, line.mid( 8 ).toUtf8() ) )
2625 int pos = line.indexOf(
',' );
2630 int epsg = line.leftRef( pos ).toInt( &ok );
2634 wkts.insert( epsg, line.mid( pos + 1 ) );
2643 bool QgsCoordinateReferenceSystem::loadIds( QHash<int, QString> &wkts )
2647 static const QStringList csvs { QStringList() << QStringLiteral(
"gcs.csv" ) << QStringLiteral(
"pcs.csv" ) << QStringLiteral(
"vertcs.csv" ) << QStringLiteral(
"compdcs.csv" ) << QStringLiteral(
"geoccs.csv" ) };
2648 for (
const QString &csv : csvs )
2650 QString filename = CPLFindFile(
"gdal", csv.toUtf8() );
2652 QFile f( filename );
2653 if ( !f.open( QIODevice::ReadOnly ) )
2656 QTextStream lines( &f );
2663 QString line = lines.readLine();
2664 if ( line.isNull() )
2667 if ( line.trimmed().isEmpty() )
2670 int pos = line.indexOf(
',' );
2673 qWarning(
"No id found in: %s", qPrintable( line ) );
2678 int epsg = line.leftRef( pos ).toInt( &ok );
2681 qWarning(
"No valid id found in: %s", qPrintable( line ) );
2686 if ( epsg == 2218 || epsg == 2221 || epsg == 2296 || epsg == 2297 || epsg == 2298 || epsg == 2299 || epsg == 2300 || epsg == 2301 || epsg == 2302 ||
2687 epsg == 2303 || epsg == 2304 || epsg == 2305 || epsg == 2306 || epsg == 2307 || epsg == 2963 || epsg == 2985 || epsg == 2986 || epsg == 3052 ||
2688 epsg == 3053 || epsg == 3139 || epsg == 3144 || epsg == 3145 || epsg == 3173 || epsg == 3295 || epsg == 3993 || epsg == 4087 || epsg == 4088 ||
2689 epsg == 5017 || epsg == 5221 || epsg == 5224 || epsg == 5225 || epsg == 5514 || epsg == 5515 || epsg == 5516 || epsg == 5819 || epsg == 5820 ||
2690 epsg == 5821 || epsg == 6200 || epsg == 6201 || epsg == 6202 || epsg == 6244 || epsg == 6245 || epsg == 6246 || epsg == 6247 || epsg == 6248 ||
2691 epsg == 6249 || epsg == 6250 || epsg == 6251 || epsg == 6252 || epsg == 6253 || epsg == 6254 || epsg == 6255 || epsg == 6256 || epsg == 6257 ||
2692 epsg == 6258 || epsg == 6259 || epsg == 6260 || epsg == 6261 || epsg == 6262 || epsg == 6263 || epsg == 6264 || epsg == 6265 || epsg == 6266 ||
2693 epsg == 6267 || epsg == 6268 || epsg == 6269 || epsg == 6270 || epsg == 6271 || epsg == 6272 || epsg == 6273 || epsg == 6274 || epsg == 6275 ||
2694 epsg == 6966 || epsg == 7082 || epsg == 32600 || epsg == 32663 || epsg == 32700 )
2697 if ( OSRImportFromEPSG(
crs, epsg ) != OGRERR_NONE )
2699 qDebug(
"EPSG %d: not imported", epsg );
2703 char *wkt =
nullptr;
2704 if ( OSRExportToWkt(
crs, &wkt ) != OGRERR_NONE )
2706 qWarning(
"EPSG %d: not exported to WKT", epsg );
2710 wkts.insert( epsg, wkt );
2718 QgsDebugMsgLevel( QStringLiteral(
"Loaded %1/%2 from %3" ).arg( QString::number( n ), QString::number( l ), filename.toUtf8().constData() ), 4 );
2721 OSRDestroySpatialReference(
crs );
2727 #if PROJ_VERSION_MAJOR>=6
2728 static void sync_db_proj_logger(
void * ,
int level,
const char *message )
2733 if ( level == PJ_LOG_ERROR )
2737 else if ( level == PJ_LOG_DEBUG )
2746 setlocale( LC_ALL,
"C" );
2749 #if PROJ_VERSION_MAJOR<6
2750 syncDatumTransform( dbFilePath );
2753 int inserted = 0, updated = 0, deleted = 0, errors = 0;
2758 if ( database.
open( dbFilePath ) != SQLITE_OK )
2764 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2772 char *errMsg =
nullptr;
2774 #if PROJ_VERSION_MAJOR<6
2776 if ( sqlite3_exec( database.get(),
"alter table tbl_srs add noupdate boolean",
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
2777 ( 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 );
2779 ( 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 );
2781 if ( sqlite3_exec( database.get(),
"create table tbl_info (proj_major INT, proj_minor INT, proj_patch INT)",
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2783 QString sql = QStringLiteral(
"INSERT INTO tbl_info(proj_major, proj_minor, proj_patch) VALUES (%1, %2,%3)" )
2784 .arg( QString::number( PROJ_VERSION_MAJOR ),
2785 QString::number( PROJ_VERSION_MINOR ),
2786 QString::number( PROJ_VERSION_PATCH ) );
2787 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2789 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2792 errMsg ? errMsg :
"(unknown error)" ) );
2794 sqlite3_free( errMsg );
2801 QString sql = QStringLiteral(
"SELECT proj_major, proj_minor, proj_patch FROM tbl_info" );
2802 statement = database.
prepare( sql, result );
2803 if ( result != SQLITE_OK )
2808 if ( statement.
step() == SQLITE_ROW )
2813 if ( major == PROJ_VERSION_MAJOR && minor == PROJ_VERSION_MINOR && patch == PROJ_VERSION_PATCH )
2819 QgsDebugMsg( QStringLiteral(
"Could not retrieve previous CRS sync PROJ version number" ) );
2826 #if PROJ_VERSION_MAJOR>=6
2829 proj_log_func( pjContext,
nullptr, sync_db_proj_logger );
2831 PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
2833 int nextSrsId = 63321;
2834 int nextSrId = 520003321;
2835 for (
auto authIter = authorities; authIter && *authIter; ++authIter )
2837 const QString authority( *authIter );
2838 QgsDebugMsgLevel( QStringLiteral(
"Loading authority '%1'" ).arg( authority ), 2 );
2839 PROJ_STRING_LIST codes = proj_get_codes_from_database( pjContext, *authIter, PJ_TYPE_CRS,
true );
2841 QStringList allCodes;
2843 for (
auto codesIter = codes; codesIter && *codesIter; ++codesIter )
2845 const QString code( *codesIter );
2848 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database( pjContext, *authIter, *codesIter, PJ_CATEGORY_CRS,
false,
nullptr ) );
2851 QgsDebugMsg( QStringLiteral(
"Could not load '%1:%2'" ).arg( authority, code ) );
2855 switch ( proj_get_type(
crs.get() ) )
2857 case PJ_TYPE_VERTICAL_CRS:
2864 crs = QgsProjUtils::crsToSingleCrs(
crs.get() );
2866 QString proj4 = getFullProjString(
crs.get() );
2867 proj4.replace( QLatin1String(
"+type=crs" ), QString() );
2868 proj4 = proj4.trimmed();
2870 if ( proj4.isEmpty() )
2872 QgsDebugMsgLevel( QStringLiteral(
"No proj4 for '%1:%2'" ).arg( authority, code ), 2 );
2877 const bool deprecated = proj_is_deprecated(
crs.get() );
2878 const QString name( proj_get_name(
crs.get() ) );
2880 QString sql = QStringLiteral(
"SELECT parameters,description,deprecated FROM tbl_srs WHERE auth_name='%1' AND auth_id='%2'" ).arg( authority, code );
2881 statement = database.
prepare( sql, result );
2882 if ( result != SQLITE_OK )
2890 bool srsDeprecated = deprecated;
2891 if ( statement.
step() == SQLITE_ROW )
2895 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2898 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
2900 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
2903 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name=%4 AND auth_id=%5" )
2906 .arg( deprecated ? 1 : 0 )
2909 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2911 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2914 errMsg ? errMsg :
"(unknown error)" ) );
2916 sqlite3_free( errMsg );
2928 QString operation =
"";
2930 getOperationAndEllipsoidFromProjString( proj4, operation, ellps );
2934 const QString dbVals = sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( authority, code ) );
2937 if ( !dbVals.isEmpty() )
2939 const QStringList parts = dbVals.split(
',' );
2940 srsId = parts.at( 0 );
2941 srId = parts.at( 1 );
2943 if ( srId.isEmpty() )
2945 srId = QString::number( nextSrId );
2948 if ( srsId.isEmpty() )
2950 srsId = QString::number( nextSrsId );
2954 if ( !srsId.isEmpty() )
2956 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)" )
2966 .arg( deprecated ? 1 : 0 );
2970 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)" )
2979 .arg( deprecated ? 1 : 0 );
2983 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2989 qCritical(
"Could not execute: %s [%s/%s]\n",
2990 sql.toLocal8Bit().constData(),
2991 sqlite3_errmsg( database.get() ),
2992 errMsg ? errMsg :
"(unknown error)" );
2996 sqlite3_free( errMsg );
3001 proj_string_list_destroy( codes );
3003 const QString sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='%1' AND NOT auth_id IN (%2)" ).arg( authority, allCodes.join(
',' ) );
3004 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
3006 deleted = sqlite3_changes( database.get() );
3011 qCritical(
"Could not execute: %s [%s]\n",
3012 sql.toLocal8Bit().constData(),
3013 sqlite3_errmsg( database.get() ) );
3017 proj_string_list_destroy( authorities );
3025 QHash<int, QString> wkts;
3027 loadWkts( wkts,
"epsg.wkt" );
3029 QgsDebugMsgLevel( QStringLiteral(
"%1 WKTs loaded" ).arg( wkts.count() ), 4 );
3031 for ( QHash<int, QString>::const_iterator it = wkts.constBegin(); it != wkts.constEnd(); ++it )
3033 QByteArray ba( it.value().toUtf8() );
3034 char *psz = ba.data();
3037 OSRDestroySpatialReference(
crs );
3039 crs = OSRNewSpatialReference(
nullptr );
3041 OGRErr ogrErr = OSRImportFromWkt(
crs, &psz );
3042 if ( ogrErr != OGRERR_NONE )
3045 if ( OSRExportToProj4(
crs, &psz ) != OGRERR_NONE )
3052 proj4 = proj4.trimmed();
3056 if ( proj4.isEmpty() )
3059 QString name( OSRIsGeographic(
crs ) ? OSRGetAttrValue(
crs,
"GEOGCS", 0 ) :
3060 OSRIsGeocentric(
crs ) ? OSRGetAttrValue(
crs,
"GEOCCS", 0 ) :
3061 OSRGetAttrValue(
crs,
"PROJCS", 0 ) );
3062 if ( name.isEmpty() )
3063 name = QObject::tr(
"Imported from GDAL" );
3065 bool deprecated = name.contains( QLatin1String(
"(deprecated)" ) );
3067 sql = QStringLiteral(
"SELECT parameters,description,deprecated,noupdate FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).arg( it.key() );
3068 statement = database.
prepare( sql, result );
3069 if ( result != SQLITE_OK )
3077 bool srsDeprecated = deprecated;
3078 if ( statement.
step() == SQLITE_ROW )
3082 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
3090 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
3092 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
3095 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name='EPSG' AND auth_id=%4" )
3098 .arg( deprecated ? 1 : 0 )
3101 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
3103 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
3106 errMsg ? errMsg :
"(unknown error)" ) );
3108 sqlite3_free( errMsg );
3119 QRegExp projRegExp(
"\\+proj=(\\S+)" );
3120 if ( projRegExp.indexIn( proj4 ) < 0 )
3122 QgsDebugMsgLevel( QStringLiteral(
"EPSG %1: no +proj argument found [%2]" ).arg( it.key() ).arg( proj4 ), 4 );
3126 QRegExp ellipseRegExp(
"\\+ellps=(\\S+)" );
3128 if ( ellipseRegExp.indexIn( proj4 ) >= 0 )
3130 ellps = ellipseRegExp.cap( 1 );
3142 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)" )
3148 .arg( OSRIsGeographic(
crs ) )
3149 .arg( deprecated ? 1 : 0 );
3152 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
3158 qCritical(
"Could not execute: %s [%s/%s]\n",
3159 sql.toLocal8Bit().constData(),
3160 sqlite3_errmsg( database.get() ),
3161 errMsg ? errMsg :
"(unknown error)" );
3165 sqlite3_free( errMsg );
3171 OSRDestroySpatialReference(
crs );
3174 sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN (" );
3176 QHash<int, QString>::const_iterator it = wkts.constBegin();
3177 for ( ; it != wkts.constEnd(); ++it )
3179 sql += delim + QString::number( it.key() );
3182 sql += QLatin1String(
") AND NOT noupdate" );
3184 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
3186 deleted = sqlite3_changes( database.get() );
3191 qCritical(
"Could not execute: %s [%s]\n",
3192 sql.toLocal8Bit().constData(),
3193 sqlite3_errmsg( database.get() ) );
3196 projCtx pContext = pj_ctx_alloc();
3198 #if !defined(PJ_VERSION) || PJ_VERSION!=470
3199 sql = QStringLiteral(
"select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated AND NOT noupdate" );
3200 statement = database.
prepare( sql, result );
3201 if ( result == SQLITE_OK )
3203 while ( statement.
step() == SQLITE_ROW )
3209 QString input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toLower(), auth_id );
3210 projPJ pj = pj_init_plus_ctx( pContext, input.toLatin1() );
3213 input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toUpper(), auth_id );
3214 pj = pj_init_plus_ctx( pContext, input.toLatin1() );
3219 char *def = pj_get_def( pj, 0 );
3225 input.prepend(
' ' ).append(
' ' );
3226 if ( proj4.startsWith( input ) )
3228 proj4 = proj4.mid( input.size() );
3229 proj4 = proj4.trimmed();
3232 if ( proj4 != params )
3234 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
3239 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
3245 qCritical(
"Could not execute: %s [%s/%s]\n",
3246 sql.toLocal8Bit().constData(),
3247 sqlite3_errmsg( database.get() ),
3248 errMsg ? errMsg :
"(unknown error)" );
3250 sqlite3_free( errMsg );
3257 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve proj string for %1 from PROJ" ).arg( input ), 4 );
3262 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve crs for %1 from PROJ" ).arg( input ), 3 );
3271 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2]\n" ).arg(
3273 sqlite3_errmsg( database.get() ) ) );
3277 pj_ctx_free( pContext );
3281 #if PROJ_VERSION_MAJOR>=6
3282 QString sql = QStringLiteral(
"UPDATE tbl_info set proj_major=%1,proj_minor=%2,proj_patch=%3" )
3283 .arg( QString::number( PROJ_VERSION_MAJOR ),
3284 QString::number( PROJ_VERSION_MINOR ),
3285 QString::number( PROJ_VERSION_PATCH ) );
3286 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
3288 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
3291 errMsg ? errMsg :
"(unknown error)" ) );
3293 sqlite3_free( errMsg );
3298 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
3300 QgsDebugMsg( QStringLiteral(
"Could not commit transaction: %1 [%2]\n" ).arg(
3302 sqlite3_errmsg( database.get() ) )
3308 QgsDebugMsgLevel( QStringLiteral(
"CRS update (inserted:%1 updated:%2 deleted:%3 errors:%4)" ).arg( inserted ).arg( updated ).arg( deleted ).arg( errors ), 4 );
3316 return updated + inserted;
3319 #if PROJ_VERSION_MAJOR<6
3320 bool QgsCoordinateReferenceSystem::syncDatumTransform(
const QString &dbPath )
3322 const char *filename = CSVFilename(
"datum_shift.csv" );
3323 FILE *fp = VSIFOpen( filename,
"rb" );
3329 char **fieldnames = CSVReadParseLine( fp );
3341 {
"SOURCE_CRS_CODE",
"source_crs_code", -1 },
3342 {
"TARGET_CRS_CODE",
"target_crs_code", -1 },
3343 {
"REMARKS",
"remarks", -1 },
3344 {
"COORD_OP_SCOPE",
"scope", -1 },
3345 {
"AREA_OF_USE_CODE",
"area_of_use_code", -1 },
3351 {
"DEPRECATED",
"deprecated", -1 },
3352 {
"COORD_OP_METHOD_CODE",
"coord_op_method_code", -1 },
3360 {
"PREFERRED",
"preferred", -1 },
3361 {
"COORD_OP_CODE",
"coord_op_code", -1 },
3364 QString update = QStringLiteral(
"UPDATE tbl_datum_transform SET " );
3366 const int n = CSLCount( fieldnames );
3367 int idxid = -1, idxrx = -1, idxry = -1, idxrz = -1, idxmcode = -1;
3372 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
3374 bool last = i ==
sizeof( map ) /
sizeof( *map ) - 1;
3376 map[i].idx = CSLFindString( fieldnames, map[i].src );
3377 if ( map[i].idx < 0 )
3379 qWarning(
"field %s not found", map[i].src );
3380 CSLDestroy( fieldnames );
3385 if ( strcmp( map[i].src,
"COORD_OP_CODE" ) == 0 )
3387 if ( strcmp( map[i].src,
"RX" ) == 0 )
3389 if ( strcmp( map[i].src,
"RY" ) == 0 )
3391 if ( strcmp( map[i].src,
"RZ" ) == 0 )
3393 if ( strcmp( map[i].src,
"COORD_OP_METHOD_CODE" ) == 0 )
3403 update += QLatin1String(
" WHERE " );
3411 update += QStringLiteral(
"%1=%%2" ).arg( map[i].dst ).arg( i + 1 );
3413 insert += map[i].dst;
3414 values += QStringLiteral(
"%%1" ).arg( i + 1 );
3417 insert =
"INSERT INTO tbl_datum_transform(" + insert +
") VALUES (" + values +
')';
3419 Q_ASSERT( idxid >= 0 );
3420 Q_ASSERT( idxrx >= 0 );
3421 Q_ASSERT( idxry >= 0 );
3422 Q_ASSERT( idxrz >= 0 );
3425 CSLDestroy( fieldnames );
3428 int openResult = database.
open( dbPath );
3429 if ( openResult != SQLITE_OK )
3435 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
3443 v.reserve(
sizeof( map ) /
sizeof( *map ) );
3447 char **values = CSVReadParseLine( fp );
3453 if ( CSLCount( values ) == 0 )
3455 CSLDestroy( values );
3459 if ( CSLCount( values ) < n )
3461 qWarning(
"Only %d columns", CSLCount( values ) );
3462 CSLDestroy( values );
3466 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
3468 int idx = map[i].idx;
3469 Q_ASSERT( idx != -1 );
3470 Q_ASSERT( idx < n );
3473 CSLDestroy( values );
3476 if ( v.at( idxmcode ).compare( QLatin1String(
"'9607'" ) ) == 0 )
3478 v[ idxmcode ] = QStringLiteral(
"'9606'" );
3479 v[ idxrx ] =
'\'' +
qgsDoubleToString( -( v[ idxrx ].remove(
'\'' ).toDouble() ) ) +
'\'';
3480 v[ idxry ] =
'\'' +
qgsDoubleToString( -( v[ idxry ].remove(
'\'' ).toDouble() ) ) +
'\'';
3481 v[ idxrz ] =
'\'' +
qgsDoubleToString( -( v[ idxrz ].remove(
'\'' ).toDouble() ) ) +
'\'';
3487 QString sql = QStringLiteral(
"SELECT coord_op_code FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( v[ idxid ] );
3489 statement = database.
prepare( sql, prepareRes );
3490 if ( prepareRes != SQLITE_OK )
3493 if ( statement.
step() == SQLITE_ROW )
3498 sql = cOpCode.isEmpty() ? insert : update;
3499 for (
int i = 0; i < v.size(); i++ )
3501 sql = sql.arg( v[i] );
3504 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
3506 qCritical(
"SQL: %s", sql.toUtf8().constData() );
3507 qCritical(
"Error: %s", sqlite3_errmsg( database.get() ) );
3511 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
3521 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::stringCache()
3523 return *sStringCache();
3526 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::projCache()
3528 return *sProj4Cache();
3531 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::ogcCache()
3533 return *sOgcCache();
3536 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::wktCache()
3538 return *sWktCache();
3541 const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srIdCache()
3543 return *sSrIdCache();
3546 const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srsIdCache()
3548 return *sSrsIdCache();
3557 #if PROJ_VERSION_MAJOR>=6
3558 else if ( PJ *obj = d->threadLocalProjObject() )
3560 QgsProjUtils::proj_pj_unique_ptr geoCrs( proj_crs_get_geodetic_crs(
QgsProjContext::get(), obj ) );
3561 return geoCrs ? QStringLiteral(
"%1:%2" ).arg( proj_get_id_auth_name( geoCrs.get(), 0 ), proj_get_id_code( geoCrs.get(), 0 ) ) : QString();
3566 return OSRGetAuthorityName( d->mCRS,
"GEOGCS" ) + QStringLiteral(
":" ) + OSRGetAuthorityCode( d->mCRS,
"GEOGCS" );
3575 #if PROJ_VERSION_MAJOR>=6
3576 PJ *QgsCoordinateReferenceSystem::projObject()
const
3578 return d->threadLocalProjObject();
3584 QStringList projections;
3586 projections.reserve( res.size() );
3589 projections << QString::number(
crs.
srsid() );
3596 QList<QgsCoordinateReferenceSystem> res;
3600 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
3601 QStringList projectionsWkt = settings.
value( QStringLiteral(
"UI/recentProjectionsWkt" ) ).toStringList();
3602 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
3603 int max = std::max( projectionsAuthId.size(), std::max( projectionsProj4.size(), projectionsWkt.size() ) );
3605 for (
int i = 0; i < max; ++i )
3607 const QString proj = projectionsProj4.value( i );
3608 const QString wkt = projectionsWkt.value( i );
3609 const QString
authid = projectionsAuthId.value( i );
3632 recent.removeAll(
crs );
3633 recent.insert( 0,
crs );
3636 recent = recent.mid( 0, 30 );
3637 QStringList authids;
3638 authids.reserve( recent.size() );
3640 proj.reserve( recent.size() );
3642 wkt.reserve( recent.size() );
3645 authids <<
c.authid();
3651 settings.
setValue( QStringLiteral(
"UI/recentProjectionsAuthId" ), authids );
3652 settings.
setValue( QStringLiteral(
"UI/recentProjectionsWkt" ), wkt );
3653 settings.
setValue( QStringLiteral(
"UI/recentProjectionsProj4" ), proj );
3658 sSrIdCacheLock()->lockForWrite();
3659 if ( !sDisableSrIdCache )
3662 sDisableSrIdCache =
true;
3663 sSrIdCache()->clear();
3665 sSrIdCacheLock()->unlock();
3667 sOgcLock()->lockForWrite();
3668 if ( !sDisableOgcCache )
3671 sDisableOgcCache =
true;
3672 sOgcCache()->clear();
3674 sOgcLock()->unlock();
3676 sProj4CacheLock()->lockForWrite();
3677 if ( !sDisableProjCache )
3680 sDisableProjCache =
true;
3681 sProj4Cache()->clear();
3683 sProj4CacheLock()->unlock();
3685 sCRSWktLock()->lockForWrite();
3686 if ( !sDisableWktCache )
3689 sDisableWktCache =
true;
3690 sWktCache()->clear();
3692 sCRSWktLock()->unlock();
3694 sCRSSrsIdLock()->lockForWrite();
3695 if ( !sDisableSrsIdCache )
3698 sDisableSrsIdCache =
true;
3699 sSrsIdCache()->clear();
3701 sCRSSrsIdLock()->unlock();
3703 sCrsStringLock()->lockForWrite();
3704 if ( !sDisableStringCache )
3707 sDisableStringCache =
true;
3708 sStringCache()->clear();
3710 sCrsStringLock()->unlock();