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 );
933 #if defined(QGISDEBUG) && QGISDEBUG>=3 937 void QgsCoordinateReferenceSystem::setGeographicFlag(
bool theGeoFlag )
939 mGeoFlag = theGeoFlag;
941 void QgsCoordinateReferenceSystem::setEpsg(
long theEpsg )
943 mAuthId =
QString(
"EPSG:%1" ).
arg( theEpsg );
945 void QgsCoordinateReferenceSystem::setProjectionAcronym(
const QString& theProjectionAcronym )
947 mProjectionAcronym = theProjectionAcronym;
949 void QgsCoordinateReferenceSystem::setEllipsoidAcronym(
const QString& theEllipsoidAcronym )
951 mEllipsoidAcronym = theEllipsoidAcronym;
954 void QgsCoordinateReferenceSystem::setMapUnits()
968 if ( OSRIsProjected( mCRS ) )
970 double toMeter = OSRGetLinearUnits( mCRS, &unitName );
978 static const double feetToMeter = 0.3048;
979 static const double smallNum = 1e-3;
981 if ( qAbs( toMeter - feetToMeter ) < smallNum )
984 QgsDebugMsg(
"Projection has linear units of " + unit );
988 else if ( unit ==
"Foot" )
998 OSRGetAngularUnits( mCRS, &unitName );
1000 if ( unit ==
"degree" )
1004 QgsDebugMsg(
"Unsupported map units of " + unit );
1023 if ( mEllipsoidAcronym.
isNull() || mProjectionAcronym.
isNull()
1026 QgsDebugMsg(
"QgsCoordinateReferenceSystem::findMatchingProj will only " 1027 "work if prj acr ellipsoid acr and proj4string are set" 1028 " and the current projection is valid!" );
1034 sqlite3_stmt *myPreparedStatement;
1039 QString mySql =
QString(
"select srs_id,parameters from tbl_srs where " 1040 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
1041 .
arg( quotedValue( mProjectionAcronym ),
1042 quotedValue( mEllipsoidAcronym ) );
1047 myResult = openDb( myDatabaseFileName, &myDatabase );
1048 if ( myResult != SQLITE_OK )
1053 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1055 if ( myResult == SQLITE_OK )
1058 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1060 QString mySrsId =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1061 QString myProj4String =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 1 ) ) );
1064 QgsDebugMsg(
"-------> MATCH FOUND in srs.db srsid: " + mySrsId );
1066 sqlite3_finalize( myPreparedStatement );
1067 sqlite3_close( myDatabase );
1076 QgsDebugMsg(
"no match found in srs.db, trying user db now!" );
1078 sqlite3_finalize( myPreparedStatement );
1079 sqlite3_close( myDatabase );
1086 myResult = openDb( myDatabaseFileName, &myDatabase );
1087 if ( myResult != SQLITE_OK )
1092 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1094 if ( myResult == SQLITE_OK )
1097 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1099 QString mySrsId =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1100 QString myProj4String =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 1 ) ) );
1103 QgsDebugMsg(
"-------> MATCH FOUND in user qgis.db srsid: " + mySrsId );
1105 sqlite3_finalize( myPreparedStatement );
1106 sqlite3_close( myDatabase );
1118 sqlite3_finalize( myPreparedStatement );
1119 sqlite3_close( myDatabase );
1125 return ( !mIsValidFlag && !theSrs.mIsValidFlag ) ||
1126 ( mIsValidFlag && theSrs.mIsValidFlag && theSrs.
authid() ==
authid() );
1131 return !( *
this == theSrs );
1139 if ( OSRExportToWkt( mCRS, &wkt ) == OGRERR_NONE )
1150 QgsDebugMsg(
"Reading Spatial Ref Sys from xml ------------------------!" );
1154 if ( ! srsNode.
isNull() )
1156 bool initialized =
false;
1189 QgsDebugMsg(
"Ignoring authid/epsg for user crs." );
1207 QgsDebugMsg(
"Setting from elements one by one" );
1213 setInternalId( myNode.toElement().text().toLong() );
1216 setSrid( myNode.toElement().text().toLong() );
1219 setAuthId( myNode.toElement().text() );
1221 myNode = srsNode.
namedItem(
"description" );
1222 setDescription( myNode.toElement().text() );
1224 myNode = srsNode.
namedItem(
"projectionacronym" );
1225 setProjectionAcronym( myNode.toElement().text() );
1227 myNode = srsNode.
namedItem(
"ellipsoidacronym" );
1228 setEllipsoidAcronym( myNode.toElement().text() );
1230 myNode = srsNode.
namedItem(
"geographicflag" );
1231 if ( myNode.toElement().text().compare(
"true" ) )
1233 setGeographicFlag(
true );
1237 setGeographicFlag(
false );
1244 mIsValidFlag =
true;
1253 .
arg(
QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
1297 mySrsElement.
appendChild( myProjectionAcronymElement );
1301 mySrsElement.
appendChild( myEllipsoidAcronymElement );
1304 QString myGeoFlagText =
"false";
1307 myGeoFlagText =
"true";
1311 mySrsElement.
appendChild( myGeographicFlagElement );
1327 QString QgsCoordinateReferenceSystem::proj4FromSrsId(
const int theSrsId )
1332 QString mySql =
QString(
"select parameters from tbl_srs where srs_id = %1 order by deprecated" ).
arg( theSrsId );
1346 myFileInfo.
setFile( myDatabaseFileName );
1347 if ( !myFileInfo.
exists() )
1361 rc = openDb( myDatabaseFileName, &db );
1368 sqlite3_stmt *ppStmt;
1370 rc = sqlite3_prepare( db, mySql.
toUtf8(), mySql.
toUtf8().
length(), &ppStmt, &pzTail );
1373 if ( rc == SQLITE_OK )
1375 if ( sqlite3_step( ppStmt ) == SQLITE_ROW )
1377 myProjString =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( ppStmt, 0 ) ) );
1381 sqlite3_finalize( ppStmt );
1383 sqlite3_close( db );
1386 return myProjString;
1389 int QgsCoordinateReferenceSystem::openDb(
const QString& path,
sqlite3 **db,
bool readonly )
1392 int myResult = readonly
1393 ? sqlite3_open_v2( path.
toUtf8().
data(), db, SQLITE_OPEN_READONLY, nullptr )
1396 if ( myResult != SQLITE_OK )
1405 .arg( sqlite3_errmsg( *db ) ),
QObject::tr(
"CRS" ) );
1412 mCustomSrsValidation = f;
1417 return mCustomSrsValidation;
1420 void QgsCoordinateReferenceSystem::debugPrint()
1444 mValidationHint = html;
1449 return mValidationHint;
1457 if ( ! mIsValidFlag )
1475 if ( getRecordCount() == 0 )
1477 mySql =
"insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 1479 +
',' + quotedValue( name )
1482 +
',' + quotedValue(
toProj4() )
1487 mySql =
"insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 1488 + quotedValue( name )
1491 +
',' + quotedValue(
toProj4() )
1496 sqlite3_stmt *myPreparedStatement;
1500 if ( myResult != SQLITE_OK )
1504 sqlite3_errmsg( myDatabase ) ) );
1508 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1511 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_DONE )
1515 return_id = sqlite3_last_insert_rowid( myDatabase );
1516 setInternalId( return_id );
1527 settings.
setValue(
"/UI/recentProjectionsProj4", projectionsProj4 );
1528 settings.
setValue(
"/UI/recentProjectionsAuthId", projectionsAuthId );
1536 long QgsCoordinateReferenceSystem::getRecordCount()
1540 sqlite3_stmt *myPreparedStatement;
1542 long myRecordCount = 0;
1545 if ( myResult != SQLITE_OK )
1547 QgsDebugMsg(
QString(
"Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
1551 QString mySql =
"select count(*) from tbl_srs";
1552 myResult = sqlite3_prepare( myDatabase, mySql.
toUtf8(), mySql.
toUtf8().
length(), &myPreparedStatement, &myTail );
1554 if ( myResult == SQLITE_OK )
1556 if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
1558 QString myRecordCountString =
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( myPreparedStatement, 0 ) ) );
1559 myRecordCount = myRecordCountString.
toLong();
1563 sqlite3_finalize( myPreparedStatement );
1564 sqlite3_close( myDatabase );
1565 return myRecordCount;
1568 QString QgsCoordinateReferenceSystem::quotedValue(
QString value )
1575 bool QgsCoordinateReferenceSystem::loadWkts(
QHash<int, QString> &wkts,
const char *filename )
1577 qDebug(
"Loading %s", filename );
1578 const char *pszFilename = CPLFindFile(
"gdal", filename );
1582 QFile csv( pszFilename );
1583 if ( !csv.
open( QIODevice::ReadOnly ) )
1600 if ( !loadWkts( wkts, line.
mid( 8 ).
toUtf8() ) )
1605 int pos = line.
indexOf(
',' );
1610 int epsg = line.
left( pos ).
toInt( &ok );
1614 wkts.
insert( epsg, line.
mid( pos + 1 ) );
1627 Q_FOREACH (
const QString& csv,
QStringList() <<
"gcs.csv" <<
"pcs.csv" <<
"vertcs.csv" <<
"compdcs.csv" <<
"geoccs.csv" )
1631 QFile f( filename );
1632 if ( !f.open( QIODevice::ReadOnly ) )
1646 int pos = line.
indexOf(
',' );
1651 int epsg = line.
left( pos ).
toInt( &ok );
1656 if ( epsg == 2218 || epsg == 2221 || epsg == 2296 || epsg == 2297 || epsg == 2298 || epsg == 2299 || epsg == 2300 || epsg == 2301 || epsg == 2302 ||
1657 epsg == 2303 || epsg == 2304 || epsg == 2305 || epsg == 2306 || epsg == 2307 || epsg == 2963 || epsg == 2985 || epsg == 2986 || epsg == 3052 ||
1658 epsg == 3053 || epsg == 3139 || epsg == 3144 || epsg == 3145 || epsg == 3173 || epsg == 3295 || epsg == 3993 || epsg == 4087 || epsg == 4088 ||
1659 epsg == 5017 || epsg == 5221 || epsg == 5224 || epsg == 5225 || epsg == 5514 || epsg == 5515 || epsg == 5516 || epsg == 5819 || epsg == 5820 ||
1660 epsg == 5821 || epsg == 32600 || epsg == 32663 || epsg == 32700 )
1663 if ( OSRImportFromEPSG( crs, epsg ) != OGRERR_NONE )
1665 qDebug(
"EPSG %d: not imported", epsg );
1669 char *wkt =
nullptr;
1670 if ( OSRExportToWkt( crs, &wkt ) != OGRERR_NONE )
1672 qWarning(
"EPSG %d: not exported to WKT", epsg );
1676 wkts.
insert( epsg, wkt );
1684 qDebug(
"Loaded %d/%d from %s", n, l, filename.
toUtf8().
constData() );
1687 OSRDestroySpatialReference( crs );
1695 syncDatumTransform( dbFilePath );
1697 int inserted = 0, updated = 0, deleted = 0, errors = 0;
1702 if ( sqlite3_open( dbFilePath.
toUtf8().
constData(), &database ) != SQLITE_OK )
1708 if ( sqlite3_exec( database,
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
1710 qCritical(
"Could not begin transaction: %s [%s]\n",
QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) );
1715 if ( sqlite3_exec( database,
"alter table tbl_srs add noupdate boolean",
nullptr,
nullptr,
nullptr ) == SQLITE_OK )
1716 ( 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 );
1718 ( void )sqlite3_exec( database,
"UPDATE tbl_srs SET srid=141001 WHERE srid=41001 AND auth_name='OSGEO' AND auth_id='41001'",
nullptr, 0, 0 );
1722 sqlite3_stmt *select;
1723 char *errMsg =
nullptr;
1729 loadWkts( wkts,
"epsg.wkt" );
1731 qDebug(
"%d WKTs loaded", wkts.
count() );
1736 char *psz = ba.
data();
1737 OGRErr ogrErr = OSRImportFromWkt( crs, &psz );
1738 if ( ogrErr != OGRERR_NONE )
1741 if ( OSRExportToProj4( crs, &psz ) != OGRERR_NONE )
1752 sql =
QString(
"SELECT parameters,noupdate FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).
arg( it.key() );
1753 if ( sqlite3_prepare( database, sql.
toAscii(), sql.
size(), &select, &tail ) != SQLITE_OK )
1755 qCritical(
"Could not prepare: %s [%s]\n", sql.
toAscii().
constData(), sqlite3_errmsg( database ) );
1760 if ( sqlite3_step( select ) == SQLITE_ROW )
1762 srsProj4 =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 0 ) );
1764 if (
QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( select, 1 ) ) ).
toInt() != 0 )
1768 sqlite3_finalize( select );
1772 if ( proj4 != srsProj4 )
1775 sql =
QString(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name='EPSG' AND auth_id=%2" ).
arg( quotedValue( proj4 ) ).
arg( it.key() );
1777 if ( sqlite3_exec( database, sql.
toUtf8(),
nullptr,
nullptr, &errMsg ) != SQLITE_OK )
1779 qCritical(
"Could not execute: %s [%s/%s]\n",
1781 sqlite3_errmsg( database ),
1782 errMsg ? errMsg :
"(unknown error)" );
1794 QRegExp projRegExp(
"\\+proj=(\\S+)" );
1795 if ( projRegExp.
indexIn( proj4 ) < 0 )
1797 QgsDebugMsg(
QString(
"EPSG %1: no +proj argument found [%2]" ).arg( it.key() ).arg( proj4 ) );
1801 QRegExp ellipseRegExp(
"\\+ellps=(\\S+)" );
1803 if ( ellipseRegExp.
indexIn( proj4 ) >= 0 )
1805 ellps = ellipseRegExp.
cap( 1 );
1808 QString name( OSRIsGeographic( crs ) ? OSRGetAttrValue( crs,
"GEOCS", 0 ) : OSRGetAttrValue( crs,
"PROJCS", 0 ) );
1812 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)" )
1813 .
arg( quotedValue( name ),
1814 quotedValue( projRegExp.
cap( 1 ) ),
1815 quotedValue( ellps ),
1816 quotedValue( proj4 ) )
1818 .arg( OSRIsGeographic( crs ) );
1821 if ( sqlite3_exec( database, sql.
toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
1827 qCritical(
"Could not execute: %s [%s/%s]\n",
1829 sqlite3_errmsg( database ),
1830 errMsg ? errMsg :
"(unknown error)" );
1834 sqlite3_free( errMsg );
1839 sql =
"DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN (";
1842 for ( ; it != wkts.
constEnd(); ++it )
1847 sql +=
") AND NOT noupdate";
1849 if ( sqlite3_exec( database, sql.
toUtf8(),
nullptr,
nullptr, nullptr ) == SQLITE_OK )
1851 deleted = sqlite3_changes( database );
1856 qCritical(
"Could not execute: %s [%s]\n",
1858 sqlite3_errmsg( database ) );
1861 #if !defined(PJ_VERSION) || PJ_VERSION!=470 1862 sql =
QString(
"select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated AND NOT noupdate" );
1863 if ( sqlite3_prepare( database, sql.toAscii(), sql.size(), &select, &tail ) == SQLITE_OK )
1865 while ( sqlite3_step( select ) == SQLITE_ROW )
1867 const char *auth_name =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 0 ) );
1868 const char *auth_id =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 1 ) );
1869 const char *params =
reinterpret_cast< const char *
>( sqlite3_column_text( select, 2 ) );
1875 input =
QString(
"+init=%1:%2" ).
arg(
QString( auth_name ).toUpper(), auth_id );
1876 pj = pj_init_plus( input.
toAscii() );
1881 char *def = pj_get_def( pj, 0 );
1890 proj4 = proj4.
mid( input.
size() );
1894 if ( proj4 != params )
1896 sql =
QString(
"UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
1897 .
arg( quotedValue( proj4 ),
1898 quotedValue( auth_name ),
1899 quotedValue( auth_id ) );
1901 if ( sqlite3_exec( database, sql.toUtf8(),
nullptr,
nullptr, &errMsg ) == SQLITE_OK )
1908 qCritical(
"Could not execute: %s [%s/%s]\n",
1909 sql.toLocal8Bit().constData(),
1910 sqlite3_errmsg( database ),
1911 errMsg ? errMsg :
"(unknown error)" );
1918 QgsDebugMsg(
QString(
"could not retrieve proj string for %1 from PROJ" ).arg( input ) );
1932 qCritical(
"Could not execute: %s [%s]\n",
1933 sql.toLocal8Bit().constData(),
1934 sqlite3_errmsg( database ) );
1938 OSRDestroySpatialReference( crs );
1940 if ( sqlite3_exec( database,
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
1942 qCritical(
"Could not commit transaction: %s [%s]\n",
QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) );
1946 sqlite3_close( database );
1948 qWarning(
"CRS update (inserted:%d updated:%d deleted:%d errors:%d)", inserted, updated, deleted, errors );
1953 return updated + inserted;
1956 bool QgsCoordinateReferenceSystem::syncDatumTransform(
const QString& dbPath )
1958 const char *filename = CSVFilename(
"datum_shift.csv" );
1959 FILE *fp = VSIFOpen( filename,
"rb" );
1965 char **fieldnames = CSVReadParseLine( fp );
1977 {
"SOURCE_CRS_CODE",
"source_crs_code", -1 },
1978 {
"TARGET_CRS_CODE",
"target_crs_code", -1 },
1979 {
"REMARKS",
"remarks", -1 },
1980 {
"COORD_OP_SCOPE",
"scope", -1 },
1981 {
"AREA_OF_USE_CODE",
"area_of_use_code", -1 },
1987 {
"DEPRECATED",
"deprecated", -1 },
1988 {
"COORD_OP_METHOD_CODE",
"coord_op_method_code", -1 },
1996 {
"PREFERRED",
"preferred", -1 },
1997 {
"COORD_OP_CODE",
"coord_op_code", -1 },
2000 QString update =
"UPDATE tbl_datum_transform SET ";
2003 int n = CSLCount( fieldnames );
2005 int idxid = -1, idxrx = -1, idxry = -1, idxrz = -1, idxmcode = -1;
2006 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
2008 bool last = i ==
sizeof( map ) /
sizeof( *map ) - 1;
2010 map[i].idx = CSLFindString( fieldnames, map[i].src );
2011 if ( map[i].idx < 0 )
2013 qWarning(
"field %s not found", map[i].src );
2014 CSLDestroy( fieldnames );
2019 if ( strcmp( map[i].src,
"COORD_OP_CODE" ) == 0 )
2021 if ( strcmp( map[i].src,
"RX" ) == 0 )
2023 if ( strcmp( map[i].src,
"RY" ) == 0 )
2025 if ( strcmp( map[i].src,
"RZ" ) == 0 )
2027 if ( strcmp( map[i].src,
"COORD_OP_METHOD_CODE" ) == 0 )
2037 update +=
" WHERE ";
2045 update +=
QString(
"%1=%%2" ).
arg( map[i].dst ).
arg( i + 1 );
2047 insert += map[i].dst;
2051 insert =
"INSERT INTO tbl_datum_transform(" + insert +
") VALUES (" + values +
')';
2056 CSLDestroy( fieldnames );
2058 Q_ASSERT( idxid >= 0 );
2059 Q_ASSERT( idxrx >= 0 );
2060 Q_ASSERT( idxry >= 0 );
2061 Q_ASSERT( idxrz >= 0 );
2065 if ( openResult != SQLITE_OK )
2071 if ( sqlite3_exec( db,
"BEGIN TRANSACTION",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2074 sqlite3_close( db );
2080 v.
reserve(
sizeof( map ) /
sizeof( *map ) );
2082 while ( !feof( fp ) )
2084 char **values = CSVReadParseLine( fp );
2088 if ( CSLCount( values ) < n )
2090 qWarning(
"Only %d columns", CSLCount( values ) );
2094 for (
unsigned int i = 0; i <
sizeof( map ) /
sizeof( *map ); i++ )
2096 int idx = map[i].idx;
2097 Q_ASSERT( idx != -1 );
2098 Q_ASSERT( idx < n );
2099 v.
insert( i, *values[ idx ] ? quotedValue( values[idx] ) :
"NULL" );
2105 v[ idxmcode ] =
"'9606'";
2106 v[ idxrx ] =
'\'' +
qgsDoubleToString( -( v[ idxrx ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2107 v[ idxry ] =
'\'' +
qgsDoubleToString( -( v[ idxry ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2108 v[ idxrz ] =
'\'' +
qgsDoubleToString( -( v[ idxrz ].
remove(
'\'' ).toDouble() ) ) +
'\'';
2114 QString sql =
QString(
"SELECT coord_op_code FROM tbl_datum_transform WHERE coord_op_code=%1" ).
arg( v[ idxid ] );
2115 int prepareRes = sqlite3_prepare( db, sql.
toAscii(), sql.
size(), &stmt, nullptr );
2116 if ( prepareRes != SQLITE_OK )
2119 if ( sqlite3_step( stmt ) == SQLITE_ROW )
2121 cOpCode =
reinterpret_cast< const char *
>( sqlite3_column_text( stmt, 0 ) );
2123 sqlite3_finalize( stmt );
2125 sql = cOpCode.
isEmpty() ? insert : update;
2126 for (
int i = 0; i < v.
size(); i++ )
2128 sql = sql.
arg( v[i] );
2131 if ( sqlite3_exec( db, sql.
toUtf8(),
nullptr,
nullptr, nullptr ) != SQLITE_OK )
2134 qCritical(
"Error: %s", sqlite3_errmsg( db ) );
2138 if ( sqlite3_exec( db,
"COMMIT",
nullptr,
nullptr,
nullptr ) != SQLITE_OK )
2144 sqlite3_close( db );
2156 return OSRGetAuthorityName( mCRS,
"GEOGCS" ) +
QLatin1String(
":" ) + OSRGetAuthorityCode( mCRS,
"GEOGCS" );
2176 if ( projectionsAuthId.
size() >= projections.
size() )
2180 projections.
clear();
2181 for (
int i = 0; i < projectionsAuthId.
size(); i++ )
2195 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)
long srsid() const
Returns the SrsId, if available.
void validate()
Perform some validation on this CRS.
QString geographicCRSAuthId() const
Returns auth id of related geographic 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 toWkt() const
Returns a WKT representation of this CRS.
long postgisSrid() const
Returns PostGIS SRID for the CRS.
bool createFromId(const long theId, CrsType theType=PostgisCrsId)
The QGis class provides global constants for use throughout the application.
bool axisInverted() const
Returns whether axis is inverted (eg.
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.
void append(const T &value)
QString fromUtf8(const char *str, int size)
const_iterator constEnd() const
#define QgsDebugMsgLevel(str, level)
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.
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...
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)
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.
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
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
long toLong(bool *ok, int base) const
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
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 (~/...
bool writeXML(QDomNode &theNode, QDomDocument &theDoc) const
Stores state to the given Dom node in the given document.
QByteArray toLatin1() const
QString mid(int position, int n) const
QStringList toStringList() const
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
void insert(int i, const T &value)
Class for storing a coordinate reference system (CRS)
const int LAT_PREFIX_LEN
The length of the string "+lat_1=".
QString authid() const
Returns the authority identifier for the CRS, which includes both the authority (eg EPSG) and the CRS...
UnitType
Map units that qgis supports.
QString left(int n) const
static QString srsDbFilePath()
Returns the path to the srs.db file.
QString description() const
Returns the descriptive name of the CRS, eg "WGS 84" or "GDA 94 / Vicgrid94".
bool operator!=(const QgsCoordinateReferenceSystem &theSrs) const
Overloaded != operator used to compare to CRS's.
void(* CUSTOM_CRS_VALIDATION)(QgsCoordinateReferenceSystem &)
QDomElement createElement(const QString &tagName)
bool operator==(const QgsCoordinateReferenceSystem &theSrs) const
Overloaded == operator used to compare to CRS's.
bool geographicFlag() const
Returns whether the CRS is a geographic CRS.
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()
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
QString toProj4() const
Returns a Proj4 string representation of this CRS.
QByteArray toUtf8() const
QGis::UnitType mapUnits() const
Returns the units for the projection used by the CRS.