Quantum GIS API Documentation  1.7.4
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 <QDomNode>
00024 #include <QDomElement>
00025 #include <QFileInfo>
00026 #include <QRegExp>
00027 #include <QTextStream>
00028 
00029 #include "qgsapplication.h"
00030 #include "qgslogger.h"
00031 #include "qgsmessageoutput.h"
00032 #include "qgis.h" //const vals declared here
00033 
00034 #include <sqlite3.h>
00035 
00036 //gdal and ogr includes (needed for == operator)
00037 #include <ogr_srs_api.h>
00038 #include <cpl_error.h>
00039 #include <cpl_conv.h>
00040 
00041 CUSTOM_CRS_VALIDATION QgsCoordinateReferenceSystem::mCustomSrsValidation = NULL;
00042 
00043 //--------------------------
00044 
00045 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem()
00046     : mMapUnits( QGis::UnknownUnit )
00047     , mIsValidFlag( 0 )
00048     , mValidationHint( "" )
00049 {
00050   mCRS = OSRNewSpatialReference( NULL );
00051 }
00052 
00053 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( QString theDefinition )
00054     : mMapUnits( QGis::UnknownUnit )
00055     , mIsValidFlag( 0 )
00056     , mValidationHint( "" )
00057 {
00058   mCRS = OSRNewSpatialReference( NULL );
00059   createFromString( theDefinition );
00060 }
00061 
00062 
00063 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( const long theId, CrsType theType )
00064     : mMapUnits( QGis::UnknownUnit )
00065     , mIsValidFlag( 0 )
00066     , mValidationHint( "" )
00067 {
00068   mCRS = OSRNewSpatialReference( NULL );
00069   createFromId( theId, theType );
00070 }
00071 
00072 QgsCoordinateReferenceSystem::~QgsCoordinateReferenceSystem()
00073 {
00074   OSRDestroySpatialReference( mCRS );
00075 }
00076 
00077 bool QgsCoordinateReferenceSystem::createFromId( const long theId, CrsType theType )
00078 {
00079   bool result = false;
00080   switch ( theType )
00081   {
00082     case InternalCrsId:
00083       result = createFromSrsId( theId );
00084       break;
00085     case PostgisCrsId:
00086       result = createFromSrid( theId );
00087       break;
00088     case EpsgCrsId:
00089       result = createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( theId ) );
00090       break;
00091     default:
00092       //THIS IS BAD...THIS PART OF CODE SHOULD NEVER BE REACHED...
00093       QgsDebugMsg( "Unexpected case reached!" );
00094   };
00095   return result;
00096 }
00097 
00098 bool QgsCoordinateReferenceSystem::createFromString( const QString theDefinition )
00099 {
00100   bool result = false;
00101   QRegExp reCrsId( "^(epsg|postgis|internal)\\:(\\d+)$", Qt::CaseInsensitive );
00102   if ( reCrsId.indexIn( theDefinition ) == 0 )
00103   {
00104     QString authName = reCrsId.cap( 1 ).toLower();
00105     CrsType type = InternalCrsId;
00106     if ( authName == "epsg" ) type = EpsgCrsId;
00107     if ( authName == "postgis" ) type = PostgisCrsId;
00108     long id = reCrsId.cap( 2 ).toLong();
00109     result = createFromId( id, type );
00110   }
00111   else
00112   {
00113     QRegExp reCrsStr( "^(?:(wkt|proj4)\\:)?(.+)$", Qt::CaseInsensitive );
00114     if ( reCrsStr.indexIn( theDefinition ) == 0 )
00115     {
00116       if ( reCrsStr.cap( 1 ).toLower() == "proj4" )
00117       {
00118         result = createFromProj4( reCrsStr.cap( 2 ) );
00119       }
00120       else
00121       {
00122         result = createFromWkt( reCrsStr.cap( 2 ) );
00123       }
00124     }
00125   }
00126   return result;
00127 }
00128 
00129 bool QgsCoordinateReferenceSystem::createFromOgcWmsCrs( QString theCrs )
00130 {
00131   QRegExp re( "(user|custom|qgis):(\\d+)", Qt::CaseInsensitive );
00132   if ( re.exactMatch( theCrs ) && createFromSrsId( re.cap( 2 ).toInt() ) )
00133   {
00134     return true;
00135   }
00136 
00137   if ( loadFromDb( QgsApplication::srsDbFilePath(), "lower(auth_name||':'||auth_id)", theCrs.toLower() ) )
00138     return true;
00139 
00140   if ( theCrs.compare( "CRS:84", Qt::CaseInsensitive ) == 0 )
00141   {
00142     createFromSrsId( GEOCRS_ID );
00143     return true;
00144   }
00145 
00146   return false;
00147 }
00148 
00149 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &srs )
00150 {
00151   mCRS = OSRNewSpatialReference( NULL );
00152   *this = srs;
00153 }
00154 
00155 // Assignment operator
00156 QgsCoordinateReferenceSystem& QgsCoordinateReferenceSystem::operator=( const QgsCoordinateReferenceSystem & srs )
00157 {
00158   if ( &srs != this )
00159   {
00160     mSrsId = srs.mSrsId;
00161     mDescription = srs.mDescription;
00162     mProjectionAcronym = srs.mProjectionAcronym;
00163     mEllipsoidAcronym = srs.mEllipsoidAcronym;
00164     mGeoFlag = srs.mGeoFlag;
00165     mMapUnits = srs.mMapUnits;
00166     mSRID = srs.mSRID;
00167     mAuthId = srs.mAuthId;
00168     mIsValidFlag = srs.mIsValidFlag;
00169     mValidationHint = srs.mValidationHint;
00170     if ( mIsValidFlag )
00171     {
00172       OSRDestroySpatialReference( mCRS );
00173       mCRS = OSRClone( srs.mCRS );
00174     }
00175   }
00176   return *this;
00177 }
00178 
00179 // Misc helper functions -----------------------
00180 
00181 
00182 void QgsCoordinateReferenceSystem::validate()
00183 {
00184   if ( mIsValidFlag )
00185     return;
00186 
00187   // try to validate using custom validation routines
00188   if ( mCustomSrsValidation )
00189     mCustomSrsValidation( this );
00190 
00191   if ( !mIsValidFlag )
00192     // set the default
00193     createFromOgcWmsCrs( GEO_EPSG_CRS_AUTHID );
00194 }
00195 
00196 bool QgsCoordinateReferenceSystem::createFromSrid( long id )
00197 {
00198   return loadFromDb( QgsApplication::srsDbFilePath(), "srid", QString::number( id ) );
00199 }
00200 
00201 bool QgsCoordinateReferenceSystem::createFromEpsg( long id )
00202 {
00203   return createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( id ) );
00204 }
00205 
00206 bool QgsCoordinateReferenceSystem::createFromSrsId( long id )
00207 {
00208   return loadFromDb( id < USER_CRS_START_ID ? QgsApplication::srsDbFilePath() : QgsApplication::qgisUserDbFilePath(),
00209                      "srs_id", QString::number( id ) );
00210 }
00211 
00212 bool QgsCoordinateReferenceSystem::loadFromDb( QString db, QString expression, QString value )
00213 {
00214   QgsDebugMsgLevel( "load CRS from " + db + " where " + expression + " is " + value, 3 );
00215   mIsValidFlag = false;
00216 
00217   QFileInfo myInfo( db );
00218   if ( !myInfo.exists() )
00219   {
00220     QgsDebugMsg( "failed : " + db + " does not exist!" );
00221     return mIsValidFlag;
00222   }
00223 
00224   sqlite3      *myDatabase;
00225   const char   *myTail;
00226   sqlite3_stmt *myPreparedStatement;
00227   int           myResult;
00228   //check the db is available
00229   myResult = openDb( db, &myDatabase );
00230   if ( myResult != SQLITE_OK )
00231   {
00232     QgsDebugMsg( "failed : " + db + " could not be opened!" );
00233     return mIsValidFlag;
00234   }
00235 
00236   /*
00237     srs_id INTEGER PRIMARY KEY,
00238     description text NOT NULL,
00239     projection_acronym text NOT NULL,
00240     ellipsoid_acronym NOT NULL,
00241     parameters text NOT NULL,
00242     srid integer NOT NULL,
00243     auth_name varchar NOT NULL,
00244     auth_id integer NOT NULL,
00245     is_geo integer NOT NULL);
00246   */
00247 
00248   QString mySql = "select srs_id,description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo from tbl_srs where " + expression + "=" + quotedValue( value );
00249   myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
00250   // XXX Need to free memory from the error msg if one is set
00251   if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00252   {
00253     mSrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) ).toLong();
00254     mDescription = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) );
00255     mProjectionAcronym = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 2 ) );
00256     mEllipsoidAcronym = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 3 ) );
00257     QString toProj4 = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 4 ) );
00258     mSRID = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 5 ) ).toLong();
00259     mAuthId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 6 ) );
00260     mGeoFlag = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 7 ) ).toInt() != 0;
00261 
00262     if ( mSrsId >= USER_CRS_START_ID && mAuthId.isEmpty() )
00263     {
00264       mAuthId = QString( "USER:%1" ).arg( mSrsId );
00265     }
00266     else if ( mAuthId.startsWith( "EPSG:", Qt::CaseInsensitive ) )
00267     {
00268       OSRDestroySpatialReference( mCRS );
00269       mCRS = OSRNewSpatialReference( NULL );
00270       mIsValidFlag = OSRSetFromUserInput( mCRS, mAuthId.toLower().toAscii() ) == OGRERR_NONE;
00271       setMapUnits();
00272     }
00273 
00274     if ( !mIsValidFlag )
00275     {
00276       setProj4String( toProj4 );
00277     }
00278   }
00279   else
00280   {
00281     QgsDebugMsg( "failed : " + mySql );
00282   }
00283   sqlite3_finalize( myPreparedStatement );
00284   sqlite3_close( myDatabase );
00285   return mIsValidFlag;
00286 }
00287 
00288 bool QgsCoordinateReferenceSystem::createFromWkt( QString theWkt )
00289 {
00290   mIsValidFlag = false;
00291 
00292   if ( theWkt.isEmpty() )
00293   {
00294     QgsDebugMsg( "theWkt is uninitialised, operation failed" );
00295     return mIsValidFlag;
00296   }
00297   QgsDebugMsg( "wkt: " + theWkt );
00298   QByteArray ba = theWkt.toLatin1();
00299   const char *pWkt = ba.data();
00300 
00301   OGRErr myInputResult = OSRImportFromWkt( mCRS, ( char ** ) & pWkt );
00302 
00303   if ( myInputResult != OGRERR_NONE )
00304   {
00305     QgsDebugMsg( "\n---------------------------------------------------------------" );
00306     QgsDebugMsg( "This CRS could *** NOT *** be set from the supplied Wkt " );
00307     QgsDebugMsg( "INPUT: " + theWkt );
00308     QgsDebugMsg( QString( "UNUSED WKT: %1" ).arg( pWkt ) );
00309     QgsDebugMsg( "---------------------------------------------------------------\n" );
00310     return mIsValidFlag;
00311   }
00312 
00313   if ( OSRAutoIdentifyEPSG( mCRS ) == OGRERR_NONE )
00314   {
00315     QString authid = QString( "%1:%2" )
00316                      .arg( OSRGetAuthorityName( mCRS, NULL ) )
00317                      .arg( OSRGetAuthorityCode( mCRS, NULL ) );
00318     QgsDebugMsg( "authid recognized as " + authid );
00319     return createFromOgcWmsCrs( authid );
00320   }
00321 
00322   // always morph from esri as it doesn't hurt anything
00323   // FW: Hey, that's not right!  It can screw stuff up! Disable
00324   //myOgrSpatialRef.morphFromESRI();
00325 
00326   // create the proj4 structs needed for transforming
00327   char *proj4src = NULL;
00328   OSRExportToProj4( mCRS, &proj4src );
00329 
00330   //now that we have the proj4string, delegate to createFromProj4 so
00331   // that we can try to fill in the remaining class members...
00332   //create from Proj will set the isValidFlag
00333   if ( !createFromProj4( proj4src ) )
00334   {
00335     CPLFree( proj4src );
00336 
00337     // try fixed up version
00338     OSRFixup( mCRS );
00339 
00340     OSRExportToProj4( mCRS, &proj4src );
00341 
00342     createFromProj4( proj4src );
00343   }
00344 
00345   CPLFree( proj4src );
00346 
00347   return mIsValidFlag;
00348   //setMapunits will be called by createfromproj above
00349 }
00350 
00351 bool QgsCoordinateReferenceSystem::isValid() const
00352 {
00353   return mIsValidFlag;
00354 }
00355 
00356 bool QgsCoordinateReferenceSystem::createFromProj4( const QString theProj4String )
00357 {
00358   //
00359   // Examples:
00360   // +proj=tmerc +lat_0=0 +lon_0=-62 +k=0.999500 +x_0=400000 +y_0=0
00361   // +ellps=clrk80 +towgs84=-255,-15,71,0,0,0,0 +units=m +no_defs
00362   //
00363   // +proj=lcc +lat_1=46.8 +lat_0=46.8 +lon_0=2.337229166666664 +k_0=0.99987742
00364   // +x_0=600000 +y_0=2200000 +a=6378249.2 +b=6356515.000000472 +units=m +no_defs
00365   //
00366   QgsDebugMsg( "proj4: " + theProj4String );
00367   mIsValidFlag = false;
00368 
00369   QRegExp myProjRegExp( "\\+proj=(\\S+)" );
00370   int myStart = myProjRegExp.indexIn( theProj4String );
00371   if ( myStart == -1 )
00372   {
00373     QgsDebugMsg( "proj string supplied has no +proj argument" );
00374     return mIsValidFlag;
00375   }
00376 
00377   mProjectionAcronym = myProjRegExp.cap( 1 );
00378 
00379   QRegExp myEllipseRegExp( "\\+ellps=(\\S+)" );
00380   myStart = myEllipseRegExp.indexIn( theProj4String );
00381   if ( myStart == -1 )
00382   {
00383     QgsDebugMsg( "proj string supplied has no +ellps argument" );
00384     mEllipsoidAcronym = "";
00385   }
00386   else
00387   {
00388     mEllipsoidAcronym = myEllipseRegExp.cap( 1 );
00389   }
00390 
00391   QRegExp myAxisRegExp( "\\+a=(\\S+)" );
00392   myStart = myAxisRegExp.indexIn( theProj4String );
00393   if ( myStart == -1 )
00394   {
00395     QgsDebugMsg( "proj string supplied has no +a argument" );
00396   }
00397 
00398   /*
00399    * We try to match the proj string to and srsid using the following logic:
00400    *
00401    * - perform a whole text search on srs name (if not null). The srs name will
00402    *   have been set if this method has been delegated to from createFromWkt.
00403    * Normally we wouldnt expect this to work, but its worth trying first
00404    * as its quicker than methods below..
00405    */
00406   long mySrsId = 0;
00407   QgsCoordinateReferenceSystem::RecordMap myRecord;
00408 
00409   /*
00410    * - if the above does not match perform a whole text search on proj4 string (if not null)
00411    */
00412   // QgsDebugMsg( "wholetext match on name failed, trying proj4string match" );
00413   myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( theProj4String.trimmed() ) );
00414   if ( myRecord.empty() )
00415   {
00416     // Ticket #722 - aaronr
00417     // Check if we can swap the lat_1 and lat_2 params (if they exist) to see if we match...
00418     // First we check for lat_1 and lat_2
00419     QRegExp myLat1RegExp( "\\+lat_1=\\S+" );
00420     QRegExp myLat2RegExp( "\\+lat_2=\\S+" );
00421     int myStart1 = 0;
00422     int myLength1 = 0;
00423     int myStart2 = 0;
00424     int myLength2 = 0;
00425     QString lat1Str = "";
00426     QString lat2Str = "";
00427     myStart1 = myLat1RegExp.indexIn( theProj4String, myStart1 );
00428     myStart2 = myLat2RegExp.indexIn( theProj4String, myStart2 );
00429     if ( myStart1 != -1 && myStart2 != -1 )
00430     {
00431       myLength1 = myLat1RegExp.matchedLength();
00432       myLength2 = myLat2RegExp.matchedLength();
00433       lat1Str = theProj4String.mid( myStart1 + LAT_PREFIX_LEN, myLength1 - LAT_PREFIX_LEN );
00434       lat2Str = theProj4String.mid( myStart2 + LAT_PREFIX_LEN, myLength2 - LAT_PREFIX_LEN );
00435     }
00436     // If we found the lat_1 and lat_2 we need to swap and check to see if we can find it...
00437     if ( lat1Str != "" && lat2Str != "" )
00438     {
00439       // Make our new string to check...
00440       QString theProj4StringModified = theProj4String;
00441       // First just swap in the lat_2 value for lat_1 value
00442       theProj4StringModified.replace( myStart1 + LAT_PREFIX_LEN, myLength1 - LAT_PREFIX_LEN, lat2Str );
00443       // Now we have to find the lat_2 location again since it has potentially moved...
00444       myStart2 = 0;
00445       myStart2 = myLat2RegExp.indexIn( theProj4String, myStart2 );
00446       theProj4StringModified.replace( myStart2 + LAT_PREFIX_LEN, myLength2 - LAT_PREFIX_LEN, lat1Str );
00447       QgsDebugMsg( "trying proj4string match with swapped lat_1,lat_2" );
00448       myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( theProj4StringModified.trimmed() ) );
00449     }
00450   }
00451 
00452   if ( myRecord.empty() )
00453   {
00454     // match all arameters individually:
00455     // - order of parameters doesn't matter
00456     // - found definition may have more parameters (like +towgs84 in GDAL)
00457     // - retry without datum, if no match is found (looks like +datum<>WGS84 was dropped in GDAL)
00458 
00459     QString sql = "SELECT * FROM tbl_srs WHERE ";
00460     QString delim = "";
00461     QString datum;
00462     foreach( QString param, theProj4String.split( " ", QString::SkipEmptyParts ) )
00463     {
00464       QString arg = QString( "' '||parameters||' ' LIKE %1" ).arg( quotedValue( QString( "% %1 %" ).arg( param ) ) );
00465       if ( param.startsWith( "+datum=" ) )
00466       {
00467         datum = arg;
00468       }
00469       else
00470       {
00471         sql += delim + arg;
00472         delim = " AND ";
00473       }
00474     }
00475 
00476     if ( !datum.isEmpty() )
00477     {
00478       myRecord = getRecord( sql + delim + datum );
00479     }
00480 
00481     if ( myRecord.empty() )
00482     {
00483       // datum might have disappeared in definition - retry without it
00484       myRecord = getRecord( sql );
00485     }
00486   }
00487 
00488   if ( !myRecord.empty() )
00489   {
00490     mySrsId = myRecord["srs_id"].toLong();
00491     QgsDebugMsg( "proj4string param match search for srsid returned srsid: " + QString::number( mySrsId ) );
00492     if ( mySrsId > 0 )
00493     {
00494       createFromSrsId( mySrsId );
00495     }
00496   }
00497   else
00498   {
00499     // Last ditch attempt to piece together what we know of the projection to find a match...
00500     QgsDebugMsg( "globbing search for srsid from this proj string" );
00501     setProj4String( theProj4String );
00502     mySrsId = findMatchingProj();
00503     QgsDebugMsg( "globbing search for srsid returned srsid: " + QString::number( mySrsId ) );
00504     if ( mySrsId > 0 )
00505     {
00506       createFromSrsId( mySrsId );
00507     }
00508     else
00509     {
00510       mIsValidFlag = false;
00511     }
00512   }
00513 
00514   // if we failed to look up the projection in database, don't worry. we can still use it :)
00515   if ( !mIsValidFlag )
00516   {
00517     QgsDebugMsg( "Projection is not found in databases." );
00518     setProj4String( theProj4String );
00519 
00520     // Is the SRS is valid now, we know it's a decent +proj string that can be entered into the srs.db
00521     if ( mIsValidFlag )
00522     {
00523       // but the proj.4 parsed string might already be in our database
00524       myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( toProj4() ) );
00525       if ( myRecord.empty() )
00526       {
00527         // It's not, so try to add it
00528         QgsDebugMsg( "Projection appears to be valid. Save to database!" );
00529         mIsValidFlag = saveAsUserCRS();
00530 
00531         if ( mIsValidFlag )
00532         {
00533           // but validate that it's there afterwards
00534           myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( toProj4() ) );
00535         }
00536       }
00537 
00538       if ( !myRecord.empty() )
00539       {
00540         // take the srid from the record
00541         mySrsId = myRecord["srs_id"].toLong();
00542         QgsDebugMsg( "proj4string match search for srsid returned srsid: " + QString::number( mySrsId ) );
00543         if ( mySrsId > 0 )
00544         {
00545           createFromSrsId( mySrsId );
00546         }
00547         else
00548         {
00549           QgsDebugMsg( QString( "invalid srid %1 found" ).arg( mySrsId ) );
00550           mIsValidFlag = false;
00551         }
00552       }
00553       else
00554       {
00555         QgsDebugMsg( "Couldn't find newly added proj string?" );
00556         mIsValidFlag = false;
00557       }
00558     }
00559   }
00560 
00561 
00562   return mIsValidFlag;
00563 }
00564 
00565 //private method meant for internal use by this class only
00566 QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord( QString theSql )
00567 {
00568   QString myDatabaseFileName;
00569   QgsCoordinateReferenceSystem::RecordMap myMap;
00570   QString myFieldName;
00571   QString myFieldValue;
00572   sqlite3      *myDatabase;
00573   const char   *myTail;
00574   sqlite3_stmt *myPreparedStatement;
00575   int           myResult;
00576 
00577   QgsDebugMsg( "running query: " + theSql );
00578   // Get the full path name to the sqlite3 spatial reference database.
00579   myDatabaseFileName = QgsApplication::srsDbFilePath();
00580   QFileInfo myInfo( myDatabaseFileName );
00581   if ( !myInfo.exists() )
00582   {
00583     QgsDebugMsg( "failed : " + myDatabaseFileName +
00584                  " does not exist!" );
00585     return myMap;
00586   }
00587 
00588   //check the db is available
00589   myResult = openDb( myDatabaseFileName, &myDatabase );
00590   if ( myResult != SQLITE_OK )
00591   {
00592     return myMap;
00593   }
00594 
00595   myResult = sqlite3_prepare( myDatabase, theSql.toUtf8(), theSql.toUtf8().length(), &myPreparedStatement, &myTail );
00596   // XXX Need to free memory from the error msg if one is set
00597   if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00598   {
00599     QgsDebugMsg( "trying system srs.db" );
00600     int myColumnCount = sqlite3_column_count( myPreparedStatement );
00601     //loop through each column in the record adding its expression name and value to the map
00602     for ( int myColNo = 0; myColNo < myColumnCount; myColNo++ )
00603     {
00604       myFieldName = QString::fromUtf8(( char * )sqlite3_column_name( myPreparedStatement, myColNo ) );
00605       myFieldValue = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, myColNo ) );
00606       myMap[myFieldName] = myFieldValue;
00607     }
00608   }
00609   else
00610   {
00611     QgsDebugMsg( "trying user qgis.db" );
00612     sqlite3_finalize( myPreparedStatement );
00613     sqlite3_close( myDatabase );
00614 
00615     myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
00616     QFileInfo myFileInfo;
00617     myFileInfo.setFile( myDatabaseFileName );
00618     if ( !myFileInfo.exists( ) )
00619     {
00620       QgsDebugMsg( "user qgis.db not found" );
00621       return myMap;
00622     }
00623 
00624     //check the db is available
00625     myResult = openDb( myDatabaseFileName, &myDatabase );
00626     if ( myResult != SQLITE_OK )
00627     {
00628       return myMap;
00629     }
00630 
00631     myResult = sqlite3_prepare( myDatabase, theSql.toUtf8(), theSql.toUtf8().length(), &myPreparedStatement, &myTail );
00632     // XXX Need to free memory from the error msg if one is set
00633     if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00634     {
00635       int myColumnCount = sqlite3_column_count( myPreparedStatement );
00636       //loop through each column in the record adding its field name and value to the map
00637       for ( int myColNo = 0; myColNo < myColumnCount; myColNo++ )
00638       {
00639         myFieldName = QString::fromUtf8(( char * )sqlite3_column_name( myPreparedStatement, myColNo ) );
00640         myFieldValue = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, myColNo ) );
00641         myMap[myFieldName] = myFieldValue;
00642       }
00643     }
00644     else
00645     {
00646       QgsDebugMsg( "failed :  " + theSql );
00647 
00648     }
00649   }
00650   sqlite3_finalize( myPreparedStatement );
00651   sqlite3_close( myDatabase );
00652 
00653 #ifdef QGISDEBUG
00654   QgsDebugMsg( "retrieved:  " + theSql );
00655   RecordMap::Iterator it;
00656   for ( it = myMap.begin(); it != myMap.end(); ++it )
00657   {
00658     QgsDebugMsgLevel( it.key() + " => " + it.value(), 2 );
00659   }
00660 #endif
00661 
00662   return myMap;
00663 }
00664 
00665 // Accessors -----------------------------------
00666 
00667 long QgsCoordinateReferenceSystem::srsid() const
00668 {
00669   return mSrsId;
00670 }
00671 
00672 long QgsCoordinateReferenceSystem::postgisSrid() const
00673 {
00674 
00675   return mSRID;
00676 
00677 }
00678 
00679 long QgsCoordinateReferenceSystem::epsg() const
00680 {
00681   if ( mAuthId.startsWith( "EPSG:", Qt::CaseInsensitive ) )
00682     return mAuthId.mid( 5 ).toLong();
00683   else
00684     return 0;
00685 }
00686 
00687 QString QgsCoordinateReferenceSystem::authid() const
00688 {
00689   return mAuthId;
00690 }
00691 
00692 QString QgsCoordinateReferenceSystem::description() const
00693 {
00694   if ( mDescription.isNull() )
00695   {
00696     return "";
00697   }
00698   else
00699   {
00700     return mDescription;
00701   }
00702 }
00703 
00704 QString QgsCoordinateReferenceSystem::projectionAcronym() const
00705 {
00706   if ( mProjectionAcronym.isNull() )
00707   {
00708     return "";
00709   }
00710   else
00711   {
00712     return mProjectionAcronym;
00713   }
00714 }
00715 
00716 QString QgsCoordinateReferenceSystem::ellipsoidAcronym() const
00717 {
00718   if ( mEllipsoidAcronym.isNull() )
00719   {
00720     return "";
00721   }
00722   else
00723   {
00724     return mEllipsoidAcronym;
00725   }
00726 }
00727 
00728 QString QgsCoordinateReferenceSystem::toProj4() const
00729 {
00730   if ( !mIsValidFlag )
00731     return "";
00732 
00733   QString toProj4;
00734   char *proj4src = NULL;
00735   OSRExportToProj4( mCRS, &proj4src );
00736   toProj4 = proj4src;
00737   CPLFree( proj4src );
00738 
00739   // Stray spaces at the end?
00740   return toProj4.trimmed();
00741 }
00742 
00743 bool QgsCoordinateReferenceSystem::geographicFlag() const
00744 {
00745   return mGeoFlag;
00746 }
00747 
00748 QGis::UnitType QgsCoordinateReferenceSystem::mapUnits() const
00749 {
00750   return mMapUnits;
00751 }
00752 
00753 
00754 // Mutators -----------------------------------
00755 
00756 
00757 void QgsCoordinateReferenceSystem::setInternalId( long theSrsId )
00758 {
00759   mSrsId = theSrsId;
00760 }
00761 void QgsCoordinateReferenceSystem::setAuthId( QString authId )
00762 {
00763   mAuthId = authId;
00764 }
00765 void QgsCoordinateReferenceSystem::setSrid( long theSrid )
00766 {
00767   mSRID = theSrid;
00768 }
00769 void QgsCoordinateReferenceSystem::setDescription( QString theDescription )
00770 {
00771   mDescription = theDescription;
00772 }
00773 void QgsCoordinateReferenceSystem::setProj4String( QString theProj4String )
00774 {
00775   const char *oldlocale = setlocale( LC_NUMERIC, NULL );
00776 
00777   setlocale( LC_NUMERIC, "C" );
00778   OSRDestroySpatialReference( mCRS );
00779   mCRS = OSRNewSpatialReference( NULL );
00780   mIsValidFlag = OSRImportFromProj4( mCRS, theProj4String.toLatin1().constData() ) == OGRERR_NONE;
00781   setMapUnits();
00782 
00783 #if defined(QGISDEBUG) && QGISDEBUG>=3
00784   debugPrint();
00785 #endif
00786 
00787   setlocale( LC_NUMERIC, oldlocale );
00788 }
00789 void QgsCoordinateReferenceSystem::setGeographicFlag( bool theGeoFlag )
00790 {
00791   mGeoFlag = theGeoFlag;
00792 }
00793 void QgsCoordinateReferenceSystem::setEpsg( long theEpsg )
00794 {
00795   mAuthId = QString( "EPSG:%1" ).arg( theEpsg );
00796 }
00797 void  QgsCoordinateReferenceSystem::setProjectionAcronym( QString theProjectionAcronym )
00798 {
00799   mProjectionAcronym = theProjectionAcronym;
00800 }
00801 void  QgsCoordinateReferenceSystem::setEllipsoidAcronym( QString theEllipsoidAcronym )
00802 {
00803   mEllipsoidAcronym = theEllipsoidAcronym;
00804 }
00805 
00806 void QgsCoordinateReferenceSystem::setMapUnits()
00807 {
00808   if ( !mIsValidFlag )
00809   {
00810     mMapUnits = QGis::UnknownUnit;
00811     return;
00812   }
00813 
00814   char *unitName;
00815 
00816   // Of interest to us is that this call adds in a unit parameter if
00817   // one doesn't already exist.
00818   OSRFixup( mCRS );
00819 
00820   if ( OSRIsProjected( mCRS ) )
00821   {
00822     double toMeter = OSRGetLinearUnits( mCRS, &unitName );
00823     QString unit( unitName );
00824 
00825     // If the units parameter was created during the Fixup() call
00826     // above, the name of the units is likely to be 'unknown'. Try to
00827     // do better than that ... (but perhaps ogr should be enhanced to
00828     // do this instead?).
00829 
00830     static const double feetToMeter = 0.3048;
00831     static const double smallNum = 1e-3;
00832 
00833     if ( qAbs( toMeter - feetToMeter ) < smallNum )
00834       unit = "Foot";
00835 
00836     QgsDebugMsg( "Projection has linear units of " + unit );
00837 
00838     if ( doubleNear( toMeter, 1.0 ) ) //Unit name for meters would be "metre"
00839       mMapUnits = QGis::Meters;
00840     else if ( unit == "Foot" )
00841       mMapUnits = QGis::Feet;
00842     else
00843     {
00844       QgsDebugMsg( "Unsupported map units of " + unit );
00845       mMapUnits = QGis::UnknownUnit;
00846     }
00847   }
00848   else
00849   {
00850     OSRGetAngularUnits( mCRS, &unitName );
00851     QString unit( unitName );
00852     if ( unit == "degree" )
00853       mMapUnits = QGis::Degrees;
00854     else
00855     {
00856       QgsDebugMsg( "Unsupported map units of " + unit );
00857       mMapUnits = QGis::UnknownUnit;
00858     }
00859     QgsDebugMsgLevel( "Projection has angular units of " + unit, 3 );
00860   }
00861 }
00862 
00863 /*
00864 *    check if srs is a geocs or a proj cs (using ogr isGeographic)
00865 *   then sequentially walk through the database (first users qgis.db srs tbl then
00866 *   system srs.db tbl), converting each entry into an ogr srs and using isSame
00867 *   or isSameGeocs (essentially calling the == overloaded operator). We'll try to
00868 *   be smart about this and first parse out the proj and ellpse strings and only
00869 *   check for a match in entities that have the same ellps and proj entries so
00870 *   that it doesnt munch yer cpu so much.
00871 */
00872 long QgsCoordinateReferenceSystem::findMatchingProj()
00873 {
00874   QgsDebugMsg( "entered." );
00875   if ( mEllipsoidAcronym.isNull() ||  mProjectionAcronym.isNull() || !mIsValidFlag )
00876   {
00877     QgsDebugMsg( "QgsCoordinateReferenceSystem::findMatchingProj will only work if prj acr ellipsoid acr and proj4string are set"
00878                  " and the current projection is valid!" );
00879     return 0;
00880   }
00881 
00882   sqlite3      *myDatabase;
00883   const char   *myTail;
00884   sqlite3_stmt *myPreparedStatement;
00885   int           myResult;
00886 
00887   // Set up the query to retrieve the projection information needed to populate the list
00888   QString mySql = QString( "select srs_id,parameters from tbl_srs where projection_acronym=%1 and ellipsoid_acronym=%2" )
00889                   .arg( quotedValue( mProjectionAcronym ) )
00890                   .arg( quotedValue( mEllipsoidAcronym ) );
00891   // Get the full path name to the sqlite3 spatial reference database.
00892   QString myDatabaseFileName = QgsApplication::srsDbFilePath();
00893 
00894   //check the db is available
00895   myResult = openDb( myDatabaseFileName, &myDatabase );
00896   if ( myResult != SQLITE_OK )
00897   {
00898     return 0;
00899   }
00900 
00901   myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
00902 // XXX Need to free memory from the error msg if one is set
00903   if ( myResult == SQLITE_OK )
00904   {
00905 
00906     while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00907     {
00908       QString mySrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
00909       QString myProj4String = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) );
00910       if ( equals( myProj4String ) )
00911       {
00912         QgsDebugMsg( "-------> MATCH FOUND in srs.db srsid: " + mySrsId );
00913         // close the sqlite3 statement
00914         sqlite3_finalize( myPreparedStatement );
00915         sqlite3_close( myDatabase );
00916         return mySrsId.toLong();
00917       }
00918       else
00919       {
00920 // QgsDebugMsg(QString(" Not matched : %1").arg(myProj4String));
00921       }
00922     }
00923   }
00924   QgsDebugMsg( "no match found in srs.db, trying user db now!" );
00925   // close the sqlite3 statement
00926   sqlite3_finalize( myPreparedStatement );
00927   sqlite3_close( myDatabase );
00928   //
00929   // Try the users db now
00930   //
00931 
00932   myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
00933   //check the db is available
00934   myResult = openDb( myDatabaseFileName, &myDatabase );
00935   if ( myResult != SQLITE_OK )
00936   {
00937     return 0;
00938   }
00939 
00940   myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
00941 // XXX Need to free memory from the error msg if one is set
00942   if ( myResult == SQLITE_OK )
00943   {
00944 
00945     while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00946     {
00947       QString mySrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
00948       QString myProj4String = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) );
00949       if ( equals( myProj4String ) )
00950       {
00951         QgsDebugMsg( "-------> MATCH FOUND in user qgis.db srsid: " + mySrsId );
00952         // close the sqlite3 statement
00953         sqlite3_finalize( myPreparedStatement );
00954         sqlite3_close( myDatabase );
00955         return mySrsId.toLong();
00956       }
00957       else
00958       {
00959 // QgsDebugMsg(QString(" Not matched : %1").arg(myProj4String));
00960       }
00961     }
00962   }
00963   QgsDebugMsg( "no match found in user db" );
00964 
00965   // close the sqlite3 statement
00966   sqlite3_finalize( myPreparedStatement );
00967   sqlite3_close( myDatabase );
00968   return 0;
00969 }
00970 
00971 bool QgsCoordinateReferenceSystem::operator==( const QgsCoordinateReferenceSystem &theSrs )
00972 {
00973   if ( !mIsValidFlag || !theSrs.mIsValidFlag )
00974   {
00975     return false;
00976   }
00977   char *thisStr;
00978   char *otherStr;
00979 
00980   // OSRIsSame is not relaibel when it comes to comparing +towgs84 parameters
00981   // Use string compare on WKT instead.
00982   if (( OSRExportToWkt( mCRS, &thisStr ) == OGRERR_NONE ) )
00983   {
00984     if ( OSRExportToWkt( theSrs.mCRS, &otherStr ) == OGRERR_NONE )
00985     {
00986       QgsDebugMsgLevel( QString( "Comparing " ) + thisStr, 3 );
00987       QgsDebugMsgLevel( QString( "     with " ) + otherStr, 3 );
00988       if ( !strcmp( thisStr, otherStr ) )
00989       {
00990         QgsDebugMsgLevel( QString( "MATCHED!" ) + otherStr, 3 );
00991         CPLFree( thisStr );
00992         CPLFree( otherStr );
00993         return true;
00994       }
00995       CPLFree( otherStr );
00996     }
00997     CPLFree( thisStr );
00998   }
00999   return false;
01000 }
01001 
01002 bool QgsCoordinateReferenceSystem::operator!=( const QgsCoordinateReferenceSystem &theSrs )
01003 {
01004   return  !( *this == theSrs );
01005 }
01006 
01007 bool QgsCoordinateReferenceSystem::equals( QString theProj4String )
01008 {
01009   QgsCoordinateReferenceSystem r;
01010   r.setProj4String( theProj4String );
01011   return *this == r;
01012 }
01013 
01014 QString QgsCoordinateReferenceSystem::toWkt() const
01015 {
01016   QString myWkt;
01017   char* Wkt;
01018   if ( OSRExportToWkt( mCRS, &Wkt ) == OGRERR_NONE )
01019   {
01020     myWkt = Wkt;
01021     OGRFree( Wkt );
01022   }
01023 
01024   return myWkt;
01025 }
01026 
01027 bool QgsCoordinateReferenceSystem::readXML( QDomNode & theNode )
01028 {
01029   QgsDebugMsg( "Reading Spatial Ref Sys from xml ------------------------!" );
01030   QDomNode srsNode  = theNode.namedItem( "spatialrefsys" );
01031 
01032   if ( ! srsNode.isNull() )
01033   {
01034     bool initialized = false;
01035 
01036     QDomNode myNode = srsNode.namedItem( "authid" );
01037     if ( !myNode.isNull() )
01038     {
01039       initialized = createFromOgcWmsCrs( myNode.toElement().text() );
01040     }
01041 
01042     if ( !initialized )
01043     {
01044       myNode = srsNode.namedItem( "epsg" );
01045       if ( !myNode.isNull() )
01046         initialized = createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( myNode.toElement().text().toLong() ) );
01047     }
01048 
01049     if ( initialized )
01050     {
01051       QgsDebugMsg( "Set from auth id" );
01052     }
01053     else
01054     {
01055       myNode = srsNode.namedItem( "proj4" );
01056 
01057       if ( createFromProj4( myNode.toElement().text() ) )
01058       {
01059         // createFromProj4() sets everything, including map units
01060         QgsDebugMsg( "Setting from proj4 string" );
01061       }
01062       else
01063       {
01064         QgsDebugMsg( "Setting from elements one by one" );
01065 
01066         myNode = srsNode.namedItem( "proj4" );
01067         setProj4String( myNode.toElement().text() );
01068 
01069         myNode = srsNode.namedItem( "srsid" );
01070         setInternalId( myNode.toElement().text().toLong() );
01071 
01072         myNode = srsNode.namedItem( "srid" );
01073         setSrid( myNode.toElement().text().toLong() );
01074 
01075         myNode = srsNode.namedItem( "authid" );
01076         setAuthId( myNode.toElement().text() );
01077 
01078         myNode = srsNode.namedItem( "description" );
01079         setDescription( myNode.toElement().text() );
01080 
01081         myNode = srsNode.namedItem( "projectionacronym" );
01082         setProjectionAcronym( myNode.toElement().text() );
01083 
01084         myNode = srsNode.namedItem( "ellipsoidacronym" );
01085         setEllipsoidAcronym( myNode.toElement().text() );
01086 
01087         myNode = srsNode.namedItem( "geographicflag" );
01088         if ( myNode.toElement().text().compare( "true" ) )
01089         {
01090           setGeographicFlag( true );
01091         }
01092         else
01093         {
01094           setGeographicFlag( false );
01095         }
01096 
01097         //make sure the map units have been set
01098         setMapUnits();
01099 
01100         //@TODO this srs needs to be validated!!!
01101         mIsValidFlag = true;//shamelessly hard coded for now
01102       }
01103     }
01104   }
01105   else
01106   {
01107     // Return default CRS if none was found in the XML.
01108     createFromId( GEOCRS_ID, InternalCrsId );
01109   }
01110   return true;
01111 }
01112 
01113 bool QgsCoordinateReferenceSystem::writeXML( QDomNode & theNode, QDomDocument & theDoc ) const
01114 {
01115 
01116   QDomElement myLayerNode = theNode.toElement();
01117   QDomElement mySrsElement  = theDoc.createElement( "spatialrefsys" );
01118 
01119   QDomElement myProj4Element  = theDoc.createElement( "proj4" );
01120   myProj4Element.appendChild( theDoc.createTextNode( toProj4() ) );
01121   mySrsElement.appendChild( myProj4Element );
01122 
01123   QDomElement mySrsIdElement  = theDoc.createElement( "srsid" );
01124   mySrsIdElement.appendChild( theDoc.createTextNode( QString::number( srsid() ) ) );
01125   mySrsElement.appendChild( mySrsIdElement );
01126 
01127   QDomElement mySridElement  = theDoc.createElement( "srid" );
01128   mySridElement.appendChild( theDoc.createTextNode( QString::number( postgisSrid() ) ) );
01129   mySrsElement.appendChild( mySridElement );
01130 
01131   QDomElement myEpsgElement  = theDoc.createElement( "authid" );
01132   myEpsgElement.appendChild( theDoc.createTextNode( authid() ) );
01133   mySrsElement.appendChild( myEpsgElement );
01134 
01135   QDomElement myDescriptionElement  = theDoc.createElement( "description" );
01136   myDescriptionElement.appendChild( theDoc.createTextNode( description() ) );
01137   mySrsElement.appendChild( myDescriptionElement );
01138 
01139   QDomElement myProjectionAcronymElement  = theDoc.createElement( "projectionacronym" );
01140   myProjectionAcronymElement.appendChild( theDoc.createTextNode( projectionAcronym() ) );
01141   mySrsElement.appendChild( myProjectionAcronymElement );
01142 
01143   QDomElement myEllipsoidAcronymElement  = theDoc.createElement( "ellipsoidacronym" );
01144   myEllipsoidAcronymElement.appendChild( theDoc.createTextNode( ellipsoidAcronym() ) );
01145   mySrsElement.appendChild( myEllipsoidAcronymElement );
01146 
01147   QDomElement myGeographicFlagElement  = theDoc.createElement( "geographicflag" );
01148   QString myGeoFlagText = "false";
01149   if ( geographicFlag() )
01150   {
01151     myGeoFlagText = "true";
01152   }
01153 
01154   myGeographicFlagElement.appendChild( theDoc.createTextNode( myGeoFlagText ) );
01155   mySrsElement.appendChild( myGeographicFlagElement );
01156 
01157   myLayerNode.appendChild( mySrsElement );
01158 
01159   return true;
01160 }
01161 
01162 
01163 
01164 //
01165 // Static helper methods below this point only please!
01166 //
01167 
01168 
01169 // Returns the whole proj4 string for the selected srsid
01170 //this is a static method! NOTE I've made it private for now to reduce API clutter TS
01171 QString QgsCoordinateReferenceSystem::proj4FromSrsId( const int theSrsId )
01172 {
01173 
01174   QString myDatabaseFileName;
01175   QString myProjString;
01176   QString mySql = "select parameters from tbl_srs where srs_id = ";
01177   mySql += QString::number( theSrsId );
01178 
01179   QgsDebugMsg( "mySrsId = " + QString::number( theSrsId ) );
01180   QgsDebugMsg( "USER_CRS_START_ID = " + QString::number( USER_CRS_START_ID ) );
01181   QgsDebugMsg( "Selection sql : " + mySql );
01182 
01183   //
01184   // Determine if this is a user projection or a system on
01185   // user projection defs all have srs_id >= 100000
01186   //
01187   if ( theSrsId >= USER_CRS_START_ID )
01188   {
01189     myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
01190     QFileInfo myFileInfo;
01191     myFileInfo.setFile( myDatabaseFileName );
01192     if ( !myFileInfo.exists( ) ) //its unlikely that this condition will ever be reached
01193     {
01194       QgsDebugMsg( "users qgis.db not found" );
01195       return NULL;
01196     }
01197   }
01198   else //must be  a system projection then
01199   {
01200     myDatabaseFileName = QgsApplication::srsDbFilePath();
01201   }
01202   QgsDebugMsg( "db = " + myDatabaseFileName );
01203 
01204   sqlite3 *db;
01205   int rc;
01206   rc = openDb( myDatabaseFileName, &db );
01207   if ( rc )
01208   {
01209     return QString();
01210   }
01211   // prepare the sql statement
01212   const char *pzTail;
01213   sqlite3_stmt *ppStmt;
01214 
01215   rc = sqlite3_prepare( db, mySql.toUtf8(), mySql.toUtf8().length(), &ppStmt, &pzTail );
01216   // XXX Need to free memory from the error msg if one is set
01217 
01218   if ( rc == SQLITE_OK )
01219   {
01220     if ( sqlite3_step( ppStmt ) == SQLITE_ROW )
01221     {
01222       myProjString = QString::fromUtf8(( char* )sqlite3_column_text( ppStmt, 0 ) );
01223     }
01224   }
01225   // close the statement
01226   sqlite3_finalize( ppStmt );
01227   // close the database
01228   sqlite3_close( db );
01229 
01230   //Q_ASSERT(myProjString.length() > 0);
01231   return myProjString;
01232 }
01233 
01234 int QgsCoordinateReferenceSystem::openDb( QString path, sqlite3 **db )
01235 {
01236   QgsDebugMsgLevel( "path = " + path, 3 );
01237   int myResult = sqlite3_open( path.toUtf8().data(), db );
01238 
01239   if ( myResult != SQLITE_OK )
01240   {
01241     QgsDebugMsg( "Can't open database: " + QString( sqlite3_errmsg( *db ) ) );
01242     // XXX This will likely never happen since on open, sqlite creates the
01243     //     database if it does not exist.
01244     // ... unfortunately it happens on Windows
01245     QgsMessageOutput* output = QgsMessageOutput::createMessageOutput();
01246     output->setTitle( "Error" );
01247     output->setMessage( QObject::tr( "Could not open CRS database %1<br>Error(%2): %3" )
01248                         .arg( path )
01249                         .arg( myResult )
01250                         .arg( sqlite3_errmsg( *db ) ), QgsMessageOutput::MessageText );
01251     output->showMessage();
01252   }
01253   return myResult;
01254 }
01255 
01256 void QgsCoordinateReferenceSystem::setCustomSrsValidation( CUSTOM_CRS_VALIDATION f )
01257 {
01258   mCustomSrsValidation = f;
01259 }
01260 
01261 CUSTOM_CRS_VALIDATION QgsCoordinateReferenceSystem::customSrsValidation()
01262 {
01263   return mCustomSrsValidation;
01264 }
01265 
01266 void QgsCoordinateReferenceSystem::debugPrint()
01267 {
01268   QgsDebugMsg( "***SpatialRefSystem***" );
01269   QgsDebugMsg( "* Valid : " + ( mIsValidFlag ? QString( "true" ) : QString( "false" ) ) );
01270   QgsDebugMsg( "* SrsId : " + QString::number( mSrsId ) );
01271   QgsDebugMsg( "* Proj4 : " + toProj4() );
01272   QgsDebugMsg( "* WKT   : " + toWkt() );
01273   QgsDebugMsg( "* Desc. : " + mDescription );
01274   if ( mapUnits() == QGis::Meters )
01275   {
01276     QgsDebugMsg( "* Units : meters" );
01277   }
01278   else if ( mapUnits() == QGis::Feet )
01279   {
01280     QgsDebugMsg( "* Units : feet" );
01281   }
01282   else if ( mapUnits() == QGis::Degrees )
01283   {
01284     QgsDebugMsg( "* Units : degrees" );
01285   }
01286 }
01287 
01288 void QgsCoordinateReferenceSystem::setValidationHint( QString html )
01289 {
01290   mValidationHint = html;
01291 }
01292 
01293 QString QgsCoordinateReferenceSystem::validationHint()
01294 {
01295   return mValidationHint;
01296 }
01297 
01300 
01301 bool QgsCoordinateReferenceSystem::saveAsUserCRS()
01302 {
01303   if ( ! mIsValidFlag )
01304   {
01305     QgsDebugMsg( "Can't save an invalid CRS!" );
01306     return false;
01307   }
01308 
01309   QString mySql;
01310   QString myName = QString( " * %1 (%2)" )
01311                    .arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ) )
01312                    .arg( toProj4() );
01313 
01314   //if this is the first record we need to ensure that its srs_id is 10000. For
01315   //any rec after that sqlite3 will take care of the autonumering
01316   //this was done to support sqlite 3.0 as it does not yet support
01317   //the autoinc related system tables.
01318   if ( getRecordCount() == 0 )
01319   {
01320     mySql = "insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ("
01321             + QString::number( USER_CRS_START_ID )
01322             + "," + quotedValue( myName )
01323             + "," + quotedValue( projectionAcronym() )
01324             + "," + quotedValue( ellipsoidAcronym() )
01325             + "," + quotedValue( toProj4() )
01326             + ",0)"; // <-- is_geo shamelessly hard coded for now
01327   }
01328   else
01329   {
01330     mySql = "insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ("
01331             + quotedValue( myName )
01332             + "," + quotedValue( projectionAcronym() )
01333             + "," + quotedValue( ellipsoidAcronym() )
01334             + "," + quotedValue( toProj4() )
01335             + ",0)"; // <-- is_geo shamelessly hard coded for now
01336   }
01337   sqlite3      *myDatabase;
01338   const char   *myTail;
01339   sqlite3_stmt *myPreparedStatement;
01340   int           myResult;
01341   //check the db is available
01342   myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
01343   if ( myResult != SQLITE_OK )
01344   {
01345     QgsDebugMsg( QString( "Can't open or create database %1: %2" )
01346                  .arg( QgsApplication::qgisUserDbFilePath() )
01347                  .arg( sqlite3_errmsg( myDatabase ) ) );
01348     return false;
01349   }
01350   QgsDebugMsg( QString( "Update or insert sql \n%1" ).arg( mySql ) );
01351   myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
01352   sqlite3_step( myPreparedStatement );
01353   // XXX Need to free memory from the error msg if one is set
01354   return myResult == SQLITE_OK;
01355 }
01356 
01357 long QgsCoordinateReferenceSystem::getRecordCount()
01358 {
01359   sqlite3      *myDatabase;
01360   const char   *myTail;
01361   sqlite3_stmt *myPreparedStatement;
01362   int           myResult;
01363   long          myRecordCount = 0;
01364   //check the db is available
01365   myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
01366   if ( myResult != SQLITE_OK )
01367   {
01368     QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
01369     return 0;
01370   }
01371   // Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
01372   QString mySql = "select count(*) from tbl_srs";
01373   myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
01374   // XXX Need to free memory from the error msg if one is set
01375   if ( myResult == SQLITE_OK )
01376   {
01377     if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
01378     {
01379       QString myRecordCountString = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
01380       myRecordCount = myRecordCountString.toLong();
01381     }
01382   }
01383   // close the sqlite3 statement
01384   sqlite3_finalize( myPreparedStatement );
01385   sqlite3_close( myDatabase );
01386   return myRecordCount;
01387 }
01388 
01389 QString QgsCoordinateReferenceSystem::quotedValue( QString value )
01390 {
01391   value.replace( "'", "''" );
01392   return value.prepend( "'" ).append( "'" );
01393 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines