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!" ) );
275 if ( !sDisableStringCache )
277 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sStringCache()->constFind( definition );
278 if ( crsIt != sStringCache()->constEnd() )
281 *
this = crsIt.value();
288 QRegularExpression reCrsId( QStringLiteral(
"^(epsg|esri|osgeo|ignf|zangi|iau2000|postgis|internal|user)\\:(\\w+)$" ), QRegularExpression::CaseInsensitiveOption );
289 QRegularExpressionMatch match = reCrsId.match( definition );
290 if ( match.capturedStart() == 0 )
292 QString authName = match.captured( 1 ).toLower();
293 if ( authName == QLatin1String(
"epsg" ) )
297 else if ( authName == QLatin1String(
"postgis" ) )
299 const long id = match.captured( 2 ).toLong();
300 result = createFromPostgisSrid(
id );
302 else if ( authName == QLatin1String(
"esri" ) || authName == QLatin1String(
"osgeo" ) || authName == QLatin1String(
"ignf" ) || authName == QLatin1String(
"zangi" ) || authName == QLatin1String(
"iau2000" ) )
308 const long id = match.captured( 2 ).toLong();
316 QRegularExpression reCrsStr(
"^(?:(wkt|proj4|proj)\\:)?(.+)$", QRegularExpression::CaseInsensitiveOption );
317 match = reCrsStr.match( definition );
318 if ( match.capturedStart() == 0 )
320 if ( match.captured( 1 ).startsWith( QLatin1String(
"proj" ), Qt::CaseInsensitive ) )
332 if ( !sDisableStringCache )
333 sStringCache()->insert( definition, *
this );
342 #if PROJ_VERSION_MAJOR<6 344 if ( definition.startsWith( QLatin1String(
"ESRI::" ) ) )
352 if ( OSRSetFromUserInput( crs, definition.toLocal8Bit().constData() ) == OGRERR_NONE )
355 OSRDestroySpatialReference( crs );
365 const char *configOld = CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" );
366 const char *configNew =
"GEOGCS";
368 if ( strcmp( configOld,
"" ) == 0 )
370 CPLSetConfigOption(
"GDAL_FIX_ESRI_WKT", configNew );
371 if ( strcmp( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) != 0 )
373 .arg( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) );
374 QgsDebugMsgLevel( QStringLiteral(
"set GDAL_FIX_ESRI_WKT : %1" ).arg( configNew ), 4 );
378 QgsDebugMsgLevel( QStringLiteral(
"GDAL_FIX_ESRI_WKT was already set : %1" ).arg( configNew ), 4 );
385 if ( !sDisableOgcCache )
387 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sOgcCache()->constFind( crs );
388 if ( crsIt != sOgcCache()->constEnd() )
391 *
this = crsIt.value();
397 QString wmsCrs =
crs;
399 QRegExp re_uri(
"http://www\\.opengis\\.net/def/crs/([^/]+).+/([^/]+)", Qt::CaseInsensitive );
400 QRegExp re_urn(
"urn:ogc:def:crs:([^:]+).+([^:]+)", Qt::CaseInsensitive );
401 if ( re_uri.exactMatch( wmsCrs ) )
403 wmsCrs = re_uri.cap( 1 ) +
':' + re_uri.cap( 2 );
405 else if ( re_urn.exactMatch( wmsCrs ) )
407 wmsCrs = re_urn.cap( 1 ) +
':' + re_urn.cap( 2 );
411 re_urn.setPattern( QStringLiteral(
"(user|custom|qgis):(\\d+)" ) );
412 if ( re_urn.exactMatch( wmsCrs ) &&
createFromSrsId( re_urn.cap( 2 ).toInt() ) )
415 if ( !sDisableOgcCache )
416 sOgcCache()->insert( crs, *
this );
421 #if PROJ_VERSION_MAJOR>=6 423 const QString legacyKey = wmsCrs.toLower();
424 for (
auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
426 if ( it.key().compare( legacyKey, Qt::CaseInsensitive ) == 0 )
428 const QStringList parts = it.key().split(
':' );
429 const QString auth = parts.at( 0 );
430 const QString code = parts.at( 1 );
431 if ( loadFromAuthCode( auth, code ) )
434 if ( !sDisableOgcCache )
435 sOgcCache()->insert( crs, *
this );
445 if ( !sDisableOgcCache )
446 sOgcCache()->insert( crs, *
this );
451 if ( wmsCrs.compare( QLatin1String(
"CRS:27" ), Qt::CaseInsensitive ) == 0 ||
452 wmsCrs.compare( QLatin1String(
"OGC:CRS27" ), Qt::CaseInsensitive ) == 0 )
459 if ( wmsCrs.compare( QLatin1String(
"CRS:83" ), Qt::CaseInsensitive ) == 0 ||
460 wmsCrs.compare( QLatin1String(
"OGC:CRS83" ), Qt::CaseInsensitive ) == 0 )
467 if ( wmsCrs.compare( QLatin1String(
"CRS:84" ), Qt::CaseInsensitive ) == 0 ||
468 wmsCrs.compare( QLatin1String(
"OGC:CRS84" ), Qt::CaseInsensitive ) == 0 )
472 d->mAxisInverted =
false;
473 d->mAxisInvertedDirty =
false;
477 if ( !sDisableOgcCache )
478 sOgcCache()->insert( crs, *
this );
484 if ( !sDisableOgcCache )
494 if ( d->mIsValid || !sCustomSrsValidation )
498 if ( sCustomSrsValidation )
499 sCustomSrsValidation( *
this );
504 return createFromPostgisSrid(
id );
507 bool QgsCoordinateReferenceSystem::createFromPostgisSrid(
const long id )
510 if ( !sDisableSrIdCache )
512 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrIdCache()->constFind(
id );
513 if ( crsIt != sSrIdCache()->constEnd() )
516 *
this = crsIt.value();
522 #if PROJ_VERSION_MAJOR>=6 524 for (
auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
526 if ( it.value().endsWith( QStringLiteral(
",%1" ).arg(
id ) ) )
528 const QStringList parts = it.key().split(
':' );
529 const QString auth = parts.at( 0 );
530 const QString code = parts.at( 1 );
531 if ( loadFromAuthCode( auth, code ) )
534 if ( !sDisableSrIdCache )
535 sSrIdCache()->insert(
id, *
this );
546 if ( !sDisableSrIdCache )
547 sSrIdCache()->insert(
id, *
this );
555 if ( !sDisableSrsIdCache )
557 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrsIdCache()->constFind(
id );
558 if ( crsIt != sSrsIdCache()->constEnd() )
561 *
this = crsIt.value();
567 #if PROJ_VERSION_MAJOR>=6 569 for (
auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
571 if ( it.value().startsWith( QString::number(
id ) +
',' ) )
573 const QStringList parts = it.key().split(
':' );
574 const QString auth = parts.at( 0 );
575 const QString code = parts.at( 1 );
576 if ( loadFromAuthCode( auth, code ) )
579 if ( !sDisableSrsIdCache )
580 sSrsIdCache()->insert(
id, *
this );
589 QStringLiteral(
"srs_id" ), QString::number(
id ) );
592 if ( !sDisableSrsIdCache )
593 sSrsIdCache()->insert(
id, *
this );
597 bool QgsCoordinateReferenceSystem::loadFromDatabase(
const QString &db,
const QString &expression,
const QString &value )
601 QgsDebugMsgLevel(
"load CRS from " + db +
" where " + expression +
" is " + value, 3 );
604 QFileInfo myInfo( db );
605 if ( !myInfo.exists() )
607 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
615 myResult = openDatabase( db, database );
616 if ( myResult != SQLITE_OK )
633 QString mySql =
"select srs_id,description,projection_acronym," 634 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo,wkt " 636 statement = database.
prepare( mySql, myResult );
639 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
644 #if PROJ_VERSION_MAJOR>=6 645 d->mEllipsoidAcronym.clear();
652 d->mIsGeographic = statement.
columnAsText( 7 ).toInt() != 0;
654 d->mAxisInvertedDirty =
true;
656 if ( d->mSrsId >=
USER_CRS_START_ID && ( d->mAuthId.isEmpty() || d->mAuthId == QChar(
':' ) ) )
658 d->mAuthId = QStringLiteral(
"USER:%1" ).arg( d->mSrsId );
660 else if ( !d->mAuthId.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive ) )
662 #if PROJ_VERSION_MAJOR>=6 663 QStringList parts = d->mAuthId.split(
':' );
664 QString auth = parts.at( 0 );
665 QString code = parts.at( 1 );
668 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database(
QgsProjContext::get(), auth.toLatin1(), code.toLatin1(), PJ_CATEGORY_CRS,
false, nullptr ) );
669 d->setPj( QgsProjUtils::crsToSingleCrs( crs.get() ) );
672 d->mIsValid = d->hasPj();
674 OSRDestroySpatialReference( d->mCRS );
675 d->mCRS = OSRNewSpatialReference(
nullptr );
676 d->mIsValid = OSRSetFromUserInput( d->mCRS, d->mAuthId.toLower().toLatin1() ) == OGRERR_NONE;
683 if ( !wkt.isEmpty() )
684 setWktString( wkt,
false );
686 setProjString( d->mProj4 );
696 #if PROJ_VERSION_MAJOR>=6 697 void QgsCoordinateReferenceSystem::removeFromCacheObjectsBelongingToCurrentThread(
PJ_CONTEXT *pj_context )
704 if ( !sDisableSrIdCache )
707 if ( !sDisableSrIdCache )
709 for (
auto it = sSrIdCache()->begin(); it != sSrIdCache()->end(); )
711 auto &v = it.value();
712 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
713 it = sSrIdCache()->erase( it );
719 if ( !sDisableOgcCache )
722 if ( !sDisableOgcCache )
724 for (
auto it = sOgcCache()->begin(); it != sOgcCache()->end(); )
726 auto &v = it.value();
727 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
728 it = sOgcCache()->erase( it );
734 if ( !sDisableProjCache )
737 if ( !sDisableProjCache )
739 for (
auto it = sProj4Cache()->begin(); it != sProj4Cache()->end(); )
741 auto &v = it.value();
742 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
743 it = sProj4Cache()->erase( it );
749 if ( !sDisableWktCache )
752 if ( !sDisableWktCache )
754 for (
auto it = sWktCache()->begin(); it != sWktCache()->end(); )
756 auto &v = it.value();
757 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
758 it = sWktCache()->erase( it );
764 if ( !sDisableSrsIdCache )
767 if ( !sDisableSrsIdCache )
769 for (
auto it = sSrsIdCache()->begin(); it != sSrsIdCache()->end(); )
771 auto &v = it.value();
772 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
773 it = sSrsIdCache()->erase( it );
779 if ( !sDisableStringCache )
782 if ( !sDisableStringCache )
784 for (
auto it = sStringCache()->begin(); it != sStringCache()->end(); )
786 auto &v = it.value();
787 if ( v.d->removeObjectsBelongingToCurrentThread( pj_context ) )
788 it = sStringCache()->erase( it );
799 if ( d->mAxisInvertedDirty )
801 #if PROJ_VERSION_MAJOR>=6 802 d->mAxisInverted = QgsProjUtils::axisOrderIsSwapped( d->threadLocalProjObject() );
804 OGRAxisOrientation orientation;
805 OSRGetAxis( d->mCRS, OSRIsGeographic( d->mCRS ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
808 if ( orientation == OAO_Other && d->mAuthId.startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
812 if ( OSRImportFromEPSGA( crs, d->mAuthId.midRef( 5 ).toInt() ) == OGRERR_NONE )
814 OSRGetAxis( crs, OSRIsGeographic( crs ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
817 OSRDestroySpatialReference( crs );
820 d->mAxisInverted = orientation == OAO_North;
822 d->mAxisInvertedDirty =
false;
825 return d->mAxisInverted;
833 if ( !sDisableWktCache )
835 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sWktCache()->constFind( wkt );
836 if ( crsIt != sWktCache()->constEnd() )
839 *
this = crsIt.value();
849 QgsDebugMsgLevel( QStringLiteral(
"theWkt is uninitialized, operation failed" ), 4 );
854 QgsCoordinateReferenceSystem::RecordMap record = getRecord(
"select * from tbl_srs where wkt=" +
QgsSqliteUtils::quotedString( wkt ) +
" order by deprecated" );
855 if ( !record.empty() )
857 long srsId = record[QStringLiteral(
"srs_id" )].toLong();
866 if ( d->mSrsId == 0 )
868 #if PROJ_VERSION_MAJOR>=6 870 long id = matchToUserCrs();
880 if ( !sDisableWktCache )
881 sWktCache()->insert( wkt, *
this );
901 if ( projString.trimmed().isEmpty() )
909 if ( !sDisableProjCache )
911 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sProj4Cache()->constFind( projString );
912 if ( crsIt != sProj4Cache()->constEnd() )
915 *
this = crsIt.value();
929 QString myProj4String = projString.trimmed();
930 myProj4String.remove( QStringLiteral(
"+type=crs" ) );
931 myProj4String = myProj4String.trimmed();
934 #if PROJ_VERSION_MAJOR>=6 936 const QString projCrsString = myProj4String + ( myProj4String.contains( QStringLiteral(
"+type=crs" ) ) ? QString() : QStringLiteral(
" +type=crs" ) );
937 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create(
QgsProjContext::get(), projCrsString.toLatin1().constData() ) );
944 const QString
authid = QStringLiteral(
"%1:%2" ).arg( authName, authCode );
948 if ( !sDisableProjCache )
949 sProj4Cache()->insert( projString, *
this );
956 QgsCoordinateReferenceSystem::RecordMap myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
958 if ( !myRecord.empty() )
960 id = myRecord[QStringLiteral(
"srs_id" )].toLong();
969 setProjString( myProj4String );
972 id = matchToUserCrs();
980 QRegExp myProjRegExp(
"\\+proj=(\\S+)" );
981 int myStart = myProjRegExp.indexIn( myProj4String );
985 if ( !sDisableProjCache )
986 sProj4Cache()->insert( projString, *
this );
991 d->mProjectionAcronym = myProjRegExp.cap( 1 );
993 QRegExp myEllipseRegExp(
"\\+ellps=(\\S+)" );
994 myStart = myEllipseRegExp.indexIn( myProj4String );
997 d->mEllipsoidAcronym.clear();
1001 d->mEllipsoidAcronym = myEllipseRegExp.cap( 1 );
1004 QRegExp myAxisRegExp(
"\\+a=(\\S+)" );
1005 myStart = myAxisRegExp.indexIn( myProj4String );
1008 QgsCoordinateReferenceSystem::RecordMap myRecord;
1014 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
1015 if ( myRecord.empty() )
1020 QRegExp myLat1RegExp(
"\\+lat_1=\\S+" );
1021 QRegExp myLat2RegExp(
"\\+lat_2=\\S+" );
1028 myStart1 = myLat1RegExp.indexIn( myProj4String, myStart1 );
1029 myStart2 = myLat2RegExp.indexIn( myProj4String, myStart2 );
1030 if ( myStart1 != -1 && myStart2 != -1 )
1032 myLength1 = myLat1RegExp.matchedLength();
1033 myLength2 = myLat2RegExp.matchedLength();
1038 if ( !lat1Str.isEmpty() && !lat2Str.isEmpty() )
1041 QString proj4StringModified = myProj4String;
1046 myStart2 = myLat2RegExp.indexIn( projString, myStart2 );
1048 QgsDebugMsgLevel( QStringLiteral(
"trying proj4string match with swapped lat_1,lat_2" ), 4 );
1049 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( proj4StringModified.trimmed() ) +
" order by deprecated" );
1053 if ( myRecord.empty() )
1060 QString sql = QStringLiteral(
"SELECT * FROM tbl_srs WHERE " );
1067 QStringList myParams;
1068 const QRegExp regExp(
"\\s+(?=\\+)" );
1070 const auto constSplit = myProj4String.split( regExp, QString::SkipEmptyParts );
1071 for (
const QString ¶m : constSplit )
1073 QString arg = QStringLiteral(
"' '||parameters||' ' LIKE %1" ).arg(
QgsSqliteUtils::quotedString( QStringLiteral(
"% %1 %" ).arg( param.trimmed() ) ) );
1074 if ( param.startsWith( QLatin1String(
"+datum=" ) ) )
1081 delim = QStringLiteral(
" AND " );
1082 myParams << param.trimmed();
1087 if ( !datum.isEmpty() )
1089 myRecord = getRecord( sql + delim + datum +
" order by deprecated" );
1092 if ( myRecord.empty() )
1095 myRecord = getRecord( sql +
" order by deprecated" );
1098 if ( !myRecord.empty() )
1101 QStringList foundParams;
1102 const auto constSplit = myRecord[
"parameters"].split( regExp, QString::SkipEmptyParts );
1103 for (
const QString ¶m : constSplit )
1105 if ( !param.startsWith( QLatin1String(
"+datum=" ) ) )
1106 foundParams << param.trimmed();
1112 if ( myParams != foundParams )
1119 if ( !myRecord.empty() )
1121 mySrsId = myRecord[QStringLiteral(
"srs_id" )].toLong();
1130 setProjString( myProj4String );
1140 d->mIsValid =
false;
1147 QgsDebugMsgLevel( QStringLiteral(
"Projection is not found in databases." ), 4 );
1149 setProjString( myProj4String );
1154 if ( !sDisableProjCache )
1155 sProj4Cache()->insert( projString, *
this );
1161 QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord(
const QString &sql )
1163 QString myDatabaseFileName;
1164 QgsCoordinateReferenceSystem::RecordMap myMap;
1165 QString myFieldName;
1166 QString myFieldValue;
1173 QFileInfo myInfo( myDatabaseFileName );
1174 if ( !myInfo.exists() )
1176 QgsDebugMsg(
"failed : " + myDatabaseFileName +
" does not exist!" );
1181 myResult = openDatabase( myDatabaseFileName, database );
1182 if ( myResult != SQLITE_OK )
1187 statement = database.
prepare( sql, myResult );
1189 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1193 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1195 myFieldName = statement.
columnName( myColNo );
1197 myMap[myFieldName] = myFieldValue;
1199 if ( statement.
step() != SQLITE_DONE )
1201 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1203 #if PROJ_VERSION_MAJOR<6 1213 if ( myMap.empty() )
1216 QFileInfo myFileInfo;
1217 myFileInfo.setFile( myDatabaseFileName );
1218 if ( !myFileInfo.exists() )
1220 QgsDebugMsg( QStringLiteral(
"user qgis.db not found" ) );
1225 myResult = openDatabase( myDatabaseFileName, database );
1226 if ( myResult != SQLITE_OK )
1231 statement = database.
prepare( sql, myResult );
1233 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
1237 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
1239 myFieldName = statement.
columnName( myColNo );
1241 myMap[myFieldName] = myFieldValue;
1244 if ( statement.
step() != SQLITE_DONE )
1246 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1277 if ( d->mDescription.isNull() )
1283 return d->mDescription;
1289 if ( !
authid().isEmpty() )
1298 return QObject::tr(
"Unknown CRS" );
1300 return QObject::tr(
"Unknown CRS: %1" ).arg(
1303 else if ( !
toProj().isEmpty() )
1304 return QObject::tr(
"Unknown CRS: %1" ).arg( type ==
MediumString ? (
toProj().left( 50 ) + QString( QChar( 0x2026 ) ) )
1312 if ( d->mProjectionAcronym.isNull() )
1318 return d->mProjectionAcronym;
1324 if ( d->mEllipsoidAcronym.isNull() )
1326 #if PROJ_VERSION_MAJOR>=6 1327 if ( PJ *obj = d->threadLocalProjObject() )
1329 QgsProjUtils::proj_pj_unique_ptr ellipsoid( proj_get_ellipsoid(
QgsProjContext::get(), obj ) );
1332 const QString ellipsoidAuthName( proj_get_id_auth_name( ellipsoid.get(), 0 ) );
1333 const QString ellipsoidAuthCode( proj_get_id_code( ellipsoid.get(), 0 ) );
1334 if ( !ellipsoidAuthName.isEmpty() && !ellipsoidAuthCode.isEmpty() )
1335 d->mEllipsoidAcronym = QStringLiteral(
"%1:%2" ).arg( ellipsoidAuthName, ellipsoidAuthCode );
1338 double semiMajor, semiMinor, invFlattening;
1339 int semiMinorComputed = 0;
1340 if ( proj_ellipsoid_get_parameters(
QgsProjContext::get(), ellipsoid.get(), &semiMajor, &semiMinor, &semiMinorComputed, &invFlattening ) )
1342 d->mEllipsoidAcronym = QStringLiteral(
"PARAMETER:%1:%2" ).arg(
qgsDoubleToString( semiMajor ),
1347 d->mEllipsoidAcronym.clear();
1352 return d->mEllipsoidAcronym;
1360 return d->mEllipsoidAcronym;
1374 if ( d->mProj4.isEmpty() )
1376 #if PROJ_VERSION_MAJOR>=6 1377 if ( PJ *obj = d->threadLocalProjObject() )
1379 d->mProj4 = getFullProjString( obj );
1382 char *proj4src =
nullptr;
1383 OSRExportToProj4( d->mCRS, &proj4src );
1384 d->mProj4 = proj4src;
1385 CPLFree( proj4src );
1389 return d->mProj4.trimmed();
1394 return d->mIsGeographic;
1402 return d->mMapUnits;
1410 #if PROJ_VERSION_MAJOR>=6 1411 PJ *obj = d->threadLocalProjObject();
1416 double southLat = 0;
1418 double northLat = 0;
1421 &westLon, &southLat, &eastLon, &northLat,
nullptr ) )
1440 int result = openDatabase( databaseFileName, database );
1441 if ( result != SQLITE_OK )
1446 QString sql = QStringLiteral(
"select west_bound_lon, north_bound_lat, east_bound_lon, south_bound_lat from tbl_bounds " 1449 statement = database.
prepare( sql, result );
1452 if ( result == SQLITE_OK )
1454 if ( statement.
step() == SQLITE_ROW )
1471 void QgsCoordinateReferenceSystem::setProjString(
const QString &proj4String )
1474 d->mProj4 = proj4String;
1477 QString trimmed = proj4String.trimmed();
1479 #if PROJ_VERSION_MAJOR>=6 1480 trimmed += QStringLiteral(
" +type=crs" );
1484 d->setPj( QgsProjUtils::proj_pj_unique_ptr( proj_create( ctx, trimmed.toLatin1().constData() ) ) );
1490 const int errNo = proj_context_errno( ctx );
1491 QgsDebugMsg( QStringLiteral(
"proj string rejected: %1" ).arg( proj_errno_string( errNo ) ) );
1493 d->mIsValid =
false;
1497 d->mEllipsoidAcronym.clear();
1501 OSRDestroySpatialReference( d->mCRS );
1502 d->mCRS = OSRNewSpatialReference(
nullptr );
1503 d->mIsValid = OSRImportFromProj4( d->mCRS, trimmed.toLatin1().constData() ) == OGRERR_NONE;
1509 projCtx pContext = pj_ctx_alloc();
1510 projPJ proj = pj_init_plus_ctx( pContext, proj4String.trimmed().toLatin1().constData() );
1513 QgsDebugMsgLevel( QStringLiteral(
"proj.4 string rejected by pj_init_plus_ctx()" ), 4 );
1514 d->mIsValid =
false;
1520 pj_ctx_free( pContext );
1526 bool QgsCoordinateReferenceSystem::setWktString(
const QString &wkt,
bool allowProjFallback )
1529 d->mIsValid =
false;
1531 #if PROJ_VERSION_MAJOR>=6 1533 ( void )allowProjFallback;
1535 PROJ_STRING_LIST warnings =
nullptr;
1536 PROJ_STRING_LIST grammerErrors =
nullptr;
1538 d->setPj( QgsProjUtils::proj_pj_unique_ptr( proj_create_from_wkt(
QgsProjContext::get(), wkt.toLatin1().constData(),
nullptr, &warnings, &grammerErrors ) ) );
1544 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
1545 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
1547 for (
auto iter = warnings; iter && *iter; ++iter )
1549 for (
auto iter = grammerErrors; iter && *iter; ++iter )
1551 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
1553 proj_string_list_destroy( warnings );
1554 proj_string_list_destroy( grammerErrors );
1556 QByteArray ba = wkt.toLatin1();
1557 const char *pWkt = ba.data();
1559 OGRErr myInputResult = OSRImportFromWkt( d->mCRS, const_cast< char ** >( & pWkt ) );
1560 res = myInputResult == OGRERR_NONE;
1563 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
1564 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
1566 QgsDebugMsg( QStringLiteral(
"UNUSED WKT: %1" ).arg( pWkt ) );
1567 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
1579 if ( !sDisableWktCache )
1580 sWktCache()->insert( wkt, *
this );
1584 #if PROJ_VERSION_MAJOR>=6 1588 QString authName( proj_get_id_auth_name( d->threadLocalProjObject(), 0 ) );
1589 QString authCode( proj_get_id_code( d->threadLocalProjObject(), 0 ) );
1591 if ( authName.isEmpty() || authCode.isEmpty() )
1594 QgsProjUtils::identifyCrs( d->threadLocalProjObject(), authName, authCode );
1597 if ( !authName.isEmpty() && !authCode.isEmpty() )
1599 if ( loadFromAuthCode( authName, authCode ) )
1602 if ( !sDisableWktCache )
1603 sWktCache()->insert( wkt, *
this );
1615 if ( OSRAutoIdentifyEPSG( d->mCRS ) == OGRERR_NONE )
1617 QString
authid = QStringLiteral(
"%1:%2" )
1618 .arg( OSRGetAuthorityName( d->mCRS,
nullptr ),
1619 OSRGetAuthorityCode( d->mCRS,
nullptr ) );
1622 if ( !sDisableWktCache )
1623 sWktCache()->insert( wkt, *
this );
1632 #if PROJ_VERSION_MAJOR<6 1633 if ( allowProjFallback )
1635 d->mIsValid =
false;
1637 char *proj4src =
nullptr;
1638 OSRExportToProj4( d->mCRS, &proj4src );
1645 CPLFree( proj4src );
1647 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0) 1649 OSRFixup( d->mCRS );
1652 OSRExportToProj4( d->mCRS, &proj4src );
1656 CPLFree( proj4src );
1658 else if ( d->mIsValid )
1666 void QgsCoordinateReferenceSystem::setMapUnits()
1674 #if PROJ_VERSION_MAJOR<6 1675 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0) 1678 OSRFixup( d->mCRS );
1682 #if PROJ_VERSION_MAJOR>=6 1690 QgsProjUtils::proj_pj_unique_ptr
crs( QgsProjUtils::crsToSingleCrs( d->threadLocalProjObject() ) );
1691 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( context, crs.get() ) );
1692 if ( !coordinateSystem )
1698 const int axisCount = proj_cs_get_axis_count( context, coordinateSystem.get() );
1699 if ( axisCount > 0 )
1701 const char *outUnitName =
nullptr;
1703 proj_cs_get_axis_info( context, coordinateSystem.get(), 0,
1712 const QString unitName( outUnitName );
1716 if ( unitName.compare( QLatin1String(
"degree" ), Qt::CaseInsensitive ) == 0 ||
1717 unitName.compare( QLatin1String(
"degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1718 unitName.compare( QLatin1String(
"degree minute second hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1719 unitName.compare( QLatin1String(
"degree minute" ), Qt::CaseInsensitive ) == 0 ||
1720 unitName.compare( QLatin1String(
"degree hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1721 unitName.compare( QLatin1String(
"degree minute hemisphere" ), Qt::CaseInsensitive ) == 0 ||
1722 unitName.compare( QLatin1String(
"hemisphere degree" ), Qt::CaseInsensitive ) == 0 ||
1723 unitName.compare( QLatin1String(
"hemisphere degree minute" ), Qt::CaseInsensitive ) == 0 ||
1724 unitName.compare( QLatin1String(
"hemisphere degree minute second" ), Qt::CaseInsensitive ) == 0 ||
1725 unitName.compare( QLatin1String(
"degree (supplier to define representation)" ), Qt::CaseInsensitive ) == 0 )
1727 else if ( unitName.compare( QLatin1String(
"metre" ), Qt::CaseInsensitive ) == 0
1728 || unitName.compare( QLatin1String(
"m" ), Qt::CaseInsensitive ) == 0
1729 || unitName.compare( QLatin1String(
"meter" ), Qt::CaseInsensitive ) == 0 )
1732 else if ( unitName.compare( QLatin1String(
"US survey foot" ), Qt::CaseInsensitive ) == 0 ||
1733 unitName.compare( QLatin1String(
"foot" ), Qt::CaseInsensitive ) == 0 )
1735 else if ( unitName.compare( QLatin1String(
"kilometre" ), Qt::CaseInsensitive ) == 0 )
1737 else if ( unitName.compare( QLatin1String(
"centimetre" ), Qt::CaseInsensitive ) == 0 )
1739 else if ( unitName.compare( QLatin1String(
"millimetre" ), Qt::CaseInsensitive ) == 0 )
1741 else if ( unitName.compare( QLatin1String(
"Statute mile" ), Qt::CaseInsensitive ) == 0 )
1743 else if ( unitName.compare( QLatin1String(
"nautical mile" ), Qt::CaseInsensitive ) == 0 )
1745 else if ( unitName.compare( QLatin1String(
"yard" ), Qt::CaseInsensitive ) == 0 )
1759 char *unitName =
nullptr;
1761 if ( OSRIsProjected( d->mCRS ) )
1763 double toMeter = OSRGetLinearUnits( d->mCRS, &unitName );
1764 QString unit( unitName );
1772 static const double SMALL_NUM = 1e-3;
1774 if ( std::fabs( toMeter - FEET_TO_METER ) < SMALL_NUM )
1775 unit = QStringLiteral(
"Foot" );
1779 else if ( unit == QLatin1String(
"Foot" ) )
1788 OSRGetAngularUnits( d->mCRS, &unitName );
1789 QString unit( unitName );
1790 if ( unit == QLatin1String(
"degree" ) )
1803 if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
1806 QgsDebugMsgLevel(
"QgsCoordinateReferenceSystem::findMatchingProj will only " 1807 "work if prj acr ellipsoid acr and proj4string are set" 1808 " and the current projection is valid!", 4 );
1818 QString mySql = QString(
"select srs_id,parameters from tbl_srs where " 1819 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1826 myResult = openDatabase( myDatabaseFileName, database );
1827 if ( myResult != SQLITE_OK )
1832 statement = database.
prepare( mySql, myResult );
1833 if ( myResult == SQLITE_OK )
1836 while ( statement.
step() == SQLITE_ROW )
1840 if (
toProj() == myProj4String.trimmed() )
1842 return mySrsId.toLong();
1853 myResult = openDatabase( myDatabaseFileName, database );
1854 if ( myResult != SQLITE_OK )
1859 statement = database.
prepare( mySql, myResult );
1861 if ( myResult == SQLITE_OK )
1863 while ( statement.
step() == SQLITE_ROW )
1867 if (
toProj() == myProj4String.trimmed() )
1869 return mySrsId.toLong();
1883 if ( !d->mIsValid && !srs.d->mIsValid )
1886 if ( !d->mIsValid || !srs.d->mIsValid )
1889 if ( ( !d->mAuthId.isEmpty() || !srs.d->mAuthId.isEmpty() ) )
1890 return d->mAuthId == srs.d->mAuthId;
1897 return !( *
this == srs );
1902 #if PROJ_VERSION_MAJOR>=6 1903 if ( PJ *obj = d->threadLocalProjObject() )
1905 PJ_WKT_TYPE type = PJ_WKT1_GDAL;
1909 type = PJ_WKT1_GDAL;
1912 type = PJ_WKT1_ESRI;
1915 type = PJ_WKT2_2015;
1918 type = PJ_WKT2_2015_SIMPLIFIED;
1921 type = PJ_WKT2_2018;
1924 type = PJ_WKT2_2018_SIMPLIFIED;
1928 const QByteArray multiLineOption = QStringLiteral(
"MULTILINE=%1" ).arg( multiline ? QStringLiteral(
"YES" ) : QStringLiteral(
"NO" ) ).toLocal8Bit();
1929 const QByteArray indentatationWidthOption = QStringLiteral(
"INDENTATION_WIDTH=%1" ).arg( multiline ? QString::number( indentationWidth ) : QStringLiteral(
"0" ) ).toLocal8Bit();
1930 const char *
const options[] = {multiLineOption.constData(), indentatationWidthOption.constData(),
nullptr};
1936 Q_UNUSED( multiline )
1937 Q_UNUSED( indentationWidth )
1938 char *wkt =
nullptr;
1940 if ( OSRExportToWkt( d->mCRS, &wkt ) == OGRERR_NONE )
1953 QDomNode srsNode = node.namedItem( QStringLiteral(
"spatialrefsys" ) );
1955 if ( ! srsNode.isNull() )
1957 bool initialized =
false;
1960 long srsid = srsNode.namedItem( QStringLiteral(
"srsid" ) ).toElement().text().toLong( &ok );
1966 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
1967 if ( !node.isNull() )
1978 node = srsNode.namedItem( QStringLiteral(
"epsg" ) );
1979 if ( !node.isNull() )
1993 const QString wkt = srsNode.namedItem( QStringLiteral(
"wkt" ) ).toElement().text();
1999 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
2000 const QString proj4 = node.toElement().text();
2007 node = srsNode.namedItem( QStringLiteral(
"proj4" ) );
2008 const QString proj4 = node.toElement().text();
2009 if ( !proj4.trimmed().isEmpty() )
2010 setProjString( node.toElement().text() );
2012 node = srsNode.namedItem( QStringLiteral(
"srsid" ) );
2013 d->mSrsId = node.toElement().text().toLong();
2015 node = srsNode.namedItem( QStringLiteral(
"srid" ) );
2016 d->mSRID = node.toElement().text().toLong();
2018 node = srsNode.namedItem( QStringLiteral(
"authid" ) );
2019 d->mAuthId = node.toElement().text();
2021 node = srsNode.namedItem( QStringLiteral(
"description" ) );
2022 d->mDescription = node.toElement().text();
2024 node = srsNode.namedItem( QStringLiteral(
"projectionacronym" ) );
2025 d->mProjectionAcronym = node.toElement().text();
2027 node = srsNode.namedItem( QStringLiteral(
"ellipsoidacronym" ) );
2028 d->mEllipsoidAcronym = node.toElement().text();
2030 node = srsNode.namedItem( QStringLiteral(
"geographicflag" ) );
2031 d->mIsGeographic = node.toElement().text().compare( QLatin1String(
"true" ) );
2040 d =
new QgsCoordinateReferenceSystemPrivate();
2048 QDomElement layerNode = node.toElement();
2049 QDomElement srsElement = doc.createElement( QStringLiteral(
"spatialrefsys" ) );
2051 QDomElement wktElement = doc.createElement( QStringLiteral(
"wkt" ) );
2052 wktElement.appendChild( doc.createTextNode(
toWkt(
WKT2_2018 ) ) );
2053 srsElement.appendChild( wktElement );
2055 QDomElement proj4Element = doc.createElement( QStringLiteral(
"proj4" ) );
2056 proj4Element.appendChild( doc.createTextNode(
toProj() ) );
2057 srsElement.appendChild( proj4Element );
2059 QDomElement srsIdElement = doc.createElement( QStringLiteral(
"srsid" ) );
2060 srsIdElement.appendChild( doc.createTextNode( QString::number(
srsid() ) ) );
2061 srsElement.appendChild( srsIdElement );
2063 QDomElement sridElement = doc.createElement( QStringLiteral(
"srid" ) );
2064 sridElement.appendChild( doc.createTextNode( QString::number(
postgisSrid() ) ) );
2065 srsElement.appendChild( sridElement );
2067 QDomElement authidElement = doc.createElement( QStringLiteral(
"authid" ) );
2068 authidElement.appendChild( doc.createTextNode(
authid() ) );
2069 srsElement.appendChild( authidElement );
2071 QDomElement descriptionElement = doc.createElement( QStringLiteral(
"description" ) );
2072 descriptionElement.appendChild( doc.createTextNode(
description() ) );
2073 srsElement.appendChild( descriptionElement );
2075 QDomElement projectionAcronymElement = doc.createElement( QStringLiteral(
"projectionacronym" ) );
2076 projectionAcronymElement.appendChild( doc.createTextNode(
projectionAcronym() ) );
2077 srsElement.appendChild( projectionAcronymElement );
2079 QDomElement ellipsoidAcronymElement = doc.createElement( QStringLiteral(
"ellipsoidacronym" ) );
2080 ellipsoidAcronymElement.appendChild( doc.createTextNode(
ellipsoidAcronym() ) );
2081 srsElement.appendChild( ellipsoidAcronymElement );
2083 QDomElement geographicFlagElement = doc.createElement( QStringLiteral(
"geographicflag" ) );
2084 QString geoFlagText = QStringLiteral(
"false" );
2087 geoFlagText = QStringLiteral(
"true" );
2090 geographicFlagElement.appendChild( doc.createTextNode( geoFlagText ) );
2091 srsElement.appendChild( geographicFlagElement );
2093 layerNode.appendChild( srsElement );
2105 QString QgsCoordinateReferenceSystem::projFromSrsId(
const int srsId )
2107 QString myDatabaseFileName;
2108 QString myProjString;
2109 QString mySql = QStringLiteral(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( srsId );
2118 QFileInfo myFileInfo;
2119 myFileInfo.setFile( myDatabaseFileName );
2120 if ( !myFileInfo.exists() )
2122 QgsDebugMsg( QStringLiteral(
"users qgis.db not found" ) );
2135 rc = openDatabase( myDatabaseFileName, database );
2141 statement = database.
prepare( mySql, rc );
2143 if ( rc == SQLITE_OK )
2145 if ( statement.
step() == SQLITE_ROW )
2151 return myProjString;
2158 myResult = database.
open_v2( path, SQLITE_OPEN_READONLY,
nullptr );
2160 myResult = database.
open( path );
2162 if ( myResult != SQLITE_OK )
2171 .arg( database.
errorMessage() ), QObject::tr(
"CRS" ) );
2178 sCustomSrsValidation = f;
2183 return sCustomSrsValidation;
2186 void QgsCoordinateReferenceSystem::debugPrint()
2188 QgsDebugMsg( QStringLiteral(
"***SpatialRefSystem***" ) );
2189 QgsDebugMsg(
"* Valid : " + ( d->mIsValid ? QString(
"true" ) : QString(
"false" ) ) );
2190 QgsDebugMsg(
"* SrsId : " + QString::number( d->mSrsId ) );
2196 QgsDebugMsg( QStringLiteral(
"* Units : meters" ) );
2200 QgsDebugMsg( QStringLiteral(
"* Units : feet" ) );
2204 QgsDebugMsg( QStringLiteral(
"* Units : degrees" ) );
2210 mValidationHint = html;
2215 return mValidationHint;
2231 QString proj4String = d->mProj4;
2232 if ( proj4String.isEmpty() )
2246 if ( getRecordCount() == 0 )
2248 mySql =
"insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo,wkt) values (" 2252 +
',' + quotedEllipsoidString
2260 mySql =
"insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo,wkt) values (" 2263 +
',' + quotedEllipsoidString
2273 if ( myResult != SQLITE_OK )
2275 QgsDebugMsg( QStringLiteral(
"Can't open or create database %1: %2" )
2280 statement = database.
prepare( mySql, myResult );
2282 qint64 returnId = -1;
2283 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_DONE )
2287 returnId = sqlite3_last_insert_rowid( database.get() );
2288 d->mSrsId = returnId;
2289 if (
authid().isEmpty() )
2290 d->mAuthId = QStringLiteral(
"USER:%1" ).arg( returnId );
2291 d->mDescription = name;
2298 long QgsCoordinateReferenceSystem::getRecordCount()
2303 long myRecordCount = 0;
2306 if ( myResult != SQLITE_OK )
2312 QString mySql = QStringLiteral(
"select count(*) from tbl_srs" );
2313 statement = database.
prepare( mySql, myResult );
2314 if ( myResult == SQLITE_OK )
2316 if ( statement.
step() == SQLITE_ROW )
2318 QString myRecordCountString = statement.
columnAsText( 0 );
2319 myRecordCount = myRecordCountString.toLong();
2322 return myRecordCount;
2325 #if PROJ_VERSION_MAJOR>=6 2326 bool testIsGeographic( PJ *
crs )
2330 QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( pjContext, crs ) );
2331 if ( coordinateSystem )
2333 const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
2334 if ( axisCount > 0 )
2336 const char *outUnitAuthName =
nullptr;
2337 const char *outUnitAuthCode =
nullptr;
2339 proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
2348 if ( outUnitAuthName && outUnitAuthCode )
2350 const char *unitCategory =
nullptr;
2351 if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode,
nullptr,
nullptr, &unitCategory ) )
2353 isGeographic = QString( unitCategory ).compare( QLatin1String(
"angular" ), Qt::CaseInsensitive ) == 0;
2361 void getOperationAndEllipsoidFromProjString(
const QString &proj, QString &operation, QString &ellipsoid )
2363 QRegExp projRegExp(
"\\+proj=(\\S+)" );
2364 if ( projRegExp.indexIn( proj ) < 0 )
2366 QgsDebugMsgLevel( QStringLiteral(
"no +proj argument found [%2]" ).arg( proj ), 2 );
2369 operation = projRegExp.cap( 1 );
2371 QRegExp ellipseRegExp(
"\\+(?:ellps|datum)=(\\S+)" );
2373 if ( ellipseRegExp.indexIn( proj ) >= 0 )
2375 ellipsoid = ellipseRegExp.cap( 1 );
2389 bool QgsCoordinateReferenceSystem::loadFromAuthCode(
const QString &auth,
const QString &code )
2392 d->mIsValid =
false;
2395 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database( pjContext, auth.toUtf8().constData(), code.toUtf8().constData(), PJ_CATEGORY_CRS,
false, nullptr ) );
2401 switch ( proj_get_type( crs.get() ) )
2403 case PJ_TYPE_VERTICAL_CRS:
2410 crs = QgsProjUtils::crsToSingleCrs( crs.get() );
2412 QString proj4 = getFullProjString( crs.get() );
2413 proj4.replace( QStringLiteral(
"+type=crs" ), QString() );
2414 proj4 = proj4.trimmed();
2418 d->mDescription = QString( proj_get_name( crs.get() ) );
2419 d->mAuthId = QStringLiteral(
"%1:%2" ).arg( auth, code );
2420 d->mIsGeographic = testIsGeographic( crs.get() );
2421 d->mAxisInvertedDirty =
true;
2424 getOperationAndEllipsoidFromProjString( proj4, operation, ellipsoid );
2425 d->mProjectionAcronym = operation;
2426 d->mEllipsoidAcronym.clear();
2427 d->setPj( std::move( crs ) );
2429 const QString dbVals = sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( auth, code ).toUpper() );
2432 if ( !dbVals.isEmpty() )
2434 const QStringList parts = dbVals.split(
',' );
2435 d->mSrsId = parts.at( 0 ).toInt();
2436 d->mSRID = parts.at( 1 ).toInt();
2444 QList<long> QgsCoordinateReferenceSystem::userSrsIds()
2446 QList<long> results;
2450 QFileInfo myInfo( db );
2451 if ( !myInfo.exists() )
2453 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
2461 int result = openDatabase( db, database );
2462 if ( result != SQLITE_OK )
2464 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
2468 QString sql = QStringLiteral(
"select srs_id from tbl_srs where srs_id >= %1" ).arg(
USER_CRS_START_ID );
2470 statement = database.
prepare( sql, rc );
2473 int ret = statement.
step();
2475 if ( ret == SQLITE_DONE )
2481 if ( ret == SQLITE_ROW )
2487 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
2495 long QgsCoordinateReferenceSystem::matchToUserCrs()
const 2497 PJ *obj = d->threadLocalProjObject();
2501 const QList< long > ids = userSrsIds();
2502 for (
long id : ids )
2505 if ( candidate.projObject() && proj_is_equivalent_to( obj, candidate.projObject(), PJ_COMP_EQUIVALENT ) )
2514 #if PROJ_VERSION_MAJOR<6 2516 bool QgsCoordinateReferenceSystem::loadWkts( QHash<int, QString> &wkts,
const char *filename )
2519 const char *pszFilename = CPLFindFile(
"gdal", filename );
2523 QFile csv( pszFilename );
2524 if ( !csv.open( QIODevice::ReadOnly ) )
2527 QTextStream lines( &csv );
2531 QString line = lines.readLine();
2532 if ( line.isNull() )
2535 if ( line.trimmed().isEmpty() || line.startsWith(
'#' ) )
2539 else if ( line.startsWith( QLatin1String(
"include " ) ) )
2541 if ( !loadWkts( wkts, line.mid( 8 ).toUtf8() ) )
2546 int pos = line.indexOf(
',' );
2551 int epsg = line.leftRef( pos ).toInt( &ok );
2555 wkts.insert( epsg, line.mid( pos + 1 ) );
2564 bool QgsCoordinateReferenceSystem::loadIds( QHash<int, QString> &wkts )
2568 static const QStringList csvs { QStringList() << QStringLiteral(
"gcs.csv" ) << QStringLiteral(
"pcs.csv" ) << QStringLiteral(
"vertcs.csv" ) << QStringLiteral(
"compdcs.csv" ) << QStringLiteral(
"geoccs.csv" ) };
2569 for (
const QString &csv : csvs )
2571 QString filename = CPLFindFile(
"gdal", csv.toUtf8() );
2573 QFile f( filename );
2574 if ( !f.open( QIODevice::ReadOnly ) )
2577 QTextStream lines( &f );
2584 QString line = lines.readLine();
2585 if ( line.isNull() )
2588 if ( line.trimmed().isEmpty() )
2591 int pos = line.indexOf(
',' );
2594 qWarning(
"No id found in: %s", qPrintable( line ) );
2599 int epsg = line.leftRef( pos ).toInt( &ok );
2602 qWarning(
"No valid id found in: %s", qPrintable( line ) );
2607 if ( epsg == 2218 || epsg == 2221 || epsg == 2296 || epsg == 2297 || epsg == 2298 || epsg == 2299 || epsg == 2300 || epsg == 2301 || epsg == 2302 ||
2608 epsg == 2303 || epsg == 2304 || epsg == 2305 || epsg == 2306 || epsg == 2307 || epsg == 2963 || epsg == 2985 || epsg == 2986 || epsg == 3052 ||
2609 epsg == 3053 || epsg == 3139 || epsg == 3144 || epsg == 3145 || epsg == 3173 || epsg == 3295 || epsg == 3993 || epsg == 4087 || epsg == 4088 ||
2610 epsg == 5017 || epsg == 5221 || epsg == 5224 || epsg == 5225 || epsg == 5514 || epsg == 5515 || epsg == 5516 || epsg == 5819 || epsg == 5820 ||
2611 epsg == 5821 || epsg == 6200 || epsg == 6201 || epsg == 6202 || epsg == 6244 || epsg == 6245 || epsg == 6246 || epsg == 6247 || epsg == 6248 ||
2612 epsg == 6249 || epsg == 6250 || epsg == 6251 || epsg == 6252 || epsg == 6253 || epsg == 6254 || epsg == 6255 || epsg == 6256 || epsg == 6257 ||
2613 epsg == 6258 || epsg == 6259 || epsg == 6260 || epsg == 6261 || epsg == 6262 || epsg == 6263 || epsg == 6264 || epsg == 6265 || epsg == 6266 ||
2614 epsg == 6267 || epsg == 6268 || epsg == 6269 || epsg == 6270 || epsg == 6271 || epsg == 6272 || epsg == 6273 || epsg == 6274 || epsg == 6275 ||
2615 epsg == 6966 || epsg == 7082 || epsg == 32600 || epsg == 32663 || epsg == 32700 )
2618 if ( OSRImportFromEPSG( crs, epsg ) != OGRERR_NONE )
2620 qDebug(
"EPSG %d: not imported", epsg );
2624 char *wkt =
nullptr;
2625 if ( OSRExportToWkt( crs, &wkt ) != OGRERR_NONE )
2627 qWarning(
"EPSG %d: not exported to WKT", epsg );
2631 wkts.insert( epsg, wkt );
2639 QgsDebugMsgLevel( QStringLiteral(
"Loaded %1/%2 from %3" ).arg( QString::number( n ), QString::number( l ), filename.toUtf8().constData() ), 4 );
2642 OSRDestroySpatialReference( crs );
2648 #if PROJ_VERSION_MAJOR>=6 2649 static void sync_db_proj_logger(
void * ,
int level,
const char *message )
2654 if ( level == PJ_LOG_ERROR )
2658 else if ( level == PJ_LOG_DEBUG )
2667 setlocale( LC_ALL,
"C" );
2670 #if PROJ_VERSION_MAJOR<6 2671 syncDatumTransform( dbFilePath );
2674 int inserted = 0, updated = 0, deleted = 0, errors = 0;
2679 if ( database.
open( dbFilePath ) != SQLITE_OK )
2685 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2691 #if PROJ_VERSION_MAJOR<6 2693 if ( sqlite3_exec( database.get(),
"alter table tbl_srs add noupdate boolean",
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2694 ( 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 );
2696 ( 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 );
2701 char *errMsg =
nullptr;
2703 #if PROJ_VERSION_MAJOR>=6 2706 proj_log_func( pjContext,
nullptr, sync_db_proj_logger );
2708 PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
2710 int nextSrsId = 63321;
2711 int nextSrId = 520003321;
2712 for (
auto authIter = authorities; authIter && *authIter; ++authIter )
2714 const QString authority( *authIter );
2715 QgsDebugMsgLevel( QStringLiteral(
"Loading authority '%1'" ).arg( authority ), 2 );
2716 PROJ_STRING_LIST codes = proj_get_codes_from_database( pjContext, *authIter, PJ_TYPE_CRS,
true );
2718 QStringList allCodes;
2720 for (
auto codesIter = codes; codesIter && *codesIter; ++codesIter )
2722 const QString code( *codesIter );
2725 QgsProjUtils::proj_pj_unique_ptr
crs( proj_create_from_database( pjContext, *authIter, *codesIter, PJ_CATEGORY_CRS,
false,
nullptr ) );
2728 QgsDebugMsg( QStringLiteral(
"Could not load '%1:%2'" ).arg( authority, code ) );
2732 switch ( proj_get_type( crs.get() ) )
2734 case PJ_TYPE_VERTICAL_CRS:
2741 crs = QgsProjUtils::crsToSingleCrs( crs.get() );
2743 QString proj4 = getFullProjString( crs.get() );
2744 proj4.replace( QStringLiteral(
"+type=crs" ), QString() );
2745 proj4 = proj4.trimmed();
2747 if ( proj4.isEmpty() )
2749 QgsDebugMsgLevel( QStringLiteral(
"No proj4 for '%1:%2'" ).arg( authority, code ), 2 );
2754 const bool deprecated = proj_is_deprecated( crs.get() );
2755 const QString name( proj_get_name( crs.get() ) );
2757 QString sql = QStringLiteral(
"SELECT parameters,description,deprecated FROM tbl_srs WHERE auth_name='%1' AND auth_id='%2'" ).arg( authority, code );
2758 statement = database.
prepare( sql, result );
2759 if ( result != SQLITE_OK )
2767 bool srsDeprecated = deprecated;
2768 if ( statement.
step() == SQLITE_ROW )
2772 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2775 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
2777 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
2780 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name=%4 AND auth_id=%5" )
2781 .arg( QgsSqliteUtils::quotedString( proj4 ) )
2782 .arg( QgsSqliteUtils::quotedString( name ) )
2783 .arg( deprecated ? 1 : 0 )
2784 .arg( QgsSqliteUtils::quotedString( authority ), QgsSqliteUtils::quotedString( code ) );
2786 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2788 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2791 errMsg ? errMsg :
"(unknown error)" ) );
2793 sqlite3_free( errMsg );
2805 QString operation =
"";
2807 getOperationAndEllipsoidFromProjString( proj4, operation, ellps );
2808 const bool isGeographic = testIsGeographic( crs.get() );
2811 const QString dbVals = sAuthIdToQgisSrsIdMap.value( QStringLiteral(
"%1:%2" ).arg( authority, code ) );
2814 if ( !dbVals.isEmpty() )
2816 const QStringList parts = dbVals.split(
',' );
2817 srsId = parts.at( 0 );
2818 srId = parts.at( 1 );
2820 if ( srId.isEmpty() )
2822 srId = QString::number( nextSrId );
2825 if ( srsId.isEmpty() )
2827 srsId = QString::number( nextSrsId );
2831 if ( !srsId.isEmpty() )
2833 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)" )
2835 .arg( QgsSqliteUtils::quotedString( name ),
2836 QgsSqliteUtils::quotedString( operation ),
2837 QgsSqliteUtils::quotedString( ellps ),
2838 QgsSqliteUtils::quotedString( proj4 ) )
2840 .arg( QgsSqliteUtils::quotedString( authority ) )
2841 .arg( QgsSqliteUtils::quotedString( code ) )
2842 .arg( isGeographic ? 1 : 0 )
2843 .arg( deprecated ? 1 : 0 );
2847 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)" )
2848 .arg( QgsSqliteUtils::quotedString( name ),
2849 QgsSqliteUtils::quotedString( operation ),
2850 QgsSqliteUtils::quotedString( ellps ),
2851 QgsSqliteUtils::quotedString( proj4 ) )
2853 .arg( QgsSqliteUtils::quotedString( authority ) )
2854 .arg( QgsSqliteUtils::quotedString( code ) )
2855 .arg( isGeographic ? 1 : 0 )
2856 .arg( deprecated ? 1 : 0 );
2860 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2866 qCritical(
"Could not execute: %s [%s/%s]\n",
2867 sql.toLocal8Bit().constData(),
2868 sqlite3_errmsg( database.get() ),
2869 errMsg ? errMsg :
"(unknown error)" );
2873 sqlite3_free( errMsg );
2878 proj_string_list_destroy( codes );
2880 const QString sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='%1' AND NOT auth_id IN (%2)" ).arg( authority, allCodes.join(
',' ) );
2881 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2883 deleted = sqlite3_changes( database.get() );
2888 qCritical(
"Could not execute: %s [%s]\n",
2889 sql.toLocal8Bit().constData(),
2890 sqlite3_errmsg( database.get() ) );
2894 proj_string_list_destroy( authorities );
2902 QHash<int, QString> wkts;
2904 loadWkts( wkts,
"epsg.wkt" );
2906 QgsDebugMsgLevel( QStringLiteral(
"%1 WKTs loaded" ).arg( wkts.count() ), 4 );
2908 for ( QHash<int, QString>::const_iterator it = wkts.constBegin(); it != wkts.constEnd(); ++it )
2910 QByteArray ba( it.value().toUtf8() );
2911 char *psz = ba.data();
2914 OSRDestroySpatialReference( crs );
2916 crs = OSRNewSpatialReference(
nullptr );
2918 OGRErr ogrErr = OSRImportFromWkt( crs, &psz );
2919 if ( ogrErr != OGRERR_NONE )
2922 if ( OSRExportToProj4( crs, &psz ) != OGRERR_NONE )
2929 proj4 = proj4.trimmed();
2933 if ( proj4.isEmpty() )
2936 QString name( OSRIsGeographic( crs ) ? OSRGetAttrValue( crs,
"GEOGCS", 0 ) :
2937 OSRIsGeocentric( crs ) ? OSRGetAttrValue( crs,
"GEOCCS", 0 ) :
2938 OSRGetAttrValue( crs,
"PROJCS", 0 ) );
2939 if ( name.isEmpty() )
2940 name = QObject::tr(
"Imported from GDAL" );
2942 bool deprecated = name.contains( QLatin1Literal(
"(deprecated)" ) );
2944 sql = QStringLiteral(
"SELECT parameters,description,deprecated,noupdate FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).arg( it.key() );
2945 statement = database.
prepare( sql, result );
2946 if ( result != SQLITE_OK )
2954 bool srsDeprecated = deprecated;
2955 if ( statement.
step() == SQLITE_ROW )
2959 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
2967 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
2969 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
2972 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name='EPSG' AND auth_id=%4" )
2975 .arg( deprecated ? 1 : 0 )
2978 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2980 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2983 errMsg ? errMsg :
"(unknown error)" ) );
2985 sqlite3_free( errMsg );
2996 QRegExp projRegExp(
"\\+proj=(\\S+)" );
2997 if ( projRegExp.indexIn( proj4 ) < 0 )
2999 QgsDebugMsgLevel( QStringLiteral(
"EPSG %1: no +proj argument found [%2]" ).arg( it.key() ).arg( proj4 ), 4 );
3003 QRegExp ellipseRegExp(
"\\+ellps=(\\S+)" );
3005 if ( ellipseRegExp.indexIn( proj4 ) >= 0 )
3007 ellps = ellipseRegExp.cap( 1 );
3019 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)" )
3025 .arg( OSRIsGeographic( crs ) )
3026 .arg( deprecated ? 1 : 0 );
3029 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
3035 qCritical(
"Could not execute: %s [%s/%s]\n",
3036 sql.toLocal8Bit().constData(),
3037 sqlite3_errmsg( database.get() ),
3038 errMsg ? errMsg :
"(unknown error)" );
3042 sqlite3_free( errMsg );
3048 OSRDestroySpatialReference( crs );
3051 sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN (" );
3053 QHash<int, QString>::const_iterator it = wkts.constBegin();
3054 for ( ; it != wkts.constEnd(); ++it )
3056 sql += delim + QString::number( it.key() );
3059 sql += QLatin1String(
") AND NOT noupdate" );
3061 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) == SQLITE_OK )
3063 deleted = sqlite3_changes( database.get() );
3068 qCritical(
"Could not execute: %s [%s]\n",
3069 sql.toLocal8Bit().constData(),
3070 sqlite3_errmsg( database.get() ) );
3073 projCtx pContext = pj_ctx_alloc();
3075 #if !defined(PJ_VERSION) || PJ_VERSION!=470 3076 sql = QStringLiteral(
"select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated AND NOT noupdate" );
3077 statement = database.
prepare( sql, result );
3078 if ( result == SQLITE_OK )
3080 while ( statement.
step() == SQLITE_ROW )
3086 QString input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toLower(), auth_id );
3087 projPJ pj = pj_init_plus_ctx( pContext, input.toLatin1() );
3090 input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toUpper(), auth_id );
3091 pj = pj_init_plus_ctx( pContext, input.toLatin1() );
3096 char *def = pj_get_def( pj, 0 );
3102 input.prepend(
' ' ).append(
' ' );
3103 if ( proj4.startsWith( input ) )
3105 proj4 = proj4.mid( input.size() );
3106 proj4 = proj4.trimmed();
3109 if ( proj4 != params )
3111 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
3116 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
3122 qCritical(
"Could not execute: %s [%s/%s]\n",
3123 sql.toLocal8Bit().constData(),
3124 sqlite3_errmsg( database.get() ),
3125 errMsg ? errMsg :
"(unknown error)" );
3127 sqlite3_free( errMsg );
3134 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve proj string for %1 from PROJ" ).arg( input ), 4 );
3139 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve crs for %1 from PROJ" ).arg( input ), 3 );
3148 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2]\n" ).arg(
3150 sqlite3_errmsg( database.get() ) ) );
3154 pj_ctx_free( pContext );
3158 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
3160 QgsDebugMsg( QStringLiteral(
"Could not commit transaction: %1 [%2]\n" ).arg(
3162 sqlite3_errmsg( database.get() ) )
3168 QgsDebugMsgLevel( QStringLiteral(
"CRS update (inserted:%1 updated:%2 deleted:%3 errors:%4)" ).arg( inserted ).arg( updated ).arg( deleted ).arg( errors ), 4 );
3176 return updated + inserted;
3179 #if PROJ_VERSION_MAJOR<6 3180 bool QgsCoordinateReferenceSystem::syncDatumTransform(
const QString &dbPath )
3182 const char *filename = CSVFilename(
"datum_shift.csv" );
3183 FILE *fp = VSIFOpen( filename,
"rb" );
3189 char **fieldnames = CSVReadParseLine( fp );
3201 {
"SOURCE_CRS_CODE",
"source_crs_code", -1 },
3202 {
"TARGET_CRS_CODE",
"target_crs_code", -1 },
3203 {
"REMARKS",
"remarks", -1 },
3204 {
"COORD_OP_SCOPE",
"scope", -1 },
3205 {
"AREA_OF_USE_CODE",
"area_of_use_code", -1 },
3211 {
"DEPRECATED",
"deprecated", -1 },
3212 {
"COORD_OP_METHOD_CODE",
"coord_op_method_code", -1 },
3220 {
"PREFERRED",
"preferred", -1 },
3221 {
"COORD_OP_CODE",
"coord_op_code", -1 },
3224 QString update = QStringLiteral(
"UPDATE tbl_datum_transform SET " );
3226 const int n = CSLCount( fieldnames );
3227 int idxid = -1, idxrx = -1, idxry = -1, idxrz = -1, idxmcode = -1;
3232 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
3234 bool last = i ==
sizeof( map ) /
sizeof( *map ) - 1;
3236 map[i].idx = CSLFindString( fieldnames, map[i].src );
3237 if ( map[i].idx < 0 )
3239 qWarning(
"field %s not found", map[i].src );
3240 CSLDestroy( fieldnames );
3245 if ( strcmp( map[i].src,
"COORD_OP_CODE" ) == 0 )
3247 if ( strcmp( map[i].src,
"RX" ) == 0 )
3249 if ( strcmp( map[i].src,
"RY" ) == 0 )
3251 if ( strcmp( map[i].src,
"RZ" ) == 0 )
3253 if ( strcmp( map[i].src,
"COORD_OP_METHOD_CODE" ) == 0 )
3263 update += QLatin1String(
" WHERE " );
3271 update += QStringLiteral(
"%1=%%2" ).arg( map[i].dst ).arg( i + 1 );
3273 insert += map[i].dst;
3274 values += QStringLiteral(
"%%1" ).arg( i + 1 );
3277 insert =
"INSERT INTO tbl_datum_transform(" + insert +
") VALUES (" + values +
')';
3279 Q_ASSERT( idxid >= 0 );
3280 Q_ASSERT( idxrx >= 0 );
3281 Q_ASSERT( idxry >= 0 );
3282 Q_ASSERT( idxrz >= 0 );
3285 CSLDestroy( fieldnames );
3288 int openResult = database.
open( dbPath );
3289 if ( openResult != SQLITE_OK )
3295 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
3303 v.reserve(
sizeof( map ) /
sizeof( *map ) );
3307 char **values = CSVReadParseLine( fp );
3313 if ( CSLCount( values ) == 0 )
3315 CSLDestroy( values );
3319 if ( CSLCount( values ) < n )
3321 qWarning(
"Only %d columns", CSLCount( values ) );
3322 CSLDestroy( values );
3326 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
3328 int idx = map[i].idx;
3329 Q_ASSERT( idx != -1 );
3330 Q_ASSERT( idx < n );
3333 CSLDestroy( values );
3336 if ( v.at( idxmcode ).compare( QLatin1String(
"'9607'" ) ) == 0 )
3338 v[ idxmcode ] = QStringLiteral(
"'9606'" );
3339 v[ idxrx ] =
'\'' +
qgsDoubleToString( -( v[ idxrx ].
remove(
'\'' ).toDouble() ) ) +
'\'';
3340 v[ idxry ] =
'\'' +
qgsDoubleToString( -( v[ idxry ].
remove(
'\'' ).toDouble() ) ) +
'\'';
3341 v[ idxrz ] =
'\'' +
qgsDoubleToString( -( v[ idxrz ].
remove(
'\'' ).toDouble() ) ) +
'\'';
3347 QString sql = QStringLiteral(
"SELECT coord_op_code FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( v[ idxid ] );
3349 statement = database.
prepare( sql, prepareRes );
3350 if ( prepareRes != SQLITE_OK )
3353 if ( statement.
step() == SQLITE_ROW )
3358 sql = cOpCode.isEmpty() ? insert : update;
3359 for (
int i = 0; i < v.size(); i++ )
3361 sql = sql.arg( v[i] );
3364 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) != SQLITE_OK )
3366 qCritical(
"SQL: %s", sql.toUtf8().constData() );
3367 qCritical(
"Error: %s", sqlite3_errmsg( database.get() ) );
3371 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
3381 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::stringCache()
3383 return *sStringCache();
3386 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::projCache()
3388 return *sProj4Cache();
3391 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::ogcCache()
3393 return *sOgcCache();
3396 const QHash<QString, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::wktCache()
3398 return *sWktCache();
3401 const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srIdCache()
3403 return *sSrIdCache();
3406 const QHash<long, QgsCoordinateReferenceSystem> &QgsCoordinateReferenceSystem::srsIdCache()
3408 return *sSrsIdCache();
3417 #if PROJ_VERSION_MAJOR>=6 3418 else if ( PJ *obj = d->threadLocalProjObject() )
3420 QgsProjUtils::proj_pj_unique_ptr geoCrs( proj_crs_get_geodetic_crs(
QgsProjContext::get(), obj ) );
3421 return geoCrs ? QStringLiteral(
"%1:%2" ).arg( proj_get_id_auth_name( geoCrs.get(), 0 ), proj_get_id_code( geoCrs.get(), 0 ) ) : QString();
3426 return OSRGetAuthorityName( d->mCRS,
"GEOGCS" ) + QStringLiteral(
":" ) + OSRGetAuthorityCode( d->mCRS,
"GEOGCS" );
3435 #if PROJ_VERSION_MAJOR>=6 3436 PJ *QgsCoordinateReferenceSystem::projObject()
const 3438 return d->threadLocalProjObject();
3444 QStringList projections;
3446 projections.reserve( res.size() );
3449 projections << QString::number(
crs.
srsid() );
3456 QList<QgsCoordinateReferenceSystem> res;
3460 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
3461 QStringList projectionsWkt = settings.
value( QStringLiteral(
"UI/recentProjectionsWkt" ) ).toStringList();
3462 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
3463 int max = std::max( projectionsAuthId.size(), std::max( projectionsProj4.size(), projectionsWkt.size() ) );
3465 for (
int i = 0; i < max; ++i )
3467 const QString proj = projectionsProj4.value( i );
3468 const QString wkt = projectionsWkt.value( i );
3469 const QString
authid = projectionsAuthId.value( i );
3472 if ( !authid.isEmpty() )
3474 if ( !crs.
isValid() && !wkt.isEmpty() )
3476 if ( !crs.
isValid() && !proj.isEmpty() )
3492 recent.removeAll( crs );
3493 recent.insert( 0, crs );
3496 recent = recent.mid( 0, 10 );
3497 QStringList authids;
3498 authids.reserve( recent.size() );
3500 proj.reserve( recent.size() );
3502 wkt.reserve( recent.size() );
3505 authids <<
c.authid();
3511 settings.
setValue( QStringLiteral(
"UI/recentProjectionsAuthId" ), authids );
3512 settings.
setValue( QStringLiteral(
"UI/recentProjectionsWkt" ), wkt );
3513 settings.
setValue( QStringLiteral(
"UI/recentProjectionsProj4" ), proj );
3518 sSrIdCacheLock()->lockForWrite();
3519 if ( !sDisableSrIdCache )
3522 sDisableSrIdCache =
true;
3523 sSrIdCache()->clear();
3525 sSrIdCacheLock()->unlock();
3527 sOgcLock()->lockForWrite();
3528 if ( !sDisableOgcCache )
3531 sDisableOgcCache =
true;
3532 sOgcCache()->clear();
3534 sOgcLock()->unlock();
3536 sProj4CacheLock()->lockForWrite();
3537 if ( !sDisableProjCache )
3540 sDisableProjCache =
true;
3541 sProj4Cache()->clear();
3543 sProj4CacheLock()->unlock();
3545 sCRSWktLock()->lockForWrite();
3546 if ( !sDisableWktCache )
3549 sDisableWktCache =
true;
3550 sWktCache()->clear();
3552 sCRSWktLock()->unlock();
3554 sCRSSrsIdLock()->lockForWrite();
3555 if ( !sDisableSrsIdCache )
3558 sDisableSrsIdCache =
true;
3559 sSrsIdCache()->clear();
3561 sCRSSrsIdLock()->unlock();
3563 sCrsStringLock()->lockForWrite();
3564 if ( !sDisableStringCache )
3567 sDisableStringCache =
true;
3568 sStringCache()->clear();
3570 sCrsStringLock()->unlock();
QString geographicCrsAuthId() const
Returns auth id of related geographic CRS.
QgsCoordinateReferenceSystem()
Constructs an invalid CRS object.
Q_DECL_DEPRECATED bool createFromId(long id, CrsType type=PostgisCrsId)
Sets this CRS by lookup of the given ID in the CRS database.
bool operator!=(const QgsCoordinateReferenceSystem &srs) const
Overloaded != operator used to compare to CRS's.
bool createFromProj(const QString &projString)
Sets this CRS by passing it a PROJ style formatted string.
A rectangle specified with double values.
QHash< QString, QgsCoordinateReferenceSystem > StringCrsCacheHash
static Q_DECL_DEPRECATED QgsCoordinateReferenceSystem fromProj4(const QString &proj4)
Creates a CRS from a proj style formatted string.
bool createFromString(const QString &definition)
Set up this CRS from a string definition.
static QList< long > validSrsIds()
Returns a list of all valid SRS IDs present in the CRS database.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
void setXMaximum(double x)
Set the maximum x value.
This class is a composition of two QSettings instances:
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
QString toProj() const
Returns a Proj string representation of this CRS.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void validate()
Perform some validation on this CRS.
long saveAsUserCrs(const QString &name, Format nativeFormat=FormatWkt)
Saves the CRS as a custom ("USER") CRS.
static void warning(const QString &msg)
Goes to qWarning.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
static void setCustomCrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS.
static QString OGRSpatialReferenceToWkt(OGRSpatialReferenceH srs)
Returns a WKT string corresponding to the specified OGR srs object.
#define Q_NOWARN_DEPRECATED_PUSH
Q_DECL_DEPRECATED QString toProj4() const
Returns a Proj string representation of this CRS.
const int LAT_PREFIX_LEN
The length of the string "+lat_1=".
Full WKT2 string, conforming to ISO 19162:2015(E) / OGC 12-063r5 with all possible nodes and new keyw...
SRID used in PostGIS. DEPRECATED – DO NOT USE.
const QgsCoordinateReferenceSystem & crs
WKT2_2018 with the simplification rule of WKT2_SIMPLIFIED.
Internal ID used by QGIS in the local SQLite database.
WKT format (always recommended over proj string format)
bool createFromOgcWmsCrs(const QString &crs)
Sets this CRS to the given OGC WMS-format Coordinate Reference Systems.
Same as WKT2_2015 with the following exceptions: UNIT keyword used. ID node only on top element...
QString errorMessage() const
Returns the most recent error message encountered by the database.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
static Q_INVOKABLE QgsCoordinateReferenceSystem fromEpsgId(long epsg)
Creates a CRS from a given EPSG ID.
void setValidationHint(const QString &html)
Set user hint for validation.
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
Format
Projection definition formats.
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define QgsDebugMsgLevel(str, level)
Q_DECL_DEPRECATED bool createFromSrid(long srid)
Sets this CRS by lookup of the given PostGIS SRID in the CRS database.
WKT1 as traditionally output by GDAL, deriving from OGC 01-009. A notable departure from WKT1_GDAL wi...
static QList< QgsCoordinateReferenceSystem > recentCoordinateReferenceSystems()
Returns a list of recently used CRS.
static Q_DECL_DEPRECATED QStringList recentProjections()
Returns a list of recently used projections.
int step()
Steps to the next record in the statement, returning the sqlite3 result code.
QString validationHint()
Gets user hint for validation.
long postgisSrid() const
Returns PostGIS SRID for the CRS.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Q_DECL_DEPRECATED long findMatchingProj()
Walks the CRS databases (both system and user database) trying to match stored PROJ string to a datab...
void setYMinimum(double y)
Set the minimum y value.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
int columnCount() const
Gets the number of columns that this statement returns.
static void pushRecentCoordinateReferenceSystem(const QgsCoordinateReferenceSystem &crs)
Pushes a recently used CRS to the top of the recent CRS list.
QHash< long, QgsCoordinateReferenceSystem > SrIdCrsCacheHash
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
Degrees, for planar geographic CRS distance measurements.
QgsCoordinateReferenceSystem & operator=(const QgsCoordinateReferenceSystem &srs)
Assignment operator.
QString columnAsText(int column) const
Returns the column value from the current statement row as a string.
IdentifierType
Type of identifier string to create.
bool isGeographic() const
Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
int open(const QString &path)
Opens the database at the specified file path.
bool createFromWkt(const QString &wkt)
Sets this CRS using a WKT definition.
~QgsCoordinateReferenceSystem()
CrsType
Enumeration of types of IDs accepted in createFromId() method.
static CUSTOM_CRS_VALIDATION customCrsValidation()
Gets custom function.
Full WKT2 string, conforming to ISO 19162:2018 / OGC 18-010, with all possible nodes and new keyword ...
A medium-length string, recommended for general purpose use.
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
DistanceUnit
Units of distance.
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
#define Q_NOWARN_DEPRECATED_POP
void unlock()
Unlocks the lock.
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
const int USER_CRS_START_ID
Magick number that determines whether a projection crsid is a system (srs.db) or user (~/...
bool createFromSrsId(long srsId)
Sets this CRS by lookup of internal QGIS CRS ID in the CRS database.
static QgsCoordinateReferenceSystem fromProj(const QString &proj)
Creates a CRS from a proj style formatted string.
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
Allow matching a BoundCRS object to its underlying SourceCRS.
bool createFromUserInput(const QString &definition)
Set up this CRS from various text formats.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void setYMaximum(double y)
Set the maximum y value.
bool hasAxisInverted() const
Returns whether axis is inverted (e.g., for WMS 1.3) for the CRS.
This class represents a coordinate reference system (CRS).
A heavily abbreviated string, for use when a compact representation is required.
Q_DECL_DEPRECATED bool createFromProj4(const QString &projString)
Sets this CRS by passing it a PROJ style formatted string.
void changeMode(Mode mode)
Change the mode of the lock to mode.
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
QgsUnitTypes::DistanceUnit mapUnits() const
Returns the units for the projection used by the CRS.
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
WktVariant
WKT formatting variants, only used for builds based on Proj >= 6.
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
QgsRectangle bounds() const
Returns the approximate bounds for the region the CRS is usable within.
long srsid() const
Returns the internal CRS ID, if available.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
bool operator==(const QgsCoordinateReferenceSystem &srs) const
Overloaded == operator used to compare to CRS's.
QString columnName(int column) const
Returns the name of column.
double columnAsDouble(int column) const
Gets column value from the current statement row as a double.
qlonglong columnAsInt64(int column) const
Gets column value from the current statement row as a long long integer (64 bits).
static int syncDatabase()
Update proj.4 parameters in our database from proj.4.
QString authid() const
Returns the authority identifier for the CRS.
static Q_DECL_DEPRECATED void setupESRIWktFix()
Make sure that ESRI WKT import is done properly.
void setXMinimum(double x)
Set the minimum x value.
static QgsCoordinateReferenceSystem fromSrsId(long srsId)
Creates a CRS from a specified QGIS SRS ID.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
void * OGRSpatialReferenceH
WKT1 as traditionally output by ESRI software, deriving from OGC 99-049.
static QString quotedString(const QString &value)
Returns a quoted string value, surround by ' characters and with special characters correctly escaped...
bool isValid() const
Returns whether this CRS is correctly initialized and usable.