QGIS API Documentation  master-6227475
src/core/qgscoordinatereferencesystem.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines