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 <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"
00033
00034 #include <sqlite3.h>
00035
00036
00037 #include <ogr_srs_api.h>
00038 #include <cpl_error.h>
00039 #include <cpl_conv.h>
00040 #include "qgslogger.h"
00041
00042 CUSTOM_CRS_VALIDATION QgsCoordinateReferenceSystem::mCustomSrsValidation = NULL;
00043
00044
00045
00046 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem()
00047 : mMapUnits( QGis::UnknownUnit )
00048 , mIsValidFlag( 0 )
00049 , mValidationHint( "" )
00050 {
00051 mCRS = OSRNewSpatialReference( NULL );
00052 }
00053
00054 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( QString theWkt )
00055 : mMapUnits( QGis::UnknownUnit )
00056 , mIsValidFlag( 0 )
00057 , mValidationHint( "" )
00058 {
00059 mCRS = OSRNewSpatialReference( NULL );
00060 createFromWkt( theWkt );
00061 }
00062
00063
00064 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( const long theId, CrsType theType )
00065 : mMapUnits( QGis::UnknownUnit )
00066 , mIsValidFlag( 0 )
00067 , mValidationHint( "" )
00068 {
00069 mCRS = OSRNewSpatialReference( NULL );
00070 createFromId( theId, theType );
00071 }
00072
00073 QgsCoordinateReferenceSystem::~QgsCoordinateReferenceSystem()
00074 {
00075 OSRDestroySpatialReference( mCRS );
00076 }
00077
00078 void QgsCoordinateReferenceSystem::createFromId( const long theId, CrsType theType )
00079 {
00080 switch ( theType )
00081 {
00082 case InternalCrsId:
00083 createFromSrsId( theId );
00084 break;
00085 case PostgisCrsId:
00086 createFromSrid( theId );
00087 break;
00088 case EpsgCrsId:
00089 createFromEpsg( theId );
00090 break;
00091 default:
00092
00093 QgsDebugMsg( "Unexpected case reached!" );
00094 };
00095 }
00096
00097 bool QgsCoordinateReferenceSystem::createFromOgcWmsCrs( QString theCrs )
00098 {
00099 if ( loadFromDb( QgsApplication::srsDbFilePath(), "lower(auth_name||':'||auth_id)", theCrs.toLower() ) )
00100 return true;
00101
00102 if ( theCrs.compare( "CRS:84", Qt::CaseInsensitive ) == 0 )
00103 {
00104 createFromSrsId( GEOCRS_ID );
00105 return true;
00106 }
00107
00108 return false;
00109 }
00110
00111 QgsCoordinateReferenceSystem::QgsCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &srs )
00112 {
00113 mCRS = OSRNewSpatialReference( NULL );
00114 *this = srs;
00115 }
00116
00117
00118 QgsCoordinateReferenceSystem& QgsCoordinateReferenceSystem::operator=( const QgsCoordinateReferenceSystem & srs )
00119 {
00120 if ( &srs != this )
00121 {
00122 mSrsId = srs.mSrsId;
00123 mDescription = srs.mDescription;
00124 mProjectionAcronym = srs.mProjectionAcronym;
00125 mEllipsoidAcronym = srs.mEllipsoidAcronym;
00126 mGeoFlag = srs.mGeoFlag;
00127 mMapUnits = srs.mMapUnits;
00128 mSRID = srs.mSRID;
00129 mAuthId = srs.mAuthId;
00130 mIsValidFlag = srs.mIsValidFlag;
00131 mValidationHint = srs.mValidationHint;
00132 if ( mIsValidFlag )
00133 {
00134 OSRDestroySpatialReference( mCRS );
00135 mCRS = OSRClone( srs.mCRS );
00136 }
00137 }
00138 return *this;
00139 }
00140
00141
00142
00143
00144 void QgsCoordinateReferenceSystem::validate()
00145 {
00146 if ( mIsValidFlag )
00147 return;
00148
00149
00150 if ( mCustomSrsValidation )
00151 mCustomSrsValidation( this );
00152
00153 if ( !mIsValidFlag )
00154
00155 createFromProj4( GEOPROJ4 );
00156 }
00157
00158 bool QgsCoordinateReferenceSystem::createFromSrid( long id )
00159 {
00160 return loadFromDb( QgsApplication::srsDbFilePath(), "srid", QString::number( id ) );
00161 }
00162
00163 bool QgsCoordinateReferenceSystem::createFromEpsg( long id )
00164 {
00165 return createFromOgcWmsCrs( QString( "EPSG:%1" ).arg( id ) );
00166 }
00167
00168 bool QgsCoordinateReferenceSystem::createFromSrsId( long id )
00169 {
00170 return loadFromDb( id < USER_CRS_START_ID ? QgsApplication::srsDbFilePath() :
00171 QgsApplication::qgisUserDbFilePath(), "srs_id", QString::number( id ) );
00172 }
00173
00174 bool QgsCoordinateReferenceSystem::loadFromDb( QString db, QString expression, QString value )
00175 {
00176 QgsDebugMsgLevel( "load CRS from " + db + " where " + expression + " is " + value, 3 );
00177 mIsValidFlag = false;
00178
00179 QFileInfo myInfo( db );
00180 if ( !myInfo.exists() )
00181 {
00182 QgsDebugMsg( "failed : " + db + " does not exist!" );
00183 return mIsValidFlag;
00184 }
00185
00186 sqlite3 *myDatabase;
00187 const char *myTail;
00188 sqlite3_stmt *myPreparedStatement;
00189 int myResult;
00190
00191 myResult = openDb( db, &myDatabase );
00192 if ( myResult != SQLITE_OK )
00193 {
00194 QgsDebugMsg( "failed : " + db + " could not be opened!" );
00195 return mIsValidFlag;
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 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 );
00211 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
00212
00213 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00214 {
00215 mSrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) ).toLong();
00216 mDescription = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) );
00217 mProjectionAcronym = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 2 ) );
00218 mEllipsoidAcronym = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 3 ) );
00219 QString toProj4 = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 4 ) );
00220 mSRID = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 5 ) ).toLong();
00221 mAuthId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 6 ) );
00222 int geo = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 7 ) ).toInt();
00223 mGeoFlag = ( geo == 0 ? false : true );
00224 setProj4String( toProj4 );
00225 setMapUnits();
00226 }
00227 else
00228 {
00229 QgsDebugMsg( "failed : " + mySql );
00230 }
00231 sqlite3_finalize( myPreparedStatement );
00232 sqlite3_close( myDatabase );
00233 return mIsValidFlag;
00234 }
00235
00236 bool QgsCoordinateReferenceSystem::createFromWkt( QString theWkt )
00237 {
00238 mIsValidFlag = false;
00239
00240 if ( theWkt.isEmpty() )
00241 {
00242 QgsDebugMsg( "theWkt is uninitialised, operation failed" );
00243 return mIsValidFlag;
00244 }
00245 QgsDebugMsg( "QgsCoordinateReferenceSystem::createFromWkt(QString theWkt) using: " + theWkt );
00246 QByteArray ba = theWkt.toLatin1();
00247 const char *pWkt = ba.data();
00248
00249 OGRErr myInputResult = OSRImportFromWkt( mCRS, ( char ** ) & pWkt );
00250
00251 if ( myInputResult != OGRERR_NONE )
00252 {
00253 QgsDebugMsg( "\n---------------------------------------------------------------" );
00254 QgsDebugMsg( "This CRS could *** NOT *** be set from the supplied Wkt " );
00255 QgsDebugMsg( "INPUT: " + theWkt );
00256 QgsDebugMsg( QString( "UNUSED WKT: %1" ).arg( pWkt ) );
00257 QgsDebugMsg( "---------------------------------------------------------------\n" );
00258 return mIsValidFlag;
00259 }
00260
00261
00262
00263
00264
00265
00266 char *proj4src = NULL;
00267 OSRExportToProj4( mCRS, &proj4src );
00268
00269
00270
00271
00272 createFromProj4( QString( proj4src ) );
00273 CPLFree( proj4src );
00274
00275 return mIsValidFlag;
00276
00277 }
00278
00279 bool QgsCoordinateReferenceSystem::isValid() const
00280 {
00281 return mIsValidFlag;
00282 }
00283
00284 bool QgsCoordinateReferenceSystem::createFromProj4( const QString theProj4String )
00285 {
00286
00287
00288
00289
00290
00291
00292
00293
00294 mIsValidFlag = false;
00295
00296 QRegExp myProjRegExp( "\\+proj=\\S+" );
00297 int myStart = 0;
00298 int myLength = 0;
00299 myStart = myProjRegExp.indexIn( theProj4String, myStart );
00300 if ( myStart == -1 )
00301 {
00302 QgsDebugMsg( "error proj string supplied has no +proj argument" );
00303 return mIsValidFlag;
00304 }
00305 else
00306 {
00307 myLength = myProjRegExp.matchedLength();
00308 }
00309
00310 mProjectionAcronym = theProj4String.mid( myStart + PROJ_PREFIX_LEN, myLength - PROJ_PREFIX_LEN );
00311
00312 QRegExp myEllipseRegExp( "\\+ellps=\\S+" );
00313 myStart = 0;
00314 myLength = 0;
00315 myStart = myEllipseRegExp.indexIn( theProj4String, myStart );
00316 if ( myStart != -1 )
00317 {
00318 myLength = myEllipseRegExp.matchedLength();
00319 mEllipsoidAcronym = theProj4String.mid( myStart + ELLPS_PREFIX_LEN, myLength - ELLPS_PREFIX_LEN );
00320 }
00321
00322 QRegExp myAxisRegExp( "\\+a=\\S+" );
00323 myStart = 0;
00324 myLength = 0;
00325 myStart = myAxisRegExp.indexIn( theProj4String, myStart );
00326 if ( myStart == -1 && mEllipsoidAcronym.isNull() )
00327 {
00328 QgsDebugMsg( "proj string supplied has no +ellps or +a argument" );
00329 return mIsValidFlag;
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 long mySrsId = 0;
00341 QgsCoordinateReferenceSystem::RecordMap myRecord;
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353 myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( theProj4String.trimmed() ) );
00354 if ( !myRecord.empty() )
00355 {
00356 mySrsId = myRecord["srs_id"].toLong();
00357 QgsDebugMsg( "proj4string match search for srsid returned srsid: " + QString::number( mySrsId ) );
00358 if ( mySrsId > 0 )
00359 {
00360 createFromSrsId( mySrsId );
00361 }
00362 }
00363 else
00364 {
00365
00366
00367
00368 QRegExp myLat1RegExp( "\\+lat_1=\\S+" );
00369 QRegExp myLat2RegExp( "\\+lat_2=\\S+" );
00370 int myStart1 = 0;
00371 int myLength1 = 0;
00372 int myStart2 = 0;
00373 int myLength2 = 0;
00374 QString lat1Str = "";
00375 QString lat2Str = "";
00376 myStart1 = myLat1RegExp.indexIn( theProj4String, myStart1 );
00377 myStart2 = myLat2RegExp.indexIn( theProj4String, myStart2 );
00378 if (( myStart1 != -1 ) && ( myStart2 != -1 ) )
00379 {
00380 myLength1 = myLat1RegExp.matchedLength();
00381 myLength2 = myLat2RegExp.matchedLength();
00382 lat1Str = theProj4String.mid( myStart1 + LAT_PREFIX_LEN, myLength1 - LAT_PREFIX_LEN );
00383 lat2Str = theProj4String.mid( myStart2 + LAT_PREFIX_LEN, myLength2 - LAT_PREFIX_LEN );
00384 }
00385
00386 if (( lat1Str != "" ) && ( lat2Str != "" ) )
00387 {
00388
00389 QString theProj4StringModified = theProj4String;
00390
00391 theProj4StringModified.replace( myStart1 + LAT_PREFIX_LEN, myLength1 - LAT_PREFIX_LEN, lat2Str );
00392
00393 myStart2 = 0;
00394 myStart2 = myLat2RegExp.indexIn( theProj4String, myStart2 );
00395 theProj4StringModified.replace( myStart2 + LAT_PREFIX_LEN, myLength2 - LAT_PREFIX_LEN, lat1Str );
00396 QgsDebugMsg( "trying proj4string match with swapped lat_1,lat_2" );
00397 myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( theProj4StringModified.trimmed() ) );
00398 if ( !myRecord.empty() )
00399 {
00400
00401 setProj4String( theProj4StringModified );
00402 mySrsId = myRecord["srs_id"].toLong();
00403 QgsDebugMsg( "proj4string match search for srsid returned srsid: " + QString::number( mySrsId ) );
00404 if ( mySrsId > 0 )
00405 {
00406 createFromSrsId( mySrsId );
00407 }
00408 }
00409 }
00410 else
00411 {
00412
00413 QgsDebugMsg( "globbing search for srsid from this proj string" );
00414 setProj4String( theProj4String );
00415 mySrsId = findMatchingProj();
00416 QgsDebugMsg( "globbing search for srsid returned srsid: " + QString::number( mySrsId ) );
00417 if ( mySrsId > 0 )
00418 {
00419 createFromSrsId( mySrsId );
00420 }
00421 else
00422 {
00423 mIsValidFlag = false;
00424 }
00425 }
00426 }
00427
00428
00429 if ( !mIsValidFlag )
00430 {
00431 QgsDebugMsg( "Projection is not found in databases." );
00432 setProj4String( theProj4String );
00433
00434
00435 if ( mIsValidFlag )
00436 {
00437
00438 myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( toProj4() ) );
00439 if ( myRecord.empty() )
00440 {
00441
00442 QgsDebugMsg( "Projection appears to be valid. Save to database!" );
00443 mIsValidFlag = saveAsUserCRS();
00444
00445 if ( mIsValidFlag )
00446 {
00447
00448 myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( toProj4() ) );
00449 }
00450 }
00451
00452 if ( !myRecord.empty() )
00453 {
00454
00455 mySrsId = myRecord["srs_id"].toLong();
00456 QgsDebugMsg( "proj4string match search for srsid returned srsid: " + QString::number( mySrsId ) );
00457 if ( mySrsId > 0 )
00458 {
00459 createFromSrsId( mySrsId );
00460 }
00461 else
00462 {
00463 QgsDebugMsg( QString( "invalid srid %1 found" ).arg( mySrsId ) );
00464 mIsValidFlag = false;
00465 }
00466 }
00467 else
00468 {
00469 QgsDebugMsg( "Couldn't find newly added proj string?" );
00470 mIsValidFlag = false;
00471 }
00472 }
00473 }
00474
00475
00476 return mIsValidFlag;
00477 }
00478
00479
00480 QgsCoordinateReferenceSystem::RecordMap QgsCoordinateReferenceSystem::getRecord( QString theSql )
00481 {
00482 QString myDatabaseFileName;
00483 QgsCoordinateReferenceSystem::RecordMap myMap;
00484 QString myFieldName;
00485 QString myFieldValue;
00486 sqlite3 *myDatabase;
00487 const char *myTail;
00488 sqlite3_stmt *myPreparedStatement;
00489 int myResult;
00490
00491 QgsDebugMsg( "running query: " + theSql );
00492
00493 myDatabaseFileName = QgsApplication::srsDbFilePath();
00494 QFileInfo myInfo( myDatabaseFileName );
00495 if ( !myInfo.exists() )
00496 {
00497 QgsDebugMsg( "failed : " + myDatabaseFileName +
00498 " does not exist!" );
00499 return myMap;
00500 }
00501
00502
00503 myResult = openDb( myDatabaseFileName, &myDatabase );
00504 if ( myResult != SQLITE_OK )
00505 {
00506 return myMap;
00507 }
00508
00509 myResult = sqlite3_prepare( myDatabase, theSql.toUtf8(), theSql.toUtf8().length(), &myPreparedStatement, &myTail );
00510
00511 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00512 {
00513 QgsDebugMsg( "trying system srs.db" );
00514 int myColumnCount = sqlite3_column_count( myPreparedStatement );
00515
00516 for ( int myColNo = 0; myColNo < myColumnCount; myColNo++ )
00517 {
00518 myFieldName = QString::fromUtf8(( char * )sqlite3_column_name( myPreparedStatement, myColNo ) );
00519 myFieldValue = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, myColNo ) );
00520 myMap[myFieldName] = myFieldValue;
00521 }
00522 }
00523 else
00524 {
00525 QgsDebugMsg( "trying user qgis.db" );
00526 sqlite3_finalize( myPreparedStatement );
00527 sqlite3_close( myDatabase );
00528
00529 myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
00530 QFileInfo myFileInfo;
00531 myFileInfo.setFile( myDatabaseFileName );
00532 if ( !myFileInfo.exists( ) )
00533 {
00534 QgsDebugMsg( "user qgis.db not found" );
00535 return myMap;
00536 }
00537
00538
00539 myResult = openDb( myDatabaseFileName, &myDatabase );
00540 if ( myResult != SQLITE_OK )
00541 {
00542 return myMap;
00543 }
00544
00545 myResult = sqlite3_prepare( myDatabase, theSql.toUtf8(), theSql.toUtf8().length(), &myPreparedStatement, &myTail );
00546
00547 if ( myResult == SQLITE_OK && sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00548 {
00549 int myColumnCount = sqlite3_column_count( myPreparedStatement );
00550
00551 for ( int myColNo = 0; myColNo < myColumnCount; myColNo++ )
00552 {
00553 myFieldName = QString::fromUtf8(( char * )sqlite3_column_name( myPreparedStatement, myColNo ) );
00554 myFieldValue = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, myColNo ) );
00555 myMap[myFieldName] = myFieldValue;
00556 }
00557 }
00558 else
00559 {
00560 QgsDebugMsg( "failed : " + theSql );
00561
00562 }
00563 }
00564 sqlite3_finalize( myPreparedStatement );
00565 sqlite3_close( myDatabase );
00566
00567 #ifdef QGISDEBUG
00568 QgsDebugMsg( "retrieved: " + theSql );
00569 RecordMap::Iterator it;
00570 for ( it = myMap.begin(); it != myMap.end(); ++it )
00571 {
00572 QgsDebugMsgLevel( it.key() + " => " + it.value(), 2 );
00573 }
00574 #endif
00575
00576 return myMap;
00577
00578
00579
00580 }
00581
00582
00583
00584 long QgsCoordinateReferenceSystem::srsid() const
00585 {
00586 return mSrsId;
00587 }
00588
00589 long QgsCoordinateReferenceSystem::postgisSrid() const
00590 {
00591
00592 return mSRID;
00593
00594 }
00595
00596 long QgsCoordinateReferenceSystem::epsg() const
00597 {
00598 if ( mAuthId.startsWith( "EPSG:", Qt::CaseInsensitive ) )
00599 return mAuthId.mid( 5 ).toLong();
00600 else
00601 return 0;
00602 }
00603
00604 QString QgsCoordinateReferenceSystem::authid() const
00605 {
00606 return mAuthId;
00607 }
00608
00609 QString QgsCoordinateReferenceSystem::description() const
00610 {
00611 if ( mDescription.isNull() )
00612 {
00613 return "";
00614 }
00615 else
00616 {
00617 return mDescription;
00618 }
00619 }
00620
00621 QString QgsCoordinateReferenceSystem::projectionAcronym() const
00622 {
00623 if ( mProjectionAcronym.isNull() )
00624 {
00625 return "";
00626 }
00627 else
00628 {
00629 return mProjectionAcronym;
00630 }
00631 }
00632
00633 QString QgsCoordinateReferenceSystem::ellipsoidAcronym() const
00634 {
00635 if ( mEllipsoidAcronym.isNull() )
00636 {
00637 return "";
00638 }
00639 else
00640 {
00641 return mEllipsoidAcronym;
00642 }
00643 }
00644
00645 QString QgsCoordinateReferenceSystem::toProj4() const
00646 {
00647 if ( !mIsValidFlag )
00648 return "";
00649
00650 QString toProj4;
00651 char *proj4src = NULL;
00652 OSRExportToProj4( mCRS, &proj4src );
00653 toProj4 = proj4src;
00654 CPLFree( proj4src );
00655
00656
00657 return toProj4.trimmed();
00658 }
00659
00660 bool QgsCoordinateReferenceSystem::geographicFlag() const
00661 {
00662 return mGeoFlag;
00663 }
00664
00665 QGis::UnitType QgsCoordinateReferenceSystem::mapUnits() const
00666 {
00667 return mMapUnits;
00668 }
00669
00670
00671
00672
00673
00674 void QgsCoordinateReferenceSystem::setInternalId( long theSrsId )
00675 {
00676 mSrsId = theSrsId;
00677 }
00678 void QgsCoordinateReferenceSystem::setAuthId( QString authId )
00679 {
00680 mAuthId = authId;
00681 }
00682 void QgsCoordinateReferenceSystem::setSrid( long theSrid )
00683 {
00684 mSRID = theSrid;
00685 }
00686 void QgsCoordinateReferenceSystem::setDescription( QString theDescription )
00687 {
00688 mDescription = theDescription;
00689 }
00690 void QgsCoordinateReferenceSystem::setProj4String( QString theProj4String )
00691 {
00692 const char *oldlocale = setlocale( LC_NUMERIC, NULL );
00693
00694 setlocale( LC_NUMERIC, "C" );
00695 OSRDestroySpatialReference( mCRS );
00696 mCRS = OSRNewSpatialReference( NULL );
00697 mIsValidFlag = OSRImportFromProj4( mCRS, theProj4String.toLatin1().constData() ) == OGRERR_NONE;
00698 setMapUnits();
00699
00700 #if defined(QGISDEBUG) && QGISDEBUG>=3
00701 debugPrint();
00702 #endif
00703
00704 setlocale( LC_NUMERIC, oldlocale );
00705 }
00706 void QgsCoordinateReferenceSystem::setGeographicFlag( bool theGeoFlag )
00707 {
00708 mGeoFlag = theGeoFlag;
00709 }
00710 void QgsCoordinateReferenceSystem::setEpsg( long theEpsg )
00711 {
00712 mAuthId = QString( "EPSG:%1" ).arg( theEpsg );
00713 }
00714 void QgsCoordinateReferenceSystem::setProjectionAcronym( QString theProjectionAcronym )
00715 {
00716 mProjectionAcronym = theProjectionAcronym;
00717 }
00718 void QgsCoordinateReferenceSystem::setEllipsoidAcronym( QString theEllipsoidAcronym )
00719 {
00720 mEllipsoidAcronym = theEllipsoidAcronym;
00721 }
00722
00723 void QgsCoordinateReferenceSystem::setMapUnits()
00724 {
00725 if ( !mIsValidFlag )
00726 {
00727 mMapUnits = QGis::UnknownUnit;
00728 return;
00729 }
00730
00731 char *unitName;
00732
00733
00734
00735 OSRFixup( mCRS );
00736
00737 if ( OSRIsProjected( mCRS ) )
00738 {
00739 double toMeter = OSRGetLinearUnits( mCRS, &unitName );
00740 QString unit( unitName );
00741
00742
00743
00744
00745
00746
00747 static const double feetToMeter = 0.3048;
00748 static const double smallNum = 1e-3;
00749
00750 if ( std::abs( toMeter - feetToMeter ) < smallNum )
00751 unit = "Foot";
00752
00753 QgsDebugMsg( "Projection has linear units of " + unit );
00754
00755 if ( unit == "Meter" )
00756 mMapUnits = QGis::Meters;
00757 else if ( unit == "Foot" )
00758 mMapUnits = QGis::Feet;
00759 else
00760 {
00761 QgsDebugMsg( "Unsupported map units of " + unit );
00762 mMapUnits = QGis::UnknownUnit;
00763 }
00764 }
00765 else
00766 {
00767 OSRGetAngularUnits( mCRS, &unitName );
00768 QString unit( unitName );
00769 if ( unit == "degree" )
00770 mMapUnits = QGis::Degrees;
00771 else
00772 {
00773 QgsDebugMsg( "Unsupported map units of " + unit );
00774 mMapUnits = QGis::UnknownUnit;
00775 }
00776 QgsDebugMsgLevel( "Projection has angular units of " + unit, 3 );
00777 }
00778 }
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789 long QgsCoordinateReferenceSystem::findMatchingProj()
00790 {
00791 QgsDebugMsg( "entered." );
00792 if ( mEllipsoidAcronym.isNull() || mProjectionAcronym.isNull() || !mIsValidFlag )
00793 {
00794 QgsDebugMsg( "QgsCoordinateReferenceSystem::findMatchingProj will only work if prj acr ellipsoid acr and proj4string are set"
00795 " and the current projection is valid!" );
00796 return 0;
00797 }
00798
00799 sqlite3 *myDatabase;
00800 const char *myTail;
00801 sqlite3_stmt *myPreparedStatement;
00802 int myResult;
00803
00804
00805 QString mySql = QString( "select srs_id,parameters from tbl_srs where projection_acronym=%1 and ellipsoid_acronym=%2" )
00806 .arg( quotedValue( mProjectionAcronym ) )
00807 .arg( quotedValue( mEllipsoidAcronym ) );
00808
00809 QString myDatabaseFileName = QgsApplication::srsDbFilePath();
00810
00811
00812 myResult = openDb( myDatabaseFileName, &myDatabase );
00813 if ( myResult != SQLITE_OK )
00814 {
00815 return 0;
00816 }
00817
00818 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
00819
00820 if ( myResult == SQLITE_OK )
00821 {
00822
00823 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00824 {
00825 QString mySrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
00826 QString myProj4String = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) );
00827 if ( equals( myProj4String ) )
00828 {
00829 QgsDebugMsg( "-------> MATCH FOUND in srs.db srsid: " + mySrsId );
00830
00831 sqlite3_finalize( myPreparedStatement );
00832 sqlite3_close( myDatabase );
00833 return mySrsId.toLong();
00834 }
00835 else
00836 {
00837
00838 }
00839 }
00840 }
00841 QgsDebugMsg( "no match found in srs.db, trying user db now!" );
00842
00843 sqlite3_finalize( myPreparedStatement );
00844 sqlite3_close( myDatabase );
00845
00846
00847
00848
00849 myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
00850
00851 myResult = openDb( myDatabaseFileName, &myDatabase );
00852 if ( myResult != SQLITE_OK )
00853 {
00854 return 0;
00855 }
00856
00857 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
00858
00859 if ( myResult == SQLITE_OK )
00860 {
00861
00862 while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
00863 {
00864 QString mySrsId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
00865 QString myProj4String = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 1 ) );
00866 if ( equals( myProj4String ) )
00867 {
00868 QgsDebugMsg( "-------> MATCH FOUND in user qgis.db srsid: " + mySrsId );
00869
00870 sqlite3_finalize( myPreparedStatement );
00871 sqlite3_close( myDatabase );
00872 return mySrsId.toLong();
00873 }
00874 else
00875 {
00876
00877 }
00878 }
00879 }
00880 QgsDebugMsg( "no match found in user db" );
00881
00882
00883 sqlite3_finalize( myPreparedStatement );
00884 sqlite3_close( myDatabase );
00885 return 0;
00886 }
00887
00888 bool QgsCoordinateReferenceSystem::operator==( const QgsCoordinateReferenceSystem &theSrs )
00889 {
00890 if ( !mIsValidFlag || !theSrs.mIsValidFlag )
00891 {
00892 return false;
00893 }
00894 char *thisStr;
00895 char *otherStr;
00896
00897
00898
00899 if (( OSRExportToWkt( mCRS, &thisStr ) == OGRERR_NONE ) )
00900 {
00901 if ( OSRExportToWkt( theSrs.mCRS, &otherStr ) == OGRERR_NONE )
00902 {
00903 QgsDebugMsgLevel( QString( "Comparing " ) + thisStr, 3 );
00904 QgsDebugMsgLevel( QString( " with " ) + otherStr, 3 );
00905 if ( !strcmp( thisStr, otherStr ) )
00906 {
00907 QgsDebugMsgLevel( QString( "MATCHED!" ) + otherStr, 3 );
00908 CPLFree( thisStr );
00909 CPLFree( otherStr );
00910 return true;
00911 }
00912 CPLFree( otherStr );
00913 }
00914 CPLFree( thisStr );
00915 }
00916 return false;
00917 }
00918
00919 bool QgsCoordinateReferenceSystem::operator!=( const QgsCoordinateReferenceSystem &theSrs )
00920 {
00921 return !( *this == theSrs );
00922 }
00923
00924 bool QgsCoordinateReferenceSystem::equals( QString theProj4String )
00925 {
00926 QgsCoordinateReferenceSystem r;
00927 r.setProj4String( theProj4String );
00928 return *this == r;
00929 }
00930
00931 QString QgsCoordinateReferenceSystem::toWkt() const
00932 {
00933 QString myWkt;
00934 char* Wkt;
00935 if ( OSRExportToWkt( mCRS, &Wkt ) == OGRERR_NONE )
00936 {
00937 myWkt = Wkt;
00938 OGRFree( Wkt );
00939 }
00940
00941 return myWkt;
00942 }
00943
00944 bool QgsCoordinateReferenceSystem::readXML( QDomNode & theNode )
00945 {
00946 QgsDebugMsg( "Reading Spatial Ref Sys from xml ------------------------!" );
00947 QDomNode srsNode = theNode.namedItem( "spatialrefsys" );
00948
00949 if ( ! srsNode.isNull() )
00950 {
00951 bool initialized = false;
00952
00953 QDomNode myNode = srsNode.namedItem( "authid" );
00954 if ( !myNode.isNull() )
00955 {
00956 initialized = createFromOgcWmsCrs( myNode.toElement().text() );
00957 }
00958
00959 if ( !initialized )
00960 {
00961 myNode = srsNode.namedItem( "epsg" );
00962 if ( !myNode.isNull() )
00963 initialized = createFromEpsg( myNode.toElement().text().toLong() );
00964 }
00965
00966 if ( initialized )
00967 {
00968 QgsDebugMsg( "Set from auth id" );
00969 }
00970 else
00971 {
00972 myNode = srsNode.namedItem( "proj4" );
00973
00974 if ( createFromProj4( myNode.toElement().text() ) )
00975 {
00976
00977 QgsDebugMsg( "Setting from proj4 string" );
00978 }
00979 else
00980 {
00981 QgsDebugMsg( "Setting from elements one by one" );
00982
00983 myNode = srsNode.namedItem( "proj4" );
00984 setProj4String( myNode.toElement().text() );
00985
00986 myNode = srsNode.namedItem( "srsid" );
00987 setInternalId( myNode.toElement().text().toLong() );
00988
00989 myNode = srsNode.namedItem( "srid" );
00990 setSrid( myNode.toElement().text().toLong() );
00991
00992 myNode = srsNode.namedItem( "authid" );
00993 setAuthId( myNode.toElement().text() );
00994
00995 myNode = srsNode.namedItem( "description" );
00996 setDescription( myNode.toElement().text() );
00997
00998 myNode = srsNode.namedItem( "projectionacronym" );
00999 setProjectionAcronym( myNode.toElement().text() );
01000
01001 myNode = srsNode.namedItem( "ellipsoidacronym" );
01002 setEllipsoidAcronym( myNode.toElement().text() );
01003
01004 myNode = srsNode.namedItem( "geographicflag" );
01005 if ( myNode.toElement().text().compare( "true" ) )
01006 {
01007 setGeographicFlag( true );
01008 }
01009 else
01010 {
01011 setGeographicFlag( false );
01012 }
01013
01014
01015 setMapUnits();
01016
01017
01018 mIsValidFlag = true;
01019 }
01020 }
01021 }
01022 else
01023 {
01024
01025 createFromId( GEOCRS_ID, InternalCrsId );
01026 }
01027 return true;
01028 }
01029
01030 bool QgsCoordinateReferenceSystem::writeXML( QDomNode & theNode, QDomDocument & theDoc ) const
01031 {
01032
01033 QDomElement myLayerNode = theNode.toElement();
01034 QDomElement mySrsElement = theDoc.createElement( "spatialrefsys" );
01035
01036 QDomElement myProj4Element = theDoc.createElement( "proj4" );
01037 myProj4Element.appendChild( theDoc.createTextNode( toProj4() ) );
01038 mySrsElement.appendChild( myProj4Element );
01039
01040 QDomElement mySrsIdElement = theDoc.createElement( "srsid" );
01041 mySrsIdElement.appendChild( theDoc.createTextNode( QString::number( srsid() ) ) );
01042 mySrsElement.appendChild( mySrsIdElement );
01043
01044 QDomElement mySridElement = theDoc.createElement( "srid" );
01045 mySridElement.appendChild( theDoc.createTextNode( QString::number( postgisSrid() ) ) );
01046 mySrsElement.appendChild( mySridElement );
01047
01048 QDomElement myEpsgElement = theDoc.createElement( "authid" );
01049 myEpsgElement.appendChild( theDoc.createTextNode( authid() ) );
01050 mySrsElement.appendChild( myEpsgElement );
01051
01052 QDomElement myDescriptionElement = theDoc.createElement( "description" );
01053 myDescriptionElement.appendChild( theDoc.createTextNode( description() ) );
01054 mySrsElement.appendChild( myDescriptionElement );
01055
01056 QDomElement myProjectionAcronymElement = theDoc.createElement( "projectionacronym" );
01057 myProjectionAcronymElement.appendChild( theDoc.createTextNode( projectionAcronym() ) );
01058 mySrsElement.appendChild( myProjectionAcronymElement );
01059
01060 QDomElement myEllipsoidAcronymElement = theDoc.createElement( "ellipsoidacronym" );
01061 myEllipsoidAcronymElement.appendChild( theDoc.createTextNode( ellipsoidAcronym() ) );
01062 mySrsElement.appendChild( myEllipsoidAcronymElement );
01063
01064 QDomElement myGeographicFlagElement = theDoc.createElement( "geographicflag" );
01065 QString myGeoFlagText = "false";
01066 if ( geographicFlag() )
01067 {
01068 myGeoFlagText = "true";
01069 }
01070
01071 myGeographicFlagElement.appendChild( theDoc.createTextNode( myGeoFlagText ) );
01072 mySrsElement.appendChild( myGeographicFlagElement );
01073
01074 myLayerNode.appendChild( mySrsElement );
01075
01076 return true;
01077 }
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088 QString QgsCoordinateReferenceSystem::proj4FromSrsId( const int theSrsId )
01089 {
01090
01091 QString myDatabaseFileName;
01092 QString myProjString;
01093 QString mySql = "select parameters from tbl_srs where srs_id = ";
01094 mySql += QString::number( theSrsId );
01095
01096 QgsDebugMsg( "mySrsId = " + QString::number( theSrsId ) );
01097 QgsDebugMsg( "USER_CRS_START_ID = " + QString::number( USER_CRS_START_ID ) );
01098 QgsDebugMsg( "Selection sql : " + mySql );
01099
01100
01101
01102
01103
01104 if ( theSrsId >= USER_CRS_START_ID )
01105 {
01106 myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
01107 QFileInfo myFileInfo;
01108 myFileInfo.setFile( myDatabaseFileName );
01109 if ( !myFileInfo.exists( ) )
01110 {
01111 QgsDebugMsg( "users qgis.db not found" );
01112 return NULL;
01113 }
01114 }
01115 else
01116 {
01117 myDatabaseFileName = QgsApplication::srsDbFilePath();
01118 }
01119 QgsDebugMsg( "db = " + myDatabaseFileName );
01120
01121 sqlite3 *db;
01122 int rc;
01123 rc = openDb( myDatabaseFileName, &db );
01124 if ( rc )
01125 {
01126 return QString();
01127 }
01128
01129 const char *pzTail;
01130 sqlite3_stmt *ppStmt;
01131
01132 rc = sqlite3_prepare( db, mySql.toUtf8(), mySql.toUtf8().length(), &ppStmt, &pzTail );
01133
01134
01135 if ( rc == SQLITE_OK )
01136 {
01137 if ( sqlite3_step( ppStmt ) == SQLITE_ROW )
01138 {
01139 myProjString = QString::fromUtf8(( char* )sqlite3_column_text( ppStmt, 0 ) );
01140 }
01141 }
01142
01143 sqlite3_finalize( ppStmt );
01144
01145 sqlite3_close( db );
01146
01147
01148 return myProjString;
01149 }
01150
01151 int QgsCoordinateReferenceSystem::openDb( QString path, sqlite3 **db )
01152 {
01153 QgsDebugMsgLevel( "path = " + path, 3 );
01154 int myResult = sqlite3_open( path.toUtf8().data(), db );
01155
01156 if ( myResult != SQLITE_OK )
01157 {
01158 QgsDebugMsg( "Can't open database: " + QString( sqlite3_errmsg( *db ) ) );
01159
01160
01161
01162 QgsMessageOutput* output = QgsMessageOutput::createMessageOutput();
01163 output->setTitle( "Error" );
01164 output->setMessage( QObject::tr( "Could not open CRS database %1<br>Error(%2): %3" )
01165 .arg( path )
01166 .arg( myResult )
01167 .arg( sqlite3_errmsg( *db ) ), QgsMessageOutput::MessageText );
01168 output->showMessage();
01169 }
01170 return myResult;
01171 }
01172
01173 void QgsCoordinateReferenceSystem::setCustomSrsValidation( CUSTOM_CRS_VALIDATION f )
01174 {
01175 mCustomSrsValidation = f;
01176 }
01177
01178 CUSTOM_CRS_VALIDATION QgsCoordinateReferenceSystem::customSrsValidation()
01179 {
01180 return mCustomSrsValidation;
01181 }
01182
01183 void QgsCoordinateReferenceSystem::debugPrint()
01184 {
01185 QgsDebugMsg( "***SpatialRefSystem***" );
01186 QgsDebugMsg( "* Valid : " + ( mIsValidFlag ? QString( "true" ) : QString( "false" ) ) );
01187 QgsDebugMsg( "* SrsId : " + QString::number( mSrsId ) );
01188 QgsDebugMsg( "* Proj4 : " + toProj4() );
01189 QgsDebugMsg( "* WKT : " + toWkt() );
01190 QgsDebugMsg( "* Desc. : " + mDescription );
01191 if ( mapUnits() == QGis::Meters )
01192 {
01193 QgsDebugMsg( "* Units : meters" );
01194 }
01195 else if ( mapUnits() == QGis::Feet )
01196 {
01197 QgsDebugMsg( "* Units : feet" );
01198 }
01199 else if ( mapUnits() == QGis::Degrees )
01200 {
01201 QgsDebugMsg( "* Units : degrees" );
01202 }
01203 }
01204
01205 void QgsCoordinateReferenceSystem::setValidationHint( QString html )
01206 {
01207 mValidationHint = html;
01208 }
01209
01210 QString QgsCoordinateReferenceSystem::validationHint()
01211 {
01212 return mValidationHint;
01213 }
01214
01217
01218 bool QgsCoordinateReferenceSystem::saveAsUserCRS()
01219 {
01220 if ( ! mIsValidFlag )
01221 {
01222 QgsDebugMsg( "Can't save an invalid CRS!" );
01223 return false;
01224 }
01225
01226 QString mySql;
01227 QString myName = QString( " * %1 (%2)" )
01228 .arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ) )
01229 .arg( toProj4() );
01230
01231
01232
01233
01234
01235 if ( getRecordCount() == 0 )
01236 {
01237 mySql = "insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ("
01238 + QString::number( USER_CRS_START_ID )
01239 + "," + quotedValue( myName )
01240 + "," + quotedValue( projectionAcronym() )
01241 + "," + quotedValue( ellipsoidAcronym() )
01242 + "," + quotedValue( toProj4() )
01243 + ",0)";
01244 }
01245 else
01246 {
01247 mySql = "insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ("
01248 + quotedValue( myName )
01249 + "," + quotedValue( projectionAcronym() )
01250 + "," + quotedValue( ellipsoidAcronym() )
01251 + "," + quotedValue( toProj4() )
01252 + ",0)";
01253 }
01254 sqlite3 *myDatabase;
01255 const char *myTail;
01256 sqlite3_stmt *myPreparedStatement;
01257 int myResult;
01258
01259 myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
01260 if ( myResult != SQLITE_OK )
01261 {
01262 QgsDebugMsg( QString( "Can't open or create database %1: %2" )
01263 .arg( QgsApplication::qgisUserDbFilePath() )
01264 .arg( sqlite3_errmsg( myDatabase ) ) );
01265 return false;
01266 }
01267 QgsDebugMsg( QString( "Update or insert sql \n%1" ).arg( mySql ) );
01268 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
01269 sqlite3_step( myPreparedStatement );
01270
01271 return myResult == SQLITE_OK;
01272 }
01273
01274 long QgsCoordinateReferenceSystem::getRecordCount()
01275 {
01276 sqlite3 *myDatabase;
01277 const char *myTail;
01278 sqlite3_stmt *myPreparedStatement;
01279 int myResult;
01280 long myRecordCount = 0;
01281
01282 myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
01283 if ( myResult != SQLITE_OK )
01284 {
01285 QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
01286 return 0;
01287 }
01288
01289 QString mySql = "select count(*) from tbl_srs";
01290 myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
01291
01292 if ( myResult == SQLITE_OK )
01293 {
01294 if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
01295 {
01296 QString myRecordCountString = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
01297 myRecordCount = myRecordCountString.toLong();
01298 }
01299 }
01300
01301 sqlite3_finalize( myPreparedStatement );
01302 sqlite3_close( myDatabase );
01303 return myRecordCount;
01304 }
01305
01306 QString QgsCoordinateReferenceSystem::quotedValue( QString value )
01307 {
01308 value.replace( "'", "''" );
01309 return value.prepend( "'" ).append( "'" );
01310 }