00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00030 #include "qgsapplication.h"
00031 #include "qgscrscache.h"
00032 #include "qgslogger.h"
00033 #include "qgsmessagelog.h"
00034 #include "qgis.h"
00035
00036 #include <sqlite3.h>
00037 #include <proj_api.h>
00038
00039
00040 #include <ogr_srs_api.h>
00041 #include <cpl_error.h>
00042 #include <cpl_conv.h>
00043
00044 CUSTOM_CRS_VALIDATION QgsCoordinateReferenceSystem::mCustomSrsValidation = NULL;
00045
00046
00047
00048 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem()
00049 : mMapUnits( QGis::UnknownUnit )
00050 , mIsValidFlag( 0 )
00051 , mValidationHint( "" )
00052 {
00053 mCRS = OSRNewSpatialReference( NULL );
00054 }
00055
00056 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( QString theDefinition )
00057 : mMapUnits( QGis::UnknownUnit )
00058 , mIsValidFlag( 0 )
00059 , mValidationHint( "" )
00060 {
00061 mCRS = OSRNewSpatialReference( NULL );
00062 createFromString( theDefinition );
00063 }
00064
00065
00066 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( const long theId, CrsType theType )
00067 : mMapUnits( QGis::UnknownUnit )
00068 , mIsValidFlag( 0 )
00069 , mValidationHint( "" )
00070 {
00071 mCRS = OSRNewSpatialReference( NULL );
00072 createFromId( theId, theType );
00073 }
00074
00075 QgsCoordinateReferenceSystem::~QgsCoordinateReferenceSystem()
00076 {
00077 OSRDestroySpatialReference( mCRS );
00078 }
00079
00080 bool QgsCoordinateReferenceSystem::createFromId( const long theId, CrsType theType )
00081 {
00082 bool result = false;
00083 switch ( theType )
00084 {
00085 case InternalCrsId:
00086 result = createFromSrsId( theId );
00087 break;
00088 case PostgisCrsId:
00089 result = createFromSrid( theId );
00090 break;
00091 case EpsgCrsId:
00092 result = createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( theId ) );
00093 break;
00094 default:
00095
00096 QgsDebugMsg( "Unexpected case reached!" );
00097 };
00098 return result;
00099 }
00100
00101 bool QgsCoordinateReferenceSystem::createFromString( const QString theDefinition )
00102 {
00103 bool result = false;
00104 QRegExp reCrsId( "^(epsg|postgis|internal)\\:(\\d+)$", Qt::CaseInsensitive );
00105 if ( reCrsId.indexIn( theDefinition ) == 0 )
00106 {
00107 QString authName = reCrsId.cap( 1 ).toLower();
00108 CrsType type = InternalCrsId;
00109 if ( authName == "epsg" )
00110 type = EpsgCrsId;
00111 if ( authName == "postgis" )
00112 type = PostgisCrsId;
00113 long id = reCrsId.cap( 2 ).toLong();
00114 result = createFromId( id, type );
00115 }
00116 else
00117 {
00118 QRegExp reCrsStr( "^(?:(wkt|proj4)\\:)?(.+)$", Qt::CaseInsensitive );
00119 if ( reCrsStr.indexIn( theDefinition ) == 0 )
00120 {
00121 if ( reCrsStr.cap( 1 ).toLower() == "proj4" )
00122 {
00123 result = createFromProj4( reCrsStr.cap( 2 ) );
00124 }
00125 else
00126 {
00127 result = createFromWkt( reCrsStr.cap( 2 ) );
00128 }
00129 }
00130 }
00131 return result;
00132 }
00133
00134 bool QgsCoordinateReferenceSystem::createFromOgcWmsCrs( QString theCrs )
00135 {
00136 QRegExp re( "(user|custom|qgis):(\\d+)", Qt::CaseInsensitive );
00137 if ( re.exactMatch( theCrs ) && createFromSrsId( re.cap( 2 ).toInt() ) )
00138 {
00139 return true;
00140 }
00141
00142 if ( loadFromDb( QgsApplication::srsDbFilePath(), "lower(auth_name||':'||auth_id)", theCrs.toLower() ) )
00143 return true;
00144
00145 if ( theCrs.compare( "CRS:84", Qt::CaseInsensitive ) == 0 )
00146 {
00147 createFromSrsId( GEOCRS_ID );
00148 return true;
00149 }
00150
00151 return false;
00152 }
00153
00154 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &srs )
00155 {
00156 mCRS = OSRNewSpatialReference( NULL );
00157 *this = srs;
00158 }
00159
00160
00161 QgsCoordinateReferenceSystem& QgsCoordinateReferenceSystem::operator=( const QgsCoordinateReferenceSystem & srs )
00162 {
00163 if ( &srs != this )
00164 {
00165 mSrsId = srs.mSrsId;
00166 mDescription = srs.mDescription;
00167 mProjectionAcronym = srs.mProjectionAcronym;
00168 mEllipsoidAcronym = srs.mEllipsoidAcronym;
00169 mGeoFlag = srs.mGeoFlag;
00170 mAxisInverted = srs.mAxisInverted;
00171 mMapUnits = srs.mMapUnits;
00172 mSRID = srs.mSRID;
00173 mAuthId = srs.mAuthId;
00174 mIsValidFlag = srs.mIsValidFlag;
00175 mValidationHint = srs.mValidationHint;
00176 mWkt = srs.mWkt;
00177 if ( mIsValidFlag )
00178 {
00179 OSRDestroySpatialReference( mCRS );
00180 mCRS = OSRClone( srs.mCRS );
00181 }
00182 }
00183 return *this;
00184 }
00185
00186
00187
00188
00189 void QgsCoordinateReferenceSystem::validate()
00190 {
00191 if ( mIsValidFlag )
00192 return;
00193
00194
00195 if ( mCustomSrsValidation )
00196 mCustomSrsValidation( this );
00197
00198 if ( !mIsValidFlag )
00199
00200 createFromOgcWmsCrs( GEO_EPSG_CRS_AUTHID );
00201 }
00202
00203 bool QgsCoordinateReferenceSystem::createFromSrid( long id )
00204 {
00205 return loadFromDb( QgsApplication::srsDbFilePath(), "srid", QString::number( id ) );
00206 }
00207
00208 bool QgsCoordinateReferenceSystem::createFromEpsg( long id )
00209 {
00210 return createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( id ) );
00211 }
00212
00213 bool QgsCoordinateReferenceSystem::createFromSrsId( long id )
00214 {
00215 return loadFromDb( id < USER_CRS_START_ID ? QgsApplication::srsDbFilePath() :
00216 QgsApplication::qgisUserDbFilePath(),
00217 "srs_id", QString::number( id ) );
00218 }
00219
00220 bool QgsCoordinateReferenceSystem::loadFromDb( QString db, QString expression, QString value )
00221 {
00222 QgsDebugMsgLevel( "load CRS from " + db + " where " + expression + " is " + value, 3 );
00223 mIsValidFlag = false;
00224 mWkt.clear();
00225
00226 QFileInfo myInfo( db );
00227 if ( !myInfo.exists() )
00228 {
00229 QgsDebugMsg( "failed : " + db + " does not exist!" );
00230 return mIsValidFlag;
00231 }
00232
00233 sqlite3 *myDatabase;
00234 const char *myTail;
00235 sqlite3_stmt *myPreparedStatement;
00236 int myResult;
00237
00238 myResult = openDb( db, &myDatabase );
00239 if ( myResult != SQLITE_OK )
00240 {
00241 QgsDebugMsg( "failed : " + db + " could not be opened!" );
00242 return mIsValidFlag;
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 QString mySql = "select srs_id,description,projection_acronym,"
00258 "ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo "
00259 "from tbl_srs where " + expression + "=" + quotedValue( value ) + " order by deprecated";
00260 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(),
00261 mySql.toUtf8().length(),
00262 &myPreparedStatement, &myTail );
00263
00264 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00265 {
00266 mSrsId = QString::fromUtf8(( char * )sqlite3_column_text(
00267 myPreparedStatement, 0 ) ).toLong();
00268 mDescription = QString::fromUtf8(( char * )sqlite3_column_text(
00269 myPreparedStatement, 1 ) );
00270 mProjectionAcronym = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 2 ) );
00271 mEllipsoidAcronym = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 3 ) );
00272 QString toProj4 = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 4 ) );
00273 mSRID = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 5 ) ).toLong();
00274 mAuthId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 6 ) );
00275 mGeoFlag = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 7 ) ).toInt() != 0;
00276 mAxisInverted = -1;
00277
00278 if ( mSrsId >= USER_CRS_START_ID && mAuthId.isEmpty() )
00279 {
00280 mAuthId = QString( "USER:%1" ).arg( mSrsId );
00281 }
00282 else if ( mAuthId.startsWith( "EPSG:", Qt::CaseInsensitive ) )
00283 {
00284 OSRDestroySpatialReference( mCRS );
00285 mCRS = OSRNewSpatialReference( NULL );
00286 mIsValidFlag = OSRSetFromUserInput( mCRS, mAuthId.toLower().toAscii() ) == OGRERR_NONE;
00287 setMapUnits();
00288 }
00289
00290 if ( !mIsValidFlag )
00291 {
00292 setProj4String( toProj4 );
00293 }
00294 }
00295 else
00296 {
00297 QgsDebugMsg( "failed : " + mySql );
00298 }
00299 sqlite3_finalize( myPreparedStatement );
00300 sqlite3_close( myDatabase );
00301 return mIsValidFlag;
00302 }
00303
00304 bool QgsCoordinateReferenceSystem::axisInverted() const
00305 {
00306 if ( mAxisInverted == -1 )
00307 {
00308 OGRAxisOrientation orientation;
00309 const char *axis0 = OSRGetAxis( mCRS, mGeoFlag ? "GEOGCS" : "PROJCS", 0, &orientation );
00310 mAxisInverted = mGeoFlag
00311 ? ( orientation == OAO_East || orientation == OAO_West || orientation == OAO_Other )
00312 : ( orientation == OAO_North || orientation == OAO_South );
00313 QgsDebugMsg( QString( "srid:%1 axis0:%2 orientation:%3 inverted:%4" ).arg( mSRID ).arg( axis0 ).arg( OSRAxisEnumToName( orientation ) ).arg( mAxisInverted ) );
00314 Q_UNUSED( axis0 );
00315 }
00316
00317 return mAxisInverted != 0;
00318 }
00319
00320 bool QgsCoordinateReferenceSystem::createFromWkt( QString theWkt )
00321 {
00322 mIsValidFlag = false;
00323 mWkt.clear();
00324
00325 if ( theWkt.isEmpty() )
00326 {
00327 QgsDebugMsg( "theWkt is uninitialised, operation failed" );
00328 return mIsValidFlag;
00329 }
00330 QgsDebugMsg( "wkt: " + theWkt );
00331 QByteArray ba = theWkt.toLatin1();
00332 const char *pWkt = ba.data();
00333
00334 OGRErr myInputResult = OSRImportFromWkt( mCRS, ( char ** ) & pWkt );
00335
00336 if ( myInputResult != OGRERR_NONE )
00337 {
00338 QgsDebugMsg( "\n---------------------------------------------------------------" );
00339 QgsDebugMsg( "This CRS could *** NOT *** be set from the supplied Wkt " );
00340 QgsDebugMsg( "INPUT: " + theWkt );
00341 QgsDebugMsg( QString( "UNUSED WKT: %1" ).arg( pWkt ) );
00342 QgsDebugMsg( "---------------------------------------------------------------\n" );
00343 return mIsValidFlag;
00344 }
00345
00346 if ( OSRAutoIdentifyEPSG( mCRS ) == OGRERR_NONE )
00347 {
00348 QString authid = QString( "%1:%2" )
00349 .arg( OSRGetAuthorityName( mCRS, NULL ) )
00350 .arg( OSRGetAuthorityCode( mCRS, NULL ) );
00351 QgsDebugMsg( "authid recognized as " + authid );
00352 return createFromOgcWmsCrs( authid );
00353 }
00354
00355
00356
00357
00358
00359
00360 char *proj4src = NULL;
00361 OSRExportToProj4( mCRS, &proj4src );
00362
00363
00364
00365
00366 if ( !createFromProj4( proj4src ) )
00367 {
00368 CPLFree( proj4src );
00369
00370
00371 OSRFixup( mCRS );
00372
00373 OSRExportToProj4( mCRS, &proj4src );
00374
00375 createFromProj4( proj4src );
00376 }
00377
00378 CPLFree( proj4src );
00379
00380 return mIsValidFlag;
00381
00382 }
00383
00384 bool QgsCoordinateReferenceSystem::isValid() const
00385 {
00386 return mIsValidFlag;
00387 }
00388
00389 bool QgsCoordinateReferenceSystem::createFromProj4( const QString theProj4String )
00390 {
00391
00392
00393
00394
00395
00396
00397
00398
00399 QgsDebugMsg( "proj4: " + theProj4String );
00400 mIsValidFlag = false;
00401 mWkt.clear();
00402
00403 QRegExp myProjRegExp( "\\+proj=(\\S+)" );
00404 int myStart = myProjRegExp.indexIn( theProj4String );
00405 if ( myStart == -1 )
00406 {
00407 QgsDebugMsg( "proj string supplied has no +proj argument" );
00408 return mIsValidFlag;
00409 }
00410
00411 mProjectionAcronym = myProjRegExp.cap( 1 );
00412
00413 QRegExp myEllipseRegExp( "\\+ellps=(\\S+)" );
00414 myStart = myEllipseRegExp.indexIn( theProj4String );
00415 if ( myStart == -1 )
00416 {
00417 QgsDebugMsg( "proj string supplied has no +ellps argument" );
00418 mEllipsoidAcronym = "";
00419 }
00420 else
00421 {
00422 mEllipsoidAcronym = myEllipseRegExp.cap( 1 );
00423 }
00424
00425 QRegExp myAxisRegExp( "\\+a=(\\S+)" );
00426 myStart = myAxisRegExp.indexIn( theProj4String );
00427 if ( myStart == -1 )
00428 {
00429 QgsDebugMsg( "proj string supplied has no +a argument" );
00430 }
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 long mySrsId = 0;
00441 QgsCoordinateReferenceSystem::RecordMap myRecord;
00442
00443
00444
00445
00446
00447 myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( theProj4String.trimmed() ) + " order by deprecated" );
00448 if ( myRecord.empty() )
00449 {
00450
00451
00452
00453 QRegExp myLat1RegExp( "\\+lat_1=\\S+" );
00454 QRegExp myLat2RegExp( "\\+lat_2=\\S+" );
00455 int myStart1 = 0;
00456 int myLength1 = 0;
00457 int myStart2 = 0;
00458 int myLength2 = 0;
00459 QString lat1Str = "";
00460 QString lat2Str = "";
00461 myStart1 = myLat1RegExp.indexIn( theProj4String, myStart1 );
00462 myStart2 = myLat2RegExp.indexIn( theProj4String, myStart2 );
00463 if ( myStart1 != -1 && myStart2 != -1 )
00464 {
00465 myLength1 = myLat1RegExp.matchedLength();
00466 myLength2 = myLat2RegExp.matchedLength();
00467 lat1Str = theProj4String.mid( myStart1 + LAT_PREFIX_LEN, myLength1 - LAT_PREFIX_LEN );
00468 lat2Str = theProj4String.mid( myStart2 + LAT_PREFIX_LEN, myLength2 - LAT_PREFIX_LEN );
00469 }
00470
00471 if ( lat1Str != "" && lat2Str != "" )
00472 {
00473
00474 QString theProj4StringModified = theProj4String;
00475
00476 theProj4StringModified.replace( myStart1 + LAT_PREFIX_LEN, myLength1 - LAT_PREFIX_LEN, lat2Str );
00477
00478 myStart2 = 0;
00479 myStart2 = myLat2RegExp.indexIn( theProj4String, myStart2 );
00480 theProj4StringModified.replace( myStart2 + LAT_PREFIX_LEN, myLength2 - LAT_PREFIX_LEN, lat1Str );
00481 QgsDebugMsg( "trying proj4string match with swapped lat_1,lat_2" );
00482 myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( theProj4StringModified.trimmed() ) + " order by deprecated" );
00483 }
00484 }
00485
00486 if ( myRecord.empty() )
00487 {
00488
00489
00490
00491
00492
00493 QString sql = "SELECT * FROM tbl_srs WHERE ";
00494 QString delim = "";
00495 QString datum;
00496
00497
00498
00499
00500 foreach( QString param, theProj4String.split( QRegExp( "\\s+(?=\\+)" ), QString::SkipEmptyParts ) )
00501 {
00502 QString arg = QString( "' '||parameters||' ' LIKE %1" ).arg( quotedValue( QString( "% %1 %" ).arg( param.trimmed() ) ) );
00503 if ( param.startsWith( "+datum=" ) )
00504 {
00505 datum = arg;
00506 }
00507 else
00508 {
00509 sql += delim + arg;
00510 delim = " AND ";
00511 }
00512 }
00513
00514 if ( !datum.isEmpty() )
00515 {
00516 myRecord = getRecord( sql + delim + datum + " order by deprecated" );
00517 }
00518
00519 if ( myRecord.empty() )
00520 {
00521
00522 myRecord = getRecord( sql + " order by deprecated" );
00523 }
00524 }
00525
00526 if ( !myRecord.empty() )
00527 {
00528 mySrsId = myRecord["srs_id"].toLong();
00529 QgsDebugMsg( "proj4string param match search for srsid returned srsid: " + QString::number( mySrsId ) );
00530 if ( mySrsId > 0 )
00531 {
00532 createFromSrsId( mySrsId );
00533 }
00534 }
00535 else
00536 {
00537
00538 QgsDebugMsg( "globbing search for srsid from this proj string" );
00539 setProj4String( theProj4String );
00540 mySrsId = findMatchingProj();
00541 QgsDebugMsg( "globbing search for srsid returned srsid: " + QString::number( mySrsId ) );
00542 if ( mySrsId > 0 )
00543 {
00544 createFromSrsId( mySrsId );
00545 }
00546 else
00547 {
00548 mIsValidFlag = false;
00549 }
00550 }
00551
00552
00553 if ( !mIsValidFlag )
00554 {
00555 QgsDebugMsg( "Projection is not found in databases." );
00556 setProj4String( theProj4String );
00557
00558
00559 if ( mIsValidFlag )
00560 {
00561
00562 myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( toProj4() ) + " order by deprecated" );
00563 if ( myRecord.empty() )
00564 {
00565
00566 QgsDebugMsg( "Projection appears to be valid. Save to database!" );
00567 mIsValidFlag = saveAsUserCRS();
00568
00569 if ( mIsValidFlag )
00570 {
00571
00572 myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( toProj4() ) + " order by deprecated" );
00573 }
00574 }
00575
00576 if ( !myRecord.empty() )
00577 {
00578
00579 mySrsId = myRecord["srs_id"].toLong();
00580 QgsDebugMsg( "proj4string match search for srsid returned srsid: " + QString::number( mySrsId ) );
00581 if ( mySrsId > 0 )
00582 {
00583 createFromSrsId( mySrsId );
00584 }
00585 else
00586 {
00587 QgsDebugMsg( QString( "invalid srid %1 found" ).arg( mySrsId ) );
00588 mIsValidFlag = false;
00589 }
00590 }
00591 else
00592 {
00593 QgsDebugMsg( "Couldn't find newly added proj string?" );
00594 mIsValidFlag = false;
00595 }
00596 }
00597 }
00598
00599 return mIsValidFlag;
00600 }
00601
00602
00603 QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord( QString theSql )
00604 {
00605 QString myDatabaseFileName;
00606 QgsCoordinateReferenceSystem::RecordMap myMap;
00607 QString myFieldName;
00608 QString myFieldValue;
00609 sqlite3 *myDatabase;
00610 const char *myTail;
00611 sqlite3_stmt *myPreparedStatement;
00612 int myResult;
00613
00614 QgsDebugMsg( "running query: " + theSql );
00615
00616 myDatabaseFileName = QgsApplication::srsDbFilePath();
00617 QFileInfo myInfo( myDatabaseFileName );
00618 if ( !myInfo.exists() )
00619 {
00620 QgsDebugMsg( "failed : " + myDatabaseFileName +
00621 " does not exist!" );
00622 return myMap;
00623 }
00624
00625
00626 myResult = openDb( myDatabaseFileName, &myDatabase );
00627 if ( myResult != SQLITE_OK )
00628 {
00629 return myMap;
00630 }
00631
00632 myResult = sqlite3_prepare( myDatabase, theSql.toUtf8(), theSql.toUtf8().length(), &myPreparedStatement, &myTail );
00633
00634 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00635 {
00636 QgsDebugMsg( "trying system srs.db" );
00637 int myColumnCount = sqlite3_column_count( myPreparedStatement );
00638
00639 for ( int myColNo = 0; myColNo < myColumnCount; myColNo++ )
00640 {
00641 myFieldName = QString::fromUtf8(( char * )sqlite3_column_name( myPreparedStatement, myColNo ) );
00642 myFieldValue = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, myColNo ) );
00643 myMap[myFieldName] = myFieldValue;
00644 }
00645 }
00646 else
00647 {
00648 QgsDebugMsg( "trying user qgis.db" );
00649 sqlite3_finalize( myPreparedStatement );
00650 sqlite3_close( myDatabase );
00651
00652 myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
00653 QFileInfo myFileInfo;
00654 myFileInfo.setFile( myDatabaseFileName );
00655 if ( !myFileInfo.exists( ) )
00656 {
00657 QgsDebugMsg( "user qgis.db not found" );
00658 return myMap;
00659 }
00660
00661
00662 myResult = openDb( myDatabaseFileName, &myDatabase );
00663 if ( myResult != SQLITE_OK )
00664 {
00665 return myMap;
00666 }
00667
00668 myResult = sqlite3_prepare( myDatabase, theSql.toUtf8(), theSql.toUtf8().length(), &myPreparedStatement, &myTail );
00669
00670 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00671 {
00672 int myColumnCount = sqlite3_column_count( myPreparedStatement );
00673
00674 for ( int myColNo = 0; myColNo < myColumnCount; myColNo++ )
00675 {
00676 myFieldName = QString::fromUtf8(( char * )sqlite3_column_name( myPreparedStatement, myColNo ) );
00677 myFieldValue = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, myColNo ) );
00678 myMap[myFieldName] = myFieldValue;
00679 }
00680 }
00681 else
00682 {
00683 QgsDebugMsg( "failed : " + theSql );
00684
00685 }
00686 }
00687 sqlite3_finalize( myPreparedStatement );
00688 sqlite3_close( myDatabase );
00689
00690 #ifdef QGISDEBUG
00691 QgsDebugMsg( "retrieved: " + theSql );
00692 RecordMap::Iterator it;
00693 for ( it = myMap.begin(); it != myMap.end(); ++it )
00694 {
00695 QgsDebugMsgLevel( it.key() + " => " + it.value(), 2 );
00696 }
00697 #endif
00698
00699 return myMap;
00700 }
00701
00702
00703
00704 long QgsCoordinateReferenceSystem::srsid() const
00705 {
00706 return mSrsId;
00707 }
00708
00709 long QgsCoordinateReferenceSystem::postgisSrid() const
00710 {
00711
00712 return mSRID;
00713
00714 }
00715
00716 long QgsCoordinateReferenceSystem::epsg() const
00717 {
00718 if ( mAuthId.startsWith( "EPSG:", Qt::CaseInsensitive ) )
00719 return mAuthId.mid( 5 ).toLong();
00720 else
00721 return 0;
00722 }
00723
00724 QString QgsCoordinateReferenceSystem::authid() const
00725 {
00726 return mAuthId;
00727 }
00728
00729 QString QgsCoordinateReferenceSystem::description() const
00730 {
00731 if ( mDescription.isNull() )
00732 {
00733 return "";
00734 }
00735 else
00736 {
00737 return mDescription;
00738 }
00739 }
00740
00741 QString QgsCoordinateReferenceSystem::projectionAcronym() const
00742 {
00743 if ( mProjectionAcronym.isNull() )
00744 {
00745 return "";
00746 }
00747 else
00748 {
00749 return mProjectionAcronym;
00750 }
00751 }
00752
00753 QString QgsCoordinateReferenceSystem::ellipsoidAcronym() const
00754 {
00755 if ( mEllipsoidAcronym.isNull() )
00756 {
00757 return "";
00758 }
00759 else
00760 {
00761 return mEllipsoidAcronym;
00762 }
00763 }
00764
00765 QString QgsCoordinateReferenceSystem::toProj4() const
00766 {
00767 if ( !mIsValidFlag )
00768 return "";
00769
00770 QString toProj4;
00771 char *proj4src = NULL;
00772 OSRExportToProj4( mCRS, &proj4src );
00773 toProj4 = proj4src;
00774 CPLFree( proj4src );
00775
00776
00777 return toProj4.trimmed();
00778 }
00779
00780 bool QgsCoordinateReferenceSystem::geographicFlag() const
00781 {
00782 return mGeoFlag;
00783 }
00784
00785 QGis::UnitType QgsCoordinateReferenceSystem::mapUnits() const
00786 {
00787 return mMapUnits;
00788 }
00789
00790
00791
00792
00793
00794 void QgsCoordinateReferenceSystem::setInternalId( long theSrsId )
00795 {
00796 mSrsId = theSrsId;
00797 }
00798 void QgsCoordinateReferenceSystem::setAuthId( QString authId )
00799 {
00800 mAuthId = authId;
00801 }
00802 void QgsCoordinateReferenceSystem::setSrid( long theSrid )
00803 {
00804 mSRID = theSrid;
00805 }
00806 void QgsCoordinateReferenceSystem::setDescription( QString theDescription )
00807 {
00808 mDescription = theDescription;
00809 }
00810 void QgsCoordinateReferenceSystem::setProj4String( QString theProj4String )
00811 {
00812 const char *oldlocale = setlocale( LC_NUMERIC, NULL );
00813
00814 setlocale( LC_NUMERIC, "C" );
00815 OSRDestroySpatialReference( mCRS );
00816 mCRS = OSRNewSpatialReference( NULL );
00817 mIsValidFlag =
00818 OSRImportFromProj4( mCRS, theProj4String.toLatin1().constData() )
00819 == OGRERR_NONE;
00820 mWkt.clear();
00821 setMapUnits();
00822
00823 #if defined(QGISDEBUG) && QGISDEBUG>=3
00824 debugPrint();
00825 #endif
00826
00827 setlocale( LC_NUMERIC, oldlocale );
00828 }
00829 void QgsCoordinateReferenceSystem::setGeographicFlag( bool theGeoFlag )
00830 {
00831 mGeoFlag = theGeoFlag;
00832 }
00833 void QgsCoordinateReferenceSystem::setEpsg( long theEpsg )
00834 {
00835 mAuthId = QString( "EPSG:%1" ).arg( theEpsg );
00836 }
00837 void QgsCoordinateReferenceSystem::setProjectionAcronym( QString theProjectionAcronym )
00838 {
00839 mProjectionAcronym = theProjectionAcronym;
00840 }
00841 void QgsCoordinateReferenceSystem::setEllipsoidAcronym( QString theEllipsoidAcronym )
00842 {
00843 mEllipsoidAcronym = theEllipsoidAcronym;
00844 }
00845
00846 void QgsCoordinateReferenceSystem::setMapUnits()
00847 {
00848 if ( !mIsValidFlag )
00849 {
00850 mMapUnits = QGis::UnknownUnit;
00851 return;
00852 }
00853
00854 char *unitName;
00855
00856
00857
00858 OSRFixup( mCRS );
00859
00860 if ( OSRIsProjected( mCRS ) )
00861 {
00862 double toMeter = OSRGetLinearUnits( mCRS, &unitName );
00863 QString unit( unitName );
00864
00865
00866
00867
00868
00869
00870 static const double feetToMeter = 0.3048;
00871 static const double smallNum = 1e-3;
00872
00873 if ( qAbs( toMeter - feetToMeter ) < smallNum )
00874 unit = "Foot";
00875
00876 QgsDebugMsg( "Projection has linear units of " + unit );
00877
00878 if ( doubleNear( toMeter, 1.0 ) )
00879 mMapUnits = QGis::Meters;
00880 else if ( unit == "Foot" )
00881 mMapUnits = QGis::Feet;
00882 else
00883 {
00884 QgsDebugMsg( "Unsupported map units of " + unit );
00885 mMapUnits = QGis::UnknownUnit;
00886 }
00887 }
00888 else
00889 {
00890 OSRGetAngularUnits( mCRS, &unitName );
00891 QString unit( unitName );
00892 if ( unit == "degree" )
00893 mMapUnits = QGis::Degrees;
00894 else
00895 {
00896 QgsDebugMsg( "Unsupported map units of " + unit );
00897 mMapUnits = QGis::UnknownUnit;
00898 }
00899 QgsDebugMsgLevel( "Projection has angular units of " + unit, 3 );
00900 }
00901 }
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912 long QgsCoordinateReferenceSystem::findMatchingProj()
00913 {
00914 QgsDebugMsg( "entered." );
00915 if ( mEllipsoidAcronym.isNull() || mProjectionAcronym.isNull()
00916 || !mIsValidFlag )
00917 {
00918 QgsDebugMsg( "QgsCoordinateReferenceSystem::findMatchingProj will only "
00919 "work if prj acr ellipsoid acr and proj4string are set"
00920 " and the current projection is valid!" );
00921 return 0;
00922 }
00923
00924 sqlite3 *myDatabase;
00925 const char *myTail;
00926 sqlite3_stmt *myPreparedStatement;
00927 int myResult;
00928
00929
00930
00931 QString mySql = QString( "select srs_id,parameters from tbl_srs where "
00932 "projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
00933 .arg( quotedValue( mProjectionAcronym ) )
00934 .arg( quotedValue( mEllipsoidAcronym ) );
00935
00936 QString myDatabaseFileName = QgsApplication::srsDbFilePath();
00937
00938
00939 myResult = openDb( myDatabaseFileName, &myDatabase );
00940 if ( myResult != SQLITE_OK )
00941 {
00942 return 0;
00943 }
00944
00945 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
00946
00947 if ( myResult == SQLITE_OK )
00948 {
00949
00950 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00951 {
00952 QString mySrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
00953 QString myProj4String = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) );
00954 if ( toProj4() == myProj4String.trimmed() )
00955 {
00956 QgsDebugMsg( "-------> MATCH FOUND in srs.db srsid: " + mySrsId );
00957
00958 sqlite3_finalize( myPreparedStatement );
00959 sqlite3_close( myDatabase );
00960 return mySrsId.toLong();
00961 }
00962 else
00963 {
00964
00965 }
00966 }
00967 }
00968 QgsDebugMsg( "no match found in srs.db, trying user db now!" );
00969
00970 sqlite3_finalize( myPreparedStatement );
00971 sqlite3_close( myDatabase );
00972
00973
00974
00975
00976 myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
00977
00978 myResult = openDb( myDatabaseFileName, &myDatabase );
00979 if ( myResult != SQLITE_OK )
00980 {
00981 return 0;
00982 }
00983
00984 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
00985
00986 if ( myResult == SQLITE_OK )
00987 {
00988
00989 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00990 {
00991 QString mySrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
00992 QString myProj4String = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) );
00993 if ( toProj4() == myProj4String.trimmed() )
00994 {
00995 QgsDebugMsg( "-------> MATCH FOUND in user qgis.db srsid: " + mySrsId );
00996
00997 sqlite3_finalize( myPreparedStatement );
00998 sqlite3_close( myDatabase );
00999 return mySrsId.toLong();
01000 }
01001 else
01002 {
01003
01004 }
01005 }
01006 }
01007 QgsDebugMsg( "no match found in user db" );
01008
01009
01010 sqlite3_finalize( myPreparedStatement );
01011 sqlite3_close( myDatabase );
01012 return 0;
01013 }
01014
01015 bool QgsCoordinateReferenceSystem::operator==( const QgsCoordinateReferenceSystem &theSrs ) const
01016 {
01017 return mIsValidFlag && theSrs.mIsValidFlag && theSrs.authid() == authid();
01018 }
01019
01020 bool QgsCoordinateReferenceSystem::operator!=( const QgsCoordinateReferenceSystem &theSrs ) const
01021 {
01022 return !( *this == theSrs );
01023 }
01024
01025 bool QgsCoordinateReferenceSystem::equals( QString theProj4String )
01026 {
01027 QgsCoordinateReferenceSystem r;
01028 r.createFromProj4( theProj4String );
01029 return *this == r;
01030 }
01031
01032 QString QgsCoordinateReferenceSystem::toWkt() const
01033 {
01034 if ( mWkt.isEmpty() )
01035 {
01036 char *wkt;
01037 if ( OSRExportToWkt( mCRS, &wkt ) == OGRERR_NONE )
01038 {
01039 mWkt = wkt;
01040 OGRFree( wkt );
01041 }
01042 }
01043 return mWkt;
01044 }
01045
01046 bool QgsCoordinateReferenceSystem::readXML( QDomNode & theNode )
01047 {
01048 QgsDebugMsg( "Reading Spatial Ref Sys from xml ------------------------!" );
01049 QDomNode srsNode = theNode.namedItem( "spatialrefsys" );
01050
01051 if ( ! srsNode.isNull() )
01052 {
01053 bool initialized = false;
01054
01055 long srsid = srsNode.namedItem( "srsid" ).toElement().text().toLong();
01056
01057 QDomNode myNode;
01058
01059 if ( srsid < USER_CRS_START_ID )
01060 {
01061 myNode = srsNode.namedItem( "authid" );
01062 if ( !myNode.isNull() )
01063 {
01064 operator=( QgsCRSCache::instance()->crsByAuthId( myNode.toElement().text() ) );
01065 if ( isValid() )
01066 {
01067 initialized = true;
01068 }
01069 }
01070
01071 if ( !initialized )
01072 {
01073 myNode = srsNode.namedItem( "epsg" );
01074 if ( !myNode.isNull() )
01075 {
01076 operator=( QgsCRSCache::instance()->crsByEpsgId( myNode.toElement().text().toLong() ) );
01077 if ( isValid() )
01078 {
01079 initialized = true;
01080 }
01081 }
01082 }
01083 }
01084 else
01085 {
01086 QgsDebugMsg( "Ignoring authid/epsg for user crs." );
01087 }
01088
01089 if ( initialized )
01090 {
01091 QgsDebugMsg( "Set from auth id" );
01092 }
01093 else
01094 {
01095 myNode = srsNode.namedItem( "proj4" );
01096
01097 if ( createFromProj4( myNode.toElement().text() ) )
01098 {
01099
01100 QgsDebugMsg( "Setting from proj4 string" );
01101 }
01102 else
01103 {
01104 QgsDebugMsg( "Setting from elements one by one" );
01105
01106 myNode = srsNode.namedItem( "proj4" );
01107 setProj4String( myNode.toElement().text() );
01108
01109 myNode = srsNode.namedItem( "srsid" );
01110 setInternalId( myNode.toElement().text().toLong() );
01111
01112 myNode = srsNode.namedItem( "srid" );
01113 setSrid( myNode.toElement().text().toLong() );
01114
01115 myNode = srsNode.namedItem( "authid" );
01116 setAuthId( myNode.toElement().text() );
01117
01118 myNode = srsNode.namedItem( "description" );
01119 setDescription( myNode.toElement().text() );
01120
01121 myNode = srsNode.namedItem( "projectionacronym" );
01122 setProjectionAcronym( myNode.toElement().text() );
01123
01124 myNode = srsNode.namedItem( "ellipsoidacronym" );
01125 setEllipsoidAcronym( myNode.toElement().text() );
01126
01127 myNode = srsNode.namedItem( "geographicflag" );
01128 if ( myNode.toElement().text().compare( "true" ) )
01129 {
01130 setGeographicFlag( true );
01131 }
01132 else
01133 {
01134 setGeographicFlag( false );
01135 }
01136
01137
01138 setMapUnits();
01139
01140
01141 mIsValidFlag = true;
01142 }
01143 }
01144 }
01145 else
01146 {
01147
01148 createFromId( GEOCRS_ID, InternalCrsId );
01149 }
01150 return true;
01151 }
01152
01153 bool QgsCoordinateReferenceSystem::writeXML( QDomNode & theNode, QDomDocument & theDoc ) const
01154 {
01155
01156 QDomElement myLayerNode = theNode.toElement();
01157 QDomElement mySrsElement = theDoc.createElement( "spatialrefsys" );
01158
01159 QDomElement myProj4Element = theDoc.createElement( "proj4" );
01160 myProj4Element.appendChild( theDoc.createTextNode( toProj4() ) );
01161 mySrsElement.appendChild( myProj4Element );
01162
01163 QDomElement mySrsIdElement = theDoc.createElement( "srsid" );
01164 mySrsIdElement.appendChild( theDoc.createTextNode( QString::number( srsid() ) ) );
01165 mySrsElement.appendChild( mySrsIdElement );
01166
01167 QDomElement mySridElement = theDoc.createElement( "srid" );
01168 mySridElement.appendChild( theDoc.createTextNode( QString::number( postgisSrid() ) ) );
01169 mySrsElement.appendChild( mySridElement );
01170
01171 QDomElement myEpsgElement = theDoc.createElement( "authid" );
01172 myEpsgElement.appendChild( theDoc.createTextNode( authid() ) );
01173 mySrsElement.appendChild( myEpsgElement );
01174
01175 QDomElement myDescriptionElement = theDoc.createElement( "description" );
01176 myDescriptionElement.appendChild( theDoc.createTextNode( description() ) );
01177 mySrsElement.appendChild( myDescriptionElement );
01178
01179 QDomElement myProjectionAcronymElement = theDoc.createElement( "projectionacronym" );
01180 myProjectionAcronymElement.appendChild( theDoc.createTextNode( projectionAcronym() ) );
01181 mySrsElement.appendChild( myProjectionAcronymElement );
01182
01183 QDomElement myEllipsoidAcronymElement = theDoc.createElement( "ellipsoidacronym" );
01184 myEllipsoidAcronymElement.appendChild( theDoc.createTextNode( ellipsoidAcronym() ) );
01185 mySrsElement.appendChild( myEllipsoidAcronymElement );
01186
01187 QDomElement myGeographicFlagElement = theDoc.createElement( "geographicflag" );
01188 QString myGeoFlagText = "false";
01189 if ( geographicFlag() )
01190 {
01191 myGeoFlagText = "true";
01192 }
01193
01194 myGeographicFlagElement.appendChild( theDoc.createTextNode( myGeoFlagText ) );
01195 mySrsElement.appendChild( myGeographicFlagElement );
01196
01197 myLayerNode.appendChild( mySrsElement );
01198
01199 return true;
01200 }
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211 QString QgsCoordinateReferenceSystem::proj4FromSrsId( const int theSrsId )
01212 {
01213
01214 QString myDatabaseFileName;
01215 QString myProjString;
01216 QString mySql = QString( "select parameters from tbl_srs where srs_id = %1 order by deprecated" ).arg( theSrsId );
01217
01218 QgsDebugMsg( "mySrsId = " + QString::number( theSrsId ) );
01219 QgsDebugMsg( "USER_CRS_START_ID = " + QString::number( USER_CRS_START_ID ) );
01220 QgsDebugMsg( "Selection sql : " + mySql );
01221
01222
01223
01224
01225
01226 if ( theSrsId >= USER_CRS_START_ID )
01227 {
01228 myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
01229 QFileInfo myFileInfo;
01230 myFileInfo.setFile( myDatabaseFileName );
01231 if ( !myFileInfo.exists( ) )
01232 {
01233 QgsDebugMsg( "users qgis.db not found" );
01234 return NULL;
01235 }
01236 }
01237 else
01238 {
01239 myDatabaseFileName = QgsApplication::srsDbFilePath();
01240 }
01241 QgsDebugMsg( "db = " + myDatabaseFileName );
01242
01243 sqlite3 *db;
01244 int rc;
01245 rc = openDb( myDatabaseFileName, &db );
01246 if ( rc )
01247 {
01248 return QString();
01249 }
01250
01251 const char *pzTail;
01252 sqlite3_stmt *ppStmt;
01253
01254 rc = sqlite3_prepare( db, mySql.toUtf8(), mySql.toUtf8().length(), &ppStmt, &pzTail );
01255
01256
01257 if ( rc == SQLITE_OK )
01258 {
01259 if ( sqlite3_step( ppStmt ) == SQLITE_ROW )
01260 {
01261 myProjString = QString::fromUtf8(( char* )sqlite3_column_text( ppStmt, 0 ) );
01262 }
01263 }
01264
01265 sqlite3_finalize( ppStmt );
01266
01267 sqlite3_close( db );
01268
01269
01270 return myProjString;
01271 }
01272
01273 int QgsCoordinateReferenceSystem::openDb( QString path, sqlite3 **db, bool readonly )
01274 {
01275 QgsDebugMsgLevel( "path = " + path, 3 );
01276 int myResult = readonly
01277 ? sqlite3_open_v2( path.toUtf8().data(), db, SQLITE_OPEN_READONLY, NULL )
01278 : sqlite3_open( path.toUtf8().data(), db );
01279
01280 if ( myResult != SQLITE_OK )
01281 {
01282 QgsDebugMsg( "Can't open database: " + QString( sqlite3_errmsg( *db ) ) );
01283
01284
01285
01286 QgsMessageLog::logMessage( QObject::tr( "Could not open CRS database %1\nError(%2): %3" )
01287 .arg( path )
01288 .arg( myResult )
01289 .arg( sqlite3_errmsg( *db ) ), QObject::tr( "CRS" ) );
01290 }
01291 return myResult;
01292 }
01293
01294 void QgsCoordinateReferenceSystem::setCustomSrsValidation( CUSTOM_CRS_VALIDATION f )
01295 {
01296 mCustomSrsValidation = f;
01297 }
01298
01299 CUSTOM_CRS_VALIDATION QgsCoordinateReferenceSystem::customSrsValidation()
01300 {
01301 return mCustomSrsValidation;
01302 }
01303
01304 void QgsCoordinateReferenceSystem::debugPrint()
01305 {
01306 QgsDebugMsg( "***SpatialRefSystem***" );
01307 QgsDebugMsg( "* Valid : " + ( mIsValidFlag ? QString( "true" ) : QString( "false" ) ) );
01308 QgsDebugMsg( "* SrsId : " + QString::number( mSrsId ) );
01309 QgsDebugMsg( "* Proj4 : " + toProj4() );
01310 QgsDebugMsg( "* WKT : " + toWkt() );
01311 QgsDebugMsg( "* Desc. : " + mDescription );
01312 if ( mapUnits() == QGis::Meters )
01313 {
01314 QgsDebugMsg( "* Units : meters" );
01315 }
01316 else if ( mapUnits() == QGis::Feet )
01317 {
01318 QgsDebugMsg( "* Units : feet" );
01319 }
01320 else if ( mapUnits() == QGis::Degrees )
01321 {
01322 QgsDebugMsg( "* Units : degrees" );
01323 }
01324 }
01325
01326 void QgsCoordinateReferenceSystem::setValidationHint( QString html )
01327 {
01328 mValidationHint = html;
01329 }
01330
01331 QString QgsCoordinateReferenceSystem::validationHint()
01332 {
01333 return mValidationHint;
01334 }
01335
01338
01339 bool QgsCoordinateReferenceSystem::saveAsUserCRS()
01340 {
01341 if ( ! mIsValidFlag )
01342 {
01343 QgsDebugMsg( "Can't save an invalid CRS!" );
01344 return false;
01345 }
01346
01347 QString mySql;
01348 QString myName = QString( " * %1 (%2)" )
01349 .arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ) )
01350 .arg( toProj4() );
01351
01352
01353
01354
01355
01356 if ( getRecordCount() == 0 )
01357 {
01358 mySql = "insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ("
01359 + QString::number( USER_CRS_START_ID )
01360 + "," + quotedValue( myName )
01361 + "," + quotedValue( projectionAcronym() )
01362 + "," + quotedValue( ellipsoidAcronym() )
01363 + "," + quotedValue( toProj4() )
01364 + ",0)";
01365 }
01366 else
01367 {
01368 mySql = "insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ("
01369 + quotedValue( myName )
01370 + "," + quotedValue( projectionAcronym() )
01371 + "," + quotedValue( ellipsoidAcronym() )
01372 + "," + quotedValue( toProj4() )
01373 + ",0)";
01374 }
01375 sqlite3 *myDatabase;
01376 const char *myTail;
01377 sqlite3_stmt *myPreparedStatement;
01378 int myResult;
01379
01380 myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
01381 if ( myResult != SQLITE_OK )
01382 {
01383 QgsDebugMsg( QString( "Can't open or create database %1: %2" )
01384 .arg( QgsApplication::qgisUserDbFilePath() )
01385 .arg( sqlite3_errmsg( myDatabase ) ) );
01386 return false;
01387 }
01388 QgsDebugMsg( QString( "Update or insert sql \n%1" ).arg( mySql ) );
01389 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
01390 sqlite3_step( myPreparedStatement );
01391
01392 QgsMessageLog::logMessage( QObject::tr( "Saved user CRS [%1]" ).arg( toProj4() ), QObject::tr( "CRS" ) );
01393
01394
01395 return myResult == SQLITE_OK;
01396 }
01397
01398 long QgsCoordinateReferenceSystem::getRecordCount()
01399 {
01400 sqlite3 *myDatabase;
01401 const char *myTail;
01402 sqlite3_stmt *myPreparedStatement;
01403 int myResult;
01404 long myRecordCount = 0;
01405
01406 myResult = sqlite3_open_v2( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL );
01407 if ( myResult != SQLITE_OK )
01408 {
01409 QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
01410 return 0;
01411 }
01412
01413 QString mySql = "select count(*) from tbl_srs";
01414 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
01415
01416 if ( myResult == SQLITE_OK )
01417 {
01418 if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
01419 {
01420 QString myRecordCountString = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
01421 myRecordCount = myRecordCountString.toLong();
01422 }
01423 }
01424
01425 sqlite3_finalize( myPreparedStatement );
01426 sqlite3_close( myDatabase );
01427 return myRecordCount;
01428 }
01429
01430 QString QgsCoordinateReferenceSystem::quotedValue( QString value )
01431 {
01432 value.replace( "'", "''" );
01433 return value.prepend( "'" ).append( "'" );
01434 }
01435
01436 int QgsCoordinateReferenceSystem::syncDb()
01437 {
01438 int updated = 0, errors = 0;
01439
01440 sqlite3 *database;
01441 if ( sqlite3_open( QgsApplication::srsDbFilePath().toUtf8().constData(), &database ) != SQLITE_OK )
01442 {
01443 qCritical( "Could not open database: %s [%s]\n", QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) );
01444 return -1;
01445 }
01446
01447 if ( sqlite3_exec( database, "BEGIN TRANSACTION", 0, 0, 0 ) != SQLITE_OK )
01448 {
01449 qCritical( "Could not begin transaction: %s [%s]\n", QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) );
01450 return -1;
01451 }
01452
01453 const char *tail;
01454 sqlite3_stmt *select;
01455 QString sql = "select auth_name,auth_id,parameters from tbl_srs WHERE auth_name IS NOT NULL AND auth_id IS NOT NULL order by deprecated";
01456 if ( sqlite3_prepare( database, sql.toAscii(), sql.size(), &select, &tail ) != SQLITE_OK )
01457 {
01458 qCritical( "Could not prepare: %s [%s]\n", sql.toAscii().constData(), sqlite3_errmsg( database ) );
01459 sqlite3_close( database );
01460 return -1;
01461 }
01462
01463 OGRSpatialReferenceH crs = OSRNewSpatialReference( NULL );
01464
01465 while ( sqlite3_step( select ) == SQLITE_ROW )
01466 {
01467 const char *auth_name = ( const char * ) sqlite3_column_text( select, 0 );
01468 const char *auth_id = ( const char * ) sqlite3_column_text( select, 1 );
01469 const char *params = ( const char * ) sqlite3_column_text( select, 2 );
01470
01471 QString proj4;
01472
01473 if ( QString( auth_name ).compare( "epsg", Qt::CaseInsensitive ) == 0 )
01474 {
01475 OGRErr ogrErr = OSRSetFromUserInput( crs, QString( "epsg:%1" ).arg( auth_id ).toAscii() );
01476
01477 if ( ogrErr == OGRERR_NONE )
01478 {
01479 char *output = 0;
01480
01481 if ( OSRExportToProj4( crs, &output ) == OGRERR_NONE )
01482 {
01483 proj4 = output;
01484 proj4 = proj4.trimmed();
01485 }
01486 else
01487 {
01488 QgsDebugMsg( QString( "could not retrieve proj.4 string for epsg:%1 from OGR" ).arg( auth_id ) );
01489 }
01490
01491 if ( output )
01492 CPLFree( output );
01493 }
01494 }
01495 #if !defined(PJ_VERSION) || PJ_VERSION!=470
01496
01497 else
01498 {
01499 QString input = QString( "+init=%1:%2" ).arg( QString( auth_name ).toLower() ).arg( auth_id );
01500 projPJ pj = pj_init_plus( input.toAscii() );
01501 if ( !pj )
01502 {
01503 input = QString( "+init=%1:%2" ).arg( QString( auth_name ).toUpper() ).arg( auth_id );
01504 pj = pj_init_plus( input.toAscii() );
01505 }
01506
01507 if ( pj )
01508 {
01509 char *def = pj_get_def( pj, 0 );
01510 if ( def )
01511 {
01512 proj4 = def;
01513 pj_dalloc( def );
01514
01515 input.prepend( ' ' ).append( ' ' );
01516 if ( proj4.startsWith( input ) )
01517 {
01518 proj4 = proj4.mid( input.size() );
01519 }
01520 }
01521 else
01522 {
01523 QgsDebugMsg( QString( "could not retrieve proj string for %1 from PROJ" ).arg( input ) );
01524 }
01525 }
01526 else
01527 {
01528 QgsDebugMsgLevel( QString( "could not retrieve crs for %1 from PROJ" ).arg( input ), 3 );
01529 }
01530
01531 pj_free( pj );
01532 }
01533 #endif
01534
01535 if ( proj4.isEmpty() )
01536 {
01537 continue;
01538 }
01539
01540 if ( proj4 != params )
01541 {
01542 char *errMsg = NULL;
01543 sql = QString( "UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
01544 .arg( quotedValue( proj4 ) )
01545 .arg( quotedValue( auth_name ) )
01546 .arg( quotedValue( auth_id ) );
01547
01548 if ( sqlite3_exec( database, sql.toUtf8(), 0, 0, &errMsg ) != SQLITE_OK )
01549 {
01550 qCritical( "Could not execute: %s [%s/%s]\n",
01551 sql.toLocal8Bit().constData(),
01552 sqlite3_errmsg( database ),
01553 errMsg ? errMsg : "(unknown error)" );
01554 errors++;
01555 }
01556 else
01557 {
01558 updated++;
01559 QgsDebugMsgLevel( QString( "SQL: %1\n OLD:%2\n NEW:%3" ).arg( sql ).arg( params ).arg( proj4 ), 3 );
01560 }
01561
01562 if ( errMsg )
01563 sqlite3_free( errMsg );
01564 }
01565 }
01566
01567 OSRDestroySpatialReference( crs );
01568
01569 sqlite3_finalize( select );
01570
01571 if ( sqlite3_exec( database, "COMMIT", 0, 0, 0 ) != SQLITE_OK )
01572 {
01573 qCritical( "Could not commit transaction: %s [%s]\n", QgsApplication::srsDbFilePath().toLocal8Bit().constData(), sqlite3_errmsg( database ) );
01574 return -1;
01575 }
01576
01577 sqlite3_close( database );
01578
01579 if ( errors > 0 )
01580 return -errors;
01581 else
01582 return updated;
01583 }