Skip to content

Commit 31c64d3

Browse files
author
timlinux
committedMay 17, 2005
Updated qgsspatialref - centralising sqlite calls (in progress) and implementing cmparitors for wkt and proj4 string so that a matchin rec (if any)can be retrieved from the database. In progress.
git-svn-id: http://svn.osgeo.org/qgis/trunk@3409 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 1092b02 commit 31c64d3

File tree

4 files changed

+248
-46
lines changed

4 files changed

+248
-46
lines changed
 

‎ChangeLog

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
Version 0.6 'Simon' .... development version
44
QGIS Change Log
55

6+
2005-04-17 [timlinux] 0.6devel23
7+
** Numerous fixes and clean ups to projection handling
68
2005-05-15 [morb_au] 0.6devel21
79
** Fixed a memory leak in the postgres provider when retrieving features
810
** Raster layers now align to the map canvas with subpixel source accuracy

‎configure.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ dnl ---------------------------------------------------------------------------
2525
MAJOR_VERSION=0
2626
MINOR_VERSION=6
2727
MICRO_VERSION=0
28-
EXTRA_VERSION=22
28+
EXTRA_VERSION=23
2929
if test $EXTRA_VERSION -eq 0; then
3030
VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}
3131
else

‎src/qgsspatialrefsys.cpp

Lines changed: 197 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
QgsSpatialRefSys::QgsSpatialRefSys() : mMapUnits(QGis::UNKNOWN) {}
2828

29-
QgsSpatialRefSys::QgsSpatialRefSys(QString theWkt) : mMapUnits(QGis::UNKNOWN)
29+
QgsSpatialRefSys::QgsSpatialRefSys(QString theWkt) : mMapUnits(QGis::UNKNOWN)
3030
{
3131
createFromWkt(theWkt);
3232
}
@@ -39,10 +39,10 @@ QgsSpatialRefSys::QgsSpatialRefSys(long theSrsId,
3939
long theSRID,
4040
long theEpsg,
4141
bool theGeoFlag)
42-
: mMapUnits(QGis::UNKNOWN)
42+
: mMapUnits(QGis::UNKNOWN)
4343
{}
4444

45-
QgsSpatialRefSys::QgsSpatialRefSys(const long theId, SRS_TYPE theType) : mMapUnits(QGis::UNKNOWN)
45+
QgsSpatialRefSys::QgsSpatialRefSys(const long theId, SRS_TYPE theType) : mMapUnits(QGis::UNKNOWN)
4646
{
4747
switch (theType)
4848
{
@@ -70,7 +70,7 @@ void QgsSpatialRefSys::validate()
7070
#ifdef QGISDEBUG
7171
std::cout << " QgsSpatialRefSys::validate" << std::endl;
7272
#endif
73-
//dont bother trying to do an initial test with gdal if
73+
//dont bother trying to do an initial test with gdal if
7474
//the proj4String is not even populated
7575
if (QString::null!=mProj4String && !mProj4String.isEmpty())
7676
{
@@ -162,7 +162,7 @@ void QgsSpatialRefSys::validate()
162162

163163
}
164164

165-
void QgsSpatialRefSys::createFromSrid(long theSrid)
165+
bool QgsSpatialRefSys::createFromSrid(long theSrid)
166166
{
167167
#ifdef QGISDEBUG
168168
std::cout << " QgsSpatialRefSys::createFromSrid" << std::endl;
@@ -232,17 +232,19 @@ void QgsSpatialRefSys::createFromSrid(long theSrid)
232232
}
233233
sqlite3_finalize(myPreparedStatement);
234234
sqlite3_close(myDatabase);
235+
return isValidFlag;
235236
}
236237

237-
void QgsSpatialRefSys::createFromWkt(QString theWkt)
238+
bool QgsSpatialRefSys::createFromWkt(QString theWkt)
238239
{
239240
if (!theWkt)
240241
{
241242
std::cout << "QgsSpatialRefSys::createFromWkt -- theWkt is uninitialised, operation failed" << std::endl;
242-
return;
243+
isValidFlag==false;
244+
return false;
243245
}
244246
#ifdef QGISDEBUG
245-
std::cout << "QgsSpatialRefSys::createFromWkt(QString theWkt) using: \n" << theWkt << std::endl;
247+
std::cout << "QgsSpatialRefSys::createFromWkt(QString theWkt) using: \n" << theWkt << std::endl;
246248
#endif
247249
//this is really ugly but we need to get a QString to a char**
248250
char *myCharArrayPointer = (char *)theWkt.latin1();
@@ -269,7 +271,8 @@ void QgsSpatialRefSys::createFromWkt(QString theWkt)
269271
std::cout << "This SRS could *** NOT *** be set from the supplied WKT " << std::endl;
270272
std::cout << "INPUT: " << std::endl << theWkt << std::endl;
271273
std::cout << "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" << std::endl;
272-
return;
274+
isValidFlag==false;
275+
return false;
273276
}
274277

275278

@@ -279,13 +282,15 @@ void QgsSpatialRefSys::createFromWkt(QString theWkt)
279282
char *proj4src;
280283
myOgrSpatialRef.exportToProj4(&proj4src);
281284

282-
//XXX TODO split out projext and ellipsoid acronym from the parameters
283-
mProj4String=QString(proj4src);
284-
285-
setMapUnits();
285+
//now that we have the proj4string, delegate to createFromProj4String so
286+
// that we can try to fill in the remaining class members...
287+
//create from Proj wil set the isValidFalg
288+
createFromProj4(QString(proj4src));
289+
return isValidFlag;
290+
//setMapunits will be called by createfromproj above
286291
}
287292

288-
void QgsSpatialRefSys::createFromEpsg(long theEpsg)
293+
bool QgsSpatialRefSys::createFromEpsg(long theEpsg)
289294
{
290295
#ifdef QGISDEBUG
291296
std::cout << " QgsSpatialRefSys::createFromEpsg" << std::endl;
@@ -353,14 +358,15 @@ void QgsSpatialRefSys::createFromEpsg(long theEpsg)
353358
}
354359
sqlite3_finalize(myPreparedStatement);
355360
sqlite3_close(myDatabase);
361+
return isValidFlag;
356362
}
357363

358364

359-
void QgsSpatialRefSys::createFromSrsId (long theSrsId)
365+
bool QgsSpatialRefSys::createFromSrsId (long theSrsId)
360366
{
361367
#ifdef QGISDEBUG
362368
std::cout << " QgsSpatialRefSys::createFromSrsId" << std::endl;
363-
#endif
369+
#endif
364370
QString myDatabaseFileName;
365371
//
366372
// Determine if this is a user projection or a system on
@@ -375,7 +381,7 @@ void QgsSpatialRefSys::createFromSrsId (long theSrsId)
375381
{
376382
isValidFlag==false;
377383
std::cout << " QgsSpatialRefSys::createFromSrid failed : users qgis.db not found" << std::endl;
378-
return;
384+
return isValidFlag;
379385
}
380386
}
381387
else //must be a system projection then
@@ -443,6 +449,7 @@ void QgsSpatialRefSys::createFromSrsId (long theSrsId)
443449
}
444450
sqlite3_finalize(myPreparedStatement);
445451
sqlite3_close(myDatabase);
452+
return isValidFlag;
446453
}
447454

448455

@@ -467,51 +474,201 @@ bool QgsSpatialRefSys::isValid() const
467474
}
468475
}
469476

470-
void QgsSpatialRefSys::createFromProj4 (const QString theProj4String)
477+
bool QgsSpatialRefSys::createFromProj4 (const QString theProj4String)
471478
{
472479
//
473480
// Example:
474-
// +proj=tmerc +lat_0=0 +lon_0=-62 +k=0.999500 +x_0=400000 +y_0=0
481+
// +proj=tmerc +lat_0=0 +lon_0=-62 +k=0.999500 +x_0=400000 +y_0=0
475482
// +ellps=clrk80 +towgs84=-255,-15,71,0,0,0,0 +units=m +no_defs
476-
//
483+
//
477484

478-
QRegExp myProjRegExp( "\\+proj=[a-zA-Z]* " );
485+
QRegExp myProjRegExp( "\\+proj=[a-zA-Z]* " );
479486
int myStart= 0;
480487
int myLength=0;
481488
myStart = myProjRegExp.search(theProj4String, myStart);
482489
if (myStart==-1)
483490
{
484491
std::cout << "QgsSpatialRefSys::createFromProj4 error proj string supplied has no +proj argument" << std::endl;
492+
isValidFlag=false;
493+
return isValidFlag;
485494
}
486495
else
487496
{
488497
myLength = myProjRegExp.matchedLength();
489498
}
490499
mProjectionAcronym = theProj4String.mid(myStart+PROJ_PREFIX_LEN,myLength);
491-
492-
QRegExp myEllipseRegExp( "\\+ellps=[a-zA-Z]* " );
500+
501+
QRegExp myEllipseRegExp( "\\+ellps=[a-zA-Z]* " );
493502
myStart= 0;
494503
myLength=0;
495504
myStart = myEllipseRegExp.search(theProj4String, myStart);
496505
if (myStart==-1)
497506
{
498507
std::cout << "QgsSpatialRefSys::createFromProj4 error proj string supplied has no +ellps argument" << std::endl;
508+
isValidFlag=false;
509+
return isValidFlag;
499510
}
500511
else
501512
{
502513
myLength = myEllipseRegExp.matchedLength();
503514
}
504515
mEllipsoidAcronym = theProj4String.mid(myStart+ELLPS_PREFIX_LEN,myLength);
516+
517+
518+
519+
/*
520+
* We try to match the proj string to and srsid using the following logic:
521+
*
522+
* - perform a whole text search on srs name (if not null). The srs name will
523+
* have been set if this method has been delegated to from createFromWkt.
524+
*/
525+
getRecord("select * from tbl_srs where where parameters='" + mProj4String + "'");
526+
/*
527+
* - if the above does not match perform a whole text search on proj4 string (if not null)
528+
*/
529+
530+
/*
531+
* - if none of the above match convert the proj4 string to an OGR SRS
532+
* then check if its a geocs or a proj cs (using ogr isGeographic)
533+
* then sequentially walk through the database (first users qgis.db srs tbl then
534+
* system srs.db tbl), converting each entry into an ogr srs and using isSame
535+
* or isSameGeocs (essentially calling the == overloaded operator). We'll try to
536+
* be smart about this and first parse out the proj and ellpse strings and only
537+
* check for a match in entities that have the same ellps and proj entries so
538+
* that it doesnt munch yer cpu so much.
539+
*/
540+
505541
setMapUnits();
542+
isValidFlag=true;
543+
return isValidFlag;
506544
}
507-
// Accessors -----------------------------------
508545

546+
QgsSpatialRefSys::RecordMap QgsSpatialRefSys::getRecord(QString theSql)
547+
{
548+
549+
QString myDatabaseFileName;
550+
QgsSpatialRefSys::RecordMap myMap;
551+
QString myFieldName;
552+
QString myFieldValue;
553+
sqlite3 *myDatabase;
554+
char *myErrorMessage = 0;
555+
const char *myTail;
556+
sqlite3_stmt *myPreparedStatement;
557+
int myResult;
558+
559+
#ifdef QGISDEBUG
560+
std::cout << " QgsSpatialRefSys::getRecord...running query:\n"<< theSql << "\n" << std::endl;
561+
std::cout << " QgsSpatialRefSys::getRecord...trying system srs.db" << std::endl;
562+
#endif
563+
// Get the package data path and set the full path name to the sqlite3 spatial reference
564+
// database.
565+
#if defined(Q_OS_MACX) || defined(WIN32)
566+
QString PKGDATAPATH = qApp->applicationDirPath() + "/share/qgis";
567+
#endif
568+
myDatabaseFileName = PKGDATAPATH;
569+
myDatabaseFileName += "/resources/srs.db";
570+
571+
572+
//check the db is available
573+
myResult = sqlite3_open(myDatabaseFileName.latin1(), &myDatabase);
574+
if(myResult)
575+
{
576+
std::cout << "Can't open database: " << sqlite3_errmsg(myDatabase) << std::endl;
577+
// XXX This will likely never happen since on open, sqlite creates the
578+
// database if it does not exist.
579+
assert(myResult == 0);
580+
}
581+
582+
583+
myResult = sqlite3_prepare(myDatabase, (const char *)theSql, theSql.length(), &myPreparedStatement, &myTail);
584+
// XXX Need to free memory from the error msg if one is set
585+
if(myResult == SQLITE_OK)
586+
{
587+
sqlite3_step(myPreparedStatement) == SQLITE_ROW;
588+
int myColumnCount = sqlite3_column_count(myPreparedStatement);
589+
//loop through each column in the record adding its field name and vvalue to the map
590+
for (int myColNo=0;myColNo < myColumnCount;myColNo++)
591+
{
592+
myFieldName = QString ((char *)sqlite3_column_name(myPreparedStatement,myColNo));
593+
myFieldValue = QString ((char *)sqlite3_column_text(myPreparedStatement,myColNo));
594+
myMap[myFieldName]=myFieldValue;
595+
}
596+
}
597+
else
598+
{
599+
#ifdef QGISDEBUG
600+
std::cout << " QgsSpatialRefSys::getRecord...trying system users.db" << std::endl;
601+
#endif
602+
sqlite3_finalize(myPreparedStatement);
603+
sqlite3_close(myDatabase);
604+
605+
myDatabaseFileName = QDir::homeDirPath () + "/.qgis/qgis.db";
606+
QFileInfo myFileInfo;
607+
myFileInfo.setFile(myDatabaseFileName);
608+
if ( !myFileInfo.exists( ) )
609+
{
610+
std::cout << " QgsSpatialRefSys::getRecord failed : users qgis.db not found" << std::endl;
611+
return myMap;
612+
}
613+
614+
//check the db is available
615+
myResult = sqlite3_open(myDatabaseFileName.latin1(), &myDatabase);
616+
if(myResult)
617+
{
618+
std::cout << "Can't open database: " << sqlite3_errmsg(myDatabase) << std::endl;
619+
// XXX This will likely never happen since on open, sqlite creates the
620+
// database if it does not exist.
621+
assert(myResult == 0);
622+
}
623+
624+
625+
myResult = sqlite3_prepare(myDatabase, (const char *)theSql, theSql.length(), &myPreparedStatement, &myTail);
626+
// XXX Need to free memory from the error msg if one is set
627+
if(myResult == SQLITE_OK)
628+
{
629+
630+
sqlite3_step(myPreparedStatement) == SQLITE_ROW;
631+
int myColumnCount = sqlite3_column_count(myPreparedStatement);
632+
//loop through each column in the record adding its field name and vvalue to the map
633+
for (int myColNo=0;myColNo < myColumnCount;myColNo++)
634+
{
635+
myFieldName = QString ((char *)sqlite3_column_name(myPreparedStatement,myColNo));
636+
myFieldValue = QString ((char *)sqlite3_column_text(myPreparedStatement,myColNo));
637+
myMap[myFieldName]=myFieldValue;
638+
}
639+
}
640+
else
641+
{
642+
#ifdef QGISDEBUG
643+
std::cout << " QgsSpatialRefSys::getRecord failed : " << theSql << std::endl;
644+
#endif
645+
646+
}
647+
}
648+
sqlite3_finalize(myPreparedStatement);
649+
sqlite3_close(myDatabase);
650+
return myMap;
651+
652+
653+
654+
}
655+
656+
// Accessors -----------------------------------
509657
/*! Get the SrsId
510658
* @return long theSrsId The internal sqlite3 srs.db primary key for this srs
511659
*/
660+
long QgsSpatialRefSys::srsid() const
661+
{
662+
return mSrsId;
663+
}
664+
/*! Get the Postgis SRID - if possible
665+
* @return long theSRID The internal postgis SRID for this SRS
666+
*/
512667
long QgsSpatialRefSys::srid() const
513668
{
669+
514670
return mSRID;
671+
515672
}
516673
/*! Get the Description
517674
* @return QString the Description A textual description of the srs.
@@ -534,7 +691,7 @@ QString QgsSpatialRefSys::ellipsoidAcronym () const
534691
{
535692
return mEllipsoidAcronym;
536693
}
537-
/* Get the Proj Proj4String.
694+
/* Get the Proj Proj4String.
538695
* @return QString theProj4String Proj4 format specifies that define this srs.
539696
*/
540697
QString QgsSpatialRefSys::proj4String() const
@@ -679,14 +836,16 @@ void QgsSpatialRefSys::setMapUnits()
679836
#ifdef QGISDEBUG
680837
std::cerr << "Projection has angular units of " << unit << '\n';
681838
#endif
839+
682840
}
683841
}
684842

843+
685844
bool QgsSpatialRefSys::operator==(const QgsSpatialRefSys &theSrs)
686845
{
687-
qWarning("QgsSpatialRefSys::operator== called ");
846+
qWarning("QgsSpatialRefSys::operator== called ");
688847

689-
bool myMatchFlag = true; //innocent until proven guilty
848+
bool myMatchFlag = true; //innocent until proven guilty
690849

691850
/* Here are the possible OGR error codes :
692851
typedef int OGRErr;
@@ -708,7 +867,7 @@ bool QgsSpatialRefSys::operator==(const QgsSpatialRefSys &theSrs)
708867
//same for the projections they define to be equivalent, which is why I dont just
709868
//compare the proj parameter strings and return the result
710869

711-
870+
712871
//create the sr and populate it from a wkt proj definition
713872
OGRSpatialReference myOgrSpatialRef1;
714873
OGRSpatialReference myOgrSpatialRef2;
@@ -739,14 +898,14 @@ bool QgsSpatialRefSys::operator==(const QgsSpatialRefSys &theSrs)
739898

740899

741900

742-
//placeholder to be replaced with ogr tests
743-
if (myMatchFlag)
744-
{
745-
qWarning("QgsSpatialRefSys::operator== result: srs's are equal ");
746-
}
747-
else
748-
{
749-
qWarning("QgsSpatialRefSys::operator== result: srs's are not equal ");
750-
}
751-
return myMatchFlag;
901+
//placeholder to be replaced with ogr tests
902+
if (myMatchFlag)
903+
{
904+
qWarning("QgsSpatialRefSys::operator== result: srs's are equal ");
905+
}
906+
else
907+
{
908+
qWarning("QgsSpatialRefSys::operator== result: srs's are not equal ");
909+
}
910+
return myMatchFlag;
752911
}

‎src/qgsspatialrefsys.h

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <qstring.h>
1010
#include <qstringlist.h>
1111
#include <qregexp.h>
12+
#include <qmap.h>
1213

1314
//qgis includes
1415
#include <qgis.h>
@@ -73,7 +74,7 @@ class QgsSpatialRefSys
7374
* @note Any members will be overwritten during this process.
7475
* @param theSrid The postgis SRID for the desired spatial reference system.
7576
*/
76-
void createFromSrid(const long theSrid);
77+
bool createFromSrid(const long theSrid);
7778
/*! Set up this srs using a WKT spatial ref sys definition.
7879
* The wkt will be converted to a proj4 string using OGR helper
7980
* functions. After this the srs databasses will be searched for matches.
@@ -82,34 +83,57 @@ class QgsSpatialRefSys
8283
* @note Any members will be overwritten during this process.
8384
* @note SRID and EPSG may be blank if no match can be found on srs db.
8485
* @param theWkt The WKT for the desired spatial reference system.
86+
* @return bool TRUE if sucess else false
8587
*/
86-
void createFromWkt(const QString theWkt);
88+
bool createFromWkt(const QString theWkt);
8789
/*! Set up this srs by fetching the appropriate information from the
8890
* sqlite backend. First the system level read only srs.db will be checked
8991
* and then the users ~/.qgis/qgis.db database will be checked for a match.
9092
* @note Any members will be overwritten during this process.
9193
* @param theEpsg The EPSG for the desired spatial reference system.
94+
* @return bool TRUE if sucess else false
9295
*/
93-
void createFromEpsg(const long theEpsg);
96+
bool createFromEpsg(const long theEpsg);
9497
/*! Set up this srs by fetching the appropriate information from the
9598
* sqlite backend. If the srsid is < 100000, only the system srs.db
9699
* will be checked. If the srsid > 100000 the srs will be retrieved from
97100
* the ~/.qgis/qgis.db
98101
* @note Any members will be overwritten during this process.
99102
* @param theSrsId The QGIS SrsId for the desired spatial reference system.
103+
* @return bool TRUE if sucess else false
100104
*/
101-
void createFromSrsId (const long theSrsId);
105+
bool createFromSrsId (const long theSrsId);
102106

103107
/*! Set up this srs by passing it a proj4 style formatted string.
104108
* The string will be parsed and the projection and ellipsoid
105109
* members set and the remainder of the proj4 string will be stored
106110
* in the parameters member. The reason for this is so that we
107111
* can easily present the user with 'natural language' representation
108112
* of the projection and ellipsoid by looking them up in the srs.bs sqlite
109-
* database.
113+
* database. Also having the ellpse and proj elements stripped out
114+
* is hepful to speed up globbing queries (see below).
115+
*
116+
* We try to match the proj string to and srsid using the following logic:
117+
*
118+
* - perform a whole text search on srs name (if not null). The srs name will
119+
* have been set if this method has been delegated to from createFromWkt.
120+
* - if the above does not match perform a whole text search on proj4 string (if not null)
121+
* - if none of the above match convert the proj4 string to an OGR SRS
122+
* then check if its a geocs or a proj cs (using ogr isGeographic)
123+
* then sequentially walk through the database (first users qgis.db srs tbl then
124+
* system srs.db tbl), converting each entry into an ogr srs and using isSame
125+
* or isSameGeocs (essentially calling the == overloaded operator). We'll try to
126+
* be smart about this and first parse out the proj and ellpse strings and only
127+
* check for a match in entities that have the same ellps and proj entries so
128+
* that it doesnt munch yer cpu so much.
129+
*
130+
* @note If the srs was not matched, we will create a new entry on the users tbl_srs
131+
* for this srs.
132+
*
110133
* @param theProjString A proj4 format string
134+
* @return bool TRUE if sucess else false
111135
*/
112-
void createFromProj4 (const QString theProjString);
136+
bool createFromProj4 (const QString theProjString);
113137

114138
/*! Find out whether this SRS is correctly initialised and useable */
115139
bool isValid() const;
@@ -118,14 +142,31 @@ class QgsSpatialRefSys
118142
* consulted and acted on accordingly. By hell or high water this
119143
* method will do its best to make sure that this SRS is valid - even
120144
* if that involves resorting to a hard coded default of geocs:wgs84.
145+
*
146+
* @note It is not usually neccessary to use this function, unless you
147+
* are trying to force theis srs to be valid.
121148
*/
122149
void validate();
150+
151+
/*! A string based associative array used for passing records around */
152+
typedef QMap<QString, QString> RecordMap;
153+
/*! Get a record from the srs.db or qgis.db backends, given an sql statment.
154+
* @note only handles queries that return a single record.
155+
* @note it will first try the system srs.db then the users qgis.db!
156+
* @param QString The sql query to execute
157+
* @return QMap An associative array of field name <-> value pairs
158+
*/
159+
RecordMap getRecord(QString theSql);
123160

124161
// Accessors -----------------------------------
125162

126-
/*! Get the SrsId
163+
/*! Get the SrsId - if possible
127164
* @return long theSrsId The internal sqlite3 srs.db primary key for this srs
128165
*/
166+
long srsid() const;
167+
/*! Get the Postgis SRID - if possible.
168+
* @return long theSRID The internal postgis SRID for this SRS
169+
*/
129170
long srid() const;
130171
/*! Get the Description
131172
* @return QString the Description A textual description of the srs.

0 commit comments

Comments
 (0)
Please sign in to comment.