26 #include <QDomElement> 29 #include <QTextStream> 31 #include <QRegularExpression> 41 #ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 42 #define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 47 #include <ogr_srs_api.h> 48 #include <cpl_error.h> 58 QReadWriteLock QgsCoordinateReferenceSystem::sSrIdCacheLock;
59 QHash< long, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sSrIdCache;
60 bool QgsCoordinateReferenceSystem::sDisableSrIdCache =
false;
62 QReadWriteLock QgsCoordinateReferenceSystem::sOgcLock;
63 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sOgcCache;
64 bool QgsCoordinateReferenceSystem::sDisableOgcCache =
false;
66 QReadWriteLock QgsCoordinateReferenceSystem::sProj4CacheLock;
67 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sProj4Cache;
68 bool QgsCoordinateReferenceSystem::sDisableProj4Cache =
false;
70 QReadWriteLock QgsCoordinateReferenceSystem::sCRSWktLock;
71 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sWktCache;
72 bool QgsCoordinateReferenceSystem::sDisableWktCache =
false;
74 QReadWriteLock QgsCoordinateReferenceSystem::sCRSSrsIdLock;
75 QHash< long, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sSrsIdCache;
76 bool QgsCoordinateReferenceSystem::sDisableSrsIdCache =
false;
78 QReadWriteLock QgsCoordinateReferenceSystem::sCrsStringLock;
79 QHash< QString, QgsCoordinateReferenceSystem > QgsCoordinateReferenceSystem::sStringCache;
80 bool QgsCoordinateReferenceSystem::sDisableStringCache =
false;
86 d =
new QgsCoordinateReferenceSystemPrivate();
91 d =
new QgsCoordinateReferenceSystemPrivate();
97 d =
new QgsCoordinateReferenceSystemPrivate();
118 Q_FOREACH (
const QString &db, dbs )
120 QFileInfo myInfo( db );
121 if ( !myInfo.exists() )
123 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
131 int result = openDatabase( db, database );
132 if ( result != SQLITE_OK )
134 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
138 QString sql = QStringLiteral(
"select srs_id from tbl_srs" );
140 statement = database.
prepare( sql, rc );
144 int ret = statement.
step();
146 if ( ret == SQLITE_DONE )
152 if ( ret == SQLITE_ROW )
158 QgsMessageLog::logMessage( QObject::tr(
"SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr(
"SpatiaLite" ) );
163 std::sort( results.begin(), results.end() );
220 QgsDebugMsg( QStringLiteral(
"Unexpected case reached!" ) );
228 if ( !sDisableStringCache )
230 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sStringCache.constFind( definition );
231 if ( crsIt != sStringCache.constEnd() )
234 *
this = crsIt.value();
241 QRegularExpression reCrsId(
"^(epsg|postgis|internal|user)\\:(\\d+)$", QRegularExpression::CaseInsensitiveOption );
242 QRegularExpressionMatch match = reCrsId.match( definition );
243 if ( match.capturedStart() == 0 )
245 QString authName = match.captured( 1 ).toLower();
247 if ( authName == QLatin1String(
"epsg" ) )
249 if ( authName == QLatin1String(
"postgis" ) )
251 long id = match.captured( 2 ).toLong();
256 QRegularExpression reCrsStr(
"^(?:(wkt|proj4)\\:)?(.+)$", QRegularExpression::CaseInsensitiveOption );
257 match = reCrsStr.match( definition );
258 if ( match.capturedStart() == 0 )
260 if ( match.captured( 1 ).compare( QLatin1String(
"proj4" ), Qt::CaseInsensitive ) == 0 )
269 QString myName = QStringLiteral(
" * %1 (%2)" )
270 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
283 if ( !sDisableStringCache )
284 sStringCache.insert( definition, *
this );
295 if ( definition.startsWith( QLatin1String(
"ESRI::" ) ) )
300 if ( OSRSetFromUserInput( crs, definition.toLocal8Bit().constData() ) == OGRERR_NONE )
302 if ( OSRExportToWkt( crs, &wkt ) == OGRERR_NONE )
307 OSRDestroySpatialReference( crs );
317 const char *configOld = CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" );
318 const char *configNew =
"GEOGCS";
320 if ( strcmp( configOld,
"" ) == 0 )
322 CPLSetConfigOption(
"GDAL_FIX_ESRI_WKT", configNew );
323 if ( strcmp( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) != 0 )
325 .arg( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) );
326 QgsDebugMsgLevel( QStringLiteral(
"set GDAL_FIX_ESRI_WKT : %1" ).arg( configNew ), 4 );
330 QgsDebugMsgLevel( QStringLiteral(
"GDAL_FIX_ESRI_WKT was already set : %1" ).arg( configNew ), 4 );
337 if ( !sDisableOgcCache )
339 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sOgcCache.constFind( crs );
340 if ( crsIt != sOgcCache.constEnd() )
343 *
this = crsIt.value();
349 QString wmsCrs =
crs;
351 QRegExp re(
"urn:ogc:def:crs:([^:]+).+([^:]+)", Qt::CaseInsensitive );
352 if ( re.exactMatch( wmsCrs ) )
354 wmsCrs = re.cap( 1 ) +
':' + re.cap( 2 );
358 re.setPattern( QStringLiteral(
"(user|custom|qgis):(\\d+)" ) );
359 if ( re.exactMatch( wmsCrs ) &&
createFromSrsId( re.cap( 2 ).toInt() ) )
362 if ( !sDisableOgcCache )
363 sOgcCache.insert( crs, *
this );
371 if ( !sDisableOgcCache )
372 sOgcCache.insert( crs, *
this );
377 if ( wmsCrs.compare( QLatin1String(
"CRS:27" ), Qt::CaseInsensitive ) == 0 ||
378 wmsCrs.compare( QLatin1String(
"OGC:CRS27" ), Qt::CaseInsensitive ) == 0 )
385 if ( wmsCrs.compare( QLatin1String(
"CRS:83" ), Qt::CaseInsensitive ) == 0 ||
386 wmsCrs.compare( QLatin1String(
"OGC:CRS83" ), Qt::CaseInsensitive ) == 0 )
393 if ( wmsCrs.compare( QLatin1String(
"CRS:84" ), Qt::CaseInsensitive ) == 0 ||
394 wmsCrs.compare( QLatin1String(
"OGC:CRS84" ), Qt::CaseInsensitive ) == 0 )
399 d->mAxisInverted =
false;
400 d->mAxisInvertedDirty =
false;
403 if ( !sDisableOgcCache )
404 sOgcCache.insert( crs, *
this );
410 if ( !sDisableOgcCache )
426 if ( mCustomSrsValidation )
427 mCustomSrsValidation( *
this );
438 if ( !sDisableSrIdCache )
440 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrIdCache.constFind(
id );
441 if ( crsIt != sSrIdCache.constEnd() )
444 *
this = crsIt.value();
453 if ( !sDisableSrIdCache )
454 sSrIdCache.insert(
id, *
this );
462 if ( !sDisableSrsIdCache )
464 QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = sSrsIdCache.constFind(
id );
465 if ( crsIt != sSrsIdCache.constEnd() )
468 *
this = crsIt.value();
476 QStringLiteral(
"srs_id" ), QString::number(
id ) );
479 if ( !sDisableSrsIdCache )
480 sSrsIdCache.insert(
id, *
this );
484 bool QgsCoordinateReferenceSystem::loadFromDatabase(
const QString &db,
const QString &expression,
const QString &value )
488 QgsDebugMsgLevel(
"load CRS from " + db +
" where " + expression +
" is " + value, 3 );
492 QFileInfo myInfo( db );
493 if ( !myInfo.exists() )
495 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
503 myResult = openDatabase( db, database );
504 if ( myResult != SQLITE_OK )
521 QString mySql =
"select srs_id,description,projection_acronym," 522 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo " 524 statement = database.
prepare( mySql, myResult );
526 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
535 d->mIsGeographic = statement.
columnAsText( 7 ).toInt() != 0;
536 d->mAxisInvertedDirty =
true;
540 d->mAuthId = QStringLiteral(
"USER:%1" ).arg( d->mSrsId );
542 else if ( d->mAuthId.startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
544 OSRDestroySpatialReference( d->mCRS );
545 d->mCRS = OSRNewSpatialReference(
nullptr );
546 d->mIsValid = OSRSetFromUserInput( d->mCRS, d->mAuthId.toLower().toLatin1() ) == OGRERR_NONE;
552 setProj4String( d->mProj4 );
564 if ( d->mAxisInvertedDirty )
566 OGRAxisOrientation orientation;
567 OSRGetAxis( d->mCRS, OSRIsGeographic( d->mCRS ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
570 if ( orientation == OAO_Other && d->mAuthId.startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
574 if ( OSRImportFromEPSGA( crs, d->mAuthId.midRef( 5 ).toInt() ) == OGRERR_NONE )
576 OSRGetAxis( crs, OSRIsGeographic( crs ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
579 OSRDestroySpatialReference( crs );
582 d->mAxisInverted = orientation == OAO_North;
583 d->mAxisInvertedDirty =
false;
586 return d->mAxisInverted;
594 if ( !sDisableWktCache )
596 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sWktCache.constFind( wkt );
597 if ( crsIt != sWktCache.constEnd() )
600 *
this = crsIt.value();
612 QgsDebugMsgLevel( QStringLiteral(
"theWkt is uninitialized, operation failed" ), 4 );
615 QByteArray ba = wkt.toLatin1();
616 const char *pWkt = ba.data();
618 OGRErr myInputResult = OSRImportFromWkt( d->mCRS, const_cast< char ** >( & pWkt ) );
620 if ( myInputResult != OGRERR_NONE )
622 QgsDebugMsg( QStringLiteral(
"\n---------------------------------------------------------------" ) );
623 QgsDebugMsg( QStringLiteral(
"This CRS could *** NOT *** be set from the supplied Wkt " ) );
625 QgsDebugMsg( QStringLiteral(
"UNUSED WKT: %1" ).arg( pWkt ) );
626 QgsDebugMsg( QStringLiteral(
"---------------------------------------------------------------\n" ) );
629 if ( !sDisableWktCache )
630 sWktCache.insert( wkt, *
this );
634 if ( OSRAutoIdentifyEPSG( d->mCRS ) == OGRERR_NONE )
636 QString
authid = QStringLiteral(
"%1:%2" )
637 .arg( OSRGetAuthorityName( d->mCRS,
nullptr ),
638 OSRGetAuthorityCode( d->mCRS,
nullptr ) );
641 if ( !sDisableWktCache )
642 sWktCache.insert( wkt, *
this );
651 char *proj4src =
nullptr;
652 OSRExportToProj4( d->mCRS, &proj4src );
661 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0) 666 OSRExportToProj4( d->mCRS, &proj4src );
674 if ( d->mSrsId == 0 )
676 QString myName = QStringLiteral(
" * %1 (%2)" )
677 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
685 if ( !sDisableWktCache )
686 sWktCache.insert( wkt, *
this );
702 if ( !sDisableProj4Cache )
704 QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = sProj4Cache.constFind( proj4String );
705 if ( crsIt != sProj4Cache.constEnd() )
708 *
this = crsIt.value();
722 QString myProj4String = proj4String.trimmed();
726 QRegExp myProjRegExp(
"\\+proj=(\\S+)" );
727 int myStart = myProjRegExp.indexIn( myProj4String );
731 if ( !sDisableProj4Cache )
732 sProj4Cache.insert( proj4String, *
this );
737 d->mProjectionAcronym = myProjRegExp.cap( 1 );
739 QRegExp myEllipseRegExp(
"\\+ellps=(\\S+)" );
740 myStart = myEllipseRegExp.indexIn( myProj4String );
743 d->mEllipsoidAcronym.clear();
747 d->mEllipsoidAcronym = myEllipseRegExp.cap( 1 );
750 QRegExp myAxisRegExp(
"\\+a=(\\S+)" );
751 myStart = myAxisRegExp.indexIn( myProj4String );
754 QgsCoordinateReferenceSystem::RecordMap myRecord;
760 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( myProj4String ) +
" order by deprecated" );
761 if ( myRecord.empty() )
766 QRegExp myLat1RegExp(
"\\+lat_1=\\S+" );
767 QRegExp myLat2RegExp(
"\\+lat_2=\\S+" );
774 myStart1 = myLat1RegExp.indexIn( myProj4String, myStart1 );
775 myStart2 = myLat2RegExp.indexIn( myProj4String, myStart2 );
776 if ( myStart1 != -1 && myStart2 != -1 )
778 myLength1 = myLat1RegExp.matchedLength();
779 myLength2 = myLat2RegExp.matchedLength();
784 if ( !lat1Str.isEmpty() && !lat2Str.isEmpty() )
787 QString proj4StringModified = myProj4String;
792 myStart2 = myLat2RegExp.indexIn( proj4String, myStart2 );
794 QgsDebugMsgLevel( QStringLiteral(
"trying proj4string match with swapped lat_1,lat_2" ), 4 );
795 myRecord = getRecord(
"select * from tbl_srs where parameters=" +
QgsSqliteUtils::quotedString( proj4StringModified.trimmed() ) +
" order by deprecated" );
799 if ( myRecord.empty() )
806 QString sql = QStringLiteral(
"SELECT * FROM tbl_srs WHERE " );
813 QStringList myParams;
814 Q_FOREACH (
const QString ¶m, myProj4String.split( QRegExp(
"\\s+(?=\\+)" ), QString::SkipEmptyParts ) )
816 QString arg = QStringLiteral(
"' '||parameters||' ' LIKE %1" ).arg(
QgsSqliteUtils::quotedString( QStringLiteral(
"% %1 %" ).arg( param.trimmed() ) ) );
817 if ( param.startsWith( QLatin1String(
"+datum=" ) ) )
824 delim = QStringLiteral(
" AND " );
825 myParams << param.trimmed();
829 if ( !datum.isEmpty() )
831 myRecord = getRecord( sql + delim + datum +
" order by deprecated" );
834 if ( myRecord.empty() )
837 myRecord = getRecord( sql +
" order by deprecated" );
840 if ( !myRecord.empty() )
843 QStringList foundParams;
844 Q_FOREACH (
const QString ¶m, myRecord[
"parameters"].split( QRegExp(
"\\s+(?=\\+)" ), QString::SkipEmptyParts ) )
846 if ( !param.startsWith( QLatin1String(
"+datum=" ) ) )
847 foundParams << param.trimmed();
853 if ( myParams != foundParams )
860 if ( !myRecord.empty() )
862 mySrsId = myRecord[QStringLiteral(
"srs_id" )].toLong();
871 setProj4String( myProj4String );
886 QgsDebugMsgLevel( QStringLiteral(
"Projection is not found in databases." ), 4 );
888 setProj4String( myProj4String );
892 if ( !sDisableProj4Cache )
893 sProj4Cache.insert( proj4String, *
this );
899 QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord(
const QString &sql )
901 QString myDatabaseFileName;
902 QgsCoordinateReferenceSystem::RecordMap myMap;
904 QString myFieldValue;
911 QFileInfo myInfo( myDatabaseFileName );
912 if ( !myInfo.exists() )
914 QgsDebugMsg(
"failed : " + myDatabaseFileName +
" does not exist!" );
919 myResult = openDatabase( myDatabaseFileName, database );
920 if ( myResult != SQLITE_OK )
925 statement = database.
prepare( sql, myResult );
927 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
931 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
933 myFieldName = statement.
columnName( myColNo );
935 myMap[myFieldName] = myFieldValue;
937 if ( statement.
step() != SQLITE_DONE )
939 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
951 QFileInfo myFileInfo;
952 myFileInfo.setFile( myDatabaseFileName );
953 if ( !myFileInfo.exists() )
955 QgsDebugMsg( QStringLiteral(
"user qgis.db not found" ) );
960 myResult = openDatabase( myDatabaseFileName, database );
961 if ( myResult != SQLITE_OK )
966 statement = database.
prepare( sql, myResult );
968 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_ROW )
972 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
974 myFieldName = statement.
columnName( myColNo );
976 myMap[myFieldName] = myFieldValue;
979 if ( statement.
step() != SQLITE_DONE )
981 QgsDebugMsgLevel( QStringLiteral(
"Multiple records found in srs.db" ), 4 );
1012 if ( d->mDescription.isNull() )
1018 return d->mDescription;
1024 if ( d->mProjectionAcronym.isNull() )
1030 return d->mProjectionAcronym;
1036 if ( d->mEllipsoidAcronym.isNull() )
1042 return d->mEllipsoidAcronym;
1051 if ( d->mProj4.isEmpty() )
1053 char *proj4src =
nullptr;
1054 OSRExportToProj4( d->mCRS, &proj4src );
1055 d->mProj4 = proj4src;
1056 CPLFree( proj4src );
1059 return d->mProj4.trimmed();
1064 return d->mIsGeographic;
1072 return d->mMapUnits;
1086 int result = openDatabase( databaseFileName, database );
1087 if ( result != SQLITE_OK )
1092 QString sql = QStringLiteral(
"select west_bound_lon, north_bound_lat, east_bound_lon, south_bound_lat from tbl_bounds " 1095 statement = database.
prepare( sql, result );
1098 if ( result == SQLITE_OK )
1100 if ( statement.
step() == SQLITE_ROW )
1121 void QgsCoordinateReferenceSystem::setInternalId(
long srsId )
1126 void QgsCoordinateReferenceSystem::setAuthId(
const QString &authId )
1129 d->mAuthId = authId;
1131 void QgsCoordinateReferenceSystem::setSrid(
long srid )
1136 void QgsCoordinateReferenceSystem::setDescription(
const QString &
description )
1141 void QgsCoordinateReferenceSystem::setProj4String(
const QString &proj4String )
1144 d->mProj4 = proj4String;
1148 OSRDestroySpatialReference( d->mCRS );
1149 d->mCRS = OSRNewSpatialReference(
nullptr );
1150 d->mIsValid = OSRImportFromProj4( d->mCRS, proj4String.trimmed().toLatin1().constData() ) == OGRERR_NONE;
1155 projCtx pContext = pj_ctx_alloc();
1156 projPJ proj = pj_init_plus_ctx( pContext, proj4String.trimmed().toLatin1().constData() );
1159 QgsDebugMsgLevel( QStringLiteral(
"proj.4 string rejected by pj_init_plus_ctx()" ), 4 );
1160 d->mIsValid =
false;
1166 pj_ctx_free( pContext );
1171 void QgsCoordinateReferenceSystem::setGeographicFlag(
bool geoFlag )
1174 d->mIsGeographic = geoFlag;
1176 void QgsCoordinateReferenceSystem::setEpsg(
long epsg )
1179 d->mAuthId = QStringLiteral(
"EPSG:%1" ).arg( epsg );
1181 void QgsCoordinateReferenceSystem::setProjectionAcronym(
const QString &
projectionAcronym )
1186 void QgsCoordinateReferenceSystem::setEllipsoidAcronym(
const QString &
ellipsoidAcronym )
1192 void QgsCoordinateReferenceSystem::setMapUnits()
1201 char *unitName =
nullptr;
1203 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,5,0) 1206 OSRFixup( d->mCRS );
1209 if ( OSRIsProjected( d->mCRS ) )
1211 double toMeter = OSRGetLinearUnits( d->mCRS, &unitName );
1212 QString unit( unitName );
1220 static const double SMALL_NUM = 1e-3;
1222 if ( std::fabs( toMeter - FEET_TO_METER ) < SMALL_NUM )
1223 unit = QStringLiteral(
"Foot" );
1227 else if ( unit == QLatin1String(
"Foot" ) )
1236 OSRGetAngularUnits( d->mCRS, &unitName );
1237 QString unit( unitName );
1238 if ( unit == QLatin1String(
"degree" ) )
1250 if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
1253 QgsDebugMsgLevel(
"QgsCoordinateReferenceSystem::findMatchingProj will only " 1254 "work if prj acr ellipsoid acr and proj4string are set" 1255 " and the current projection is valid!", 4 );
1265 QString mySql = QString(
"select srs_id,parameters from tbl_srs where " 1266 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1273 myResult = openDatabase( myDatabaseFileName, database );
1274 if ( myResult != SQLITE_OK )
1279 statement = database.
prepare( mySql, myResult );
1280 if ( myResult == SQLITE_OK )
1283 while ( statement.
step() == SQLITE_ROW )
1287 if (
toProj4() == myProj4String.trimmed() )
1289 return mySrsId.toLong();
1300 myResult = openDatabase( myDatabaseFileName, database );
1301 if ( myResult != SQLITE_OK )
1306 statement = database.
prepare( mySql, myResult );
1308 if ( myResult == SQLITE_OK )
1310 while ( statement.
step() == SQLITE_ROW )
1314 if (
toProj4() == myProj4String.trimmed() )
1316 return mySrsId.toLong();
1326 return ( !d->mIsValid && !srs.d->mIsValid ) ||
1327 ( d->mIsValid && srs.d->mIsValid && srs.
authid() ==
authid() );
1332 return !( *
this == srs );
1337 if ( d->mWkt.isEmpty() )
1339 char *wkt =
nullptr;
1340 if ( OSRExportToWkt( d->mCRS, &wkt ) == OGRERR_NONE )
1353 QDomNode srsNode = node.namedItem( QStringLiteral(
"spatialrefsys" ) );
1355 if ( ! srsNode.isNull() )
1357 bool initialized =
false;
1359 long srsid = srsNode.namedItem( QStringLiteral(
"srsid" ) ).toElement().text().toLong();
1365 myNode = srsNode.namedItem( QStringLiteral(
"authid" ) );
1366 if ( !myNode.isNull() )
1377 myNode = srsNode.namedItem( QStringLiteral(
"epsg" ) );
1378 if ( !myNode.isNull() )
1391 myNode = srsNode.namedItem( QStringLiteral(
"proj4" ) );
1397 myNode = srsNode.namedItem( QStringLiteral(
"proj4" ) );
1398 setProj4String( myNode.toElement().text() );
1400 myNode = srsNode.namedItem( QStringLiteral(
"srsid" ) );
1401 setInternalId( myNode.toElement().text().toLong() );
1403 myNode = srsNode.namedItem( QStringLiteral(
"srid" ) );
1404 setSrid( myNode.toElement().text().toLong() );
1406 myNode = srsNode.namedItem( QStringLiteral(
"authid" ) );
1407 setAuthId( myNode.toElement().text() );
1409 myNode = srsNode.namedItem( QStringLiteral(
"description" ) );
1410 setDescription( myNode.toElement().text() );
1412 myNode = srsNode.namedItem( QStringLiteral(
"projectionacronym" ) );
1413 setProjectionAcronym( myNode.toElement().text() );
1415 myNode = srsNode.namedItem( QStringLiteral(
"ellipsoidacronym" ) );
1416 setEllipsoidAcronym( myNode.toElement().text() );
1418 myNode = srsNode.namedItem( QStringLiteral(
"geographicflag" ) );
1419 if ( myNode.toElement().text().compare( QLatin1String(
"true" ) ) )
1421 setGeographicFlag(
true );
1425 setGeographicFlag(
false );
1435 if ( d->mSrsId == 0 )
1437 QString myName = QStringLiteral(
" * %1 (%2)" )
1438 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
1448 d =
new QgsCoordinateReferenceSystemPrivate();
1457 QDomElement myLayerNode = node.toElement();
1458 QDomElement mySrsElement = doc.createElement( QStringLiteral(
"spatialrefsys" ) );
1460 QDomElement myProj4Element = doc.createElement( QStringLiteral(
"proj4" ) );
1461 myProj4Element.appendChild( doc.createTextNode(
toProj4() ) );
1462 mySrsElement.appendChild( myProj4Element );
1464 QDomElement mySrsIdElement = doc.createElement( QStringLiteral(
"srsid" ) );
1465 mySrsIdElement.appendChild( doc.createTextNode( QString::number(
srsid() ) ) );
1466 mySrsElement.appendChild( mySrsIdElement );
1468 QDomElement mySridElement = doc.createElement( QStringLiteral(
"srid" ) );
1469 mySridElement.appendChild( doc.createTextNode( QString::number(
postgisSrid() ) ) );
1470 mySrsElement.appendChild( mySridElement );
1472 QDomElement myEpsgElement = doc.createElement( QStringLiteral(
"authid" ) );
1473 myEpsgElement.appendChild( doc.createTextNode(
authid() ) );
1474 mySrsElement.appendChild( myEpsgElement );
1476 QDomElement myDescriptionElement = doc.createElement( QStringLiteral(
"description" ) );
1477 myDescriptionElement.appendChild( doc.createTextNode(
description() ) );
1478 mySrsElement.appendChild( myDescriptionElement );
1480 QDomElement myProjectionAcronymElement = doc.createElement( QStringLiteral(
"projectionacronym" ) );
1481 myProjectionAcronymElement.appendChild( doc.createTextNode(
projectionAcronym() ) );
1482 mySrsElement.appendChild( myProjectionAcronymElement );
1484 QDomElement myEllipsoidAcronymElement = doc.createElement( QStringLiteral(
"ellipsoidacronym" ) );
1485 myEllipsoidAcronymElement.appendChild( doc.createTextNode(
ellipsoidAcronym() ) );
1486 mySrsElement.appendChild( myEllipsoidAcronymElement );
1488 QDomElement myGeographicFlagElement = doc.createElement( QStringLiteral(
"geographicflag" ) );
1489 QString myGeoFlagText = QStringLiteral(
"false" );
1492 myGeoFlagText = QStringLiteral(
"true" );
1495 myGeographicFlagElement.appendChild( doc.createTextNode( myGeoFlagText ) );
1496 mySrsElement.appendChild( myGeographicFlagElement );
1498 myLayerNode.appendChild( mySrsElement );
1512 QString QgsCoordinateReferenceSystem::proj4FromSrsId(
const int srsId )
1514 QString myDatabaseFileName;
1515 QString myProjString;
1516 QString mySql = QStringLiteral(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( srsId );
1525 QFileInfo myFileInfo;
1526 myFileInfo.setFile( myDatabaseFileName );
1527 if ( !myFileInfo.exists() )
1529 QgsDebugMsg( QStringLiteral(
"users qgis.db not found" ) );
1542 rc = openDatabase( myDatabaseFileName, database );
1548 statement = database.
prepare( mySql, rc );
1550 if ( rc == SQLITE_OK )
1552 if ( statement.
step() == SQLITE_ROW )
1558 return myProjString;
1565 myResult = database.
open_v2( path, SQLITE_OPEN_READONLY,
nullptr );
1567 myResult = database.
open( path );
1569 if ( myResult != SQLITE_OK )
1578 .arg( database.
errorMessage() ), QObject::tr(
"CRS" ) );
1585 mCustomSrsValidation = f;
1590 return mCustomSrsValidation;
1593 void QgsCoordinateReferenceSystem::debugPrint()
1595 QgsDebugMsg( QStringLiteral(
"***SpatialRefSystem***" ) );
1596 QgsDebugMsg(
"* Valid : " + ( d->mIsValid ? QString(
"true" ) : QString(
"false" ) ) );
1597 QgsDebugMsg(
"* SrsId : " + QString::number( d->mSrsId ) );
1603 QgsDebugMsg( QStringLiteral(
"* Units : meters" ) );
1607 QgsDebugMsg( QStringLiteral(
"* Units : feet" ) );
1611 QgsDebugMsg( QStringLiteral(
"* Units : degrees" ) );
1618 d->mValidationHint = html;
1623 return d->mValidationHint;
1639 QString proj4String = d->mProj4;
1640 if ( proj4String.isEmpty() )
1653 if ( getRecordCount() == 0 )
1655 mySql =
"insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 1659 +
',' + quotedEllipsoidString
1665 mySql =
"insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 1668 +
',' + quotedEllipsoidString
1677 if ( myResult != SQLITE_OK )
1679 QgsDebugMsg( QStringLiteral(
"Can't open or create database %1: %2" )
1684 statement = database.
prepare( mySql, myResult );
1687 if ( myResult == SQLITE_OK && statement.
step() == SQLITE_DONE )
1691 returnId = sqlite3_last_insert_rowid( database.get() );
1692 setInternalId( returnId );
1693 if (
authid().isEmpty() )
1694 setAuthId( QStringLiteral(
"USER:%1" ).arg( returnId ) );
1695 setDescription( name );
1700 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
1701 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
1704 projectionsProj4.append(
toProj4() );
1705 projectionsAuthId.append(
authid() );
1706 settings.
setValue( QStringLiteral(
"UI/recentProjectionsProj4" ), projectionsProj4 );
1707 settings.
setValue( QStringLiteral(
"UI/recentProjectionsAuthId" ), projectionsAuthId );
1717 long QgsCoordinateReferenceSystem::getRecordCount()
1722 long myRecordCount = 0;
1725 if ( myResult != SQLITE_OK )
1731 QString mySql = QStringLiteral(
"select count(*) from tbl_srs" );
1732 statement = database.
prepare( mySql, myResult );
1733 if ( myResult == SQLITE_OK )
1735 if ( statement.
step() == SQLITE_ROW )
1737 QString myRecordCountString = statement.
columnAsText( 0 );
1738 myRecordCount = myRecordCountString.toLong();
1741 return myRecordCount;
1745 bool QgsCoordinateReferenceSystem::loadWkts( QHash<int, QString> &wkts,
const char *filename )
1748 const char *pszFilename = CPLFindFile(
"gdal", filename );
1752 QFile csv( pszFilename );
1753 if ( !csv.open( QIODevice::ReadOnly ) )
1756 QTextStream lines( &csv );
1760 QString line = lines.readLine();
1761 if ( line.isNull() )
1764 if ( line.trimmed().isEmpty() || line.startsWith(
'#' ) )
1768 else if ( line.startsWith( QLatin1String(
"include " ) ) )
1770 if ( !loadWkts( wkts, line.mid( 8 ).toUtf8() ) )
1775 int pos = line.indexOf(
',' );
1780 int epsg = line.leftRef( pos ).toInt( &ok );
1784 wkts.insert( epsg, line.mid( pos + 1 ) );
1793 bool QgsCoordinateReferenceSystem::loadIds( QHash<int, QString> &wkts )
1797 Q_FOREACH (
const QString &csv, QStringList() <<
"gcs.csv" <<
"pcs.csv" <<
"vertcs.csv" <<
"compdcs.csv" <<
"geoccs.csv" )
1800 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,0,0) 1801 const QString filename = CPLFindFile(
"gdal", csv.toUtf8() );
1806 QFile f( filename );
1807 if ( !f.open( QIODevice::ReadOnly ) )
1810 QTextStream lines( &f );
1817 QString line = lines.readLine();
1818 if ( line.isNull() )
1821 if ( line.trimmed().isEmpty() )
1824 int pos = line.indexOf(
',' );
1827 qWarning(
"No id found in: %s", qPrintable( line ) );
1832 int epsg = line.leftRef( pos ).toInt( &ok );
1835 qWarning(
"No valid id found in: %s", qPrintable( line ) );
1840 if ( epsg == 2218 || epsg == 2221 || epsg == 2296 || epsg == 2297 || epsg == 2298 || epsg == 2299 || epsg == 2300 || epsg == 2301 || epsg == 2302 ||
1841 epsg == 2303 || epsg == 2304 || epsg == 2305 || epsg == 2306 || epsg == 2307 || epsg == 2963 || epsg == 2985 || epsg == 2986 || epsg == 3052 ||
1842 epsg == 3053 || epsg == 3139 || epsg == 3144 || epsg == 3145 || epsg == 3173 || epsg == 3295 || epsg == 3993 || epsg == 4087 || epsg == 4088 ||
1843 epsg == 5017 || epsg == 5221 || epsg == 5224 || epsg == 5225 || epsg == 5514 || epsg == 5515 || epsg == 5516 || epsg == 5819 || epsg == 5820 ||
1844 epsg == 5821 || epsg == 6200 || epsg == 6201 || epsg == 6202 || epsg == 6244 || epsg == 6245 || epsg == 6246 || epsg == 6247 || epsg == 6248 ||
1845 epsg == 6249 || epsg == 6250 || epsg == 6251 || epsg == 6252 || epsg == 6253 || epsg == 6254 || epsg == 6255 || epsg == 6256 || epsg == 6257 ||
1846 epsg == 6258 || epsg == 6259 || epsg == 6260 || epsg == 6261 || epsg == 6262 || epsg == 6263 || epsg == 6264 || epsg == 6265 || epsg == 6266 ||
1847 epsg == 6267 || epsg == 6268 || epsg == 6269 || epsg == 6270 || epsg == 6271 || epsg == 6272 || epsg == 6273 || epsg == 6274 || epsg == 6275 ||
1848 epsg == 6966 || epsg == 7082 || epsg == 32600 || epsg == 32663 || epsg == 32700 )
1851 if ( OSRImportFromEPSG( crs, epsg ) != OGRERR_NONE )
1853 qDebug(
"EPSG %d: not imported", epsg );
1857 char *wkt =
nullptr;
1858 if ( OSRExportToWkt( crs, &wkt ) != OGRERR_NONE )
1860 qWarning(
"EPSG %d: not exported to WKT", epsg );
1864 wkts.insert( epsg, wkt );
1872 QgsDebugMsgLevel( QStringLiteral(
"Loaded %1/%2 from %3" ).arg( QString::number( n ), QString::number( l ), filename.toUtf8().constData() ), 4 );
1875 OSRDestroySpatialReference( crs );
1880 #if defined(PJ_VERSION) && PJ_VERSION>=600 1881 static void qgis_stderr_logger(
void *app_data,
int level,
const char *msg )
1883 if ( strcmp( msg,
"proj_create: crs not found" ) == 0 )
1885 pj_stderr_logger( app_data, level, msg );
1891 setlocale( LC_ALL,
"C" );
1893 syncDatumTransform( dbFilePath );
1895 int inserted = 0, updated = 0, deleted = 0, errors = 0;
1900 if ( database.
open( dbFilePath ) != SQLITE_OK )
1906 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
1913 if ( sqlite3_exec( database.get(),
"alter table tbl_srs add noupdate boolean",
nullptr,
nullptr, nullptr ) == SQLITE_OK )
1914 ( 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 );
1916 ( 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 );
1921 char *errMsg =
nullptr;
1925 QHash<int, QString> wkts;
1927 loadWkts( wkts,
"epsg.wkt" );
1929 QgsDebugMsgLevel( QStringLiteral(
"%1 WKTs loaded" ).arg( wkts.count() ), 4 );
1931 for ( QHash<int, QString>::const_iterator it = wkts.constBegin(); it != wkts.constEnd(); ++it )
1933 QByteArray ba( it.value().toUtf8() );
1934 char *psz = ba.data();
1937 OSRDestroySpatialReference( crs );
1939 crs = OSRNewSpatialReference(
nullptr );
1941 OGRErr ogrErr = OSRImportFromWkt( crs, &psz );
1942 if ( ogrErr != OGRERR_NONE )
1945 if ( OSRExportToProj4( crs, &psz ) != OGRERR_NONE )
1952 proj4 = proj4.trimmed();
1956 if ( proj4.isEmpty() )
1959 QString name( OSRIsGeographic( crs ) ? OSRGetAttrValue( crs,
"GEOGCS", 0 ) :
1960 OSRIsGeocentric( crs ) ? OSRGetAttrValue( crs,
"GEOCCS", 0 ) :
1961 OSRGetAttrValue( crs,
"PROJCS", 0 ) );
1962 if ( name.isEmpty() )
1963 name = QObject::tr(
"Imported from GDAL" );
1965 bool deprecated = name.contains( QLatin1Literal(
"(deprecated)" ) );
1967 sql = QStringLiteral(
"SELECT parameters,description,deprecated,noupdate FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).arg( it.key() );
1968 statement = database.
prepare( sql, result );
1969 if ( result != SQLITE_OK )
1977 bool srsDeprecated = deprecated;
1978 if ( statement.
step() == SQLITE_ROW )
1982 srsDeprecated = statement.
columnAsText( 2 ).toInt() != 0;
1990 if ( !srsProj4.isEmpty() || !srsDesc.isEmpty() )
1992 if ( proj4 != srsProj4 || name != srsDesc || deprecated != srsDeprecated )
1995 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name='EPSG' AND auth_id=%4" )
1998 .arg( deprecated ? 1 : 0 )
2001 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
2003 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2/%3]\n" ).arg(
2006 errMsg ? errMsg :
"(unknown error)" ) );
2008 sqlite3_free( errMsg );
2019 QRegExp projRegExp(
"\\+proj=(\\S+)" );
2020 if ( projRegExp.indexIn( proj4 ) < 0 )
2022 QgsDebugMsgLevel( QStringLiteral(
"EPSG %1: no +proj argument found [%2]" ).arg( it.key() ).arg( proj4 ), 4 );
2026 QRegExp ellipseRegExp(
"\\+ellps=(\\S+)" );
2028 if ( ellipseRegExp.indexIn( proj4 ) >= 0 )
2030 ellps = ellipseRegExp.cap( 1 );
2042 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)" )
2048 .arg( OSRIsGeographic( crs ) )
2049 .arg( deprecated ? 1 : 0 );
2052 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2058 qCritical(
"Could not execute: %s [%s/%s]\n",
2059 sql.toLocal8Bit().constData(),
2060 sqlite3_errmsg( database.get() ),
2061 errMsg ? errMsg :
"(unknown error)" );
2065 sqlite3_free( errMsg );
2071 OSRDestroySpatialReference( crs );
2074 sql = QStringLiteral(
"DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN (" );
2076 QHash<int, QString>::const_iterator it = wkts.constBegin();
2077 for ( ; it != wkts.constEnd(); ++it )
2079 sql += delim + QString::number( it.key() );
2082 sql += QLatin1String(
") AND NOT noupdate" );
2084 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) == SQLITE_OK )
2086 deleted = sqlite3_changes( database.get() );
2091 qCritical(
"Could not execute: %s [%s]\n",
2092 sql.toLocal8Bit().constData(),
2093 sqlite3_errmsg( database.get() ) );
2096 projCtx pContext = pj_ctx_alloc();
2098 #if !defined(PJ_VERSION) || PJ_VERSION!=470 2099 #if defined(PJ_VERSION) && PJ_VERSION>=600 2100 pj_ctx_set_logger( pContext, qgis_stderr_logger );
2102 sql = QStringLiteral(
"select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated AND NOT noupdate" );
2103 statement = database.
prepare( sql, result );
2104 if ( result == SQLITE_OK )
2106 while ( statement.
step() == SQLITE_ROW )
2112 QString input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toLower(), auth_id );
2113 projPJ pj = pj_init_plus_ctx( pContext, input.toLatin1() );
2116 input = QStringLiteral(
"+init=%1:%2" ).arg( auth_name.toUpper(), auth_id );
2117 pj = pj_init_plus_ctx( pContext, input.toLatin1() );
2122 char *def = pj_get_def( pj, 0 );
2128 input.prepend(
' ' ).append(
' ' );
2129 if ( proj4.startsWith( input ) )
2131 proj4 = proj4.mid( input.size() );
2132 proj4 = proj4.trimmed();
2135 if ( proj4 != params )
2137 sql = QStringLiteral(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
2142 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
2148 qCritical(
"Could not execute: %s [%s/%s]\n",
2149 sql.toLocal8Bit().constData(),
2150 sqlite3_errmsg( database.get() ),
2151 errMsg ? errMsg :
"(unknown error)" );
2153 sqlite3_free( errMsg );
2160 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve proj string for %1 from PROJ" ).arg( input ), 4 );
2165 QgsDebugMsgLevel( QStringLiteral(
"could not retrieve crs for %1 from PROJ" ).arg( input ), 3 );
2174 QgsDebugMsg( QStringLiteral(
"Could not execute: %1 [%2]\n" ).arg(
2176 sqlite3_errmsg( database.get() ) ) );
2180 pj_ctx_free( pContext );
2182 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2184 QgsDebugMsg( QStringLiteral(
"Could not commit transaction: %1 [%2]\n" ).arg(
2186 sqlite3_errmsg( database.get() ) )
2191 Q_UNUSED( deleted );
2192 QgsDebugMsgLevel( QStringLiteral(
"CRS update (inserted:%1 updated:%2 deleted:%3 errors:%4)" ).arg( QString::number( inserted ), QString::number( updated ), QString::number( deleted ), QString::number( errors ) ), 4 );
2197 return updated + inserted;
2200 bool QgsCoordinateReferenceSystem::syncDatumTransform(
const QString &dbPath )
2202 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,0,0) 2203 const char *filename = CSVFilename(
"datum_shift.csv" );
2204 FILE *fp = VSIFOpen( filename,
"rb" );
2207 FILE *fp = VSIFOpen( filename.toUtf8().constData(),
"rb" );
2214 char **fieldnames = CSVReadParseLine( fp );
2226 {
"SOURCE_CRS_CODE",
"source_crs_code", -1 },
2227 {
"TARGET_CRS_CODE",
"target_crs_code", -1 },
2228 {
"REMARKS",
"remarks", -1 },
2229 {
"COORD_OP_SCOPE",
"scope", -1 },
2230 {
"AREA_OF_USE_CODE",
"area_of_use_code", -1 },
2236 {
"DEPRECATED",
"deprecated", -1 },
2237 {
"COORD_OP_METHOD_CODE",
"coord_op_method_code", -1 },
2245 {
"PREFERRED",
"preferred", -1 },
2246 {
"COORD_OP_CODE",
"coord_op_code", -1 },
2249 QString update = QStringLiteral(
"UPDATE tbl_datum_transform SET " );
2250 QString insert, values;
2252 int n = CSLCount( fieldnames );
2254 int idxid = -1, idxrx = -1, idxry = -1, idxrz = -1, idxmcode = -1;
2255 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
2257 bool last = i ==
sizeof( map ) /
sizeof( *map ) - 1;
2259 map[i].idx = CSLFindString( fieldnames, map[i].src );
2260 if ( map[i].idx < 0 )
2262 qWarning(
"field %s not found", map[i].src );
2263 CSLDestroy( fieldnames );
2268 if ( strcmp( map[i].src,
"COORD_OP_CODE" ) == 0 )
2270 if ( strcmp( map[i].src,
"RX" ) == 0 )
2272 if ( strcmp( map[i].src,
"RY" ) == 0 )
2274 if ( strcmp( map[i].src,
"RZ" ) == 0 )
2276 if ( strcmp( map[i].src,
"COORD_OP_METHOD_CODE" ) == 0 )
2286 update += QLatin1String(
" WHERE " );
2294 update += QStringLiteral(
"%1=%%2" ).arg( map[i].dst ).arg( i + 1 );
2296 insert += map[i].dst;
2297 values += QStringLiteral(
"%%1" ).arg( i + 1 );
2300 insert =
"INSERT INTO tbl_datum_transform(" + insert +
") VALUES (" + values +
')';
2302 CSLDestroy( fieldnames );
2304 Q_ASSERT( idxid >= 0 );
2305 Q_ASSERT( idxrx >= 0 );
2306 Q_ASSERT( idxry >= 0 );
2307 Q_ASSERT( idxrz >= 0 );
2310 int openResult = database.
open( dbPath );
2311 if ( openResult != SQLITE_OK )
2317 if ( sqlite3_exec( database.get(),
"BEGIN TRANSACTION",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2325 v.reserve(
sizeof( map ) /
sizeof( *map ) );
2329 char **values = CSVReadParseLine( fp );
2335 if ( CSLCount( values ) == 0 )
2337 CSLDestroy( values );
2341 if ( CSLCount( values ) < n )
2343 qWarning(
"Only %d columns", CSLCount( values ) );
2344 CSLDestroy( values );
2348 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
2350 int idx = map[i].idx;
2351 Q_ASSERT( idx != -1 );
2352 Q_ASSERT( idx < n );
2355 CSLDestroy( values );
2358 if ( v.at( idxmcode ).compare( QLatin1String(
"'9607'" ) ) == 0 )
2360 v[ idxmcode ] = QStringLiteral(
"'9606'" );
2361 v[ idxrx ] =
'\'' +
qgsDoubleToString( -( v[ idxrx ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2362 v[ idxry ] =
'\'' +
qgsDoubleToString( -( v[ idxry ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2363 v[ idxrz ] =
'\'' +
qgsDoubleToString( -( v[ idxrz ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2369 QString sql = QStringLiteral(
"SELECT coord_op_code FROM tbl_datum_transform WHERE coord_op_code=%1" ).arg( v[ idxid ] );
2371 statement = database.
prepare( sql, prepareRes );
2372 if ( prepareRes != SQLITE_OK )
2375 if ( statement.
step() == SQLITE_ROW )
2380 sql = cOpCode.isEmpty() ? insert : update;
2381 for (
int i = 0; i < v.size(); i++ )
2383 sql = sql.arg( v[i] );
2386 if ( sqlite3_exec( database.get(), sql.toUtf8(),
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2388 qCritical(
"SQL: %s", sql.toUtf8().constData() );
2389 qCritical(
"Error: %s", sqlite3_errmsg( database.get() ) );
2393 if ( sqlite3_exec( database.get(),
"COMMIT",
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2410 return OSRGetAuthorityName( d->mCRS,
"GEOGCS" ) + QStringLiteral(
":" ) + OSRGetAuthorityCode( d->mCRS,
"GEOGCS" );
2420 QStringList projections;
2424 projections = settings.
value( QStringLiteral(
"UI/recentProjections" ) ).toStringList();
2428 QStringList projectionsProj4 = settings.
value( QStringLiteral(
"UI/recentProjectionsProj4" ) ).toStringList();
2429 QStringList projectionsAuthId = settings.
value( QStringLiteral(
"UI/recentProjectionsAuthId" ) ).toStringList();
2430 if ( projectionsAuthId.size() >= projections.size() )
2434 projections.clear();
2435 for (
int i = 0; i < projectionsAuthId.size(); i++ )
2443 if ( i >= projectionsProj4.size() || !crs.
createFromProj4( projectionsProj4.at( i ) ) )
2449 if ( crs.
srsid() == 0 )
2454 projections << QString::number( crs.
srsid() );
2462 sSrIdCacheLock.lockForWrite();
2463 if ( !sDisableSrIdCache )
2466 sDisableSrIdCache =
true;
2469 sSrIdCacheLock.unlock();
2471 sOgcLock.lockForWrite();
2472 if ( !sDisableOgcCache )
2475 sDisableOgcCache =
true;
2480 sProj4CacheLock.lockForWrite();
2481 if ( !sDisableProj4Cache )
2484 sDisableProj4Cache =
true;
2485 sProj4Cache.clear();
2487 sProj4CacheLock.unlock();
2489 sCRSWktLock.lockForWrite();
2490 if ( !sDisableWktCache )
2493 sDisableWktCache =
true;
2496 sCRSWktLock.unlock();
2498 sCRSSrsIdLock.lockForWrite();
2499 if ( !sDisableSrsIdCache )
2502 sDisableSrsIdCache =
true;
2503 sSrsIdCache.clear();
2505 sCRSSrsIdLock.unlock();
2507 sCrsStringLock.lockForWrite();
2508 if ( !sDisableStringCache )
2511 sDisableStringCache =
true;
2512 sStringCache.clear();
2514 sCrsStringLock.unlock();
QgsCoordinateReferenceSystem()
Constructs an invalid CRS object.
bool createFromId(long id, CrsType type=PostgisCrsId)
Sets this CRS by lookup of the given ID in the CRS database.
QString geographicCrsAuthId() const
Returns auth id of related geographic CRS.
QString columnName(int column) const
Returns the name of column.
A rectangle specified with double values.
static QgsCoordinateReferenceSystem fromProj4(const QString &proj4)
Creates a CRS from a proj4 style formatted string.
bool createFromString(const QString &definition)
Set up this CRS from a string definition.
static QList< long > validSrsIds()
Returns a list of all valid SRS IDs present in the CRS database.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
void setXMaximum(double x)
Set the maximum x value.
This class is a composition of two QSettings instances:
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
long srsid() const
Returns the internal CRS ID, if available.
void validate()
Perform some validation on this CRS.
static void warning(const QString &msg)
Goes to qWarning.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
static void setCustomCrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS.
QString toWkt() const
Returns a WKT representation of this CRS.
long postgisSrid() const
Returns PostGIS SRID for the CRS.
const int LAT_PREFIX_LEN
The length of the string "+lat_1=".
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool operator!=(const QgsCoordinateReferenceSystem &srs) const
Overloaded != operator used to compare to CRS's.
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
const QgsCoordinateReferenceSystem & crs
Internal ID used by QGIS in the local SQLite database.
bool operator==(const QgsCoordinateReferenceSystem &srs) const
Overloaded == operator used to compare to CRS's.
qlonglong columnAsInt64(int column) const
Gets column value from the current statement row as a long long integer (64 bits).
long saveAsUserCrs(const QString &name)
Save the proj4-string as a custom CRS.
bool createFromOgcWmsCrs(const QString &crs)
Sets this CRS to the given OGC WMS-format Coordinate Reference Systems.
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.
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
#define QgsDebugMsgLevel(str, level)
bool createFromSrid(long srid)
Sets this CRS by lookup of the given PostGIS SRID in the CRS database.
double columnAsDouble(int column) const
Gets column value from the current statement row as a double.
static QStringList recentProjections()
Returns a list of recently used projections.
int step()
Steps to the next record in the statement, returning the sqlite3 result code.
QString validationHint()
Gets user hint for validation.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
long findMatchingProj()
Walks the CRS databases (both system and user database) trying to match stored PROJ string to a datab...
void setYMinimum(double y)
Set the minimum y value.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Degrees, for planar geographic CRS distance measurements.
QgsCoordinateReferenceSystem & operator=(const QgsCoordinateReferenceSystem &srs)
Assignment operator.
const QString GEO_EPSG_CRS_AUTHID
Geographic coord sys from EPSG authority.
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
int columnCount() const
Gets the number of columns that this statement returns.
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 QString pkgDataPath()
Returns the common root path of all application data directories.
static CUSTOM_CRS_VALIDATION customCrsValidation()
Gets custom function.
DistanceUnit
Units of distance.
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
void unlock()
Unlocks the lock.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
const int USER_CRS_START_ID
Magick number that determines whether a projection crsid is a system (srs.db) or user (~/...
bool createFromSrsId(long srsId)
Sets this CRS by lookup of internal QGIS CRS ID in the CRS database.
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool createFromUserInput(const QString &definition)
Set up this CRS from various text formats.
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
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.
This class represents a coordinate reference system (CRS).
bool createFromProj4(const QString &projString)
Sets this CRS by passing it a PROJ style formatted string.
QString authid() const
Returns the authority identifier for the CRS.
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.
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
QString columnAsText(int column) const
Returns the column value from the current statement row as a string.
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
bool isGeographic() const
Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
QString errorMessage() const
Returns the most recent error message encountered by the database.
static int syncDatabase()
Update proj.4 parameters in our database from proj.4.
static void setupESRIWktFix()
Make sure that ESRI WKT import is done properly.
void setXMinimum(double x)
Set the minimum x value.
bool hasAxisInverted() const
Returns whether axis is inverted (e.g., for WMS 1.3) for the CRS.
static QgsCoordinateReferenceSystem fromSrsId(long srsId)
Creates a CRS from a specified QGIS SRS ID.
void * OGRSpatialReferenceH
static QString quotedString(const QString &value)
Returns a quoted string value, surround by ' characters and with special characters correctly escaped...
QString toProj4() const
Returns a Proj4 string representation of this CRS.
QgsRectangle bounds() const
Returns the approximate bounds for the region the CRS is usable within.