Quantum GIS API Documentation
1.7.4
|
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 }