1
#include "qgsspatialrefsys.h"
13
#include <QDomElement>
14
#include <QMessageBox>
16
#include <qgsapplication.h>
17
#include <qgslayerprojectionselector.h>
18
#include "qgslogger.h"
19
#include <qgsproject.h>
20
#include <qgis.h> //const vals declared here
23
//gdal and ogr includes (needed for == operator)
25
#include <ogr_spatialref.h>
26
#include <cpl_error.h>
29
//--------------------------
31
QgsSpatialRefSys::QgsSpatialRefSys()
32
: mMapUnits(QGis::UNKNOWN),
38
QgsSpatialRefSys::QgsSpatialRefSys(QString theWkt)
39
: mMapUnits(QGis::UNKNOWN),
42
createFromWkt(theWkt);
45
QgsSpatialRefSys::QgsSpatialRefSys(long theSrsId,
46
QString theDescription,
47
QString theProjectionAcronym,
48
QString theEllipsoidAcronym,
49
QString theProj4String,
53
: mMapUnits(QGis::UNKNOWN),
59
QgsSpatialRefSys::QgsSpatialRefSys(const long theId, SRS_TYPE theType)
60
: mMapUnits(QGis::UNKNOWN),
63
createFromId(theId, theType);
66
void QgsSpatialRefSys::createFromId(const long theId, SRS_TYPE theType)
71
createFromSrsId(theId);
74
createFromSrid(theId);
77
createFromEpsg(theId);
80
//THIS IS BAD...THIS PART OF CODE SHOULD NEVER BE REACHED...
81
QgsLogger::critical("Unexpected case reached in " + QString(__FILE__) + " : " + QString(__LINE__));
87
bool QgsSpatialRefSys::createFromOgcWmsCrs(QString theCrs)
89
QStringList parts = theCrs.split(":");
91
if (parts.at(0) == "EPSG")
93
createFromEpsg( parts.at(1).toLong() );
95
else if (parts.at(0) == "CRS")
97
if (parts.at(1) == "84")
99
//! \todo - CRS:84 is hardcoded to EPSG:4326 - see if this is appropriate
101
* See WMS 1.3 standard appendix B3 for details
103
createFromEpsg( 4326 );
115
// Assignment operator
116
QgsSpatialRefSys& QgsSpatialRefSys::operator=(const QgsSpatialRefSys& srs)
121
mDescription = srs.mDescription;
122
mProjectionAcronym = srs.mProjectionAcronym;
123
mEllipsoidAcronym = srs.mEllipsoidAcronym;
124
mProj4String = srs.mProj4String;
125
mGeoFlag = srs.mGeoFlag;
126
mMapUnits = srs.mMapUnits;
129
mIsValidFlag = srs.mIsValidFlag;
134
// Misc helper functions -----------------------
137
void QgsSpatialRefSys::validate()
139
QgsDebugMsg("QgsSpatialRefSys::validate");
140
//dont bother trying to do an initial test with gdal if
141
//the proj4String is not even populated
142
if (QString::null!=mProj4String && !mProj4String.isEmpty())
144
//first of all use gdal to test if this is an ok srs already
145
//if not we will prompt the user for and srs
146
//then retest using gdal
147
//if the retest fails we will then set this srs to the GEOCS/WGS84 default
150
/* Here are the possible OGR error codes :
153
#define OGRERR_NONE 0
154
#define OGRERR_NOT_ENOUGH_DATA 1 --> not enough data to deserialize
155
#define OGRERR_NOT_ENOUGH_MEMORY 2
156
#define OGRERR_UNSUPPORTED_GEOMETRY_TYPE 3
157
#define OGRERR_UNSUPPORTED_OPERATION 4
158
#define OGRERR_CORRUPT_DATA 5
159
#define OGRERR_FAILURE 6
160
#define OGRERR_UNSUPPORTED_SRS 7 */
162
//get the wkt into ogr
163
//this is really ugly but we need to get a QString to a char**
164
const char *mySourceCharArrayPointer = mProj4String.latin1();
165
//create the sr and populate it from a wkt proj definition
166
OGRSpatialReference myOgrSpatialRef;
167
OGRErr myInputResult = myOgrSpatialRef.importFromProj4( mySourceCharArrayPointer );
169
if (myInputResult==OGRERR_NONE)
171
//srs is valid so nothing more to do...
172
createFromProj4(mProj4String);
177
QSettings mySettings;
178
QString myDefaultProjectionOption =
179
mySettings.readEntry("/Projections/defaultBehaviour");
181
if (myDefaultProjectionOption=="prompt")
183
//@note this class is not a descendent of QWidget so we cant pass
184
//it in the ctor of the layer projection selector
186
QgsLayerProjectionSelector * mySelector = new QgsLayerProjectionSelector();
188
QgsProject::instance()->readNumEntry("SpatialRefSys","/ProjectSRSID",GEOSRS_ID);
189
mySelector->setSelectedSRSID(myDefaultSRS);
190
if(mySelector->exec())
192
createFromSrsId(mySelector->getCurrentSRSID());
198
QApplication::restoreOverrideCursor();
202
else if (myDefaultProjectionOption=="useProject")
204
// XXX TODO: Change project to store selected CS as 'projectSRS' not 'selectedWKT'
205
mProj4String = QgsProject::instance()->readEntry("SpatialRefSys","//ProjectSRSProj4String",GEOPROJ4);
207
else ///Projections/defaultBehaviour==useGlobal
209
// XXX TODO: Change global settings to store default CS as 'defaultSRS' not 'defaultProjectionWKT'
210
int srs_id = mySettings.readNumEntry("/Projections/defaultProjectionSRSID",GEOSRS_ID);
211
createFromSrsId(srs_id);
216
// This is the second check after the user assigned SRS has been retrieved
217
// If it still does not work, we will simply use the QgsSpatialRefSys const GEOPROJ4 for the job
220
//this is really ugly but we need to get a QString to a char**
221
const char *mySourceCharArrayPointer = mProj4String.latin1();
222
//create the sr and populate it from a wkt proj definition
223
OGRSpatialReference myOgrSpatialRef;
224
OGRErr myInputResult = myOgrSpatialRef.importFromProj4( mySourceCharArrayPointer );
226
if (! myInputResult==OGRERR_NONE)
228
//default to proj 4..if all else fails we will use that for this srs
229
mProj4String = GEOPROJ4;
232
createFromProj4(mProj4String);
237
bool QgsSpatialRefSys::createFromSrid(long theSrid)
239
QgsDebugMsg("QgsSpatialRefSys::createFromSrid");
241
// Get the full path name to the sqlite3 spatial reference database.
242
QString myDatabaseFileName = QgsApplication::srsDbFilePath();
247
sqlite3_stmt *myPreparedStatement;
249
//check the db is available
250
myResult = openDb(myDatabaseFileName, &myDatabase);
257
srs_id INTEGER PRIMARY KEY,
258
description text NOT NULL,
259
projection_acronym text NOT NULL,
260
ellipsoid_acronym NOT NULL,
261
parameters text NOT NULL,
262
srid integer NOT NULL,
263
epsg integer NOT NULL,
264
is_geo integer NOT NULL);
267
QString mySql = "select srs_id,description,projection_acronym,ellipsoid_acronym,parameters,srid,epsg,is_geo from tbl_srs where srid='" + QString::number(theSrid) + "'";
268
myResult = sqlite3_prepare(myDatabase, mySql.utf8(), mySql.length(), &myPreparedStatement, &myTail);
269
// XXX Need to free memory from the error msg if one is set
270
if(myResult == SQLITE_OK && sqlite3_step(myPreparedStatement) == SQLITE_ROW)
272
mSrsId = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,0)).toLong();
273
mDescription = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,1));
274
mProjectionAcronym = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,2));
275
mEllipsoidAcronym = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,3));
276
mProj4String = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,4));
277
mSRID = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,5)).toLong();
278
mEpsg = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,6)).toLong();
279
int geo = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,7)).toInt();
280
mGeoFlag = (geo == 0 ? false : true);
287
QgsDebugMsg("QgsSpatialRefSys::createFromSrid failed : " + mySql);
288
mIsValidFlag = false;
290
sqlite3_finalize(myPreparedStatement);
291
sqlite3_close(myDatabase);
295
bool QgsSpatialRefSys::createFromWkt(QString theWkt)
297
if (theWkt.isEmpty())
299
QgsLogger::critical("QgsSpatialRefSys::createFromWkt -- theWkt is uninitialised, operation failed");
300
mIsValidFlag = false;
303
QgsDebugMsg("QgsSpatialRefSys::createFromWkt(QString theWkt) using: " + theWkt);
304
//this is really ugly but we need to get a QString to a char**
305
const char *myCharArrayPointer = theWkt.latin1(); //Why doesn't it work with toLocal8Bit().data()?
306
char *pWkt = (char *)myCharArrayPointer;
307
/* Here are the possible OGR error codes :
309
#define OGRERR_NONE 0
310
#define OGRERR_NOT_ENOUGH_DATA 1 --> not enough data to deserialize
311
#define OGRERR_NOT_ENOUGH_MEMORY 2
312
#define OGRERR_UNSUPPORTED_GEOMETRY_TYPE 3
313
#define OGRERR_UNSUPPORTED_OPERATION 4
314
#define OGRERR_CORRUPT_DATA 5
315
#define OGRERR_FAILURE 6
316
#define OGRERR_UNSUPPORTED_SRS 7
319
OGRSpatialReference myOgrSpatialRef;
321
OGRErr myInputResult = myOgrSpatialRef.importFromWkt( &pWkt );
322
if (myInputResult != OGRERR_NONE)
324
QgsDebugMsg("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv");
325
QgsDebugMsg("QgsSpatialRefSys::createFromWkt(QString theWkt) ");
326
QgsDebugMsg("This SRS could *** NOT *** be set from the supplied WKT ");
327
QgsDebugMsg("INPUT: " + theWkt);
328
QgsDebugMsg("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
329
mIsValidFlag = false;
334
// always morph from esri as it doesn't hurt anything
335
myOgrSpatialRef.morphFromESRI();
336
// create the proj4 structs needed for transforming
338
myOgrSpatialRef.exportToProj4(&proj4src);
340
//now that we have the proj4string, delegate to createFromProj4String so
341
// that we can try to fill in the remaining class members...
342
//create from Proj wil set the isValidFalg
343
createFromProj4(QString(proj4src));
345
//setMapunits will be called by createfromproj above
348
bool QgsSpatialRefSys::createFromEpsg(long theEpsg)
350
QgsDebugMsg("QgsSpatialRefSys::createFromEpsg with " + QString::number(theEpsg));
351
// Get the full path name to the sqlite3 spatial reference database.
352
QString myDatabaseFileName = QgsApplication::srsDbFilePath();
357
sqlite3_stmt *myPreparedStatement;
359
//check the db is available
360
myResult = openDb(myDatabaseFileName, &myDatabase);
367
srs_id INTEGER PRIMARY KEY,
368
description text NOT NULL,
369
projection_acronym text NOT NULL,
370
ellipsoid_acronym NOT NULL,
371
parameters text NOT NULL,
372
srid integer NOT NULL,
373
epsg integer NOT NULL,
374
is_geo integer NOT NULL);
377
QString mySql = "select srs_id,description,projection_acronym,ellipsoid_acronym,parameters,srid,epsg,is_geo from tbl_srs where epsg='" + QString::number(theEpsg) + "'";
378
myResult = sqlite3_prepare(myDatabase, mySql.utf8(), mySql.length(), &myPreparedStatement, &myTail);
379
// XXX Need to free memory from the error msg if one is set
380
if(myResult == SQLITE_OK && sqlite3_step(myPreparedStatement) == SQLITE_ROW)
382
mSrsId = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,0)).toLong();
383
mDescription = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,1));
384
mProjectionAcronym = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,2));
385
mEllipsoidAcronym = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,3));
386
mProj4String = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,4));
387
mSRID = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,5)).toLong();
388
mEpsg = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,6)).toLong();
389
int geo = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,7)).toInt();
390
mGeoFlag = (geo == 0 ? false : true);
397
QgsLogger::critical(" QgsSpatialRefSys::createFromEpsg failed : " + mySql);
398
mIsValidFlag = false;
400
sqlite3_finalize(myPreparedStatement);
401
sqlite3_close(myDatabase);
406
bool QgsSpatialRefSys::createFromSrsId (long theSrsId)
408
QgsDebugMsg("QgsSpatialRefSys::createFromSrsId");
409
QString myDatabaseFileName;
411
// Determine if this is a user projection or a system on
412
// user projection defs all have srs_id >= 100000
414
if (theSrsId>= USER_PROJECTION_START_ID)
416
myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
417
QFileInfo myFileInfo;
418
myFileInfo.setFile(myDatabaseFileName);
419
if ( !myFileInfo.exists( ) )
421
mIsValidFlag = false;
422
QgsLogger::warning("QgsSpatialRefSys::createFromSrid failed : users qgis.db not found");
426
else //must be a system projection then
428
// Get the full path name to the sqlite3 spatial reference database.
429
myDatabaseFileName = QgsApplication::srsDbFilePath();
435
sqlite3_stmt *myPreparedStatement;
437
//check the db is available
438
myResult = openDb(myDatabaseFileName, &myDatabase);
445
srs_id INTEGER PRIMARY KEY,
446
description text NOT NULL,
447
projection_acronym text NOT NULL,
448
ellipsoid_acronym NOT NULL,
449
parameters text NOT NULL,
450
srid integer NOT NULL,
451
epsg integer NOT NULL,
452
is_geo integer NOT NULL);
455
QString mySql = "select srs_id,description,projection_acronym,ellipsoid_acronym,parameters,srid,epsg,is_geo from tbl_srs where srs_id='" + QString::number(theSrsId) + "'";
456
myResult = sqlite3_prepare(myDatabase, mySql.utf8(), mySql.length(), &myPreparedStatement, &myTail);
457
// XXX Need to free memory from the error msg if one is set
458
if(myResult == SQLITE_OK && sqlite3_step(myPreparedStatement) == SQLITE_ROW)
460
mSrsId = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,0)).toLong();
461
mDescription = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,1));
462
mProjectionAcronym = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,2));
463
mEllipsoidAcronym = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,3));
464
mProj4String = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,4));
465
mSRID = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,5)).toLong();
466
mEpsg = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,6)).toLong();
467
int geo = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,7)).toInt();
468
mGeoFlag = (geo == 0 ? false : true);
475
QgsLogger::warning("QgsSpatialRefSys::createFromSrsId failed : " + mySql);
476
mIsValidFlag = false;
478
sqlite3_finalize(myPreparedStatement);
479
sqlite3_close(myDatabase);
487
bool QgsSpatialRefSys::isValid() const
489
if (mProj4String.isEmpty())
492
//this is really ugly but we need to get a QString to a char**
493
const char *mySourceCharArrayPointer = mProj4String.latin1();
494
//create the sr and populate it from a wkt proj definition
495
OGRSpatialReference myOgrSpatialRef;
496
OGRErr myResult = myOgrSpatialRef.importFromProj4( mySourceCharArrayPointer );
497
if (myResult==OGRERR_NONE)
499
//srs is valid so nothing more to do...
508
bool QgsSpatialRefSys::createFromProj4 (const QString theProj4String)
513
// +proj=tmerc +lat_0=0 +lon_0=-62 +k=0.999500 +x_0=400000 +y_0=0
514
// +ellps=clrk80 +towgs84=-255,-15,71,0,0,0,0 +units=m +no_defs
518
QRegExp myProjRegExp( "\\+proj=\\S+" );
521
myStart = myProjRegExp.search(theProj4String, myStart);
524
QgsLogger::warning("QgsSpatialRefSys::createFromProj4 error proj string supplied has no +proj argument");
529
myLength = myProjRegExp.matchedLength();
532
mProjectionAcronym = theProj4String.mid(myStart+PROJ_PREFIX_LEN,myLength-PROJ_PREFIX_LEN);
534
QRegExp myEllipseRegExp( "\\+ellps=\\S+" );
537
myStart = myEllipseRegExp.search(theProj4String, myStart);
540
std::cout << "QgsSpatialRefSys::createFromProj4 error proj string supplied has no +ellps argument" << std::endl;
546
myLength = myEllipseRegExp.matchedLength();
548
mEllipsoidAcronym = theProj4String.mid(myStart+ELLPS_PREFIX_LEN,myLength-ELLPS_PREFIX_LEN);
549
//mproj4string must be set here for the rest of this method to behave in a meaningful way...
550
mProj4String = theProj4String;
554
* We try to match the proj string to and srsid using the following logic:
556
* - perform a whole text search on srs name (if not null). The srs name will
557
* have been set if this method has been delegated to from createFromWkt.
558
* Normally we wouldnt expect this to work, but its worth trying first
559
* as its quicker than methods below..
562
QgsSpatialRefSys::RecordMap myRecord;
563
if (!mDescription.stripWhiteSpace ().isEmpty())
565
myRecord = getRecord("select * from tbl_srs where description='" + mDescription.stripWhiteSpace () + "'");
567
if (!myRecord.empty())
569
mySrsId=myRecord["srs_id"].toLong();
570
QgsDebugMsg("QgsSpatialRefSys::createFromProj4 Projection Description match search for srsid returned srsid: "\
571
+ QString::number(mySrsId));
574
createFromSrsId(mySrsId);
580
* - if the above does not match perform a whole text search on proj4 string (if not null)
582
QgsDebugMsg("QgsSpatialRefSys::createFromProj4 wholetext match on name failed, trying proj4string match");
583
myRecord = getRecord("select * from tbl_srs where parameters='" + mProj4String.stripWhiteSpace () + "'");
584
if (!myRecord.empty())
586
mySrsId=myRecord["srs_id"].toLong();
587
QgsDebugMsg("QgsSpatialRefSys::createFromProj4 proj4string match search for srsid returned srsid: " \
588
+ QString::number(mySrsId));
591
createFromSrsId(mySrsId);
597
QgsDebugMsg("QgsSpatialRefSys::createFromProj4 globbing search for srsid from this proj string");
598
mySrsId = findMatchingProj();
599
QgsDebugMsg("QgsSpatialRefSys::createFromProj4 globbing search for srsid returned srsid: "\
600
+ QString::number(mySrsId));
603
createFromSrsId(mySrsId);
608
/* If its still empty after all the above steps then all we can do is keep the proj string
609
* with what was passed in and hope for the best...If its not empty we can fill other member details in
614
QgsSpatialRefSys::RecordMap QgsSpatialRefSys::getRecord(QString theSql)
617
QString myDatabaseFileName;
618
QgsSpatialRefSys::RecordMap myMap;
620
QString myFieldValue;
623
sqlite3_stmt *myPreparedStatement;
626
QgsDebugMsg("QgsSpatialRefSys::getRecord...running query: " + theSql);
627
// Get the full path name to the sqlite3 spatial reference database.
628
myDatabaseFileName = QgsApplication::srsDbFilePath();
630
//check the db is available
631
myResult = openDb(myDatabaseFileName, &myDatabase);
637
myResult = sqlite3_prepare(myDatabase, theSql.utf8(), theSql.length(), &myPreparedStatement, &myTail);
638
// XXX Need to free memory from the error msg if one is set
639
if(myResult == SQLITE_OK && sqlite3_step(myPreparedStatement) == SQLITE_ROW)
641
int myColumnCount = sqlite3_column_count(myPreparedStatement);
642
//loop through each column in the record adding its field name and vvalue to the map
643
for (int myColNo=0;myColNo < myColumnCount;myColNo++)
645
myFieldName = QString::fromUtf8((char *)sqlite3_column_name(myPreparedStatement,myColNo));
646
myFieldValue = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,myColNo));
647
myMap[myFieldName]=myFieldValue;
652
QgsDebugMsg("QgsSpatialRefSys::getRecord...trying system users.db");
653
sqlite3_finalize(myPreparedStatement);
654
sqlite3_close(myDatabase);
656
myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
657
QFileInfo myFileInfo;
658
myFileInfo.setFile(myDatabaseFileName);
659
if ( !myFileInfo.exists( ) )
661
QgsLogger::warning("QgsSpatialRefSys::getRecord failed : users qgis.db not found");
665
//check the db is available
666
myResult = openDb(myDatabaseFileName, &myDatabase);
672
myResult = sqlite3_prepare(myDatabase, theSql.utf8(), theSql.length(), &myPreparedStatement, &myTail);
673
// XXX Need to free memory from the error msg if one is set
674
if(myResult == SQLITE_OK && sqlite3_step(myPreparedStatement) == SQLITE_ROW)
676
int myColumnCount = sqlite3_column_count(myPreparedStatement);
677
//loop through each column in the record adding its field name and vvalue to the map
678
for (int myColNo=0;myColNo < myColumnCount;myColNo++)
680
myFieldName = QString::fromUtf8((char *)sqlite3_column_name(myPreparedStatement,myColNo));
681
myFieldValue = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,myColNo));
682
myMap[myFieldName]=myFieldValue;
687
QgsLogger::warning("QgsSpatialRefSys::getRecord failed : " + theSql);
691
sqlite3_finalize(myPreparedStatement);
692
sqlite3_close(myDatabase);
695
QgsDebugMsg("QgsSpatialRefSys::getRecord retrieved: " + theSql);
696
RecordMap::Iterator it;
697
for ( it = myMap.begin(); it != myMap.end(); ++it )
699
QgsDebugMsgLevel(it.key() + " => " + it.data(), 2);
709
// Accessors -----------------------------------
711
* @return long theSrsId The internal sqlite3 srs.db primary key for this srs
713
long QgsSpatialRefSys::srsid() const
717
/*! Get the Postgis SRID - if possible
718
* @return long theSRID The internal postgis SRID for this SRS
720
long QgsSpatialRefSys::srid() const
726
/*! Get the Description
727
* @return QString the Description A textual description of the srs.
729
QString QgsSpatialRefSys::description () const
731
if (mDescription.isNull())
740
/*! Get the Projection Acronym
741
* @return QString theProjectionAcronym The official proj4 acronym for the projection family
743
QString QgsSpatialRefSys::projectionAcronym() const
745
if (mProjectionAcronym.isNull())
751
return mProjectionAcronym;
754
/*! Get the Ellipsoid Acronym
755
* @return QString theEllipsoidAcronym The official proj4 acronym for the ellipoid
757
QString QgsSpatialRefSys::ellipsoidAcronym () const
759
if (mEllipsoidAcronym.isNull())
765
return mEllipsoidAcronym;
768
/* Get the Proj Proj4String.
769
* @return QString theProj4String Proj4 format specifies that define this srs.
771
QString QgsSpatialRefSys::proj4String() const
773
if (mProj4String.isNull())
782
/*! Get this Geographic? flag
783
* @return bool theGeoFlag Whether this is a geographic or projected coordinate system
785
bool QgsSpatialRefSys::geographicFlag () const
789
/*! Get the units that the projection is in
790
* @return QGis::units
792
QGis::units QgsSpatialRefSys::mapUnits() const
797
/*! Set the postgis srid for this srs
798
* @return long theSRID the Postgis spatial_ref_sys identifier for this srs (defaults to 0)
800
long QgsSpatialRefSys::postgisSrid () const
804
/*! Set the EPSG identifier for this srs
805
* @return long theEpsg the ESPG identifier for this srs (defaults to 0)
807
long QgsSpatialRefSys::epsg () const
812
// Mutators -----------------------------------
815
void QgsSpatialRefSys::setSrsId(long theSrsId)
819
void QgsSpatialRefSys::setSrid(long theSrid)
823
void QgsSpatialRefSys::setDescription (QString theDescription)
825
mDescription = theDescription;
827
void QgsSpatialRefSys::setProj4String (QString theProj4String)
829
mProj4String = theProj4String;
831
void QgsSpatialRefSys::setGeographicFlag (bool theGeoFlag)
835
void QgsSpatialRefSys::setEpsg (long theEpsg)
839
void QgsSpatialRefSys::setProjectionAcronym(QString theProjectionAcronym)
841
mProjectionAcronym=theProjectionAcronym;
843
void QgsSpatialRefSys::setEllipsoidAcronym(QString theEllipsoidAcronym)
845
mEllipsoidAcronym=theEllipsoidAcronym;
847
/*! Work out the projection units and set the appropriate local variable
850
void QgsSpatialRefSys::setMapUnits()
852
if (mProj4String.isEmpty())
854
QgsLogger::warning("No proj4 projection string. Unable to set map units.");
855
mMapUnits = QGis::UNKNOWN;
860
OGRSpatialReference myOgrSpatialRef;
861
myOgrSpatialRef.importFromProj4(mProj4String.latin1());
863
// Of interest to us is that this call adds in a unit parameter if
864
// one doesn't already exist.
865
myOgrSpatialRef.Fixup();
867
if (myOgrSpatialRef.IsProjected())
869
double toMeter = myOgrSpatialRef.GetLinearUnits(&unitName);
870
QString unit(unitName);
872
// If the units parameter was created during the Fixup() call
873
// above, the name of the units is likely to be 'unknown'. Try to
874
// do better than that ... (but perhaps ogr should be enhanced to
875
// do this instead?).
877
static const double feetToMeter = 0.3048;
878
static const double smallNum = 1e-3;
880
if (std::abs(toMeter - feetToMeter) < smallNum)
883
QgsDebugMsg("Projection has linear units of " + unit);
886
mMapUnits = QGis::METERS;
887
else if (unit == "Foot")
888
mMapUnits = QGis::FEET;
891
QgsLogger::warning("Unsupported map units of " + unit);
892
mMapUnits = QGis::UNKNOWN;
897
myOgrSpatialRef.GetAngularUnits(&unitName);
898
QString unit(unitName);
899
if (unit == "degree")
900
mMapUnits = QGis::DEGREES;
903
QgsLogger::warning("Unsupported map units of " + unit);
904
mMapUnits = QGis::UNKNOWN;
906
QgsDebugMsg("Projection has angular units of " + unit);
912
* check if srs is a geocs or a proj cs (using ogr isGeographic)
913
* then sequentially walk through the database (first users qgis.db srs tbl then
914
* system srs.db tbl), converting each entry into an ogr srs and using isSame
915
* or isSameGeocs (essentially calling the == overloaded operator). We'll try to
916
* be smart about this and first parse out the proj and ellpse strings and only
917
* check for a match in entities that have the same ellps and proj entries so
918
* that it doesnt munch yer cpu so much.
920
long QgsSpatialRefSys::findMatchingProj()
922
QgsDebugMsg("QgsSpatialRefSys::findMatchingProj...");
923
if (mEllipsoidAcronym.isNull() || mProjectionAcronym.isNull() || mProj4String.isNull())
925
QgsLogger::warning("QgsSpatialRefSys::findMatchingProj will only work if prj acr ellipsoid acr and proj4string are set!...");
931
sqlite3_stmt *myPreparedStatement;
934
// Set up the query to retreive the projection information needed to populate the list
935
QString mySql = QString ("select srs_id,parameters from tbl_srs where projection_acronym='" +
936
mProjectionAcronym + "' and ellipsoid_acronym='" + mEllipsoidAcronym + "'");
937
// Get the full path name to the sqlite3 spatial reference database.
938
QString myDatabaseFileName = QgsApplication::srsDbFilePath();
941
//check the db is available
942
myResult = openDb(myDatabaseFileName, &myDatabase);
948
myResult = sqlite3_prepare(myDatabase, mySql.utf8(), mySql.length(), &myPreparedStatement, &myTail);
949
// XXX Need to free memory from the error msg if one is set
950
if(myResult == SQLITE_OK)
953
while(sqlite3_step(myPreparedStatement) == SQLITE_ROW)
955
QString mySrsId = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,0));
956
QString myProj4String = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement, 1));
957
if (this->equals(myProj4String))
959
QgsDebugMsg("QgsSpatialRefSys::findMatchingProj -------> MATCH FOUND in srs.db srsid: " + mySrsId);
960
// close the sqlite3 statement
961
sqlite3_finalize(myPreparedStatement);
962
sqlite3_close(myDatabase);
963
return mySrsId.toLong();
967
//std::cout << " Not matched : " << myProj4String << std::endl;
971
//std::cout << "QgsSpatialRefSys::findMatchingProj -------> no match found in srs.db, trying user db now!" << std::endl;
972
// close the sqlite3 statement
973
sqlite3_finalize(myPreparedStatement);
974
sqlite3_close(myDatabase);
976
// Try the users db now
979
myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
980
//check the db is available
981
myResult = openDb(myDatabaseFileName, &myDatabase);
987
myResult = sqlite3_prepare(myDatabase, mySql.utf8(), mySql.length(), &myPreparedStatement, &myTail);
988
// XXX Need to free memory from the error msg if one is set
989
if(myResult == SQLITE_OK)
992
while(sqlite3_step(myPreparedStatement) == SQLITE_ROW)
994
QString mySrsId = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement,0));
995
QString myProj4String = QString::fromUtf8((char *)sqlite3_column_text(myPreparedStatement, 1));
996
if (this->equals(myProj4String))
998
QgsDebugMsg("QgsSpatialRefSys::findMatchingProj -------> MATCH FOUND in user qgis.db srsid: " + mySrsId);
999
// close the sqlite3 statement
1000
sqlite3_finalize(myPreparedStatement);
1001
sqlite3_close(myDatabase);
1002
return mySrsId.toLong();
1006
//std::cout << " Not matched : " << myProj4String << std::endl;
1010
QgsLogger::warning("QgsSpatialRefSys::findMatchingProj -------> no match found in user db");
1012
// close the sqlite3 statement
1013
sqlite3_finalize(myPreparedStatement);
1014
sqlite3_close(myDatabase);
1019
bool QgsSpatialRefSys::operator==(const QgsSpatialRefSys &theSrs)
1021
//qWarning("QgsSpatialRefSys::operator==(const QgsSpatialRefSys &theSrs) called ");
1022
//simply delegate to the overloaded == operator below...
1023
return this->equals(theSrs.mProj4String);
1027
bool QgsSpatialRefSys::equals(QString theProj4CharArray)
1029
//qWarning("QgsSpatialRefSys::operator==(const char *theProj4CharArray) called ");
1030
bool myMatchFlag = false; //guilty until proven innocent
1032
/* Here are the possible OGR error codes :
1035
#define OGRERR_NONE 0
1036
#define OGRERR_NOT_ENOUGH_DATA 1 --> not enough data to deserialize
1037
#define OGRERR_NOT_ENOUGH_MEMORY 2
1038
#define OGRERR_UNSUPPORTED_GEOMETRY_TYPE 3
1039
#define OGRERR_UNSUPPORTED_OPERATION 4
1040
#define OGRERR_CORRUPT_DATA 5
1041
#define OGRERR_FAILURE 6
1042
#define OGRERR_UNSUPPORTED_SRS 7 */
1044
//get the wkt into ogr
1045
//this is really ugly but we need to get a QString to a char**
1046
const char *myCharArrayPointer1 = mProj4String.latin1();
1048
//note that the proj strings above do not neccessarily need to be exactly the
1049
//same for the projections they define to be equivalent, which is why I dont just
1050
//compare the proj parameter strings and return the result
1053
//create the sr and populate it from a wkt proj definition
1054
OGRSpatialReference myOgrSpatialRef1;
1055
OGRSpatialReference myOgrSpatialRef2;
1056
OGRErr myInputResult1 = myOgrSpatialRef1.importFromProj4( myCharArrayPointer1 );
1057
OGRErr myInputResult2 = myOgrSpatialRef2.importFromProj4( theProj4CharArray.latin1() );
1059
if (myOgrSpatialRef1.IsGeographic() && myOgrSpatialRef2.IsGeographic())
1061
// qWarning("QgsSpatialRefSys::operator== srs1 and srs2 are geographic ");
1062
myMatchFlag = myOgrSpatialRef1.IsSameGeogCS(&myOgrSpatialRef2);
1064
else if (myOgrSpatialRef1.IsProjected() && myOgrSpatialRef2.IsProjected())
1066
// qWarning("QgsSpatialRefSys::operator== srs1 and srs2 are projected ");
1067
myMatchFlag = myOgrSpatialRef1.IsSame(&myOgrSpatialRef2);
1069
// qWarning("QgsSpatialRefSys::operator== srs1 and srs2 are different types ");
1070
myMatchFlag = false;
1073
//find out the units:
1074
/* Not needed anymore here - keeping here as a note because I am gonna use it elsewhere
1075
const char *myUnitsArrayPointer1;
1076
const char *myUnitsArrayPointer2;
1077
OGRErr myUnitsValid1 = myOgrSpatialRef1.GetLinearUnits(&myUnitsArrayPointer1 );
1078
OGRErr myUnitsValid2 = myOgrSpatialRef2.GetLinearUnits(&myUnitsArrayPointer2 );
1079
QString myUnitsString1(myUnitsArrayPointer1);
1080
QString myUnitsString2(myUnitsArrayPointer2);
1086
//placeholder to be replaced with ogr tests
1089
// qWarning("QgsSpatialRefSys::operator== result: srs's are equal ");
1093
// qWarning("QgsSpatialRefSys::operator== result: srs's are not equal ");
1098
OGRSpatialReference QgsSpatialRefSys::toOgrSrs()
1100
OGRSpatialReference myOgrSpatialRef1;
1101
OGRErr myInputResult1 = myOgrSpatialRef1.importFromProj4(mProj4String.latin1());
1102
return myOgrSpatialRef1;
1105
bool QgsSpatialRefSys::readXML( QDomNode & theNode )
1107
QgsDebugMsg("Reading Spatial Ref Sys from xml ------------------------!");
1108
QDomNode myNode = theNode.namedItem("proj4");
1109
QDomElement myElement = myNode.toElement();
1110
setProj4String(myElement.text());
1112
myNode = theNode.namedItem("srsid");
1113
myElement = myNode.toElement();
1114
setSrsId(myElement.text().toLong());
1116
myNode = theNode.namedItem("srid");
1117
myElement = myNode.toElement();
1118
setSrid(myElement.text().toLong());
1120
myNode = theNode.namedItem("epsg");
1121
myElement = myNode.toElement();
1122
setEpsg(myElement.text().toLong());
1124
myNode = theNode.namedItem("description");
1125
myElement = myNode.toElement();
1126
setDescription(myElement.text());
1128
myNode = theNode.namedItem("projectionacronym");
1129
myElement = myNode.toElement();
1130
setProjectionAcronym(myElement.text());
1132
myNode = theNode.namedItem("ellipsoidacronym");
1133
myElement = myNode.toElement();
1134
setEllipsoidAcronym(myElement.text());
1136
myNode = theNode.namedItem("geographicflag");
1137
myElement = myNode.toElement();
1138
if (myElement.text().compare("true"))
1140
setGeographicFlag(true);
1144
setGeographicFlag(false);
1146
//make sure the map units have been set
1150
//@TODO this srs needs to be validated!!!
1151
mIsValidFlag=true;//shamelessly hard coded for now
1159
bool QgsSpatialRefSys::writeXML( QDomNode & theNode, QDomDocument & theDoc )
1162
QDomElement myLayerNode = theNode.toElement();
1163
QDomElement mySrsElement = theDoc.createElement( "spatialrefsys" );
1165
QDomElement myProj4Element = theDoc.createElement( "proj4" );
1166
myProj4Element.appendChild(theDoc.createTextNode( proj4String()));
1167
mySrsElement.appendChild(myProj4Element);
1169
QDomElement mySrsIdElement = theDoc.createElement( "srsid" );
1170
mySrsIdElement.appendChild(theDoc.createTextNode( QString::number(srsid())));
1171
mySrsElement.appendChild(mySrsIdElement);
1173
QDomElement mySridElement = theDoc.createElement( "srid" );
1174
mySridElement.appendChild(theDoc.createTextNode( QString::number(srid())));
1175
mySrsElement.appendChild(mySridElement);
1177
QDomElement myEpsgElement = theDoc.createElement( "epsg" );
1178
myEpsgElement.appendChild(theDoc.createTextNode( QString::number(epsg())));
1179
mySrsElement.appendChild(myEpsgElement);
1181
QDomElement myDescriptionElement = theDoc.createElement( "description" );
1182
myDescriptionElement.appendChild(theDoc.createTextNode( description()));
1183
mySrsElement.appendChild(myDescriptionElement);
1185
QDomElement myProjectionAcronymElement = theDoc.createElement( "projectionacronym" );
1186
myProjectionAcronymElement.appendChild(theDoc.createTextNode( projectionAcronym()));
1187
mySrsElement.appendChild(myProjectionAcronymElement);
1189
QDomElement myEllipsoidAcronymElement = theDoc.createElement( "ellipsoidacronym" );
1190
myEllipsoidAcronymElement.appendChild(theDoc.createTextNode( ellipsoidAcronym()));
1191
mySrsElement.appendChild(myEllipsoidAcronymElement);
1193
QDomElement myGeographicFlagElement = theDoc.createElement( "geographicflag" );
1194
QString myGeoFlagText = "false";
1195
if (geographicFlag())
1197
myGeoFlagText="true";
1200
myGeographicFlagElement.appendChild(theDoc.createTextNode( myGeoFlagText ));
1201
mySrsElement.appendChild(myGeographicFlagElement);
1203
myLayerNode.appendChild( mySrsElement );
1213
// Static helper methods below this point only please!
1217
// Returns the whole proj4 string for the selected srsid
1218
//this is a static method!
1219
QString QgsSpatialRefSys::getProj4FromSrsId(const int theSrsId)
1222
QString myDatabaseFileName;
1223
QString myProjString;
1224
QString mySql = "select parameters from tbl_srs where srs_id = ";
1225
mySql += QString::number(theSrsId);
1227
QgsDebugMsg("QgsSpatialRefSys::getProj4FromSrsId : mySrsId = " + QString::number(theSrsId));
1228
QgsDebugMsg("QgsSpatialRefSys::getProj4FromSrsId : USER_PROJECTION_START_ID = " +\
1229
QString::number(USER_PROJECTION_START_ID));
1230
QgsDebugMsg("QgsSpatialRefSys::getProj4FromSrsId :Selection sql : " + mySql);
1233
// Determine if this is a user projection or a system on
1234
// user projection defs all have srs_id >= 100000
1236
if (theSrsId >= USER_PROJECTION_START_ID)
1238
myDatabaseFileName = QgsApplication::qgisUserDbFilePath();
1239
QFileInfo myFileInfo;
1240
myFileInfo.setFile(myDatabaseFileName);
1241
if ( !myFileInfo.exists( ) ) //its unlikely that this condition will ever be reached
1243
QgsLogger::critical("QgsSpatialRefSys::getProj4FromSrsId : users qgis.db not found");
1247
else //must be a system projection then
1249
myDatabaseFileName = QgsApplication::srsDbFilePath();
1251
QgsDebugMsg("QgsSpatialRefSys::getProj4FromSrsId db = " + myDatabaseFileName);
1255
rc = openDb(myDatabaseFileName, &db);
1260
// prepare the sql statement
1262
sqlite3_stmt *ppStmt;
1264
rc = sqlite3_prepare(db, mySql.utf8(), mySql.length(), &ppStmt, &pzTail);
1265
// XXX Need to free memory from the error msg if one is set
1269
if(sqlite3_step(ppStmt) == SQLITE_ROW)
1271
myProjString = QString::fromUtf8((char*)sqlite3_column_text(ppStmt, 0));
1274
// close the statement
1275
sqlite3_finalize(ppStmt);
1276
// close the database
1279
//assert(myProjString.length() > 0);
1280
return myProjString;
1283
int QgsSpatialRefSys::openDb(QString path, sqlite3 **db)
1285
QgsDebugMsg("QgsSpatialRefSys::openDb path = " + path);
1286
int myResult = sqlite3_open(path.toLocal8Bit().data(), db);
1290
QgsLogger::critical("Can't open database: " + QString(sqlite3_errmsg(*db)));
1291
// XXX This will likely never happen since on open, sqlite creates the
1292
// database if it does not exist.
1293
// ... unfortunately it happens on Windows
1294
QMessageBox::warning(0,"Error","Could not open SRS database "
1295
+ path + "<br>Error(" + QString::number(myResult)
1296
+ "): " + QString(sqlite3_errmsg(*db)) );