23 #include <QTemporaryFile> 25 #include <QDomElement> 28 #include <QTextStream> 43 #include <ogr_srs_api.h> 44 #include <cpl_error.h> 55 , mMapUnits(
QGis::UnknownUnit )
58 , mValidationHint(
"" )
59 , mAxisInverted( false )
61 mCRS = OSRNewSpatialReference(
nullptr );
67 , mMapUnits(
QGis::UnknownUnit )
70 , mValidationHint(
"" )
71 , mAxisInverted( false )
73 mCRS = OSRNewSpatialReference(
nullptr );
81 , mMapUnits(
QGis::UnknownUnit )
84 , mValidationHint(
"" )
85 , mAxisInverted( false )
87 mCRS = OSRNewSpatialReference(
nullptr );
93 OSRDestroySpatialReference( mCRS );
120 QRegExp reCrsId(
"^(epsg|postgis|internal)\\:(\\d+)$", Qt::CaseInsensitive );
121 if ( reCrsId.
indexIn( theDefinition ) == 0 )
125 if ( authName ==
"epsg" )
127 if ( authName ==
"postgis" )
134 QRegExp reCrsStr(
"^(?:(wkt|proj4)\\:)?(.+)$", Qt::CaseInsensitive );
135 if ( reCrsStr.
indexIn( theDefinition ) == 0 )
147 .
arg(
QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
168 #if GDAL_VERSION_NUM >= 1900 177 if ( OSRExportToWkt( crs, &wkt ) == OGRERR_NONE )
182 OSRDestroySpatialReference( crs );
192 #if GDAL_VERSION_NUM >= 1900 193 const char* configOld = CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" );
194 const char* configNew =
"GEOGCS";
196 if ( strcmp( configOld,
"" ) == 0 )
198 CPLSetConfigOption(
"GDAL_FIX_ESRI_WKT", configNew );
199 if ( strcmp( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) != 0 )
201 .arg( configNew, CPLGetConfigOption(
"GDAL_FIX_ESRI_WKT",
"" ) ) );
213 QRegExp re(
"urn:ogc:def:crs:([^:]+).+([^:]+)", Qt::CaseInsensitive );
216 theCrs = re.
cap( 1 ) +
':' + re.
cap( 2 );
231 if ( theCrs.
compare(
"CRS:27", Qt::CaseInsensitive ) == 0 ||
232 theCrs.
compare(
"OGC:CRS27", Qt::CaseInsensitive ) == 0 )
239 if ( theCrs.
compare(
"CRS:83", Qt::CaseInsensitive ) == 0 ||
240 theCrs.
compare(
"OGC:CRS83", Qt::CaseInsensitive ) == 0 )
247 if ( theCrs.
compare(
"CRS:84", Qt::CaseInsensitive ) == 0 ||
248 theCrs.
compare(
"OGC:CRS84", Qt::CaseInsensitive ) == 0 )
260 mCRS = OSRNewSpatialReference(
nullptr );
270 mDescription = srs.mDescription;
271 mProjectionAcronym = srs.mProjectionAcronym;
272 mEllipsoidAcronym = srs.mEllipsoidAcronym;
273 mGeoFlag = srs.mGeoFlag;
274 mAxisInverted = srs.mAxisInverted;
275 mMapUnits = srs.mMapUnits;
277 mAuthId = srs.mAuthId;
278 mIsValidFlag = srs.mIsValidFlag;
279 mValidationHint = srs.mValidationHint;
284 OSRDestroySpatialReference( mCRS );
285 mCRS = OSRClone( srs.mCRS );
300 if ( mCustomSrsValidation )
301 mCustomSrsValidation( *
this );
321 bool QgsCoordinateReferenceSystem::loadFromDb(
const QString& db,
const QString& expression,
const QString& value )
323 QgsDebugMsgLevel(
"load CRS from " + db +
" where " + expression +
" is " + value, 3 );
324 mIsValidFlag =
false;
330 QgsDebugMsg(
"failed : " + db +
" does not exist!" );
336 sqlite3_stmt *myPreparedStatement;
339 myResult = openDb( db, &myDatabase );
340 if ( myResult != SQLITE_OK )
342 QgsDebugMsg(
"failed : " + db +
" could not be opened!" );
358 QString mySql =
"select srs_id,description,projection_acronym," 359 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo " 360 "from tbl_srs where " + expression +
'=' + quotedValue( value ) +
" order by deprecated";
361 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(),
363 &myPreparedStatement, &myTail );
365 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
367 mSrsId =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text(
368 myPreparedStatement, 0 ) ) ).
toLong();
369 mDescription =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text(
370 myPreparedStatement, 1 ) ) );
371 mProjectionAcronym =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 2 ) ) );
372 mEllipsoidAcronym =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 3 ) ) );
373 mProj4 =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 4 ) ) );
374 mSRID =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 5 ) ) ).
toLong() ;
375 mAuthId =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 6 ) ) );
376 mGeoFlag =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 7 ) ) ).
toInt() != 0;
383 else if ( mAuthId.
startsWith(
"EPSG:", Qt::CaseInsensitive ) )
385 OSRDestroySpatialReference( mCRS );
386 mCRS = OSRNewSpatialReference(
nullptr );
387 mIsValidFlag = OSRSetFromUserInput( mCRS, mAuthId.
toLower().
toAscii() ) == OGRERR_NONE;
393 setProj4String( mProj4 );
400 sqlite3_finalize( myPreparedStatement );
401 sqlite3_close( myDatabase );
407 if ( mAxisInverted == -1 )
409 OGRAxisOrientation orientation;
410 OSRGetAxis( mCRS, OSRIsGeographic( mCRS ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
413 if ( orientation == OAO_Other && mAuthId.
startsWith(
"EPSG:", Qt::CaseInsensitive ) )
417 if ( OSRImportFromEPSGA( crs, mAuthId.
mid( 5 ).
toInt() ) == OGRERR_NONE )
419 OSRGetAxis( crs, OSRIsGeographic( crs ) ?
"GEOGCS" :
"PROJCS", 0, &orientation );
422 OSRDestroySpatialReference( crs );
425 mAxisInverted = orientation == OAO_North;
428 return mAxisInverted != 0;
433 mIsValidFlag =
false;
439 QgsDebugMsg(
"theWkt is uninitialized, operation failed" );
444 const char *pWkt = ba.
data();
446 OGRErr myInputResult = OSRImportFromWkt( mCRS, const_cast< char ** >( & pWkt ) );
448 if ( myInputResult != OGRERR_NONE )
450 QgsDebugMsg(
"\n---------------------------------------------------------------" );
451 QgsDebugMsg(
"This CRS could *** NOT *** be set from the supplied Wkt " );
454 QgsDebugMsg(
"---------------------------------------------------------------\n" );
458 if ( OSRAutoIdentifyEPSG( mCRS ) == OGRERR_NONE )
461 .
arg( OSRGetAuthorityName( mCRS,
nullptr ),
462 OSRGetAuthorityCode( mCRS,
nullptr ) );
472 char *proj4src =
nullptr;
473 OSRExportToProj4( mCRS, &proj4src );
485 OSRExportToProj4( mCRS, &proj4src );
496 .
arg(
QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
524 mIsValidFlag =
false;
527 QRegExp myProjRegExp(
"\\+proj=(\\S+)" );
528 int myStart = myProjRegExp.
indexIn( myProj4String );
531 QgsDebugMsg(
"proj string supplied has no +proj argument" );
535 mProjectionAcronym = myProjRegExp.
cap( 1 );
537 QRegExp myEllipseRegExp(
"\\+ellps=(\\S+)" );
538 myStart = myEllipseRegExp.
indexIn( myProj4String );
541 QgsDebugMsg(
"proj string supplied has no +ellps argument" );
542 mEllipsoidAcronym =
"";
546 mEllipsoidAcronym = myEllipseRegExp.
cap( 1 );
549 QRegExp myAxisRegExp(
"\\+a=(\\S+)" );
550 myStart = myAxisRegExp.
indexIn( myProj4String );
553 QgsDebugMsg(
"proj string supplied has no +a argument" );
571 myRecord = getRecord(
"select * from tbl_srs where parameters=" + quotedValue( myProj4String ) +
" order by deprecated" );
572 if ( myRecord.
empty() )
577 QRegExp myLat1RegExp(
"\\+lat_1=\\S+" );
578 QRegExp myLat2RegExp(
"\\+lat_2=\\S+" );
585 myStart1 = myLat1RegExp.
indexIn( myProj4String, myStart1 );
586 myStart2 = myLat2RegExp.
indexIn( myProj4String, myStart2 );
587 if ( myStart1 != -1 && myStart2 != -1 )
595 if ( lat1Str !=
"" && lat2Str !=
"" )
598 QString theProj4StringModified = myProj4String;
603 myStart2 = myLat2RegExp.
indexIn( theProj4String, myStart2 );
605 QgsDebugMsg(
"trying proj4string match with swapped lat_1,lat_2" );
606 myRecord = getRecord(
"select * from tbl_srs where parameters=" + quotedValue( theProj4StringModified.
trimmed() ) +
" order by deprecated" );
610 if ( myRecord.
empty() )
617 QString sql =
"SELECT * FROM tbl_srs WHERE ";
625 Q_FOREACH (
const QString& param, myProj4String.
split(
QRegExp(
"\\s+(?=\\+)" ), QString::SkipEmptyParts ) )
642 myRecord = getRecord( sql + delim + datum +
" order by deprecated" );
645 if ( myRecord.
empty() )
648 myRecord = getRecord( sql +
" order by deprecated" );
651 if ( !myRecord.
empty() )
655 Q_FOREACH (
const QString& param, myRecord[
"parameters"].split(
QRegExp(
"\\s+(?=\\+)" ), QString::SkipEmptyParts ) )
658 foundParams << param.
trimmed();
664 if ( myParams != foundParams )
671 if ( !myRecord.
empty() )
673 mySrsId = myRecord[
"srs_id"].toLong();
683 QgsDebugMsg(
"globbing search for srsid from this proj string" );
684 setProj4String( myProj4String );
693 mIsValidFlag =
false;
700 QgsDebugMsg(
"Projection is not found in databases." );
702 setProj4String( myProj4String );
717 sqlite3_stmt *myPreparedStatement;
726 QgsDebugMsg(
"failed : " + myDatabaseFileName +
" does not exist!" );
731 myResult = openDb( myDatabaseFileName, &myDatabase );
732 if ( myResult != SQLITE_OK )
737 myResult = sqlite3_prepare( myDatabase, theSql.
toUtf8(), theSql.
toUtf8().
length(), &myPreparedStatement, &myTail );
739 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
742 int myColumnCount = sqlite3_column_count( myPreparedStatement );
744 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
746 myFieldName =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_name( myPreparedStatement, myColNo ) ) );
747 myFieldValue =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, myColNo ) ) );
748 myMap[myFieldName] = myFieldValue;
750 if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE )
764 sqlite3_finalize( myPreparedStatement );
765 sqlite3_close( myDatabase );
769 myFileInfo.
setFile( myDatabaseFileName );
770 if ( !myFileInfo.
exists() )
777 myResult = openDb( myDatabaseFileName, &myDatabase );
778 if ( myResult != SQLITE_OK )
783 myResult = sqlite3_prepare( myDatabase, theSql.
toUtf8(), theSql.
toUtf8().
length(), &myPreparedStatement, &myTail );
785 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
787 int myColumnCount = sqlite3_column_count( myPreparedStatement );
789 for (
int myColNo = 0; myColNo < myColumnCount; myColNo++ )
791 myFieldName =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_name( myPreparedStatement, myColNo ) ) );
792 myFieldValue =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, myColNo ) ) );
793 myMap[myFieldName] = myFieldValue;
796 if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE )
807 sqlite3_finalize( myPreparedStatement );
808 sqlite3_close( myDatabase );
813 for ( it = myMap.
begin(); it != myMap.
end(); ++it )
841 if ( mDescription.
isNull() )
853 if ( mProjectionAcronym.
isNull() )
859 return mProjectionAcronym;
865 if ( mEllipsoidAcronym.
isNull() )
871 return mEllipsoidAcronym;
882 char *proj4src =
nullptr;
883 OSRExportToProj4( mCRS, &proj4src );
905 void QgsCoordinateReferenceSystem::setInternalId(
long theSrsId )
909 void QgsCoordinateReferenceSystem::setAuthId(
const QString& authId )
913 void QgsCoordinateReferenceSystem::setSrid(
long theSrid )
917 void QgsCoordinateReferenceSystem::setDescription(
const QString& theDescription )
919 mDescription = theDescription;
921 void QgsCoordinateReferenceSystem::setProj4String(
const QString& theProj4String )
923 mProj4 = theProj4String;
927 OSRDestroySpatialReference( mCRS );
928 mCRS = OSRNewSpatialReference(
nullptr );
937 QgsDebugMsg(
"proj.4 string rejected by pj_init_plus()" );
938 mIsValidFlag =
false;
947 #if defined(QGISDEBUG) && QGISDEBUG>=3 951 void QgsCoordinateReferenceSystem::setGeographicFlag(
bool theGeoFlag )
953 mGeoFlag = theGeoFlag;
955 void QgsCoordinateReferenceSystem::setEpsg(
long theEpsg )
957 mAuthId =
QString(
"EPSG:%1" ).
arg( theEpsg );
959 void QgsCoordinateReferenceSystem::setProjectionAcronym(
const QString& theProjectionAcronym )
961 mProjectionAcronym = theProjectionAcronym;
963 void QgsCoordinateReferenceSystem::setEllipsoidAcronym(
const QString& theEllipsoidAcronym )
965 mEllipsoidAcronym = theEllipsoidAcronym;
968 void QgsCoordinateReferenceSystem::setMapUnits()
982 if ( OSRIsProjected( mCRS ) )
984 double toMeter = OSRGetLinearUnits( mCRS, &unitName );
992 static const double feetToMeter = 0.3048;
993 static const double smallNum = 1e-3;
995 if ( qAbs( toMeter - feetToMeter ) < smallNum )
998 QgsDebugMsg(
"Projection has linear units of " + unit );
1002 else if ( unit ==
"Foot" )
1006 QgsDebugMsg(
"Unsupported map units of " + unit );
1012 OSRGetAngularUnits( mCRS, &unitName );
1014 if ( unit ==
"degree" )
1018 QgsDebugMsg(
"Unsupported map units of " + unit );
1037 if ( mEllipsoidAcronym.
isNull() || mProjectionAcronym.
isNull()
1040 QgsDebugMsg(
"QgsCoordinateReferenceSystem::findMatchingProj will only " 1041 "work if prj acr ellipsoid acr and proj4string are set" 1042 " and the current projection is valid!" );
1048 sqlite3_stmt *myPreparedStatement;
1053 QString mySql =
QString(
"select srs_id,parameters from tbl_srs where " 1054 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1055 .
arg( quotedValue( mProjectionAcronym ),
1056 quotedValue( mEllipsoidAcronym ) );
1061 myResult = openDb( myDatabaseFileName, &myDatabase );
1062 if ( myResult != SQLITE_OK )
1067 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1069 if ( myResult == SQLITE_OK )
1072 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1074 QString mySrsId =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1075 QString myProj4String =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 1 ) ) );
1078 QgsDebugMsg(
"-------> MATCH FOUND in srs.db srsid: " + mySrsId );
1080 sqlite3_finalize( myPreparedStatement );
1081 sqlite3_close( myDatabase );
1090 QgsDebugMsg(
"no match found in srs.db, trying user db now!" );
1092 sqlite3_finalize( myPreparedStatement );
1093 sqlite3_close( myDatabase );
1100 myResult = openDb( myDatabaseFileName, &myDatabase );
1101 if ( myResult != SQLITE_OK )
1106 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1108 if ( myResult == SQLITE_OK )
1111 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1113 QString mySrsId =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1114 QString myProj4String =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 1 ) ) );
1117 QgsDebugMsg(
"-------> MATCH FOUND in user qgis.db srsid: " + mySrsId );
1119 sqlite3_finalize( myPreparedStatement );
1120 sqlite3_close( myDatabase );
1132 sqlite3_finalize( myPreparedStatement );
1133 sqlite3_close( myDatabase );
1139 return ( !mIsValidFlag && !theSrs.mIsValidFlag ) ||
1140 ( mIsValidFlag && theSrs.mIsValidFlag && theSrs.
authid() ==
authid() );
1145 return !( *
this == theSrs );
1153 if ( OSRExportToWkt( mCRS, &wkt ) == OGRERR_NONE )
1164 QgsDebugMsg(
"Reading Spatial Ref Sys from xml ------------------------!" );
1168 if ( ! srsNode.
isNull() )
1170 bool initialized =
false;
1203 QgsDebugMsg(
"Ignoring authid/epsg for user crs." );
1221 QgsDebugMsg(
"Setting from elements one by one" );
1227 setInternalId( myNode.toElement().text().toLong() );
1230 setSrid( myNode.toElement().text().toLong() );
1233 setAuthId( myNode.toElement().text() );
1235 myNode = srsNode.
namedItem(
"description" );
1236 setDescription( myNode.toElement().text() );
1238 myNode = srsNode.
namedItem(
"projectionacronym" );
1239 setProjectionAcronym( myNode.toElement().text() );
1241 myNode = srsNode.
namedItem(
"ellipsoidacronym" );
1242 setEllipsoidAcronym( myNode.toElement().text() );
1244 myNode = srsNode.
namedItem(
"geographicflag" );
1245 if ( myNode.toElement().text().compare(
"true" ) )
1247 setGeographicFlag(
true );
1251 setGeographicFlag(
false );
1258 mIsValidFlag =
true;
1267 .
arg(
QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
1311 mySrsElement.
appendChild( myProjectionAcronymElement );
1315 mySrsElement.
appendChild( myEllipsoidAcronymElement );
1318 QString myGeoFlagText =
"false";
1321 myGeoFlagText =
"true";
1325 mySrsElement.
appendChild( myGeographicFlagElement );
1341 QString QgsCoordinateReferenceSystem::proj4FromSrsId(
const int theSrsId )
1346 QString mySql =
QString(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).
arg( theSrsId );
1360 myFileInfo.
setFile( myDatabaseFileName );
1361 if ( !myFileInfo.
exists() )
1375 rc = openDb( myDatabaseFileName, &db );
1382 sqlite3_stmt *ppStmt;
1384 rc = sqlite3_prepare( db, mySql.
toUtf8(), mySql.
toUtf8().
length(), &ppStmt, &pzTail );
1387 if ( rc == SQLITE_OK )
1389 if ( sqlite3_step( ppStmt ) == SQLITE_ROW )
1391 myProjString =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( ppStmt, 0 ) ) );
1395 sqlite3_finalize( ppStmt );
1397 sqlite3_close( db );
1400 return myProjString;
1403 int QgsCoordinateReferenceSystem::openDb(
const QString& path,
sqlite3 **db,
bool readonly )
1406 int myResult = readonly
1407 ? sqlite3_open_v2( path.
toUtf8().
data(), db, SQLITE_OPEN_READONLY, nullptr )
1410 if ( myResult != SQLITE_OK )
1419 .arg( sqlite3_errmsg( *db ) ),
QObject::tr(
"CRS" ) );
1426 mCustomSrsValidation = f;
1431 return mCustomSrsValidation;
1434 void QgsCoordinateReferenceSystem::debugPrint()
1458 mValidationHint = html;
1463 return mValidationHint;
1471 if ( ! mIsValidFlag )
1489 if ( getRecordCount() == 0 )
1491 mySql =
"insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 1493 +
',' + quotedValue( name )
1496 +
',' + quotedValue(
toProj4() )
1501 mySql =
"insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 1502 + quotedValue( name )
1505 +
',' + quotedValue(
toProj4() )
1510 sqlite3_stmt *myPreparedStatement;
1514 if ( myResult != SQLITE_OK )
1518 sqlite3_errmsg( myDatabase ) ) );
1522 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1525 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1529 return_id = sqlite3_last_insert_rowid( myDatabase );
1530 setInternalId( return_id );
1541 settings.
setValue(
"/UI/recentProjectionsProj4", projectionsProj4 );
1542 settings.
setValue(
"/UI/recentProjectionsAuthId", projectionsAuthId );
1550 long QgsCoordinateReferenceSystem::getRecordCount()
1554 sqlite3_stmt *myPreparedStatement;
1556 long myRecordCount = 0;
1559 if ( myResult != SQLITE_OK )
1561 QgsDebugMsg(
QString(
"Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
1565 QString mySql =
"select count(*) from tbl_srs";
1566 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1568 if ( myResult == SQLITE_OK )
1570 if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1572 QString myRecordCountString =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1573 myRecordCount = myRecordCountString.
toLong();
1577 sqlite3_finalize( myPreparedStatement );
1578 sqlite3_close( myDatabase );
1579 return myRecordCount;
1582 QString QgsCoordinateReferenceSystem::quotedValue(
QString value )
1589 bool QgsCoordinateReferenceSystem::loadWkts(
QHash<int, QString> &wkts,
const char *filename )
1591 qDebug(
"Loading %s", filename );
1592 const char *pszFilename = CPLFindFile(
"gdal", filename );
1596 QFile csv( pszFilename );
1597 if ( !csv.
open( QIODevice::ReadOnly ) )
1614 if ( !loadWkts( wkts, line.
mid( 8 ).
toUtf8() ) )
1619 int pos = line.
indexOf(
',' );
1624 int epsg = line.
left( pos ).
toInt( &ok );
1628 wkts.
insert( epsg, line.
mid( pos + 1 ) );
1641 Q_FOREACH (
const QString& csv,
QStringList() <<
"gcs.csv" <<
"pcs.csv" <<
"vertcs.csv" <<
"compdcs.csv" <<
"geoccs.csv" )
1645 QFile f( filename );
1646 if ( !f.open( QIODevice::ReadOnly ) )
1660 int pos = line.
indexOf(
',' );
1665 int epsg = line.
left( pos ).
toInt( &ok );
1670 if ( epsg == 2218 || epsg == 2221 || epsg == 2296 || epsg == 2297 || epsg == 2298 || epsg == 2299 || epsg == 2300 || epsg == 2301 || epsg == 2302 ||
1671 epsg == 2303 || epsg == 2304 || epsg == 2305 || epsg == 2306 || epsg == 2307 || epsg == 2963 || epsg == 2985 || epsg == 2986 || epsg == 3052 ||
1672 epsg == 3053 || epsg == 3139 || epsg == 3144 || epsg == 3145 || epsg == 3173 || epsg == 3295 || epsg == 3993 || epsg == 4087 || epsg == 4088 ||
1673 epsg == 5017 || epsg == 5221 || epsg == 5224 || epsg == 5225 || epsg == 5514 || epsg == 5515 || epsg == 5516 || epsg == 5819 || epsg == 5820 ||
1674 epsg == 5821 || epsg == 6200 || epsg == 6201 || epsg == 6202 || epsg == 6244 || epsg == 6245 || epsg == 6246 || epsg == 6247 || epsg == 6248 ||
1675 epsg == 6249 || epsg == 6250 || epsg == 6251 || epsg == 6252 || epsg == 6253 || epsg == 6254 || epsg == 6255 || epsg == 6256 || epsg == 6257 ||
1676 epsg == 6258 || epsg == 6259 || epsg == 6260 || epsg == 6261 || epsg == 6262 || epsg == 6263 || epsg == 6264 || epsg == 6265 || epsg == 6266 ||
1677 epsg == 6267 || epsg == 6268 || epsg == 6269 || epsg == 6270 || epsg == 6271 || epsg == 6272 || epsg == 6273 || epsg == 6274 || epsg == 6275 ||
1678 epsg == 32600 || epsg == 32663 || epsg == 32700 )
1681 if ( OSRImportFromEPSG( crs, epsg ) != OGRERR_NONE )
1683 qDebug(
"EPSG %d: not imported", epsg );
1687 char *wkt =
nullptr;
1688 if ( OSRExportToWkt( crs, &wkt ) != OGRERR_NONE )
1690 qWarning(
"EPSG %d: not exported to WKT", epsg );
1694 wkts.
insert( epsg, wkt );
1702 qDebug(
"Loaded %d/%d from %s", n, l, filename.
toUtf8().
constData() );
1705 OSRDestroySpatialReference( crs );
1713 syncDatumTransform( dbFilePath );
1715 int inserted = 0, updated = 0, deleted = 0, errors = 0;
1720 if ( sqlite3_open( dbFilePath.
toUtf8().
constData(), &database ) != SQLITE_OK )
1726 if ( sqlite3_exec( database,
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
1728 qCritical(
"Could not begin transaction: %s [%s]\n",
QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) );
1733 if ( sqlite3_exec( database,
"alter table tbl_srs add noupdate boolean",
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
1734 ( 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 );
1736 ( void )sqlite3_exec( database,
"UPDATE tbl_srs SET srid=141001 WHERE srid=41001 AND auth_name='OSGEO' AND auth_id='41001'",
nullptr, 0, 0 );
1740 sqlite3_stmt *select;
1741 char *errMsg =
nullptr;
1747 loadWkts( wkts,
"epsg.wkt" );
1749 qDebug(
"%d WKTs loaded", wkts.
count() );
1754 char *psz = ba.
data();
1755 OGRErr ogrErr = OSRImportFromWkt( crs, &psz );
1756 if ( ogrErr != OGRERR_NONE )
1759 if ( OSRExportToProj4( crs, &psz ) != OGRERR_NONE )
1770 sql =
QString(
"SELECT parameters,noupdate FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).
arg( it.key() );
1771 if ( sqlite3_prepare( database, sql.
toAscii(), sql.
size(), &select, &tail ) != SQLITE_OK )
1773 qCritical(
"Could not prepare: %s [%s]\n", sql.
toAscii().
constData(), sqlite3_errmsg( database ) );
1778 if ( sqlite3_step( select ) == SQLITE_ROW )
1780 srsProj4 =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 0 ) );
1782 if (
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( select, 1 ) ) ).
toInt() != 0 )
1786 sqlite3_finalize( select );
1790 if ( proj4 != srsProj4 )
1793 sql =
QString(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name='EPSG' AND auth_id=%2" ).
arg( quotedValue( proj4 ) ).
arg( it.key() );
1795 if ( sqlite3_exec( database, sql.
toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
1797 qCritical(
"Could not execute: %s [%s/%s]\n",
1799 sqlite3_errmsg( database ),
1800 errMsg ? errMsg :
"(unknown error)" );
1812 QRegExp projRegExp(
"\\+proj=(\\S+)" );
1813 if ( projRegExp.
indexIn( proj4 ) < 0 )
1815 QgsDebugMsg(
QString(
"EPSG %1: no +proj argument found [%2]" ).arg( it.key() ).arg( proj4 ) );
1819 QRegExp ellipseRegExp(
"\\+ellps=(\\S+)" );
1821 if ( ellipseRegExp.
indexIn( proj4 ) >= 0 )
1823 ellps = ellipseRegExp.
cap( 1 );
1826 QString name( OSRIsGeographic( crs ) ? OSRGetAttrValue( crs,
"GEOCS", 0 ) : OSRGetAttrValue( crs,
"PROJCS", 0 ) );
1830 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)" )
1831 .
arg( quotedValue( name ),
1832 quotedValue( projRegExp.
cap( 1 ) ),
1833 quotedValue( ellps ),
1834 quotedValue( proj4 ) )
1836 .arg( OSRIsGeographic( crs ) );
1839 if ( sqlite3_exec( database, sql.
toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
1845 qCritical(
"Could not execute: %s [%s/%s]\n",
1847 sqlite3_errmsg( database ),
1848 errMsg ? errMsg :
"(unknown error)" );
1852 sqlite3_free( errMsg );
1857 sql =
"DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN (";
1860 for ( ; it != wkts.
constEnd(); ++it )
1865 sql +=
") AND NOT noupdate";
1867 if ( sqlite3_exec( database, sql.
toUtf8(),
nullptr,
nullptr, nullptr ) == SQLITE_OK )
1869 deleted = sqlite3_changes( database );
1874 qCritical(
"Could not execute: %s [%s]\n",
1876 sqlite3_errmsg( database ) );
1879 #if !defined(PJ_VERSION) || PJ_VERSION!=470 1880 sql =
QString(
"select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated AND NOT noupdate" );
1881 if ( sqlite3_prepare( database, sql.toAscii(), sql.size(), &select, &tail ) == SQLITE_OK )
1883 while ( sqlite3_step( select ) == SQLITE_ROW )
1885 const char *auth_name =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 0 ) );
1886 const char *auth_id =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 1 ) );
1887 const char *params =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 2 ) );
1893 input =
QString(
"+init=%1:%2" ).
arg(
QString( auth_name ).toUpper(), auth_id );
1894 pj = pj_init_plus( input.
toAscii() );
1899 char *def = pj_get_def( pj, 0 );
1908 proj4 = proj4.
mid( input.
size() );
1912 if ( proj4 != params )
1914 sql =
QString(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
1915 .
arg( quotedValue( proj4 ),
1916 quotedValue( auth_name ),
1917 quotedValue( auth_id ) );
1919 if ( sqlite3_exec( database, sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
1926 qCritical(
"Could not execute: %s [%s/%s]\n",
1927 sql.toLocal8Bit().constData(),
1928 sqlite3_errmsg( database ),
1929 errMsg ? errMsg :
"(unknown error)" );
1936 QgsDebugMsg(
QString(
"could not retrieve proj string for %1 from PROJ" ).arg( input ) );
1950 qCritical(
"Could not execute: %s [%s]\n",
1951 sql.toLocal8Bit().constData(),
1952 sqlite3_errmsg( database ) );
1956 OSRDestroySpatialReference( crs );
1958 if ( sqlite3_exec( database,
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
1960 qCritical(
"Could not commit transaction: %s [%s]\n",
QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) );
1964 sqlite3_close( database );
1966 qWarning(
"CRS update (inserted:%d updated:%d deleted:%d errors:%d)", inserted, updated, deleted, errors );
1971 return updated + inserted;
1974 bool QgsCoordinateReferenceSystem::syncDatumTransform(
const QString& dbPath )
1976 const char *filename = CSVFilename(
"datum_shift.csv" );
1977 FILE *fp = VSIFOpen( filename,
"rb" );
1983 char **fieldnames = CSVReadParseLine( fp );
1995 {
"SOURCE_CRS_CODE",
"source_crs_code", -1 },
1996 {
"TARGET_CRS_CODE",
"target_crs_code", -1 },
1997 {
"REMARKS",
"remarks", -1 },
1998 {
"COORD_OP_SCOPE",
"scope", -1 },
1999 {
"AREA_OF_USE_CODE",
"area_of_use_code", -1 },
2005 {
"DEPRECATED",
"deprecated", -1 },
2006 {
"COORD_OP_METHOD_CODE",
"coord_op_method_code", -1 },
2014 {
"PREFERRED",
"preferred", -1 },
2015 {
"COORD_OP_CODE",
"coord_op_code", -1 },
2018 QString update =
"UPDATE tbl_datum_transform SET ";
2021 int n = CSLCount( fieldnames );
2023 int idxid = -1, idxrx = -1, idxry = -1, idxrz = -1, idxmcode = -1;
2024 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
2026 bool last = i ==
sizeof( map ) /
sizeof( *map ) - 1;
2028 map[i].idx = CSLFindString( fieldnames, map[i].src );
2029 if ( map[i].idx < 0 )
2031 qWarning(
"field %s not found", map[i].src );
2032 CSLDestroy( fieldnames );
2037 if ( strcmp( map[i].src,
"COORD_OP_CODE" ) == 0 )
2039 if ( strcmp( map[i].src,
"RX" ) == 0 )
2041 if ( strcmp( map[i].src,
"RY" ) == 0 )
2043 if ( strcmp( map[i].src,
"RZ" ) == 0 )
2045 if ( strcmp( map[i].src,
"COORD_OP_METHOD_CODE" ) == 0 )
2055 update +=
" WHERE ";
2063 update +=
QString(
"%1=%%2" ).
arg( map[i].dst ).
arg( i + 1 );
2065 insert += map[i].dst;
2069 insert =
"INSERT INTO tbl_datum_transform(" + insert +
") VALUES (" + values +
')';
2074 CSLDestroy( fieldnames );
2076 Q_ASSERT( idxid >= 0 );
2077 Q_ASSERT( idxrx >= 0 );
2078 Q_ASSERT( idxry >= 0 );
2079 Q_ASSERT( idxrz >= 0 );
2083 if ( openResult != SQLITE_OK )
2089 if ( sqlite3_exec( db,
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2092 sqlite3_close( db );
2098 v.
reserve(
sizeof( map ) /
sizeof( *map ) );
2100 while ( !feof( fp ) )
2102 char **values = CSVReadParseLine( fp );
2106 if ( CSLCount( values ) < n )
2108 qWarning(
"Only %d columns", CSLCount( values ) );
2112 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
2114 int idx = map[i].idx;
2115 Q_ASSERT( idx != -1 );
2116 Q_ASSERT( idx < n );
2117 v.
insert( i, *values[ idx ] ? quotedValue( values[idx] ) :
"NULL" );
2123 v[ idxmcode ] =
"'9606'";
2124 v[ idxrx ] =
'\'' +
qgsDoubleToString( -( v[ idxrx ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2125 v[ idxry ] =
'\'' +
qgsDoubleToString( -( v[ idxry ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2126 v[ idxrz ] =
'\'' +
qgsDoubleToString( -( v[ idxrz ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2132 QString sql =
QString(
"SELECT coord_op_code FROM tbl_datum_transform WHERE coord_op_code=%1" ).
arg( v[ idxid ] );
2133 int prepareRes = sqlite3_prepare( db, sql.
toAscii(), sql.
size(), &stmt, nullptr );
2134 if ( prepareRes != SQLITE_OK )
2137 if ( sqlite3_step( stmt ) == SQLITE_ROW )
2139 cOpCode =
reinterpret_cast< const char *
>( sqlite3_column_text( stmt, 0 ) );
2141 sqlite3_finalize( stmt );
2143 sql = cOpCode.
isEmpty() ? insert : update;
2144 for (
int i = 0; i < v.
size(); i++ )
2146 sql = sql.
arg( v[i] );
2149 if ( sqlite3_exec( db, sql.
toUtf8(),
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2152 qCritical(
"Error: %s", sqlite3_errmsg( db ) );
2156 if ( sqlite3_exec( db,
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2162 sqlite3_close( db );
2174 return OSRGetAuthorityName( mCRS,
"GEOGCS" ) +
QLatin1String(
":" ) + OSRGetAuthorityCode( mCRS,
"GEOGCS" );
2194 if ( projectionsAuthId.
size() >= projections.
size() )
2198 projections.
clear();
2199 for (
int i = 0; i < projectionsAuthId.
size(); i++ )
2213 if ( crs.
srsid() == 0 )
QgsCoordinateReferenceSystem()
Default constructor.
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)
const QgsCoordinateReferenceSystem & crsByAuthId(const QString &authid)
Returns the CRS for authid, e.g.
iterator insert(const Key &key, const T &value)
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)
The QGis class provides global constants for use throughout the application.
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)
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
bool createFromOgcWmsCrs(QString theCrs)
Set up this CRS from the given OGC CRS.
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)
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()
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