24 #include <QTemporaryFile> 26 #include <QDomElement> 29 #include <QTextStream> 44 #include <ogr_srs_api.h> 45 #include <cpl_error.h> 55 d =
new QgsCoordinateReferenceSystemPrivate();
60 d =
new QgsCoordinateReferenceSystemPrivate();
66 d =
new QgsCoordinateReferenceSystemPrivate();
109 QRegExp reCrsId(
"^(epsg|postgis|internal)\\:(\\d+)$", Qt::CaseInsensitive );
110 if ( reCrsId.
indexIn( theDefinition ) == 0 )
114 if ( authName ==
"epsg" )
116 if ( authName ==
"postgis" )
123 QRegExp reCrsStr(
"^(?:(wkt|proj4)\\:)?(.+)$", Qt::CaseInsensitive );
124 if ( reCrsStr.
indexIn( theDefinition ) == 0 )
136 .
arg(
QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
157 #if GDAL_VERSION_NUM >= 1900 166 if ( OSRExportToWkt( crs, &wkt ) == OGRERR_NONE )
171 OSRDestroySpatialReference( crs );
181 #if GDAL_VERSION_NUM >= 1900 182 const char* configOld = CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" );
183 const char* configNew =
"GEOGCS";
185 if ( strcmp( configOld,
"" ) == 0 )
187 CPLSetConfigOption(
"GDAL_FIX_ESRI_WKT", configNew );
188 if ( strcmp( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) != 0 )
190 .arg( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) );
204 QRegExp re(
"urn:ogc:def:crs:([^:]+).+([^:]+)", Qt::CaseInsensitive );
207 wmsCrs = re.
cap( 1 ) +
':' + re.
cap( 2 );
222 if ( wmsCrs.
compare(
"CRS:27", Qt::CaseInsensitive ) == 0 ||
223 wmsCrs.
compare(
"OGC:CRS27", Qt::CaseInsensitive ) == 0 )
230 if ( wmsCrs.
compare(
"CRS:83", Qt::CaseInsensitive ) == 0 ||
231 wmsCrs.
compare(
"OGC:CRS83", Qt::CaseInsensitive ) == 0 )
238 if ( wmsCrs.
compare(
"CRS:84", Qt::CaseInsensitive ) == 0 ||
239 wmsCrs.
compare(
"OGC:CRS84", Qt::CaseInsensitive ) == 0 )
244 d->mAxisInverted =
false;
245 d->mAxisInvertedDirty =
false;
264 if ( mCustomSrsValidation )
265 mCustomSrsValidation( *
this );
285 bool QgsCoordinateReferenceSystem::loadFromDb(
const QString& db,
const QString& expression,
const QString& value )
289 QgsDebugMsgLevel(
"load CRS from " + db +
" where " + expression +
" is " + value, 3 );
296 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
302 sqlite3_stmt *myPreparedStatement;
305 myResult = openDb( db, &myDatabase );
306 if ( myResult != SQLITE_OK )
308 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
324 QString mySql =
"select srs_id,description,projection_acronym," 325 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo " 326 "from tbl_srs where " + expression +
'=' + quotedValue( value ) +
" order by deprecated";
327 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(),
329 &myPreparedStatement, &myTail );
331 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
333 d->mSrsId =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text(
334 myPreparedStatement, 0 ) ) ).
toLong();
335 d->mDescription =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text(
336 myPreparedStatement, 1 ) ) );
337 d->mProjectionAcronym =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 2 ) ) );
338 d->mEllipsoidAcronym =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 3 ) ) );
339 d->mProj4 =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 4 ) ) );
340 d->mSRID =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 5 ) ) ).
toLong() ;
341 d->mAuthId =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 6 ) ) );
342 d->mIsGeographic =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 7 ) ) ).
toInt() != 0;
343 d->mAxisInvertedDirty =
true;
347 d->mAuthId =
QString(
"USER:%1" ).
arg( d->mSrsId );
349 else if ( d->mAuthId.startsWith(
"EPSG:", Qt::CaseInsensitive ) )
351 OSRDestroySpatialReference( d->mCRS );
352 d->mCRS = OSRNewSpatialReference(
nullptr );
353 d->mIsValid = OSRSetFromUserInput( d->mCRS, d->mAuthId.toLower().toAscii() ) == OGRERR_NONE;
359 setProj4String( d->mProj4 );
366 sqlite3_finalize( myPreparedStatement );
367 sqlite3_close( myDatabase );
373 if ( d->mAxisInvertedDirty )
375 OGRAxisOrientation orientation;
376 OSRGetAxis( d->mCRS, OSRIsGeographic( d->mCRS ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
379 if ( orientation == OAO_Other && d->mAuthId.startsWith(
"EPSG:", Qt::CaseInsensitive ) )
383 if ( OSRImportFromEPSGA( crs, d->mAuthId.mid( 5 ).toInt() ) == OGRERR_NONE )
385 OSRGetAxis( crs, OSRIsGeographic( crs ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
388 OSRDestroySpatialReference( crs );
391 d->mAxisInverted = orientation == OAO_North;
392 d->mAxisInvertedDirty =
false;
395 return d->mAxisInverted;
408 QgsDebugMsg(
"theWkt is uninitialized, operation failed" );
413 const char *pWkt = ba.
data();
415 OGRErr myInputResult = OSRImportFromWkt( d->mCRS, const_cast< char ** >( & pWkt ) );
417 if ( myInputResult != OGRERR_NONE )
419 QgsDebugMsg(
"\n---------------------------------------------------------------" );
420 QgsDebugMsg(
"This CRS could *** NOT *** be set from the supplied Wkt " );
423 QgsDebugMsg(
"---------------------------------------------------------------\n" );
427 if ( OSRAutoIdentifyEPSG( d->mCRS ) == OGRERR_NONE )
430 .
arg( OSRGetAuthorityName( d->mCRS,
nullptr ),
431 OSRGetAuthorityCode( d->mCRS,
nullptr ) );
441 char *proj4src =
nullptr;
442 OSRExportToProj4( d->mCRS, &proj4src );
454 OSRExportToProj4( d->mCRS, &proj4src );
462 if ( d->mSrsId == 0 )
465 .
arg(
QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
498 QRegExp myProjRegExp(
"\\+proj=(\\S+)" );
499 int myStart = myProjRegExp.
indexIn( myProj4String );
502 QgsDebugMsg(
"proj string supplied has no +proj argument" );
506 d->mProjectionAcronym = myProjRegExp.
cap( 1 );
508 QRegExp myEllipseRegExp(
"\\+ellps=(\\S+)" );
509 myStart = myEllipseRegExp.
indexIn( myProj4String );
512 QgsDebugMsg(
"proj string supplied has no +ellps argument" );
513 d->mEllipsoidAcronym.clear();
517 d->mEllipsoidAcronym = myEllipseRegExp.
cap( 1 );
520 QRegExp myAxisRegExp(
"\\+a=(\\S+)" );
521 myStart = myAxisRegExp.
indexIn( myProj4String );
524 QgsDebugMsg(
"proj string supplied has no +a argument" );
542 myRecord = getRecord(
"select * from tbl_srs where parameters=" + quotedValue( myProj4String ) +
" order by deprecated" );
543 if ( myRecord.
empty() )
548 QRegExp myLat1RegExp(
"\\+lat_1=\\S+" );
549 QRegExp myLat2RegExp(
"\\+lat_2=\\S+" );
556 myStart1 = myLat1RegExp.
indexIn( myProj4String, myStart1 );
557 myStart2 = myLat2RegExp.
indexIn( myProj4String, myStart2 );
558 if ( myStart1 != -1 && myStart2 != -1 )
566 if ( lat1Str !=
"" && lat2Str !=
"" )
569 QString theProj4StringModified = myProj4String;
574 myStart2 = myLat2RegExp.
indexIn( theProj4String, myStart2 );
576 QgsDebugMsg(
"trying proj4string match with swapped lat_1,lat_2" );
577 myRecord = getRecord(
"select * from tbl_srs where parameters=" + quotedValue( theProj4StringModified.
trimmed() ) +
" order by deprecated" );
581 if ( myRecord.
empty() )
588 QString sql =
"SELECT * FROM tbl_srs WHERE ";
596 Q_FOREACH (
const QString& param, myProj4String.
split(
QRegExp(
"\\s+(?=\\+)" ), QString::SkipEmptyParts ) )
613 myRecord = getRecord( sql + delim + datum +
" order by deprecated" );
616 if ( myRecord.
empty() )
619 myRecord = getRecord( sql +
" order by deprecated" );
622 if ( !myRecord.
empty() )
626 Q_FOREACH (
const QString& param, myRecord[
"parameters"].split(
QRegExp(
"\\s+(?=\\+)" ), QString::SkipEmptyParts ) )
629 foundParams << param.
trimmed();
635 if ( myParams != foundParams )
642 if ( !myRecord.
empty() )
644 mySrsId = myRecord[
"srs_id"].toLong();
654 QgsDebugMsg(
"globbing search for srsid from this proj string" );
655 setProj4String( myProj4String );
671 QgsDebugMsg(
"Projection is not found in databases." );
673 setProj4String( myProj4String );
688 sqlite3_stmt *myPreparedStatement;
697 QgsDebugMsg(
"failed : " + myDatabaseFileName +
" does not exist!" );
702 myResult = openDb( myDatabaseFileName, &myDatabase );
703 if ( myResult != SQLITE_OK )
708 myResult = sqlite3_prepare( myDatabase, theSql.
toUtf8(), theSql.
toUtf8().
length(), &myPreparedStatement, &myTail );
710 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
713 int myColumnCount = sqlite3_column_count( myPreparedStatement );
715 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
717 myFieldName =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_name( myPreparedStatement, myColNo ) ) );
718 myFieldValue =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, myColNo ) ) );
719 myMap[myFieldName] = myFieldValue;
721 if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE )
735 sqlite3_finalize( myPreparedStatement );
736 sqlite3_close( myDatabase );
740 myFileInfo.
setFile( myDatabaseFileName );
741 if ( !myFileInfo.
exists() )
748 myResult = openDb( myDatabaseFileName, &myDatabase );
749 if ( myResult != SQLITE_OK )
754 myResult = sqlite3_prepare( myDatabase, theSql.
toUtf8(), theSql.
toUtf8().
length(), &myPreparedStatement, &myTail );
756 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
758 int myColumnCount = sqlite3_column_count( myPreparedStatement );
760 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
762 myFieldName =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_name( myPreparedStatement, myColNo ) ) );
763 myFieldValue =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, myColNo ) ) );
764 myMap[myFieldName] = myFieldValue;
767 if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE )
778 sqlite3_finalize( myPreparedStatement );
779 sqlite3_close( myDatabase );
784 for ( it = myMap.
begin(); it != myMap.
end(); ++it )
812 if ( d->mDescription.isNull() )
818 return d->mDescription;
824 if ( d->mProjectionAcronym.isNull() )
830 return d->mProjectionAcronym;
836 if ( d->mEllipsoidAcronym.isNull() )
842 return d->mEllipsoidAcronym;
851 if ( d->mProj4.isEmpty() )
853 char *proj4src =
nullptr;
854 OSRExportToProj4( d->mCRS, &proj4src );
855 d->mProj4 = proj4src;
859 return d->mProj4.trimmed();
864 return d->mIsGeographic;
876 void QgsCoordinateReferenceSystem::setInternalId(
long theSrsId )
879 d->mSrsId = theSrsId;
881 void QgsCoordinateReferenceSystem::setAuthId(
const QString& authId )
886 void QgsCoordinateReferenceSystem::setSrid(
long theSrid )
891 void QgsCoordinateReferenceSystem::setDescription(
const QString& theDescription )
894 d->mDescription = theDescription;
896 void QgsCoordinateReferenceSystem::setProj4String(
const QString& theProj4String )
899 d->mProj4 = theProj4String;
903 OSRDestroySpatialReference( d->mCRS );
904 d->mCRS = OSRNewSpatialReference(
nullptr );
910 projCtx pContext = pj_ctx_alloc();
914 QgsDebugMsg(
"proj.4 string rejected by pj_init_plus()" );
921 pj_ctx_free( pContext );
925 #if defined(QGISDEBUG) && QGISDEBUG>=3 929 void QgsCoordinateReferenceSystem::setGeographicFlag(
bool theGeoFlag )
932 d->mIsGeographic = theGeoFlag;
934 void QgsCoordinateReferenceSystem::setEpsg(
long theEpsg )
937 d->mAuthId =
QString(
"EPSG:%1" ).
arg( theEpsg );
939 void QgsCoordinateReferenceSystem::setProjectionAcronym(
const QString& theProjectionAcronym )
942 d->mProjectionAcronym = theProjectionAcronym;
944 void QgsCoordinateReferenceSystem::setEllipsoidAcronym(
const QString& theEllipsoidAcronym )
947 d->mEllipsoidAcronym = theEllipsoidAcronym;
950 void QgsCoordinateReferenceSystem::setMapUnits()
965 if ( OSRIsProjected( d->mCRS ) )
967 double toMeter = OSRGetLinearUnits( d->mCRS, &unitName );
975 static const double feetToMeter = 0.3048;
976 static const double smallNum = 1e-3;
978 if ( qAbs( toMeter - feetToMeter ) < smallNum )
981 QgsDebugMsg(
"Projection has linear units of " + unit );
985 else if ( unit ==
"Foot" )
995 OSRGetAngularUnits( d->mCRS, &unitName );
997 if ( unit ==
"degree" )
1001 QgsDebugMsg(
"Unsupported map units of " + unit );
1019 if ( d->mEllipsoidAcronym.isNull() || d->mProjectionAcronym.isNull()
1022 QgsDebugMsg(
"QgsCoordinateReferenceSystem::findMatchingProj will only " 1023 "work if prj acr ellipsoid acr and proj4string are set" 1024 " and the current projection is valid!" );
1030 sqlite3_stmt *myPreparedStatement;
1035 QString mySql =
QString(
"select srs_id,parameters from tbl_srs where " 1036 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1037 .
arg( quotedValue( d->mProjectionAcronym ),
1038 quotedValue( d->mEllipsoidAcronym ) );
1043 myResult = openDb( myDatabaseFileName, &myDatabase );
1044 if ( myResult != SQLITE_OK )
1049 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1051 if ( myResult == SQLITE_OK )
1054 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1056 QString mySrsId =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1057 QString myProj4String =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 1 ) ) );
1060 QgsDebugMsg(
"-------> MATCH FOUND in srs.db srsid: " + mySrsId );
1062 sqlite3_finalize( myPreparedStatement );
1063 sqlite3_close( myDatabase );
1072 QgsDebugMsg(
"no match found in srs.db, trying user db now!" );
1074 sqlite3_finalize( myPreparedStatement );
1075 sqlite3_close( myDatabase );
1082 myResult = openDb( myDatabaseFileName, &myDatabase );
1083 if ( myResult != SQLITE_OK )
1088 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1090 if ( myResult == SQLITE_OK )
1093 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1095 QString mySrsId =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1096 QString myProj4String =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 1 ) ) );
1099 QgsDebugMsg(
"-------> MATCH FOUND in user qgis.db srsid: " + mySrsId );
1101 sqlite3_finalize( myPreparedStatement );
1102 sqlite3_close( myDatabase );
1114 sqlite3_finalize( myPreparedStatement );
1115 sqlite3_close( myDatabase );
1121 return ( !d->mIsValid && !theSrs.d->mIsValid ) ||
1122 ( d->mIsValid && theSrs.d->mIsValid && theSrs.
authid() ==
authid() );
1127 return !( *
this == theSrs );
1132 if ( d->mWkt.isEmpty() )
1135 if ( OSRExportToWkt( d->mCRS, &wkt ) == OGRERR_NONE )
1147 QgsDebugMsg(
"Reading Spatial Ref Sys from xml ------------------------!" );
1151 if ( ! srsNode.
isNull() )
1153 bool initialized =
false;
1186 QgsDebugMsg(
"Ignoring authid/epsg for user crs." );
1204 QgsDebugMsg(
"Setting from elements one by one" );
1210 setInternalId( myNode.toElement().text().toLong() );
1213 setSrid( myNode.toElement().text().toLong() );
1216 setAuthId( myNode.toElement().text() );
1218 myNode = srsNode.
namedItem(
"description" );
1219 setDescription( myNode.toElement().text() );
1221 myNode = srsNode.
namedItem(
"projectionacronym" );
1222 setProjectionAcronym( myNode.toElement().text() );
1224 myNode = srsNode.
namedItem(
"ellipsoidacronym" );
1225 setEllipsoidAcronym( myNode.toElement().text() );
1227 myNode = srsNode.
namedItem(
"geographicflag" );
1228 if ( myNode.toElement().text().compare(
"true" ) )
1230 setGeographicFlag(
true );
1234 setGeographicFlag(
false );
1247 if ( d->mSrsId == 0 )
1250 .
arg(
QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
1294 mySrsElement.
appendChild( myProjectionAcronymElement );
1298 mySrsElement.
appendChild( myEllipsoidAcronymElement );
1301 QString myGeoFlagText =
"false";
1304 myGeoFlagText =
"true";
1308 mySrsElement.
appendChild( myGeographicFlagElement );
1324 QString QgsCoordinateReferenceSystem::proj4FromSrsId(
const int theSrsId )
1329 QString mySql =
QString(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).
arg( theSrsId );
1343 myFileInfo.
setFile( myDatabaseFileName );
1344 if ( !myFileInfo.
exists() )
1358 rc = openDb( myDatabaseFileName, &db );
1365 sqlite3_stmt *ppStmt;
1367 rc = sqlite3_prepare( db, mySql.
toUtf8(), mySql.
toUtf8().
length(), &ppStmt, &pzTail );
1370 if ( rc == SQLITE_OK )
1372 if ( sqlite3_step( ppStmt ) == SQLITE_ROW )
1374 myProjString =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( ppStmt, 0 ) ) );
1378 sqlite3_finalize( ppStmt );
1380 sqlite3_close( db );
1383 return myProjString;
1386 int QgsCoordinateReferenceSystem::openDb(
const QString& path,
sqlite3 **db,
bool readonly )
1389 int myResult = readonly
1390 ? sqlite3_open_v2( path.
toUtf8().
data(), db, SQLITE_OPEN_READONLY, nullptr )
1393 if ( myResult != SQLITE_OK )
1402 .arg( sqlite3_errmsg( *db ) ),
QObject::tr(
"CRS" ) );
1409 mCustomSrsValidation = f;
1414 return mCustomSrsValidation;
1417 void QgsCoordinateReferenceSystem::debugPrint()
1442 d->mValidationHint = html;
1447 return d->mValidationHint;
1463 QString proj4String = d->mProj4;
1473 if ( getRecordCount() == 0 )
1475 mySql =
"insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 1477 +
',' + quotedValue( name )
1480 +
',' + quotedValue(
toProj4() )
1485 mySql =
"insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 1486 + quotedValue( name )
1489 +
',' + quotedValue(
toProj4() )
1494 sqlite3_stmt *myPreparedStatement;
1498 if ( myResult != SQLITE_OK )
1502 sqlite3_errmsg( myDatabase ) ) );
1506 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1509 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1513 return_id = sqlite3_last_insert_rowid( myDatabase );
1514 setInternalId( return_id );
1525 settings.
setValue(
"/UI/recentProjectionsProj4", projectionsProj4 );
1526 settings.
setValue(
"/UI/recentProjectionsAuthId", projectionsAuthId );
1534 long QgsCoordinateReferenceSystem::getRecordCount()
1538 sqlite3_stmt *myPreparedStatement;
1540 long myRecordCount = 0;
1543 if ( myResult != SQLITE_OK )
1545 QgsDebugMsg(
QString(
"Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
1549 QString mySql =
"select count(*) from tbl_srs";
1550 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1552 if ( myResult == SQLITE_OK )
1554 if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1556 QString myRecordCountString =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1557 myRecordCount = myRecordCountString.
toLong();
1561 sqlite3_finalize( myPreparedStatement );
1562 sqlite3_close( myDatabase );
1563 return myRecordCount;
1566 QString QgsCoordinateReferenceSystem::quotedValue(
QString value )
1573 bool QgsCoordinateReferenceSystem::loadWkts(
QHash<int, QString> &wkts,
const char *filename )
1575 qDebug(
"Loading %s", filename );
1576 const char *pszFilename = CPLFindFile(
"gdal", filename );
1580 QFile csv( pszFilename );
1581 if ( !csv.
open( QIODevice::ReadOnly ) )
1598 if ( !loadWkts( wkts, line.
mid( 8 ).
toUtf8() ) )
1603 int pos = line.
indexOf(
',' );
1608 int epsg = line.
left( pos ).
toInt( &ok );
1612 wkts.
insert( epsg, line.
mid( pos + 1 ) );
1625 Q_FOREACH (
const QString& csv,
QStringList() <<
"gcs.csv" <<
"pcs.csv" <<
"vertcs.csv" <<
"compdcs.csv" <<
"geoccs.csv" )
1629 QFile f( filename );
1630 if ( !f.open( QIODevice::ReadOnly ) )
1644 int pos = line.
indexOf(
',' );
1649 int epsg = line.
left( pos ).
toInt( &ok );
1654 if ( epsg == 2218 || epsg == 2221 || epsg == 2296 || epsg == 2297 || epsg == 2298 || epsg == 2299 || epsg == 2300 || epsg == 2301 || epsg == 2302 ||
1655 epsg == 2303 || epsg == 2304 || epsg == 2305 || epsg == 2306 || epsg == 2307 || epsg == 2963 || epsg == 2985 || epsg == 2986 || epsg == 3052 ||
1656 epsg == 3053 || epsg == 3139 || epsg == 3144 || epsg == 3145 || epsg == 3173 || epsg == 3295 || epsg == 3993 || epsg == 4087 || epsg == 4088 ||
1657 epsg == 5017 || epsg == 5221 || epsg == 5224 || epsg == 5225 || epsg == 5514 || epsg == 5515 || epsg == 5516 || epsg == 5819 || epsg == 5820 ||
1658 epsg == 5821 || epsg == 6200 || epsg == 6201 || epsg == 6202 || epsg == 6244 || epsg == 6245 || epsg == 6246 || epsg == 6247 || epsg == 6248 ||
1659 epsg == 6249 || epsg == 6250 || epsg == 6251 || epsg == 6252 || epsg == 6253 || epsg == 6254 || epsg == 6255 || epsg == 6256 || epsg == 6257 ||
1660 epsg == 6258 || epsg == 6259 || epsg == 6260 || epsg == 6261 || epsg == 6262 || epsg == 6263 || epsg == 6264 || epsg == 6265 || epsg == 6266 ||
1661 epsg == 6267 || epsg == 6268 || epsg == 6269 || epsg == 6270 || epsg == 6271 || epsg == 6272 || epsg == 6273 || epsg == 6274 || epsg == 6275 ||
1662 epsg == 32600 || epsg == 32663 || epsg == 32700 )
1665 if ( OSRImportFromEPSG( crs, epsg ) != OGRERR_NONE )
1667 qDebug(
"EPSG %d: not imported", epsg );
1671 char *wkt =
nullptr;
1672 if ( OSRExportToWkt( crs, &wkt ) != OGRERR_NONE )
1674 qWarning(
"EPSG %d: not exported to WKT", epsg );
1678 wkts.
insert( epsg, wkt );
1686 qDebug(
"Loaded %d/%d from %s", n, l, filename.
toUtf8().
constData() );
1689 OSRDestroySpatialReference( crs );
1697 syncDatumTransform( dbFilePath );
1699 int inserted = 0, updated = 0, deleted = 0, errors = 0;
1704 if ( sqlite3_open( dbFilePath.
toUtf8().
constData(), &database ) != SQLITE_OK )
1710 if ( sqlite3_exec( database,
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
1712 qCritical(
"Could not begin transaction: %s [%s]\n",
QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) );
1717 if ( sqlite3_exec( database,
"alter table tbl_srs add noupdate boolean",
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
1718 ( void )sqlite3_exec( database,
"update tbl_srs set noupdate=(auth_name='EPSG' and auth_id in (5513,5514,5221,2065,102067,4156,4818))",
nullptr, 0, 0 );
1720 ( void )sqlite3_exec( database,
"UPDATE tbl_srs SET srid=141001 WHERE srid=41001 AND auth_name='OSGEO' AND auth_id='41001'",
nullptr, 0, 0 );
1724 sqlite3_stmt *select;
1725 char *errMsg =
nullptr;
1731 loadWkts( wkts,
"epsg.wkt" );
1733 qDebug(
"%d WKTs loaded", wkts.
count() );
1738 char *psz = ba.
data();
1739 OGRErr ogrErr = OSRImportFromWkt( crs, &psz );
1740 if ( ogrErr != OGRERR_NONE )
1743 if ( OSRExportToProj4( crs, &psz ) != OGRERR_NONE )
1754 sql =
QString(
"SELECT parameters,noupdate FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).
arg( it.key() );
1755 if ( sqlite3_prepare( database, sql.
toAscii(), sql.
size(), &select, &tail ) != SQLITE_OK )
1757 qCritical(
"Could not prepare: %s [%s]\n", sql.
toAscii().
constData(), sqlite3_errmsg( database ) );
1762 if ( sqlite3_step( select ) == SQLITE_ROW )
1764 srsProj4 =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 0 ) );
1766 if (
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( select, 1 ) ) ).
toInt() != 0 )
1770 sqlite3_finalize( select );
1774 if ( proj4 != srsProj4 )
1777 sql =
QString(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name='EPSG' AND auth_id=%2" ).
arg( quotedValue( proj4 ) ).
arg( it.key() );
1779 if ( sqlite3_exec( database, sql.
toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
1781 qCritical(
"Could not execute: %s [%s/%s]\n",
1783 sqlite3_errmsg( database ),
1784 errMsg ? errMsg :
"(unknown error)" );
1796 QRegExp projRegExp(
"\\+proj=(\\S+)" );
1797 if ( projRegExp.
indexIn( proj4 ) < 0 )
1799 QgsDebugMsg(
QString(
"EPSG %1: no +proj argument found [%2]" ).arg( it.key() ).arg( proj4 ) );
1803 QRegExp ellipseRegExp(
"\\+ellps=(\\S+)" );
1805 if ( ellipseRegExp.
indexIn( proj4 ) >= 0 )
1807 ellps = ellipseRegExp.
cap( 1 );
1810 QString name( OSRIsGeographic( crs ) ? OSRGetAttrValue( crs,
"GEOGCS", 0 ) : OSRGetAttrValue( crs,
"PROJCS", 0 ) );
1814 sql =
QString(
"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,0)" )
1815 .
arg( quotedValue( name ),
1816 quotedValue( projRegExp.
cap( 1 ) ),
1817 quotedValue( ellps ),
1818 quotedValue( proj4 ) )
1820 .arg( OSRIsGeographic( crs ) );
1823 if ( sqlite3_exec( database, sql.
toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
1829 qCritical(
"Could not execute: %s [%s/%s]\n",
1831 sqlite3_errmsg( database ),
1832 errMsg ? errMsg :
"(unknown error)" );
1836 sqlite3_free( errMsg );
1841 sql =
"DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN (";
1844 for ( ; it != wkts.
constEnd(); ++it )
1849 sql +=
") AND NOT noupdate";
1851 if ( sqlite3_exec( database, sql.
toUtf8(),
nullptr,
nullptr, nullptr ) == SQLITE_OK )
1853 deleted = sqlite3_changes( database );
1858 qCritical(
"Could not execute: %s [%s]\n",
1860 sqlite3_errmsg( database ) );
1863 projCtx pContext = pj_ctx_alloc();
1865 #if !defined(PJ_VERSION) || PJ_VERSION!=470 1866 sql =
QString(
"select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated AND NOT noupdate" );
1867 if ( sqlite3_prepare( database, sql.
toAscii(), sql.
size(), &select, &tail ) == SQLITE_OK )
1869 while ( sqlite3_step( select ) == SQLITE_ROW )
1871 const char *auth_name =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 0 ) );
1872 const char *auth_id =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 1 ) );
1873 const char *params =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 2 ) );
1879 input =
QString(
"+init=%1:%2" ).
arg(
QString( auth_name ).toUpper(), auth_id );
1880 pj = pj_init_plus_ctx( pContext, input.
toAscii() );
1885 char *def = pj_get_def( pj, 0 );
1894 proj4 = proj4.
mid( input.
size() );
1898 if ( proj4 != params )
1900 sql =
QString(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
1901 .
arg( quotedValue( proj4 ),
1902 quotedValue( auth_name ),
1903 quotedValue( auth_id ) );
1905 if ( sqlite3_exec( database, sql.
toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
1912 qCritical(
"Could not execute: %s [%s/%s]\n",
1914 sqlite3_errmsg( database ),
1915 errMsg ? errMsg :
"(unknown error)" );
1922 QgsDebugMsg(
QString(
"could not retrieve proj string for %1 from PROJ" ).arg( input ) );
1936 qCritical(
"Could not execute: %s [%s]\n",
1938 sqlite3_errmsg( database ) );
1942 OSRDestroySpatialReference( crs );
1943 pj_ctx_free( pContext );
1945 if ( sqlite3_exec( database,
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
1947 qCritical(
"Could not commit transaction: %s [%s]\n",
QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) );
1951 sqlite3_close( database );
1953 qWarning(
"CRS update (inserted:%d updated:%d deleted:%d errors:%d)", inserted, updated, deleted, errors );
1958 return updated + inserted;
1961 bool QgsCoordinateReferenceSystem::syncDatumTransform(
const QString& dbPath )
1963 const char *filename = CSVFilename(
"datum_shift.csv" );
1964 FILE *fp = VSIFOpen( filename,
"rb" );
1970 char **fieldnames = CSVReadParseLine( fp );
1982 {
"SOURCE_CRS_CODE",
"source_crs_code", -1 },
1983 {
"TARGET_CRS_CODE",
"target_crs_code", -1 },
1984 {
"REMARKS",
"remarks", -1 },
1985 {
"COORD_OP_SCOPE",
"scope", -1 },
1986 {
"AREA_OF_USE_CODE",
"area_of_use_code", -1 },
1992 {
"DEPRECATED",
"deprecated", -1 },
1993 {
"COORD_OP_METHOD_CODE",
"coord_op_method_code", -1 },
2001 {
"PREFERRED",
"preferred", -1 },
2002 {
"COORD_OP_CODE",
"coord_op_code", -1 },
2005 QString update =
"UPDATE tbl_datum_transform SET ";
2008 int n = CSLCount( fieldnames );
2010 int idxid = -1, idxrx = -1, idxry = -1, idxrz = -1, idxmcode = -1;
2011 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
2013 bool last = i ==
sizeof( map ) /
sizeof( *map ) - 1;
2015 map[i].idx = CSLFindString( fieldnames, map[i].src );
2016 if ( map[i].idx < 0 )
2018 qWarning(
"field %s not found", map[i].src );
2019 CSLDestroy( fieldnames );
2024 if ( strcmp( map[i].src,
"COORD_OP_CODE" ) == 0 )
2026 if ( strcmp( map[i].src,
"RX" ) == 0 )
2028 if ( strcmp( map[i].src,
"RY" ) == 0 )
2030 if ( strcmp( map[i].src,
"RZ" ) == 0 )
2032 if ( strcmp( map[i].src,
"COORD_OP_METHOD_CODE" ) == 0 )
2042 update +=
" WHERE ";
2050 update +=
QString(
"%1=%%2" ).
arg( map[i].dst ).
arg( i + 1 );
2052 insert += map[i].dst;
2056 insert =
"INSERT INTO tbl_datum_transform(" + insert +
") VALUES (" + values +
')';
2061 CSLDestroy( fieldnames );
2063 Q_ASSERT( idxid >= 0 );
2064 Q_ASSERT( idxrx >= 0 );
2065 Q_ASSERT( idxry >= 0 );
2066 Q_ASSERT( idxrz >= 0 );
2070 if ( openResult != SQLITE_OK )
2076 if ( sqlite3_exec( db,
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2079 sqlite3_close( db );
2085 v.
reserve(
sizeof( map ) /
sizeof( *map ) );
2089 char **values = CSVReadParseLine( fp );
2095 if ( CSLCount( values ) < n )
2097 qWarning(
"Only %d columns", CSLCount( values ) );
2101 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
2103 int idx = map[i].idx;
2104 Q_ASSERT( idx != -1 );
2105 Q_ASSERT( idx < n );
2106 v.
insert( i, *values[ idx ] ? quotedValue( values[idx] ) :
"NULL" );
2112 v[ idxmcode ] =
"'9606'";
2113 v[ idxrx ] =
'\'' +
qgsDoubleToString( -( v[ idxrx ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2114 v[ idxry ] =
'\'' +
qgsDoubleToString( -( v[ idxry ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2115 v[ idxrz ] =
'\'' +
qgsDoubleToString( -( v[ idxrz ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2121 QString sql =
QString(
"SELECT coord_op_code FROM tbl_datum_transform WHERE coord_op_code=%1" ).
arg( v[ idxid ] );
2122 int prepareRes = sqlite3_prepare( db, sql.
toAscii(), sql.
size(), &stmt, nullptr );
2123 if ( prepareRes != SQLITE_OK )
2126 if ( sqlite3_step( stmt ) == SQLITE_ROW )
2128 cOpCode =
reinterpret_cast< const char *
>( sqlite3_column_text( stmt, 0 ) );
2130 sqlite3_finalize( stmt );
2132 sql = cOpCode.
isEmpty() ? insert : update;
2133 for (
int i = 0; i < v.
size(); i++ )
2135 sql = sql.
arg( v[i] );
2138 if ( sqlite3_exec( db, sql.
toUtf8(),
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2141 qCritical(
"Error: %s", sqlite3_errmsg( db ) );
2145 if ( sqlite3_exec( db,
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2151 sqlite3_close( db );
2163 return OSRGetAuthorityName( d->mCRS,
"GEOGCS" ) +
QLatin1String(
":" ) + OSRGetAuthorityCode( d->mCRS,
"GEOGCS" );
2183 if ( projectionsAuthId.
size() >= projections.
size() )
2187 projections.
clear();
2188 for (
int i = 0; i < projectionsAuthId.
size(); i++ )
2202 if ( crs.
srsid() == 0 )
QgsCoordinateReferenceSystem()
bool createFromSrid(const long theSrid)
Set up this CRS by fetching the appropriate information from the sqlite backend.
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QString cap(int nth) const
QString & append(QChar ch)
iterator insert(const Key &key, const T &value)
QgsCoordinateReferenceSystem crsByOgcWmsCrs(const QString &ogcCrs) const
Returns the CRS from a given OGC WMS-format Coordinate Reference System string.
const Key key(const T &value) const
bool createFromWkt(const QString &theWkt)
Set up this CRS using a WKT spatial ref sys definition.
static QString qgisUserDbFilePath()
Returns the path to the user qgis.db file.
QDomNode appendChild(const QDomNode &newChild)
QString readLine(qint64 maxlen)
void validate()
Perform some validation on this CRS.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QString & prepend(QChar ch)
static void warning(const QString &msg)
Goes to qWarning.
void setFile(const QString &file)
const T & at(int i) const
QString toProj4() const
Returns a Proj4 string representation of this CRS.
bool createFromId(const long theId, CrsType theType=PostgisCrsId)
bool createFromOgcWmsCrs(const QString &theCrs)
Sets this CRS to the given OGC WMS-format Coordinate Reference Systems.
static CUSTOM_CRS_VALIDATION customSrsValidation()
Gets custom function.
int count(const Key &key) const
QString tr(const char *sourceText, const char *disambiguation, int n)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
bool createFromString(const QString &theDefinition)
Set up this CRS from a string definition, by default a WKT definition.
static void setCustomSrsValidation(CUSTOM_CRS_VALIDATION f)
Sets custom function to force valid CRS QGIS uses implementation in QgisGui::customSrsValidation.
void setPattern(const QString &pattern)
QDomElement toElement() const
int matchedLength() const
void setValue(const QString &key, const QVariant &value)
int indexIn(const QString &str, int offset, CaretMode caretMode) const
void setValidationHint(const QString &html)
Set user hint for validation.
QString number(int n, int base)
bool createFromSrsId(const long theSrsId)
Set up this CRS by fetching the appropriate information from the sqlite backend.
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
void append(const T &value)
QString fromUtf8(const char *str, int size)
const_iterator constEnd() const
QString geographicCRSAuthId() const
Returns auth id of related geographic CRS.
#define QgsDebugMsgLevel(str, level)
bool operator!=(const QgsCoordinateReferenceSystem &theSrs) const
Overloaded != operator used to compare to CRS's.
bool readXML(const QDomNode &theNode)
Restores state from the given Dom node.
static QStringList recentProjections()
Returns a list of recently used projections.
QString validationHint()
Get user hint for validation.
bool createFromUserInput(const QString &theDefinition)
Set up this CRS from a various text formats.
long postgisSrid() const
Returns PostGIS SRID for the CRS.
int toInt(bool *ok, int base) const
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
long findMatchingProj()
This is a globbing function to try to find a record in the database that matches a CRS defined only b...
QGis::UnitType mapUnits() const
Returns the units for the projection used by the CRS.
const char * constData() const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
const long GEOCRS_ID
Magic number for a geographic coord sys in QGIS srs.db tbl_srs.srs_id.
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
QString description() const
Returns the descriptive name of the CRS, eg "WGS 84" or "GDA 94 / Vicgrid94".
QgsCoordinateReferenceSystem & operator=(const QgsCoordinateReferenceSystem &srs)
Assignment operator.
const QString GEO_EPSG_CRS_AUTHID
Geographic coord sys from EPSG authority.
static int syncDb()
Update proj.4 parameters in our database from proj.4.
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
bool saveAsUserCRS(const QString &name)
Save the proj4-string as a custom CRS.
~QgsCoordinateReferenceSystem()
QDomText createTextNode(const QString &value)
QByteArray toLocal8Bit() const
QDomNode namedItem(const QString &name) const
bool operator==(const QgsCoordinateReferenceSystem &theSrs) const
Overloaded == operator used to compare to CRS's.
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
long toLong(bool *ok, int base) const
QString & replace(int position, int n, QChar after)
QVariant value(const QString &key, const QVariant &defaultValue) const
const_iterator constBegin() const
const int USER_CRS_START_ID
Magick number that determines whether a projection crsid is a system (srs.db) or user (~/...
QByteArray toLatin1() const
QString mid(int position, int n) const
QStringList toStringList() const
void insert(int i, const T &value)
Class for storing a coordinate reference system (CRS)
QString toWkt() const
Returns a WKT representation of this CRS.
const int LAT_PREFIX_LEN
The length of the string "+lat_1=".
UnitType
Map units that qgis supports.
QString left(int n) const
static QString srsDbFilePath()
Returns the path to the srs.db file.
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
bool writeXML(QDomNode &theNode, QDomDocument &theDoc) const
Stores state to the given Dom node in the given document.
QDomElement createElement(const QString &tagName)
long srsid() const
Returns the SrsId, if available.
int compare(const QString &other) const
bool exactMatch(const QString &str) const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
static QgsCRSCache * instance()
Returns a pointer to the QgsCRSCache singleton.
QString authid() const
Returns the authority identifier for the CRS, which includes both the authority (eg EPSG) and the CRS...
static void setupESRIWktFix()
Make sure that ESRI WKT import is done properly.
QByteArray toAscii() const
bool createFromProj4(const QString &theProjString)
Set up this CRS by passing it a proj4 style formatted string.
void * OGRSpatialReferenceH
bool geographicFlag() const
Returns whether the CRS is a geographic CRS.
bool axisInverted() const
Returns whether axis is inverted (eg.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QByteArray toUtf8() const