|
QGIS API Documentation
master-59fd5e0
|
00001 /*************************************************************************** 00002 qgscoordinatereferencesystem.cpp 00003 00004 ------------------- 00005 begin : 2007 00006 copyright : (C) 2007 by Gary E. Sherman 00007 email : sherman@mrcc.com 00008 ***************************************************************************/ 00009 00010 /*************************************************************************** 00011 * * 00012 * This program is free software; you can redistribute it and/or modify * 00013 * it under the terms of the GNU General Public License as published by * 00014 * the Free Software Foundation; either version 2 of the License, or * 00015 * (at your option) any later version. * 00016 * * 00017 ***************************************************************************/ 00018 #include "qgscoordinatereferencesystem.h" 00019 00020 #include <cmath> 00021 00022 #include <QDir> 00023 #include <QTemporaryFile> 00024 #include <QDomNode> 00025 #include <QDomElement> 00026 #include <QFileInfo> 00027 #include <QRegExp> 00028 #include <QTextStream> 00029 #include <QFile> 00030 #include <QSettings> 00031 00032 #include "qgsapplication.h" 00033 #include "qgscrscache.h" 00034 #include "qgslogger.h" 00035 #include "qgsmessagelog.h" 00036 #include "qgis.h" //const vals declared here 00037 00038 #include <sqlite3.h> 00039 #include <proj_api.h> 00040 00041 //gdal and ogr includes (needed for == operator) 00042 #include <ogr_srs_api.h> 00043 #include <cpl_error.h> 00044 #include <cpl_conv.h> 00045 00046 CUSTOM_CRS_VALIDATION QgsCoordinateReferenceSystem::mCustomSrsValidation = NULL; 00047 00048 //-------------------------- 00049 00050 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem() 00051 : mSrsId( 0 ) 00052 , mGeoFlag( false ) 00053 , mMapUnits( QGis::UnknownUnit ) 00054 , mSRID( 0 ) 00055 , mIsValidFlag( 0 ) 00056 , mValidationHint( "" ) 00057 , mAxisInverted( false ) 00058 { 00059 mCRS = OSRNewSpatialReference( NULL ); 00060 } 00061 00062 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( QString theDefinition ) 00063 : mSrsId( 0 ) 00064 , mGeoFlag( false ) 00065 , mMapUnits( QGis::UnknownUnit ) 00066 , mSRID( 0 ) 00067 , mIsValidFlag( 0 ) 00068 , mValidationHint( "" ) 00069 , mAxisInverted( false ) 00070 { 00071 mCRS = OSRNewSpatialReference( NULL ); 00072 createFromString( theDefinition ); 00073 } 00074 00075 00076 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( const long theId, CrsType theType ) 00077 : mSrsId( 0 ) 00078 , mGeoFlag( false ) 00079 , mMapUnits( QGis::UnknownUnit ) 00080 , mSRID( 0 ) 00081 , mIsValidFlag( 0 ) 00082 , mValidationHint( "" ) 00083 , mAxisInverted( false ) 00084 { 00085 mCRS = OSRNewSpatialReference( NULL ); 00086 createFromId( theId, theType ); 00087 } 00088 00089 QgsCoordinateReferenceSystem::~QgsCoordinateReferenceSystem() 00090 { 00091 OSRDestroySpatialReference( mCRS ); 00092 } 00093 00094 bool QgsCoordinateReferenceSystem::createFromId( const long theId, CrsType theType ) 00095 { 00096 bool result = false; 00097 switch ( theType ) 00098 { 00099 case InternalCrsId: 00100 result = createFromSrsId( theId ); 00101 break; 00102 case PostgisCrsId: 00103 result = createFromSrid( theId ); 00104 break; 00105 case EpsgCrsId: 00106 result = createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( theId ) ); 00107 break; 00108 default: 00109 //THIS IS BAD...THIS PART OF CODE SHOULD NEVER BE REACHED... 00110 QgsDebugMsg( "Unexpected case reached!" ); 00111 }; 00112 return result; 00113 } 00114 00115 bool QgsCoordinateReferenceSystem::createFromString( const QString theDefinition ) 00116 { 00117 bool result = false; 00118 QRegExp reCrsId( "^(epsg|postgis|internal)\\:(\\d+)$", Qt::CaseInsensitive ); 00119 if ( reCrsId.indexIn( theDefinition ) == 0 ) 00120 { 00121 QString authName = reCrsId.cap( 1 ).toLower(); 00122 CrsType type = InternalCrsId; 00123 if ( authName == "epsg" ) 00124 type = EpsgCrsId; 00125 if ( authName == "postgis" ) 00126 type = PostgisCrsId; 00127 long id = reCrsId.cap( 2 ).toLong(); 00128 result = createFromId( id, type ); 00129 } 00130 else 00131 { 00132 QRegExp reCrsStr( "^(?:(wkt|proj4)\\:)?(.+)$", Qt::CaseInsensitive ); 00133 if ( reCrsStr.indexIn( theDefinition ) == 0 ) 00134 { 00135 if ( reCrsStr.cap( 1 ).toLower() == "proj4" ) 00136 { 00137 result = createFromProj4( reCrsStr.cap( 2 ) ); 00138 //TODO: createFromProj4 used to save to the user database any new CRS 00139 // this behavior was changed in order to separate creation and saving. 00140 // Not sure if it necessary to save it here, should be checked by someone 00141 // familiar with the code (should also give a more descriptive name to the generated CRS) 00142 if ( srsid() == 0 ) 00143 { 00144 QString myName = QString( " * %1 (%2)" ) 00145 .arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ) ) 00146 .arg( toProj4() ); 00147 saveAsUserCRS( myName ); 00148 } 00149 } 00150 else 00151 { 00152 result = createFromWkt( reCrsStr.cap( 2 ) ); 00153 } 00154 } 00155 } 00156 return result; 00157 } 00158 00159 bool QgsCoordinateReferenceSystem::createFromUserInput( const QString theDefinition ) 00160 { 00161 QString theWkt; 00162 char *wkt = NULL; 00163 OGRSpatialReferenceH crs = OSRNewSpatialReference( NULL ); 00164 00165 // make sure towgs84 parameter is loaded if using an ESRI definition and gdal >= 1.9 00166 #if GDAL_VERSION_NUM >= 1900 00167 if ( theDefinition.startsWith( "ESRI::" ) ) 00168 { 00169 setupESRIWktFix(); 00170 } 00171 #endif 00172 00173 if ( OSRSetFromUserInput( crs, theDefinition.toLocal8Bit().constData() ) == OGRERR_NONE ) 00174 { 00175 if ( OSRExportToWkt( crs, &wkt ) == OGRERR_NONE ) 00176 { 00177 theWkt = wkt; 00178 OGRFree( wkt ); 00179 } 00180 OSRDestroySpatialReference( crs ); 00181 } 00182 //QgsDebugMsg( "theDefinition: " + theDefinition + " theWkt = " + theWkt ); 00183 return createFromWkt( theWkt ); 00184 } 00185 00186 void QgsCoordinateReferenceSystem::setupESRIWktFix( ) 00187 { 00188 // make sure towgs84 parameter is loaded if gdal >= 1.9 00189 // this requires setting GDAL_FIX_ESRI_WKT=GEOGCS (see qgis bug #5598 and gdal bug #4673) 00190 #if GDAL_VERSION_NUM >= 1900 00191 const char* configOld = CPLGetConfigOption( "GDAL_FIX_ESRI_WKT", "" ); 00192 const char* configNew = "GEOGCS"; 00193 // only set if it was not set, to let user change the value if needed 00194 if ( strcmp( configOld, "" ) == 0 ) 00195 { 00196 CPLSetConfigOption( "GDAL_FIX_ESRI_WKT", configNew ); 00197 if ( strcmp( configNew, CPLGetConfigOption( "GDAL_FIX_ESRI_WKT", "" ) ) != 0 ) 00198 QgsLogger::warning( QString( "GDAL_FIX_ESRI_WKT could not be set to %1 : %2" 00199 ).arg( configNew ).arg( CPLGetConfigOption( "GDAL_FIX_ESRI_WKT", "" ) ) ) ; 00200 QgsDebugMsg( QString( "set GDAL_FIX_ESRI_WKT : %1" ).arg( configNew ) ); 00201 } 00202 else 00203 { 00204 QgsDebugMsg( QString( "GDAL_FIX_ESRI_WKT was already set : %1" ).arg( configNew ) ); 00205 } 00206 #endif 00207 } 00208 00209 bool QgsCoordinateReferenceSystem::createFromOgcWmsCrs( QString theCrs ) 00210 { 00211 QRegExp re( "urn:ogc:def:crs:([^:]+).+([^:]+)", Qt::CaseInsensitive ); 00212 if ( re.exactMatch( theCrs ) ) 00213 { 00214 theCrs = re.cap( 1 ) + ":" + re.cap( 2 ); 00215 } 00216 else 00217 { 00218 re.setPattern( "(user|custom|qgis):(\\d+)" ); 00219 if ( re.exactMatch( theCrs ) && createFromSrsId( re.cap( 2 ).toInt() ) ) 00220 { 00221 return true; 00222 } 00223 } 00224 00225 if ( loadFromDb( QgsApplication::srsDbFilePath(), "lower(auth_name||':'||auth_id)", theCrs.toLower() ) ) 00226 return true; 00227 00228 // NAD27 00229 if ( theCrs.compare( "CRS:27", Qt::CaseInsensitive ) == 0 || 00230 theCrs.compare( "OGC:CRS27", Qt::CaseInsensitive ) == 0 ) 00231 { 00232 // TODO: verify same axis orientation 00233 return createFromOgcWmsCrs( "EPSG:4267" ); 00234 } 00235 00236 // NAD83 00237 if ( theCrs.compare( "CRS:83", Qt::CaseInsensitive ) == 0 || 00238 theCrs.compare( "OGC:CRS83", Qt::CaseInsensitive ) == 0 ) 00239 { 00240 // TODO: verify same axis orientation 00241 return createFromOgcWmsCrs( "EPSG:4269" ); 00242 } 00243 00244 // WGS84 00245 if ( theCrs.compare( "CRS:84", Qt::CaseInsensitive ) == 0 || 00246 theCrs.compare( "OGC:CRS84", Qt::CaseInsensitive ) == 0 ) 00247 { 00248 createFromOgcWmsCrs( "EPSG:4326" ); 00249 mAxisInverted = 0; 00250 return mIsValidFlag; 00251 } 00252 00253 return false; 00254 } 00255 00256 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &srs ) 00257 { 00258 mCRS = OSRNewSpatialReference( NULL ); 00259 *this = srs; 00260 } 00261 00262 // Assignment operator 00263 QgsCoordinateReferenceSystem& QgsCoordinateReferenceSystem::operator=( const QgsCoordinateReferenceSystem & srs ) 00264 { 00265 if ( &srs != this ) 00266 { 00267 mSrsId = srs.mSrsId; 00268 mDescription = srs.mDescription; 00269 mProjectionAcronym = srs.mProjectionAcronym; 00270 mEllipsoidAcronym = srs.mEllipsoidAcronym; 00271 mGeoFlag = srs.mGeoFlag; 00272 mAxisInverted = srs.mAxisInverted; 00273 mMapUnits = srs.mMapUnits; 00274 mSRID = srs.mSRID; 00275 mAuthId = srs.mAuthId; 00276 mIsValidFlag = srs.mIsValidFlag; 00277 mValidationHint = srs.mValidationHint; 00278 mWkt = srs.mWkt; 00279 if ( mIsValidFlag ) 00280 { 00281 OSRDestroySpatialReference( mCRS ); 00282 mCRS = OSRClone( srs.mCRS ); 00283 } 00284 } 00285 return *this; 00286 } 00287 00288 // Misc helper functions ----------------------- 00289 00290 00291 void QgsCoordinateReferenceSystem::validate() 00292 { 00293 if ( mIsValidFlag ) 00294 return; 00295 00296 // try to validate using custom validation routines 00297 if ( mCustomSrsValidation ) 00298 mCustomSrsValidation( *this ); 00299 00300 if ( !mIsValidFlag ) 00301 { 00302 *this = QgsCRSCache::instance()->crsByAuthId( GEO_EPSG_CRS_AUTHID ); 00303 } 00304 } 00305 00306 bool QgsCoordinateReferenceSystem::createFromSrid( long id ) 00307 { 00308 return loadFromDb( QgsApplication::srsDbFilePath(), "srid", QString::number( id ) ); 00309 } 00310 00311 bool QgsCoordinateReferenceSystem::createFromSrsId( long id ) 00312 { 00313 return loadFromDb( id < USER_CRS_START_ID ? QgsApplication::srsDbFilePath() : 00314 QgsApplication::qgisUserDbFilePath(), 00315 "srs_id", QString::number( id ) ); 00316 } 00317 00318 bool QgsCoordinateReferenceSystem::loadFromDb( QString db, QString expression, QString value ) 00319 { 00320 QgsDebugMsgLevel( "load CRS from " + db + " where " + expression + " is " + value, 3 ); 00321 mIsValidFlag = false; 00322 mWkt.clear(); 00323 00324 QFileInfo myInfo( db ); 00325 if ( !myInfo.exists() ) 00326 { 00327 QgsDebugMsg( "failed : " + db + " does not exist!" ); 00328 return mIsValidFlag; 00329 } 00330 00331 sqlite3 *myDatabase; 00332 const char *myTail; 00333 sqlite3_stmt *myPreparedStatement; 00334 int myResult; 00335 //check the db is available 00336 myResult = openDb( db, &myDatabase ); 00337 if ( myResult != SQLITE_OK ) 00338 { 00339 QgsDebugMsg( "failed : " + db + " could not be opened!" ); 00340 return mIsValidFlag; 00341 } 00342 00343 /* 00344 srs_id INTEGER PRIMARY KEY, 00345 description text NOT NULL, 00346 projection_acronym text NOT NULL, 00347 ellipsoid_acronym NOT NULL, 00348 parameters text NOT NULL, 00349 srid integer NOT NULL, 00350 auth_name varchar NOT NULL, 00351 auth_id integer NOT NULL, 00352 is_geo integer NOT NULL); 00353 */ 00354 00355 QString mySql = "select srs_id,description,projection_acronym," 00356 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo " 00357 "from tbl_srs where " + expression + "=" + quotedValue( value ) + " order by deprecated"; 00358 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), 00359 mySql.toUtf8().length(), 00360 &myPreparedStatement, &myTail ); 00361 // XXX Need to free memory from the error msg if one is set 00362 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW ) 00363 { 00364 mSrsId = QString::fromUtf8(( char * )sqlite3_column_text( 00365 myPreparedStatement, 0 ) ).toLong(); 00366 mDescription = QString::fromUtf8(( char * )sqlite3_column_text( 00367 myPreparedStatement, 1 ) ); 00368 mProjectionAcronym = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 2 ) ); 00369 mEllipsoidAcronym = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 3 ) ); 00370 QString toProj4 = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 4 ) ); 00371 mSRID = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 5 ) ).toLong(); 00372 mAuthId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 6 ) ); 00373 mGeoFlag = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 7 ) ).toInt() != 0; 00374 mAxisInverted = -1; 00375 00376 if ( mSrsId >= USER_CRS_START_ID && mAuthId.isEmpty() ) 00377 { 00378 mAuthId = QString( "USER:%1" ).arg( mSrsId ); 00379 } 00380 else if ( mAuthId.startsWith( "EPSG:", Qt::CaseInsensitive ) ) 00381 { 00382 OSRDestroySpatialReference( mCRS ); 00383 mCRS = OSRNewSpatialReference( NULL ); 00384 mIsValidFlag = OSRSetFromUserInput( mCRS, mAuthId.toLower().toAscii() ) == OGRERR_NONE; 00385 setMapUnits(); 00386 } 00387 00388 if ( !mIsValidFlag ) 00389 { 00390 setProj4String( toProj4 ); 00391 } 00392 } 00393 else 00394 { 00395 QgsDebugMsg( "failed : " + mySql ); 00396 } 00397 sqlite3_finalize( myPreparedStatement ); 00398 sqlite3_close( myDatabase ); 00399 return mIsValidFlag; 00400 } 00401 00402 bool QgsCoordinateReferenceSystem::axisInverted() const 00403 { 00404 if ( mAxisInverted == -1 ) 00405 { 00406 OGRAxisOrientation orientation; 00407 const char *axis0 = OSRGetAxis( mCRS, mGeoFlag ? "GEOGCS" : "PROJCS", 0, &orientation ); 00408 mAxisInverted = mGeoFlag 00409 ? ( orientation == OAO_East || orientation == OAO_West || orientation == OAO_Other ) 00410 : ( orientation == OAO_North || orientation == OAO_South ); 00411 QgsDebugMsg( QString( "srid:%1 axis0:%2 orientation:%3 inverted:%4" ).arg( mSRID ).arg( axis0 ).arg( OSRAxisEnumToName( orientation ) ).arg( mAxisInverted ) ); 00412 Q_UNUSED( axis0 ); 00413 } 00414 00415 return mAxisInverted != 0; 00416 } 00417 00418 bool QgsCoordinateReferenceSystem::createFromWkt( QString theWkt ) 00419 { 00420 mIsValidFlag = false; 00421 mWkt.clear(); 00422 00423 if ( theWkt.isEmpty() ) 00424 { 00425 QgsDebugMsg( "theWkt is uninitialised, operation failed" ); 00426 return mIsValidFlag; 00427 } 00428 QgsDebugMsg( "wkt: " + theWkt ); 00429 QByteArray ba = theWkt.toLatin1(); 00430 const char *pWkt = ba.data(); 00431 00432 OGRErr myInputResult = OSRImportFromWkt( mCRS, ( char ** ) & pWkt ); 00433 00434 if ( myInputResult != OGRERR_NONE ) 00435 { 00436 QgsDebugMsg( "\n---------------------------------------------------------------" ); 00437 QgsDebugMsg( "This CRS could *** NOT *** be set from the supplied Wkt " ); 00438 QgsDebugMsg( "INPUT: " + theWkt ); 00439 QgsDebugMsg( QString( "UNUSED WKT: %1" ).arg( pWkt ) ); 00440 QgsDebugMsg( "---------------------------------------------------------------\n" ); 00441 return mIsValidFlag; 00442 } 00443 00444 if ( OSRAutoIdentifyEPSG( mCRS ) == OGRERR_NONE ) 00445 { 00446 QString authid = QString( "%1:%2" ) 00447 .arg( OSRGetAuthorityName( mCRS, NULL ) ) 00448 .arg( OSRGetAuthorityCode( mCRS, NULL ) ); 00449 QgsDebugMsg( "authid recognized as " + authid ); 00450 return createFromOgcWmsCrs( authid ); 00451 } 00452 00453 // always morph from esri as it doesn't hurt anything 00454 // FW: Hey, that's not right! It can screw stuff up! Disable 00455 //myOgrSpatialRef.morphFromESRI(); 00456 00457 // create the proj4 structs needed for transforming 00458 char *proj4src = NULL; 00459 OSRExportToProj4( mCRS, &proj4src ); 00460 00461 //now that we have the proj4string, delegate to createFromProj4 so 00462 // that we can try to fill in the remaining class members... 00463 //create from Proj will set the isValidFlag 00464 if ( !createFromProj4( proj4src ) ) 00465 { 00466 CPLFree( proj4src ); 00467 00468 // try fixed up version 00469 OSRFixup( mCRS ); 00470 00471 OSRExportToProj4( mCRS, &proj4src ); 00472 00473 createFromProj4( proj4src ); 00474 } 00475 //TODO: createFromProj4 used to save to the user database any new CRS 00476 // this behavior was changed in order to separate creation and saving. 00477 // Not sure if it necessary to save it here, should be checked by someone 00478 // familiar with the code (should also give a more descriptive name to the generated CRS) 00479 if ( mSrsId == 0 ) 00480 { 00481 QString myName = QString( " * %1 (%2)" ) 00482 .arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ) ) 00483 .arg( toProj4() ); 00484 saveAsUserCRS( myName ); 00485 } 00486 00487 CPLFree( proj4src ); 00488 00489 return mIsValidFlag; 00490 //setMapunits will be called by createfromproj above 00491 } 00492 00493 bool QgsCoordinateReferenceSystem::isValid() const 00494 { 00495 return mIsValidFlag; 00496 } 00497 00498 bool QgsCoordinateReferenceSystem::createFromProj4( const QString theProj4String ) 00499 { 00500 // 00501 // Examples: 00502 // +proj=tmerc +lat_0=0 +lon_0=-62 +k=0.999500 +x_0=400000 +y_0=0 00503 // +ellps=clrk80 +towgs84=-255,-15,71,0,0,0,0 +units=m +no_defs 00504 // 00505 // +proj=lcc +lat_1=46.8 +lat_0=46.8 +lon_0=2.337229166666664 +k_0=0.99987742 00506 // +x_0=600000 +y_0=2200000 +a=6378249.2 +b=6356515.000000472 +units=m +no_defs 00507 // 00508 QString myProj4String = theProj4String.trimmed(); 00509 QgsDebugMsg( "proj4: " + myProj4String ); 00510 mIsValidFlag = false; 00511 mWkt.clear(); 00512 00513 QRegExp myProjRegExp( "\\+proj=(\\S+)" ); 00514 int myStart = myProjRegExp.indexIn( myProj4String ); 00515 if ( myStart == -1 ) 00516 { 00517 QgsDebugMsg( "proj string supplied has no +proj argument" ); 00518 return mIsValidFlag; 00519 } 00520 00521 mProjectionAcronym = myProjRegExp.cap( 1 ); 00522 00523 QRegExp myEllipseRegExp( "\\+ellps=(\\S+)" ); 00524 myStart = myEllipseRegExp.indexIn( myProj4String ); 00525 if ( myStart == -1 ) 00526 { 00527 QgsDebugMsg( "proj string supplied has no +ellps argument" ); 00528 mEllipsoidAcronym = ""; 00529 } 00530 else 00531 { 00532 mEllipsoidAcronym = myEllipseRegExp.cap( 1 ); 00533 } 00534 00535 QRegExp myAxisRegExp( "\\+a=(\\S+)" ); 00536 myStart = myAxisRegExp.indexIn( myProj4String ); 00537 if ( myStart == -1 ) 00538 { 00539 QgsDebugMsg( "proj string supplied has no +a argument" ); 00540 } 00541 00542 /* 00543 * We try to match the proj string to and srsid using the following logic: 00544 * 00545 * - perform a whole text search on srs name (if not null). The srs name will 00546 * have been set if this method has been delegated to from createFromWkt. 00547 * Normally we wouldnt expect this to work, but its worth trying first 00548 * as its quicker than methods below.. 00549 */ 00550 long mySrsId = 0; 00551 QgsCoordinateReferenceSystem::RecordMap myRecord; 00552 00553 /* 00554 * - if the above does not match perform a whole text search on proj4 string (if not null) 00555 */ 00556 // QgsDebugMsg( "wholetext match on name failed, trying proj4string match" ); 00557 myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( myProj4String ) + " order by deprecated" ); 00558 if ( myRecord.empty() ) 00559 { 00560 // Ticket #722 - aaronr 00561 // Check if we can swap the lat_1 and lat_2 params (if they exist) to see if we match... 00562 // First we check for lat_1 and lat_2 00563 QRegExp myLat1RegExp( "\\+lat_1=\\S+" ); 00564 QRegExp myLat2RegExp( "\\+lat_2=\\S+" ); 00565 int myStart1 = 0; 00566 int myLength1 = 0; 00567 int myStart2 = 0; 00568 int myLength2 = 0; 00569 QString lat1Str = ""; 00570 QString lat2Str = ""; 00571 myStart1 = myLat1RegExp.indexIn( myProj4String, myStart1 ); 00572 myStart2 = myLat2RegExp.indexIn( myProj4String, myStart2 ); 00573 if ( myStart1 != -1 && myStart2 != -1 ) 00574 { 00575 myLength1 = myLat1RegExp.matchedLength(); 00576 myLength2 = myLat2RegExp.matchedLength(); 00577 lat1Str = myProj4String.mid( myStart1 + LAT_PREFIX_LEN, myLength1 - LAT_PREFIX_LEN ); 00578 lat2Str = myProj4String.mid( myStart2 + LAT_PREFIX_LEN, myLength2 - LAT_PREFIX_LEN ); 00579 } 00580 // If we found the lat_1 and lat_2 we need to swap and check to see if we can find it... 00581 if ( lat1Str != "" && lat2Str != "" ) 00582 { 00583 // Make our new string to check... 00584 QString theProj4StringModified = myProj4String; 00585 // First just swap in the lat_2 value for lat_1 value 00586 theProj4StringModified.replace( myStart1 + LAT_PREFIX_LEN, myLength1 - LAT_PREFIX_LEN, lat2Str ); 00587 // Now we have to find the lat_2 location again since it has potentially moved... 00588 myStart2 = 0; 00589 myStart2 = myLat2RegExp.indexIn( theProj4String, myStart2 ); 00590 theProj4StringModified.replace( myStart2 + LAT_PREFIX_LEN, myLength2 - LAT_PREFIX_LEN, lat1Str ); 00591 QgsDebugMsg( "trying proj4string match with swapped lat_1,lat_2" ); 00592 myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( theProj4StringModified.trimmed() ) + " order by deprecated" ); 00593 } 00594 } 00595 00596 if ( myRecord.empty() ) 00597 { 00598 // match all parameters individually: 00599 // - order of parameters doesn't matter 00600 // - found definition may have more parameters (like +towgs84 in GDAL) 00601 // - retry without datum, if no match is found (looks like +datum<>WGS84 was dropped in GDAL) 00602 00603 QString sql = "SELECT * FROM tbl_srs WHERE "; 00604 QString delim = ""; 00605 QString datum; 00606 00607 // split on spaces followed by a plus sign (+) to deal 00608 // also with parameters containing spaces (e.g. +nadgrids) 00609 // make sure result is trimmed (#5598) 00610 foreach ( QString param, myProj4String.split( QRegExp( "\\s+(?=\\+)" ), QString::SkipEmptyParts ) ) 00611 { 00612 QString arg = QString( "' '||parameters||' ' LIKE %1" ).arg( quotedValue( QString( "% %1 %" ).arg( param.trimmed() ) ) ); 00613 if ( param.startsWith( "+datum=" ) ) 00614 { 00615 datum = arg; 00616 } 00617 else 00618 { 00619 sql += delim + arg; 00620 delim = " AND "; 00621 } 00622 } 00623 00624 if ( !datum.isEmpty() ) 00625 { 00626 myRecord = getRecord( sql + delim + datum + " order by deprecated" ); 00627 } 00628 00629 if ( myRecord.empty() ) 00630 { 00631 // datum might have disappeared in definition - retry without it 00632 myRecord = getRecord( sql + " order by deprecated" ); 00633 } 00634 } 00635 00636 if ( !myRecord.empty() ) 00637 { 00638 mySrsId = myRecord["srs_id"].toLong(); 00639 QgsDebugMsg( "proj4string param match search for srsid returned srsid: " + QString::number( mySrsId ) ); 00640 if ( mySrsId > 0 ) 00641 { 00642 createFromSrsId( mySrsId ); 00643 } 00644 } 00645 else 00646 { 00647 // Last ditch attempt to piece together what we know of the projection to find a match... 00648 QgsDebugMsg( "globbing search for srsid from this proj string" ); 00649 setProj4String( myProj4String ); 00650 mySrsId = findMatchingProj(); 00651 QgsDebugMsg( "globbing search for srsid returned srsid: " + QString::number( mySrsId ) ); 00652 if ( mySrsId > 0 ) 00653 { 00654 createFromSrsId( mySrsId ); 00655 } 00656 else 00657 { 00658 mIsValidFlag = false; 00659 } 00660 } 00661 00662 // if we failed to look up the projection in database, don't worry. we can still use it :) 00663 if ( !mIsValidFlag ) 00664 { 00665 QgsDebugMsg( "Projection is not found in databases." ); 00666 //setProj4String will set mIsValidFlag to true if there is no issue 00667 setProj4String( myProj4String ); 00668 } 00669 00670 return mIsValidFlag; 00671 } 00672 00673 //private method meant for internal use by this class only 00674 QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord( QString theSql ) 00675 { 00676 QString myDatabaseFileName; 00677 QgsCoordinateReferenceSystem::RecordMap myMap; 00678 QString myFieldName; 00679 QString myFieldValue; 00680 sqlite3 *myDatabase; 00681 const char *myTail; 00682 sqlite3_stmt *myPreparedStatement; 00683 int myResult; 00684 00685 QgsDebugMsg( "running query: " + theSql ); 00686 // Get the full path name to the sqlite3 spatial reference database. 00687 myDatabaseFileName = QgsApplication::srsDbFilePath(); 00688 QFileInfo myInfo( myDatabaseFileName ); 00689 if ( !myInfo.exists() ) 00690 { 00691 QgsDebugMsg( "failed : " + myDatabaseFileName + " does not exist!" ); 00692 return myMap; 00693 } 00694 00695 //check the db is available 00696 myResult = openDb( myDatabaseFileName, &myDatabase ); 00697 if ( myResult != SQLITE_OK ) 00698 { 00699 return myMap; 00700 } 00701 00702 myResult = sqlite3_prepare( myDatabase, theSql.toUtf8(), theSql.toUtf8().length(), &myPreparedStatement, &myTail ); 00703 // XXX Need to free memory from the error msg if one is set 00704 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW ) 00705 { 00706 QgsDebugMsg( "trying system srs.db" ); 00707 int myColumnCount = sqlite3_column_count( myPreparedStatement ); 00708 //loop through each column in the record adding its expression name and value to the map 00709 for ( int myColNo = 0; myColNo < myColumnCount; myColNo++ ) 00710 { 00711 myFieldName = QString::fromUtf8(( char * )sqlite3_column_name( myPreparedStatement, myColNo ) ); 00712 myFieldValue = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, myColNo ) ); 00713 myMap[myFieldName] = myFieldValue; 00714 } 00715 if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE ) 00716 { 00717 QgsDebugMsg( "Multiple records found in srs.db" ); 00718 myMap.clear(); 00719 } 00720 } 00721 else 00722 { 00723 QgsDebugMsg( "failed : " + theSql ); 00724 } 00725 00726 if ( myMap.empty() ) 00727 { 00728 QgsDebugMsg( "trying user qgis.db" ); 00729 sqlite3_finalize( myPreparedStatement ); 00730 sqlite3_close( myDatabase ); 00731 00732 myDatabaseFileName = QgsApplication::qgisUserDbFilePath(); 00733 QFileInfo myFileInfo; 00734 myFileInfo.setFile( myDatabaseFileName ); 00735 if ( !myFileInfo.exists( ) ) 00736 { 00737 QgsDebugMsg( "user qgis.db not found" ); 00738 return myMap; 00739 } 00740 00741 //check the db is available 00742 myResult = openDb( myDatabaseFileName, &myDatabase ); 00743 if ( myResult != SQLITE_OK ) 00744 { 00745 return myMap; 00746 } 00747 00748 myResult = sqlite3_prepare( myDatabase, theSql.toUtf8(), theSql.toUtf8().length(), &myPreparedStatement, &myTail ); 00749 // XXX Need to free memory from the error msg if one is set 00750 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW ) 00751 { 00752 int myColumnCount = sqlite3_column_count( myPreparedStatement ); 00753 //loop through each column in the record adding its field name and value to the map 00754 for ( int myColNo = 0; myColNo < myColumnCount; myColNo++ ) 00755 { 00756 myFieldName = QString::fromUtf8(( char * )sqlite3_column_name( myPreparedStatement, myColNo ) ); 00757 myFieldValue = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, myColNo ) ); 00758 myMap[myFieldName] = myFieldValue; 00759 } 00760 00761 if ( sqlite3_step( myPreparedStatement ) != SQLITE_DONE ) 00762 { 00763 QgsDebugMsg( "Multiple records found in srs.db" ); 00764 myMap.clear(); 00765 } 00766 } 00767 else 00768 { 00769 QgsDebugMsg( "failed : " + theSql ); 00770 } 00771 } 00772 sqlite3_finalize( myPreparedStatement ); 00773 sqlite3_close( myDatabase ); 00774 00775 #ifdef QGISDEBUG 00776 QgsDebugMsg( "retrieved: " + theSql ); 00777 RecordMap::Iterator it; 00778 for ( it = myMap.begin(); it != myMap.end(); ++it ) 00779 { 00780 QgsDebugMsgLevel( it.key() + " => " + it.value(), 2 ); 00781 } 00782 #endif 00783 00784 return myMap; 00785 } 00786 00787 // Accessors ----------------------------------- 00788 00789 long QgsCoordinateReferenceSystem::srsid() const 00790 { 00791 return mSrsId; 00792 } 00793 00794 long QgsCoordinateReferenceSystem::postgisSrid() const 00795 { 00796 00797 return mSRID; 00798 00799 } 00800 00801 QString QgsCoordinateReferenceSystem::authid() const 00802 { 00803 return mAuthId; 00804 } 00805 00806 QString QgsCoordinateReferenceSystem::description() const 00807 { 00808 if ( mDescription.isNull() ) 00809 { 00810 return ""; 00811 } 00812 else 00813 { 00814 return mDescription; 00815 } 00816 } 00817 00818 QString QgsCoordinateReferenceSystem::projectionAcronym() const 00819 { 00820 if ( mProjectionAcronym.isNull() ) 00821 { 00822 return ""; 00823 } 00824 else 00825 { 00826 return mProjectionAcronym; 00827 } 00828 } 00829 00830 QString QgsCoordinateReferenceSystem::ellipsoidAcronym() const 00831 { 00832 if ( mEllipsoidAcronym.isNull() ) 00833 { 00834 return ""; 00835 } 00836 else 00837 { 00838 return mEllipsoidAcronym; 00839 } 00840 } 00841 00842 QString QgsCoordinateReferenceSystem::toProj4() const 00843 { 00844 if ( !mIsValidFlag ) 00845 return ""; 00846 00847 QString toProj4; 00848 char *proj4src = NULL; 00849 OSRExportToProj4( mCRS, &proj4src ); 00850 toProj4 = proj4src; 00851 CPLFree( proj4src ); 00852 00853 // Stray spaces at the end? 00854 return toProj4.trimmed(); 00855 } 00856 00857 bool QgsCoordinateReferenceSystem::geographicFlag() const 00858 { 00859 return mGeoFlag; 00860 } 00861 00862 QGis::UnitType QgsCoordinateReferenceSystem::mapUnits() const 00863 { 00864 return mMapUnits; 00865 } 00866 00867 00868 // Mutators ----------------------------------- 00869 00870 00871 void QgsCoordinateReferenceSystem::setInternalId( long theSrsId ) 00872 { 00873 mSrsId = theSrsId; 00874 } 00875 void QgsCoordinateReferenceSystem::setAuthId( QString authId ) 00876 { 00877 mAuthId = authId; 00878 } 00879 void QgsCoordinateReferenceSystem::setSrid( long theSrid ) 00880 { 00881 mSRID = theSrid; 00882 } 00883 void QgsCoordinateReferenceSystem::setDescription( QString theDescription ) 00884 { 00885 mDescription = theDescription; 00886 } 00887 void QgsCoordinateReferenceSystem::setProj4String( QString theProj4String ) 00888 { 00889 char *oldlocale = setlocale( LC_NUMERIC, NULL ); 00890 /* the next setlocale() invalides the return of previous setlocale() */ 00891 if ( oldlocale ) 00892 oldlocale = strdup( oldlocale ); 00893 00894 setlocale( LC_NUMERIC, "C" ); 00895 OSRDestroySpatialReference( mCRS ); 00896 mCRS = OSRNewSpatialReference( NULL ); 00897 mIsValidFlag = 00898 OSRImportFromProj4( mCRS, theProj4String.trimmed().toLatin1().constData() ) 00899 == OGRERR_NONE; 00900 mWkt.clear(); 00901 setMapUnits(); 00902 00903 #if defined(QGISDEBUG) && QGISDEBUG>=3 00904 debugPrint(); 00905 #endif 00906 00907 setlocale( LC_NUMERIC, oldlocale ); 00908 free( oldlocale ); 00909 } 00910 void QgsCoordinateReferenceSystem::setGeographicFlag( bool theGeoFlag ) 00911 { 00912 mGeoFlag = theGeoFlag; 00913 } 00914 void QgsCoordinateReferenceSystem::setEpsg( long theEpsg ) 00915 { 00916 mAuthId = QString( "EPSG:%1" ).arg( theEpsg ); 00917 } 00918 void QgsCoordinateReferenceSystem::setProjectionAcronym( QString theProjectionAcronym ) 00919 { 00920 mProjectionAcronym = theProjectionAcronym; 00921 } 00922 void QgsCoordinateReferenceSystem::setEllipsoidAcronym( QString theEllipsoidAcronym ) 00923 { 00924 mEllipsoidAcronym = theEllipsoidAcronym; 00925 } 00926 00927 void QgsCoordinateReferenceSystem::setMapUnits() 00928 { 00929 if ( !mIsValidFlag ) 00930 { 00931 mMapUnits = QGis::UnknownUnit; 00932 return; 00933 } 00934 00935 char *unitName; 00936 00937 // Of interest to us is that this call adds in a unit parameter if 00938 // one doesn't already exist. 00939 OSRFixup( mCRS ); 00940 00941 if ( OSRIsProjected( mCRS ) ) 00942 { 00943 double toMeter = OSRGetLinearUnits( mCRS, &unitName ); 00944 QString unit( unitName ); 00945 00946 // If the units parameter was created during the Fixup() call 00947 // above, the name of the units is likely to be 'unknown'. Try to 00948 // do better than that ... (but perhaps ogr should be enhanced to 00949 // do this instead?). 00950 00951 static const double feetToMeter = 0.3048; 00952 static const double smallNum = 1e-3; 00953 00954 if ( qAbs( toMeter - feetToMeter ) < smallNum ) 00955 unit = "Foot"; 00956 00957 QgsDebugMsg( "Projection has linear units of " + unit ); 00958 00959 if ( qgsDoubleNear( toMeter, 1.0 ) ) //Unit name for meters would be "metre" 00960 mMapUnits = QGis::Meters; 00961 else if ( unit == "Foot" ) 00962 mMapUnits = QGis::Feet; 00963 else 00964 { 00965 QgsDebugMsg( "Unsupported map units of " + unit ); 00966 mMapUnits = QGis::UnknownUnit; 00967 } 00968 } 00969 else 00970 { 00971 OSRGetAngularUnits( mCRS, &unitName ); 00972 QString unit( unitName ); 00973 if ( unit == "degree" ) 00974 mMapUnits = QGis::Degrees; 00975 else 00976 { 00977 QgsDebugMsg( "Unsupported map units of " + unit ); 00978 mMapUnits = QGis::UnknownUnit; 00979 } 00980 QgsDebugMsgLevel( "Projection has angular units of " + unit, 3 ); 00981 } 00982 } 00983 00984 /* 00985 * check if srs is a geocs or a proj cs (using ogr isGeographic) 00986 * then sequentially walk through the database (first users qgis.db srs tbl then 00987 * system srs.db tbl), converting each entry into an ogr srs and using isSame 00988 * or isSameGeocs (essentially calling the == overloaded operator). We'll try to 00989 * be smart about this and first parse out the proj and ellpse strings and only 00990 * check for a match in entities that have the same ellps and proj entries so 00991 * that it doesnt munch yer cpu so much. 00992 */ 00993 long QgsCoordinateReferenceSystem::findMatchingProj() 00994 { 00995 QgsDebugMsg( "entered." ); 00996 if ( mEllipsoidAcronym.isNull() || mProjectionAcronym.isNull() 00997 || !mIsValidFlag ) 00998 { 00999 QgsDebugMsg( "QgsCoordinateReferenceSystem::findMatchingProj will only " 01000 "work if prj acr ellipsoid acr and proj4string are set" 01001 " and the current projection is valid!" ); 01002 return 0; 01003 } 01004 01005 sqlite3 *myDatabase; 01006 const char *myTail; 01007 sqlite3_stmt *myPreparedStatement; 01008 int myResult; 01009 01010 // Set up the query to retrieve the projection information 01011 // needed to populate the list 01012 QString mySql = QString( "select srs_id,parameters from tbl_srs where " 01013 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" ) 01014 .arg( quotedValue( mProjectionAcronym ) ) 01015 .arg( quotedValue( mEllipsoidAcronym ) ); 01016 // Get the full path name to the sqlite3 spatial reference database. 01017 QString myDatabaseFileName = QgsApplication::srsDbFilePath(); 01018 01019 //check the db is available 01020 myResult = openDb( myDatabaseFileName, &myDatabase ); 01021 if ( myResult != SQLITE_OK ) 01022 { 01023 return 0; 01024 } 01025 01026 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 01027 // XXX Need to free memory from the error msg if one is set 01028 if ( myResult == SQLITE_OK ) 01029 { 01030 01031 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW ) 01032 { 01033 QString mySrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) ); 01034 QString myProj4String = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) ); 01035 if ( toProj4() == myProj4String.trimmed() ) 01036 { 01037 QgsDebugMsg( "-------> MATCH FOUND in srs.db srsid: " + mySrsId ); 01038 // close the sqlite3 statement 01039 sqlite3_finalize( myPreparedStatement ); 01040 sqlite3_close( myDatabase ); 01041 return mySrsId.toLong(); 01042 } 01043 else 01044 { 01045 // QgsDebugMsg(QString(" Not matched : %1").arg(myProj4String)); 01046 } 01047 } 01048 } 01049 QgsDebugMsg( "no match found in srs.db, trying user db now!" ); 01050 // close the sqlite3 statement 01051 sqlite3_finalize( myPreparedStatement ); 01052 sqlite3_close( myDatabase ); 01053 // 01054 // Try the users db now 01055 // 01056 01057 myDatabaseFileName = QgsApplication::qgisUserDbFilePath(); 01058 //check the db is available 01059 myResult = openDb( myDatabaseFileName, &myDatabase ); 01060 if ( myResult != SQLITE_OK ) 01061 { 01062 return 0; 01063 } 01064 01065 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 01066 // XXX Need to free memory from the error msg if one is set 01067 if ( myResult == SQLITE_OK ) 01068 { 01069 01070 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW ) 01071 { 01072 QString mySrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) ); 01073 QString myProj4String = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) ); 01074 if ( toProj4() == myProj4String.trimmed() ) 01075 { 01076 QgsDebugMsg( "-------> MATCH FOUND in user qgis.db srsid: " + mySrsId ); 01077 // close the sqlite3 statement 01078 sqlite3_finalize( myPreparedStatement ); 01079 sqlite3_close( myDatabase ); 01080 return mySrsId.toLong(); 01081 } 01082 else 01083 { 01084 // QgsDebugMsg(QString(" Not matched : %1").arg(myProj4String)); 01085 } 01086 } 01087 } 01088 QgsDebugMsg( "no match found in user db" ); 01089 01090 // close the sqlite3 statement 01091 sqlite3_finalize( myPreparedStatement ); 01092 sqlite3_close( myDatabase ); 01093 return 0; 01094 } 01095 01096 bool QgsCoordinateReferenceSystem::operator==( const QgsCoordinateReferenceSystem &theSrs ) const 01097 { 01098 return mIsValidFlag && theSrs.mIsValidFlag && theSrs.authid() == authid(); 01099 } 01100 01101 bool QgsCoordinateReferenceSystem::operator!=( const QgsCoordinateReferenceSystem &theSrs ) const 01102 { 01103 return !( *this == theSrs ); 01104 } 01105 01106 QString QgsCoordinateReferenceSystem::toWkt() const 01107 { 01108 if ( mWkt.isEmpty() ) 01109 { 01110 char *wkt; 01111 if ( OSRExportToWkt( mCRS, &wkt ) == OGRERR_NONE ) 01112 { 01113 mWkt = wkt; 01114 OGRFree( wkt ); 01115 } 01116 } 01117 return mWkt; 01118 } 01119 01120 bool QgsCoordinateReferenceSystem::readXML( QDomNode & theNode ) 01121 { 01122 QgsDebugMsg( "Reading Spatial Ref Sys from xml ------------------------!" ); 01123 QDomNode srsNode = theNode.namedItem( "spatialrefsys" ); 01124 01125 if ( ! srsNode.isNull() ) 01126 { 01127 bool initialized = false; 01128 01129 long srsid = srsNode.namedItem( "srsid" ).toElement().text().toLong(); 01130 01131 QDomNode myNode; 01132 01133 if ( srsid < USER_CRS_START_ID ) 01134 { 01135 myNode = srsNode.namedItem( "authid" ); 01136 if ( !myNode.isNull() ) 01137 { 01138 operator=( QgsCRSCache::instance()->crsByAuthId( myNode.toElement().text() ) ); 01139 if ( isValid() ) 01140 { 01141 initialized = true; 01142 } 01143 } 01144 01145 if ( !initialized ) 01146 { 01147 myNode = srsNode.namedItem( "epsg" ); 01148 if ( !myNode.isNull() ) 01149 { 01150 operator=( QgsCRSCache::instance()->crsByEpsgId( myNode.toElement().text().toLong() ) ); 01151 if ( isValid() ) 01152 { 01153 initialized = true; 01154 } 01155 } 01156 } 01157 } 01158 else 01159 { 01160 QgsDebugMsg( "Ignoring authid/epsg for user crs." ); 01161 } 01162 01163 if ( initialized ) 01164 { 01165 QgsDebugMsg( "Set from auth id" ); 01166 } 01167 else 01168 { 01169 myNode = srsNode.namedItem( "proj4" ); 01170 01171 if ( createFromProj4( myNode.toElement().text() ) ) 01172 { 01173 // createFromProj4() sets everything, including map units 01174 QgsDebugMsg( "Setting from proj4 string" ); 01175 } 01176 else 01177 { 01178 QgsDebugMsg( "Setting from elements one by one" ); 01179 01180 myNode = srsNode.namedItem( "proj4" ); 01181 setProj4String( myNode.toElement().text() ); 01182 01183 myNode = srsNode.namedItem( "srsid" ); 01184 setInternalId( myNode.toElement().text().toLong() ); 01185 01186 myNode = srsNode.namedItem( "srid" ); 01187 setSrid( myNode.toElement().text().toLong() ); 01188 01189 myNode = srsNode.namedItem( "authid" ); 01190 setAuthId( myNode.toElement().text() ); 01191 01192 myNode = srsNode.namedItem( "description" ); 01193 setDescription( myNode.toElement().text() ); 01194 01195 myNode = srsNode.namedItem( "projectionacronym" ); 01196 setProjectionAcronym( myNode.toElement().text() ); 01197 01198 myNode = srsNode.namedItem( "ellipsoidacronym" ); 01199 setEllipsoidAcronym( myNode.toElement().text() ); 01200 01201 myNode = srsNode.namedItem( "geographicflag" ); 01202 if ( myNode.toElement().text().compare( "true" ) ) 01203 { 01204 setGeographicFlag( true ); 01205 } 01206 else 01207 { 01208 setGeographicFlag( false ); 01209 } 01210 01211 //make sure the map units have been set 01212 setMapUnits(); 01213 01214 //@TODO this srs needs to be validated!!! 01215 mIsValidFlag = true; //shamelessly hard coded for now 01216 } 01217 //TODO: createFromProj4 used to save to the user database any new CRS 01218 // this behavior was changed in order to separate creation and saving. 01219 // Not sure if it necessary to save it here, should be checked by someone 01220 // familiar with the code (should also give a more descriptive name to the generated CRS) 01221 if ( mSrsId == 0 ) 01222 { 01223 QString myName = QString( " * %1 (%2)" ) 01224 .arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ) ) 01225 .arg( toProj4() ); 01226 saveAsUserCRS( myName ); 01227 } 01228 01229 } 01230 } 01231 else 01232 { 01233 // Return default CRS if none was found in the XML. 01234 createFromId( GEOCRS_ID, InternalCrsId ); 01235 } 01236 return true; 01237 } 01238 01239 bool QgsCoordinateReferenceSystem::writeXML( QDomNode & theNode, QDomDocument & theDoc ) const 01240 { 01241 01242 QDomElement myLayerNode = theNode.toElement(); 01243 QDomElement mySrsElement = theDoc.createElement( "spatialrefsys" ); 01244 01245 QDomElement myProj4Element = theDoc.createElement( "proj4" ); 01246 myProj4Element.appendChild( theDoc.createTextNode( toProj4() ) ); 01247 mySrsElement.appendChild( myProj4Element ); 01248 01249 QDomElement mySrsIdElement = theDoc.createElement( "srsid" ); 01250 mySrsIdElement.appendChild( theDoc.createTextNode( QString::number( srsid() ) ) ); 01251 mySrsElement.appendChild( mySrsIdElement ); 01252 01253 QDomElement mySridElement = theDoc.createElement( "srid" ); 01254 mySridElement.appendChild( theDoc.createTextNode( QString::number( postgisSrid() ) ) ); 01255 mySrsElement.appendChild( mySridElement ); 01256 01257 QDomElement myEpsgElement = theDoc.createElement( "authid" ); 01258 myEpsgElement.appendChild( theDoc.createTextNode( authid() ) ); 01259 mySrsElement.appendChild( myEpsgElement ); 01260 01261 QDomElement myDescriptionElement = theDoc.createElement( "description" ); 01262 myDescriptionElement.appendChild( theDoc.createTextNode( description() ) ); 01263 mySrsElement.appendChild( myDescriptionElement ); 01264 01265 QDomElement myProjectionAcronymElement = theDoc.createElement( "projectionacronym" ); 01266 myProjectionAcronymElement.appendChild( theDoc.createTextNode( projectionAcronym() ) ); 01267 mySrsElement.appendChild( myProjectionAcronymElement ); 01268 01269 QDomElement myEllipsoidAcronymElement = theDoc.createElement( "ellipsoidacronym" ); 01270 myEllipsoidAcronymElement.appendChild( theDoc.createTextNode( ellipsoidAcronym() ) ); 01271 mySrsElement.appendChild( myEllipsoidAcronymElement ); 01272 01273 QDomElement myGeographicFlagElement = theDoc.createElement( "geographicflag" ); 01274 QString myGeoFlagText = "false"; 01275 if ( geographicFlag() ) 01276 { 01277 myGeoFlagText = "true"; 01278 } 01279 01280 myGeographicFlagElement.appendChild( theDoc.createTextNode( myGeoFlagText ) ); 01281 mySrsElement.appendChild( myGeographicFlagElement ); 01282 01283 myLayerNode.appendChild( mySrsElement ); 01284 01285 return true; 01286 } 01287 01288 01289 01290 // 01291 // Static helper methods below this point only please! 01292 // 01293 01294 01295 // Returns the whole proj4 string for the selected srsid 01296 //this is a static method! NOTE I've made it private for now to reduce API clutter TS 01297 QString QgsCoordinateReferenceSystem::proj4FromSrsId( const int theSrsId ) 01298 { 01299 01300 QString myDatabaseFileName; 01301 QString myProjString; 01302 QString mySql = QString( "select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( theSrsId ); 01303 01304 QgsDebugMsg( "mySrsId = " + QString::number( theSrsId ) ); 01305 QgsDebugMsg( "USER_CRS_START_ID = " + QString::number( USER_CRS_START_ID ) ); 01306 QgsDebugMsg( "Selection sql : " + mySql ); 01307 01308 // 01309 // Determine if this is a user projection or a system on 01310 // user projection defs all have srs_id >= 100000 01311 // 01312 if ( theSrsId >= USER_CRS_START_ID ) 01313 { 01314 myDatabaseFileName = QgsApplication::qgisUserDbFilePath(); 01315 QFileInfo myFileInfo; 01316 myFileInfo.setFile( myDatabaseFileName ); 01317 if ( !myFileInfo.exists( ) ) //its unlikely that this condition will ever be reached 01318 { 01319 QgsDebugMsg( "users qgis.db not found" ); 01320 return NULL; 01321 } 01322 } 01323 else //must be a system projection then 01324 { 01325 myDatabaseFileName = QgsApplication::srsDbFilePath(); 01326 } 01327 QgsDebugMsg( "db = " + myDatabaseFileName ); 01328 01329 sqlite3 *db; 01330 int rc; 01331 rc = openDb( myDatabaseFileName, &db ); 01332 if ( rc ) 01333 { 01334 return QString(); 01335 } 01336 // prepare the sql statement 01337 const char *pzTail; 01338 sqlite3_stmt *ppStmt; 01339 01340 rc = sqlite3_prepare( db, mySql.toUtf8(), mySql.toUtf8().length(), &ppStmt, &pzTail ); 01341 // XXX Need to free memory from the error msg if one is set 01342 01343 if ( rc == SQLITE_OK ) 01344 { 01345 if ( sqlite3_step( ppStmt ) == SQLITE_ROW ) 01346 { 01347 myProjString = QString::fromUtf8(( char* )sqlite3_column_text( ppStmt, 0 ) ); 01348 } 01349 } 01350 // close the statement 01351 sqlite3_finalize( ppStmt ); 01352 // close the database 01353 sqlite3_close( db ); 01354 01355 //Q_ASSERT(myProjString.length() > 0); 01356 return myProjString; 01357 } 01358 01359 int QgsCoordinateReferenceSystem::openDb( QString path, sqlite3 **db, bool readonly ) 01360 { 01361 QgsDebugMsgLevel( "path = " + path, 3 ); 01362 int myResult = readonly 01363 ? sqlite3_open_v2( path.toUtf8().data(), db, SQLITE_OPEN_READONLY, NULL ) 01364 : sqlite3_open( path.toUtf8().data(), db ); 01365 01366 if ( myResult != SQLITE_OK ) 01367 { 01368 QgsDebugMsg( "Can't open database: " + QString( sqlite3_errmsg( *db ) ) ); 01369 // XXX This will likely never happen since on open, sqlite creates the 01370 // database if it does not exist. 01371 // ... unfortunately it happens on Windows 01372 QgsMessageLog::logMessage( QObject::tr( "Could not open CRS database %1\nError(%2): %3" ) 01373 .arg( path ) 01374 .arg( myResult ) 01375 .arg( sqlite3_errmsg( *db ) ), QObject::tr( "CRS" ) ); 01376 } 01377 return myResult; 01378 } 01379 01380 void QgsCoordinateReferenceSystem::setCustomSrsValidation( CUSTOM_CRS_VALIDATION f ) 01381 { 01382 mCustomSrsValidation = f; 01383 } 01384 01385 CUSTOM_CRS_VALIDATION QgsCoordinateReferenceSystem::customSrsValidation() 01386 { 01387 return mCustomSrsValidation; 01388 } 01389 01390 void QgsCoordinateReferenceSystem::debugPrint() 01391 { 01392 QgsDebugMsg( "***SpatialRefSystem***" ); 01393 QgsDebugMsg( "* Valid : " + ( mIsValidFlag ? QString( "true" ) : QString( "false" ) ) ); 01394 QgsDebugMsg( "* SrsId : " + QString::number( mSrsId ) ); 01395 QgsDebugMsg( "* Proj4 : " + toProj4() ); 01396 QgsDebugMsg( "* WKT : " + toWkt() ); 01397 QgsDebugMsg( "* Desc. : " + mDescription ); 01398 if ( mapUnits() == QGis::Meters ) 01399 { 01400 QgsDebugMsg( "* Units : meters" ); 01401 } 01402 else if ( mapUnits() == QGis::Feet ) 01403 { 01404 QgsDebugMsg( "* Units : feet" ); 01405 } 01406 else if ( mapUnits() == QGis::Degrees ) 01407 { 01408 QgsDebugMsg( "* Units : degrees" ); 01409 } 01410 } 01411 01412 void QgsCoordinateReferenceSystem::setValidationHint( QString html ) 01413 { 01414 mValidationHint = html; 01415 } 01416 01417 QString QgsCoordinateReferenceSystem::validationHint() 01418 { 01419 return mValidationHint; 01420 } 01421 01424 01425 bool QgsCoordinateReferenceSystem::saveAsUserCRS( QString name ) 01426 { 01427 if ( ! mIsValidFlag ) 01428 { 01429 QgsDebugMsg( "Can't save an invalid CRS!" ); 01430 return false; 01431 } 01432 01433 QString mySql; 01434 01435 //if this is the first record we need to ensure that its srs_id is 10000. For 01436 //any rec after that sqlite3 will take care of the autonumering 01437 //this was done to support sqlite 3.0 as it does not yet support 01438 //the autoinc related system tables. 01439 if ( getRecordCount() == 0 ) 01440 { 01441 mySql = "insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 01442 + QString::number( USER_CRS_START_ID ) 01443 + "," + quotedValue( name ) 01444 + "," + quotedValue( projectionAcronym() ) 01445 + "," + quotedValue( ellipsoidAcronym() ) 01446 + "," + quotedValue( toProj4() ) 01447 + ",0)"; // <-- is_geo shamelessly hard coded for now 01448 } 01449 else 01450 { 01451 mySql = "insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values (" 01452 + quotedValue( name ) 01453 + "," + quotedValue( projectionAcronym() ) 01454 + "," + quotedValue( ellipsoidAcronym() ) 01455 + "," + quotedValue( toProj4() ) 01456 + ",0)"; // <-- is_geo shamelessly hard coded for now 01457 } 01458 sqlite3 *myDatabase; 01459 const char *myTail; 01460 sqlite3_stmt *myPreparedStatement; 01461 int myResult; 01462 //check the db is available 01463 myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase ); 01464 if ( myResult != SQLITE_OK ) 01465 { 01466 QgsDebugMsg( QString( "Can't open or create database %1: %2" ) 01467 .arg( QgsApplication::qgisUserDbFilePath() ) 01468 .arg( sqlite3_errmsg( myDatabase ) ) ); 01469 return false; 01470 } 01471 QgsDebugMsg( QString( "Update or insert sql \n%1" ).arg( mySql ) ); 01472 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 01473 sqlite3_step( myPreparedStatement ); 01474 01475 QgsMessageLog::logMessage( QObject::tr( "Saved user CRS [%1]" ).arg( toProj4() ), QObject::tr( "CRS" ) ); 01476 01477 int return_id; 01478 if ( myResult == SQLITE_OK ) 01479 { 01480 return_id = sqlite3_last_insert_rowid( myDatabase ); 01481 setInternalId( return_id ); 01482 01483 //We add the just created user CRS to the list of recently used CRS 01484 QSettings settings; 01485 //QStringList recentProjections = settings.value( "/UI/recentProjections" ).toStringList(); 01486 QStringList projectionsProj4 = settings.value( "/UI/recentProjectionsProj4" ).toStringList(); 01487 QStringList projectionsAuthId = settings.value( "/UI/recentProjectionsAuthId" ).toStringList(); 01488 //recentProjections.append(); 01489 //settings.setValue( "/UI/recentProjections", recentProjections ); 01490 projectionsProj4.append( toProj4() ); 01491 projectionsAuthId.append( authid() ); 01492 settings.setValue( "/UI/recentProjectionsProj4", projectionsProj4 ); 01493 settings.setValue( "/UI/recentProjectionsAuthId", projectionsAuthId ); 01494 01495 } 01496 else 01497 return_id = -1; 01498 return return_id; 01499 } 01500 01501 long QgsCoordinateReferenceSystem::getRecordCount() 01502 { 01503 sqlite3 *myDatabase; 01504 const char *myTail; 01505 sqlite3_stmt *myPreparedStatement; 01506 int myResult; 01507 long myRecordCount = 0; 01508 //check the db is available 01509 myResult = sqlite3_open_v2( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL ); 01510 if ( myResult != SQLITE_OK ) 01511 { 01512 QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) ); 01513 return 0; 01514 } 01515 // Set up the query to retrieve the projection information needed to populate the ELLIPSOID list 01516 QString mySql = "select count(*) from tbl_srs"; 01517 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail ); 01518 // XXX Need to free memory from the error msg if one is set 01519 if ( myResult == SQLITE_OK ) 01520 { 01521 if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW ) 01522 { 01523 QString myRecordCountString = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) ); 01524 myRecordCount = myRecordCountString.toLong(); 01525 } 01526 } 01527 // close the sqlite3 statement 01528 sqlite3_finalize( myPreparedStatement ); 01529 sqlite3_close( myDatabase ); 01530 return myRecordCount; 01531 } 01532 01533 QString QgsCoordinateReferenceSystem::quotedValue( QString value ) 01534 { 01535 value.replace( "'", "''" ); 01536 return value.prepend( "'" ).append( "'" ); 01537 } 01538 01539 // adapted from gdal/ogr/ogr_srs_dict.cpp 01540 bool QgsCoordinateReferenceSystem::loadWkts( QHash<int, QString> &wkts, const char *filename ) 01541 { 01542 qDebug( "Loading %s", filename ); 01543 const char *pszFilename = CPLFindFile( "gdal", filename ); 01544 if ( !pszFilename ) 01545 return false; 01546 01547 QFile csv( pszFilename ); 01548 if ( !csv.open( QIODevice::ReadOnly ) ) 01549 return false; 01550 01551 QTextStream lines( &csv ); 01552 01553 for ( ;; ) 01554 { 01555 QString line = lines.readLine(); 01556 if ( line.isNull() ) 01557 break; 01558 01559 if ( line.startsWith( '#' ) ) 01560 { 01561 continue; 01562 } 01563 else if ( line.startsWith( "include " ) ) 01564 { 01565 if ( !loadWkts( wkts, line.mid( 8 ).toUtf8() ) ) 01566 break; 01567 } 01568 else 01569 { 01570 int pos = line.indexOf( "," ); 01571 if ( pos < 0 ) 01572 return false; 01573 01574 bool ok; 01575 int epsg = line.left( pos ).toInt( &ok ); 01576 if ( !ok ) 01577 return false; 01578 01579 wkts.insert( epsg, line.mid( pos + 1 ) ); 01580 } 01581 } 01582 01583 csv.close(); 01584 01585 return true; 01586 } 01587 01588 bool QgsCoordinateReferenceSystem::loadIDs( QHash<int, QString> &wkts ) 01589 { 01590 OGRSpatialReferenceH crs = OSRNewSpatialReference( NULL ); 01591 01592 foreach ( QString csv, QStringList() << "gcs.csv" << "pcs.csv" << "vertcs.csv" << "compdcs.csv" << "geoccs.csv" ) 01593 { 01594 QString filename = CPLFindFile( "gdal", csv.toUtf8() ); 01595 01596 QFile f( filename ); 01597 if ( !f.open( QIODevice::ReadOnly ) ) 01598 continue; 01599 01600 QTextStream lines( &f ); 01601 int l = 0, n = 0; 01602 01603 lines.readLine(); 01604 for ( ;; ) 01605 { 01606 l++; 01607 QString line = lines.readLine(); 01608 if ( line.isNull() ) 01609 break; 01610 01611 int pos = line.indexOf( "," ); 01612 if ( pos < 0 ) 01613 continue; 01614 01615 bool ok; 01616 int epsg = line.left( pos ).toInt( &ok ); 01617 if ( !ok ) 01618 continue; 01619 01620 // some CRS are known to fail (see http://trac.osgeo.org/gdal/ticket/2900) 01621 if ( epsg == 2218 || epsg == 2221 || epsg == 2296 || epsg == 2297 || epsg == 2298 || epsg == 2299 || epsg == 2300 || epsg == 2301 || epsg == 2302 || 01622 epsg == 2303 || epsg == 2304 || epsg == 2305 || epsg == 2306 || epsg == 2307 || epsg == 2963 || epsg == 2985 || epsg == 2986 || epsg == 3052 || 01623 epsg == 3053 || epsg == 3139 || epsg == 3144 || epsg == 3145 || epsg == 3173 || epsg == 3295 || epsg == 3993 || epsg == 4087 || epsg == 4088 || 01624 epsg == 5017 || epsg == 5221 || epsg == 5224 || epsg == 5225 || epsg == 5514 || epsg == 5515 || epsg == 5516 || epsg == 5819 || epsg == 5820 || 01625 epsg == 5821 || epsg == 32600 || epsg == 32663 || epsg == 32700 ) 01626 continue; 01627 01628 if ( OSRImportFromEPSG( crs, epsg ) != OGRERR_NONE ) 01629 { 01630 qDebug( "EPSG %d: not imported", epsg ); 01631 continue; 01632 } 01633 01634 char *wkt = 0; 01635 if ( OSRExportToWkt( crs, &wkt ) != OGRERR_NONE ) 01636 { 01637 qWarning( "EPSG %d: not exported to WKT", epsg ); 01638 continue; 01639 } 01640 01641 wkts.insert( epsg, wkt ); 01642 n++; 01643 01644 OGRFree( wkt ); 01645 } 01646 01647 f.close(); 01648 01649 qDebug( "Loaded %d/%d from %s", n, l, filename.toUtf8().constData() ); 01650 } 01651 01652 OSRDestroySpatialReference( crs ); 01653 01654 return true; 01655 } 01656 01657 int QgsCoordinateReferenceSystem::syncDb() 01658 { 01659 int inserted = 0, updated = 0, deleted = 0, errors = 0; 01660 01661 sqlite3 *database; 01662 if ( sqlite3_open( QgsApplication::srsDbFilePath().toUtf8().constData(), &database ) != SQLITE_OK ) 01663 { 01664 qCritical( "Could not open database: %s [%s]\n", QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) ); 01665 return -1; 01666 } 01667 01668 if ( sqlite3_exec( database, "BEGIN TRANSACTION", 0, 0, 0 ) != SQLITE_OK ) 01669 { 01670 qCritical( "Could not begin transaction: %s [%s]\n", QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) ); 01671 return -1; 01672 01673 } 01674 01675 sqlite3_exec( database, "UPDATE tbl_srs SET srid=141001 WHERE srid=41001 AND auth_name='OSGEO' AND auth_id='41001'", 0, 0, 0 ); 01676 01677 OGRSpatialReferenceH crs = OSRNewSpatialReference( NULL ); 01678 const char *tail; 01679 sqlite3_stmt *select; 01680 char *errMsg = NULL; 01681 01682 QString proj4; 01683 QString sql; 01684 QHash<int, QString> wkts; 01685 loadIDs( wkts ); 01686 loadWkts( wkts, "epsg.wkt" ); 01687 01688 qDebug( "%d WKTs loaded", wkts.count() ); 01689 01690 for ( QHash<int, QString>::const_iterator it = wkts.constBegin(); it != wkts.constEnd(); ++it ) 01691 { 01692 QByteArray ba( it.value().toUtf8() ); 01693 char *psz = ba.data(); 01694 OGRErr ogrErr = OSRImportFromWkt( crs, &psz ); 01695 if ( ogrErr != OGRERR_NONE ) 01696 { 01697 continue; 01698 } 01699 01700 if ( OSRExportToProj4( crs, &psz ) != OGRERR_NONE ) 01701 continue; 01702 01703 proj4 = psz; 01704 proj4 = proj4.trimmed(); 01705 01706 CPLFree( psz ); 01707 01708 if ( proj4.isEmpty() ) 01709 { 01710 continue; 01711 } 01712 01713 sql = QString( "SELECT parameters FROM tbl_srs WHERE auth_name='EPSG' AND auth_id='%1'" ).arg( it.key() ); 01714 if ( sqlite3_prepare( database, sql.toAscii(), sql.size(), &select, &tail ) != SQLITE_OK ) 01715 { 01716 qCritical( "Could not prepare: %s [%s]\n", sql.toAscii().constData(), sqlite3_errmsg( database ) ); 01717 continue; 01718 } 01719 01720 QString srsProj4; 01721 if ( sqlite3_step( select ) == SQLITE_ROW ) 01722 { 01723 srsProj4 = ( const char * ) sqlite3_column_text( select, 0 ); 01724 } 01725 01726 sqlite3_finalize( select ); 01727 01728 if ( !srsProj4.isEmpty() ) 01729 { 01730 if ( proj4 != srsProj4 ) 01731 { 01732 errMsg = NULL; 01733 sql = QString( "UPDATE tbl_srs SET parameters=%1 WHERE auth_name='EPSG' AND auth_id=%2" ).arg( quotedValue( proj4 ) ).arg( it.key() ); 01734 01735 if ( sqlite3_exec( database, sql.toUtf8(), 0, 0, &errMsg ) != SQLITE_OK ) 01736 { 01737 qCritical( "Could not execute: %s [%s/%s]\n", 01738 sql.toLocal8Bit().constData(), 01739 sqlite3_errmsg( database ), 01740 errMsg ? errMsg : "(unknown error)" ); 01741 errors++; 01742 } 01743 else 01744 { 01745 updated++; 01746 QgsDebugMsgLevel( QString( "SQL: %1\n OLD:%2\n NEW:%3" ).arg( sql ).arg( srsProj4 ).arg( proj4 ), 3 ); 01747 } 01748 } 01749 } 01750 else 01751 { 01752 QRegExp projRegExp( "\\+proj=(\\S+)" ); 01753 if ( projRegExp.indexIn( proj4 ) < 0 ) 01754 { 01755 QgsDebugMsg( QString( "EPSG %1: no +proj argument found [%2]" ).arg( it.key() ).arg( proj4 ) ); 01756 continue; 01757 } 01758 01759 QRegExp ellipseRegExp( "\\+ellps=(\\S+)" ); 01760 QString ellps; 01761 if ( ellipseRegExp.indexIn( proj4 ) >= 0 ) 01762 { 01763 ellps = ellipseRegExp.cap( 1 ); 01764 } 01765 01766 QString name( OSRIsGeographic( crs ) ? OSRGetAttrValue( crs, "GEOCS", 0 ) : OSRGetAttrValue( crs, "PROJCS", 0 ) ); 01767 if ( name.isEmpty() ) 01768 name = QObject::tr( "Imported from GDAL" ); 01769 01770 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)" ) 01771 .arg( quotedValue( name ) ) 01772 .arg( quotedValue( projRegExp.cap( 1 ) ) ) 01773 .arg( quotedValue( ellps ) ) 01774 .arg( quotedValue( proj4 ) ) 01775 .arg( it.key() ) 01776 .arg( OSRIsGeographic( crs ) ); 01777 01778 errMsg = NULL; 01779 if ( sqlite3_exec( database, sql.toUtf8(), 0, 0, &errMsg ) == SQLITE_OK ) 01780 { 01781 inserted++; 01782 } 01783 else 01784 { 01785 qCritical( "Could not execute: %s [%s/%s]\n", 01786 sql.toLocal8Bit().constData(), 01787 sqlite3_errmsg( database ), 01788 errMsg ? errMsg : "(unknown error)" ); 01789 errors++; 01790 01791 if ( errMsg ) 01792 sqlite3_free( errMsg ); 01793 } 01794 } 01795 } 01796 01797 sql = "DELETE FROM tbl_srs WHERE auth_name='EPSG' AND NOT auth_id IN ("; 01798 QString delim; 01799 foreach ( int i, wkts.keys() ) 01800 { 01801 sql += delim + QString::number( i ); 01802 delim = ","; 01803 } 01804 sql += ")"; 01805 01806 if ( sqlite3_exec( database, sql.toUtf8(), 0, 0, 0 ) == SQLITE_OK ) 01807 { 01808 deleted = sqlite3_changes( database ); 01809 } 01810 else 01811 { 01812 errors++; 01813 qCritical( "Could not execute: %s [%s]\n", 01814 sql.toLocal8Bit().constData(), 01815 sqlite3_errmsg( database ) ); 01816 } 01817 01818 #if !defined(PJ_VERSION) || PJ_VERSION!=470 01819 sql = QString( "select auth_name,auth_id,parameters from tbl_srs WHERE auth_name<>'EPSG' AND NOT deprecated" ); 01820 if ( sqlite3_prepare( database, sql.toAscii(), sql.size(), &select, &tail ) == SQLITE_OK ) 01821 { 01822 while ( sqlite3_step( select ) == SQLITE_ROW ) 01823 { 01824 const char *auth_name = ( const char * ) sqlite3_column_text( select, 0 ); 01825 const char *auth_id = ( const char * ) sqlite3_column_text( select, 1 ); 01826 const char *params = ( const char * ) sqlite3_column_text( select, 2 ); 01827 01828 QString input = QString( "+init=%1:%2" ).arg( QString( auth_name ).toLower() ).arg( auth_id ); 01829 projPJ pj = pj_init_plus( input.toAscii() ); 01830 if ( !pj ) 01831 { 01832 input = QString( "+init=%1:%2" ).arg( QString( auth_name ).toUpper() ).arg( auth_id ); 01833 pj = pj_init_plus( input.toAscii() ); 01834 } 01835 01836 if ( pj ) 01837 { 01838 char *def = pj_get_def( pj, 0 ); 01839 if ( def ) 01840 { 01841 proj4 = def; 01842 pj_dalloc( def ); 01843 01844 input.prepend( ' ' ).append( ' ' ); 01845 if ( proj4.startsWith( input ) ) 01846 { 01847 proj4 = proj4.mid( input.size() ); 01848 proj4 = proj4.trimmed(); 01849 } 01850 01851 if ( proj4 != params ) 01852 { 01853 sql = QString( "UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" ) 01854 .arg( quotedValue( proj4 ) ) 01855 .arg( quotedValue( auth_name ) ) 01856 .arg( quotedValue( auth_id ) ); 01857 01858 if ( sqlite3_exec( database, sql.toUtf8(), 0, 0, &errMsg ) == SQLITE_OK ) 01859 { 01860 updated++; 01861 QgsDebugMsgLevel( QString( "SQL: %1\n OLD:%2\n NEW:%3" ).arg( sql ).arg( params ).arg( proj4 ), 3 ); 01862 } 01863 else 01864 { 01865 qCritical( "Could not execute: %s [%s/%s]\n", 01866 sql.toLocal8Bit().constData(), 01867 sqlite3_errmsg( database ), 01868 errMsg ? errMsg : "(unknown error)" ); 01869 errors++; 01870 } 01871 } 01872 } 01873 else 01874 { 01875 QgsDebugMsg( QString( "could not retrieve proj string for %1 from PROJ" ).arg( input ) ); 01876 } 01877 } 01878 else 01879 { 01880 QgsDebugMsgLevel( QString( "could not retrieve crs for %1 from PROJ" ).arg( input ), 3 ); 01881 } 01882 01883 pj_free( pj ); 01884 } 01885 } 01886 else 01887 { 01888 errors++; 01889 qCritical( "Could not execute: %s [%s]\n", 01890 sql.toLocal8Bit().constData(), 01891 sqlite3_errmsg( database ) ); 01892 } 01893 #endif 01894 01895 OSRDestroySpatialReference( crs ); 01896 01897 if ( sqlite3_exec( database, "COMMIT", 0, 0, 0 ) != SQLITE_OK ) 01898 { 01899 qCritical( "Could not commit transaction: %s [%s]\n", QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) ); 01900 return -1; 01901 } 01902 01903 sqlite3_close( database ); 01904 01905 qWarning( "CRS update (inserted:%d updated:%d deleted:%d errors:%d)", inserted, updated, deleted, errors ); 01906 01907 if ( errors > 0 ) 01908 return -errors; 01909 else 01910 return updated + inserted; 01911 }