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/qgis@3409 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
timlinux 2005-05-17 08:21:14 +00:00
parent 060ac1f52f
commit 2dc3552f12
4 changed files with 250 additions and 48 deletions

View File

@ -3,6 +3,8 @@
Version 0.6 'Simon' .... development version
QGIS Change Log
2005-04-17 [timlinux] 0.6devel23
** Numerous fixes and clean ups to projection handling
2005-05-15 [morb_au] 0.6devel21
** Fixed a memory leak in the postgres provider when retrieving features
** Raster layers now align to the map canvas with subpixel source accuracy

View File

@ -25,7 +25,7 @@ dnl ---------------------------------------------------------------------------
MAJOR_VERSION=0
MINOR_VERSION=6
MICRO_VERSION=0
EXTRA_VERSION=22
EXTRA_VERSION=23
if test $EXTRA_VERSION -eq 0; then
VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}
else

View File

@ -26,7 +26,7 @@
QgsSpatialRefSys::QgsSpatialRefSys() : mMapUnits(QGis::UNKNOWN) {}
QgsSpatialRefSys::QgsSpatialRefSys(QString theWkt) : mMapUnits(QGis::UNKNOWN)
QgsSpatialRefSys::QgsSpatialRefSys(QString theWkt) : mMapUnits(QGis::UNKNOWN)
{
createFromWkt(theWkt);
}
@ -39,10 +39,10 @@ QgsSpatialRefSys::QgsSpatialRefSys(long theSrsId,
long theSRID,
long theEpsg,
bool theGeoFlag)
: mMapUnits(QGis::UNKNOWN)
: mMapUnits(QGis::UNKNOWN)
{}
QgsSpatialRefSys::QgsSpatialRefSys(const long theId, SRS_TYPE theType) : mMapUnits(QGis::UNKNOWN)
QgsSpatialRefSys::QgsSpatialRefSys(const long theId, SRS_TYPE theType) : mMapUnits(QGis::UNKNOWN)
{
switch (theType)
{
@ -70,7 +70,7 @@ void QgsSpatialRefSys::validate()
#ifdef QGISDEBUG
std::cout << " QgsSpatialRefSys::validate" << std::endl;
#endif
//dont bother trying to do an initial test with gdal if
//dont bother trying to do an initial test with gdal if
//the proj4String is not even populated
if (QString::null!=mProj4String && !mProj4String.isEmpty())
{
@ -162,7 +162,7 @@ void QgsSpatialRefSys::validate()
}
void QgsSpatialRefSys::createFromSrid(long theSrid)
bool QgsSpatialRefSys::createFromSrid(long theSrid)
{
#ifdef QGISDEBUG
std::cout << " QgsSpatialRefSys::createFromSrid" << std::endl;
@ -232,17 +232,19 @@ void QgsSpatialRefSys::createFromSrid(long theSrid)
}
sqlite3_finalize(myPreparedStatement);
sqlite3_close(myDatabase);
return isValidFlag;
}
void QgsSpatialRefSys::createFromWkt(QString theWkt)
bool QgsSpatialRefSys::createFromWkt(QString theWkt)
{
if (!theWkt)
{
std::cout << "QgsSpatialRefSys::createFromWkt -- theWkt is uninitialised, operation failed" << std::endl;
return;
isValidFlag==false;
return false;
}
#ifdef QGISDEBUG
std::cout << "QgsSpatialRefSys::createFromWkt(QString theWkt) using: \n" << theWkt << std::endl;
std::cout << "QgsSpatialRefSys::createFromWkt(QString theWkt) using: \n" << theWkt << std::endl;
#endif
//this is really ugly but we need to get a QString to a char**
char *myCharArrayPointer = (char *)theWkt.latin1();
@ -269,7 +271,8 @@ void QgsSpatialRefSys::createFromWkt(QString theWkt)
std::cout << "This SRS could *** NOT *** be set from the supplied WKT " << std::endl;
std::cout << "INPUT: " << std::endl << theWkt << std::endl;
std::cout << "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" << std::endl;
return;
isValidFlag==false;
return false;
}
@ -279,13 +282,15 @@ void QgsSpatialRefSys::createFromWkt(QString theWkt)
char *proj4src;
myOgrSpatialRef.exportToProj4(&proj4src);
//XXX TODO split out projext and ellipsoid acronym from the parameters
mProj4String=QString(proj4src);
setMapUnits();
//now that we have the proj4string, delegate to createFromProj4String so
// that we can try to fill in the remaining class members...
//create from Proj wil set the isValidFalg
createFromProj4(QString(proj4src));
return isValidFlag;
//setMapunits will be called by createfromproj above
}
void QgsSpatialRefSys::createFromEpsg(long theEpsg)
bool QgsSpatialRefSys::createFromEpsg(long theEpsg)
{
#ifdef QGISDEBUG
std::cout << " QgsSpatialRefSys::createFromEpsg" << std::endl;
@ -353,14 +358,15 @@ void QgsSpatialRefSys::createFromEpsg(long theEpsg)
}
sqlite3_finalize(myPreparedStatement);
sqlite3_close(myDatabase);
return isValidFlag;
}
void QgsSpatialRefSys::createFromSrsId (long theSrsId)
bool QgsSpatialRefSys::createFromSrsId (long theSrsId)
{
#ifdef QGISDEBUG
std::cout << " QgsSpatialRefSys::createFromSrsId" << std::endl;
#endif
#endif
QString myDatabaseFileName;
//
// Determine if this is a user projection or a system on
@ -375,7 +381,7 @@ void QgsSpatialRefSys::createFromSrsId (long theSrsId)
{
isValidFlag==false;
std::cout << " QgsSpatialRefSys::createFromSrid failed : users qgis.db not found" << std::endl;
return;
return isValidFlag;
}
}
else //must be a system projection then
@ -443,6 +449,7 @@ void QgsSpatialRefSys::createFromSrsId (long theSrsId)
}
sqlite3_finalize(myPreparedStatement);
sqlite3_close(myDatabase);
return isValidFlag;
}
@ -467,51 +474,201 @@ bool QgsSpatialRefSys::isValid() const
}
}
void QgsSpatialRefSys::createFromProj4 (const QString theProj4String)
bool QgsSpatialRefSys::createFromProj4 (const QString theProj4String)
{
//
// Example:
// +proj=tmerc +lat_0=0 +lon_0=-62 +k=0.999500 +x_0=400000 +y_0=0
// +proj=tmerc +lat_0=0 +lon_0=-62 +k=0.999500 +x_0=400000 +y_0=0
// +ellps=clrk80 +towgs84=-255,-15,71,0,0,0,0 +units=m +no_defs
//
//
QRegExp myProjRegExp( "\\+proj=[a-zA-Z]* " );
QRegExp myProjRegExp( "\\+proj=[a-zA-Z]* " );
int myStart= 0;
int myLength=0;
myStart = myProjRegExp.search(theProj4String, myStart);
if (myStart==-1)
{
std::cout << "QgsSpatialRefSys::createFromProj4 error proj string supplied has no +proj argument" << std::endl;
isValidFlag=false;
return isValidFlag;
}
else
{
myLength = myProjRegExp.matchedLength();
}
mProjectionAcronym = theProj4String.mid(myStart+PROJ_PREFIX_LEN,myLength);
QRegExp myEllipseRegExp( "\\+ellps=[a-zA-Z]* " );
QRegExp myEllipseRegExp( "\\+ellps=[a-zA-Z]* " );
myStart= 0;
myLength=0;
myStart = myEllipseRegExp.search(theProj4String, myStart);
if (myStart==-1)
{
std::cout << "QgsSpatialRefSys::createFromProj4 error proj string supplied has no +ellps argument" << std::endl;
isValidFlag=false;
return isValidFlag;
}
else
{
myLength = myEllipseRegExp.matchedLength();
}
mEllipsoidAcronym = theProj4String.mid(myStart+ELLPS_PREFIX_LEN,myLength);
setMapUnits();
}
// Accessors -----------------------------------
/*
* We try to match the proj string to and srsid using the following logic:
*
* - perform a whole text search on srs name (if not null). The srs name will
* have been set if this method has been delegated to from createFromWkt.
*/
getRecord("select * from tbl_srs where where parameters='" + mProj4String + "'");
/*
* - if the above does not match perform a whole text search on proj4 string (if not null)
*/
/*
* - if none of the above match convert the proj4 string to an OGR SRS
* then check if its a geocs or a proj cs (using ogr isGeographic)
* then sequentially walk through the database (first users qgis.db srs tbl then
* system srs.db tbl), converting each entry into an ogr srs and using isSame
* or isSameGeocs (essentially calling the == overloaded operator). We'll try to
* be smart about this and first parse out the proj and ellpse strings and only
* check for a match in entities that have the same ellps and proj entries so
* that it doesnt munch yer cpu so much.
*/
setMapUnits();
isValidFlag=true;
return isValidFlag;
}
QgsSpatialRefSys::RecordMap QgsSpatialRefSys::getRecord(QString theSql)
{
QString myDatabaseFileName;
QgsSpatialRefSys::RecordMap myMap;
QString myFieldName;
QString myFieldValue;
sqlite3 *myDatabase;
char *myErrorMessage = 0;
const char *myTail;
sqlite3_stmt *myPreparedStatement;
int myResult;
#ifdef QGISDEBUG
std::cout << " QgsSpatialRefSys::getRecord...running query:\n"<< theSql << "\n" << std::endl;
std::cout << " QgsSpatialRefSys::getRecord...trying system srs.db" << std::endl;
#endif
// Get the package data path and set the full path name to the sqlite3 spatial reference
// database.
#if defined(Q_OS_MACX) || defined(WIN32)
QString PKGDATAPATH = qApp->applicationDirPath() + "/share/qgis";
#endif
myDatabaseFileName = PKGDATAPATH;
myDatabaseFileName += "/resources/srs.db";
//check the db is available
myResult = sqlite3_open(myDatabaseFileName.latin1(), &myDatabase);
if(myResult)
{
std::cout << "Can't open database: " << sqlite3_errmsg(myDatabase) << std::endl;
// XXX This will likely never happen since on open, sqlite creates the
// database if it does not exist.
assert(myResult == 0);
}
myResult = sqlite3_prepare(myDatabase, (const char *)theSql, theSql.length(), &myPreparedStatement, &myTail);
// XXX Need to free memory from the error msg if one is set
if(myResult == SQLITE_OK)
{
sqlite3_step(myPreparedStatement) == SQLITE_ROW;
int myColumnCount = sqlite3_column_count(myPreparedStatement);
//loop through each column in the record adding its field name and vvalue to the map
for (int myColNo=0;myColNo < myColumnCount;myColNo++)
{
myFieldName = QString ((char *)sqlite3_column_name(myPreparedStatement,myColNo));
myFieldValue = QString ((char *)sqlite3_column_text(myPreparedStatement,myColNo));
myMap[myFieldName]=myFieldValue;
}
}
else
{
#ifdef QGISDEBUG
std::cout << " QgsSpatialRefSys::getRecord...trying system users.db" << std::endl;
#endif
sqlite3_finalize(myPreparedStatement);
sqlite3_close(myDatabase);
myDatabaseFileName = QDir::homeDirPath () + "/.qgis/qgis.db";
QFileInfo myFileInfo;
myFileInfo.setFile(myDatabaseFileName);
if ( !myFileInfo.exists( ) )
{
std::cout << " QgsSpatialRefSys::getRecord failed : users qgis.db not found" << std::endl;
return myMap;
}
//check the db is available
myResult = sqlite3_open(myDatabaseFileName.latin1(), &myDatabase);
if(myResult)
{
std::cout << "Can't open database: " << sqlite3_errmsg(myDatabase) << std::endl;
// XXX This will likely never happen since on open, sqlite creates the
// database if it does not exist.
assert(myResult == 0);
}
myResult = sqlite3_prepare(myDatabase, (const char *)theSql, theSql.length(), &myPreparedStatement, &myTail);
// XXX Need to free memory from the error msg if one is set
if(myResult == SQLITE_OK)
{
sqlite3_step(myPreparedStatement) == SQLITE_ROW;
int myColumnCount = sqlite3_column_count(myPreparedStatement);
//loop through each column in the record adding its field name and vvalue to the map
for (int myColNo=0;myColNo < myColumnCount;myColNo++)
{
myFieldName = QString ((char *)sqlite3_column_name(myPreparedStatement,myColNo));
myFieldValue = QString ((char *)sqlite3_column_text(myPreparedStatement,myColNo));
myMap[myFieldName]=myFieldValue;
}
}
else
{
#ifdef QGISDEBUG
std::cout << " QgsSpatialRefSys::getRecord failed : " << theSql << std::endl;
#endif
}
}
sqlite3_finalize(myPreparedStatement);
sqlite3_close(myDatabase);
return myMap;
}
// Accessors -----------------------------------
/*! Get the SrsId
* @return long theSrsId The internal sqlite3 srs.db primary key for this srs
*/
long QgsSpatialRefSys::srsid() const
{
return mSrsId;
}
/*! Get the Postgis SRID - if possible
* @return long theSRID The internal postgis SRID for this SRS
*/
long QgsSpatialRefSys::srid() const
{
return mSRID;
}
/*! Get the Description
* @return QString the Description A textual description of the srs.
@ -534,7 +691,7 @@ QString QgsSpatialRefSys::ellipsoidAcronym () const
{
return mEllipsoidAcronym;
}
/* Get the Proj Proj4String.
/* Get the Proj Proj4String.
* @return QString theProj4String Proj4 format specifies that define this srs.
*/
QString QgsSpatialRefSys::proj4String() const
@ -679,14 +836,16 @@ void QgsSpatialRefSys::setMapUnits()
#ifdef QGISDEBUG
std::cerr << "Projection has angular units of " << unit << '\n';
#endif
}
}
bool QgsSpatialRefSys::operator==(const QgsSpatialRefSys &theSrs)
{
qWarning("QgsSpatialRefSys::operator== called ");
qWarning("QgsSpatialRefSys::operator== called ");
bool myMatchFlag = true; //innocent until proven guilty
bool myMatchFlag = true; //innocent until proven guilty
/* Here are the possible OGR error codes :
typedef int OGRErr;
@ -708,7 +867,7 @@ bool QgsSpatialRefSys::operator==(const QgsSpatialRefSys &theSrs)
//same for the projections they define to be equivalent, which is why I dont just
//compare the proj parameter strings and return the result
//create the sr and populate it from a wkt proj definition
OGRSpatialReference myOgrSpatialRef1;
OGRSpatialReference myOgrSpatialRef2;
@ -739,14 +898,14 @@ bool QgsSpatialRefSys::operator==(const QgsSpatialRefSys &theSrs)
//placeholder to be replaced with ogr tests
if (myMatchFlag)
{
qWarning("QgsSpatialRefSys::operator== result: srs's are equal ");
}
else
{
qWarning("QgsSpatialRefSys::operator== result: srs's are not equal ");
}
return myMatchFlag;
//placeholder to be replaced with ogr tests
if (myMatchFlag)
{
qWarning("QgsSpatialRefSys::operator== result: srs's are equal ");
}
else
{
qWarning("QgsSpatialRefSys::operator== result: srs's are not equal ");
}
return myMatchFlag;
}

View File

@ -9,6 +9,7 @@
#include <qstring.h>
#include <qstringlist.h>
#include <qregexp.h>
#include <qmap.h>
//qgis includes
#include <qgis.h>
@ -73,7 +74,7 @@ class QgsSpatialRefSys
* @note Any members will be overwritten during this process.
* @param theSrid The postgis SRID for the desired spatial reference system.
*/
void createFromSrid(const long theSrid);
bool createFromSrid(const long theSrid);
/*! Set up this srs using a WKT spatial ref sys definition.
* The wkt will be converted to a proj4 string using OGR helper
* functions. After this the srs databasses will be searched for matches.
@ -82,23 +83,26 @@ class QgsSpatialRefSys
* @note Any members will be overwritten during this process.
* @note SRID and EPSG may be blank if no match can be found on srs db.
* @param theWkt The WKT for the desired spatial reference system.
* @return bool TRUE if sucess else false
*/
void createFromWkt(const QString theWkt);
bool createFromWkt(const QString theWkt);
/*! Set up this srs by fetching the appropriate information from the
* sqlite backend. First the system level read only srs.db will be checked
* and then the users ~/.qgis/qgis.db database will be checked for a match.
* @note Any members will be overwritten during this process.
* @param theEpsg The EPSG for the desired spatial reference system.
* @return bool TRUE if sucess else false
*/
void createFromEpsg(const long theEpsg);
bool createFromEpsg(const long theEpsg);
/*! Set up this srs by fetching the appropriate information from the
* sqlite backend. If the srsid is < 100000, only the system srs.db
* will be checked. If the srsid > 100000 the srs will be retrieved from
* the ~/.qgis/qgis.db
* @note Any members will be overwritten during this process.
* @param theSrsId The QGIS SrsId for the desired spatial reference system.
* @return bool TRUE if sucess else false
*/
void createFromSrsId (const long theSrsId);
bool createFromSrsId (const long theSrsId);
/*! Set up this srs by passing it a proj4 style formatted string.
* The string will be parsed and the projection and ellipsoid
@ -106,10 +110,30 @@ class QgsSpatialRefSys
* in the parameters member. The reason for this is so that we
* can easily present the user with 'natural language' representation
* of the projection and ellipsoid by looking them up in the srs.bs sqlite
* database.
* database. Also having the ellpse and proj elements stripped out
* is hepful to speed up globbing queries (see below).
*
* We try to match the proj string to and srsid using the following logic:
*
* - perform a whole text search on srs name (if not null). The srs name will
* have been set if this method has been delegated to from createFromWkt.
* - if the above does not match perform a whole text search on proj4 string (if not null)
* - if none of the above match convert the proj4 string to an OGR SRS
* then check if its a geocs or a proj cs (using ogr isGeographic)
* then sequentially walk through the database (first users qgis.db srs tbl then
* system srs.db tbl), converting each entry into an ogr srs and using isSame
* or isSameGeocs (essentially calling the == overloaded operator). We'll try to
* be smart about this and first parse out the proj and ellpse strings and only
* check for a match in entities that have the same ellps and proj entries so
* that it doesnt munch yer cpu so much.
*
* @note If the srs was not matched, we will create a new entry on the users tbl_srs
* for this srs.
*
* @param theProjString A proj4 format string
* @return bool TRUE if sucess else false
*/
void createFromProj4 (const QString theProjString);
bool createFromProj4 (const QString theProjString);
/*! Find out whether this SRS is correctly initialised and useable */
bool isValid() const;
@ -118,14 +142,31 @@ class QgsSpatialRefSys
* consulted and acted on accordingly. By hell or high water this
* method will do its best to make sure that this SRS is valid - even
* if that involves resorting to a hard coded default of geocs:wgs84.
*
* @note It is not usually neccessary to use this function, unless you
* are trying to force theis srs to be valid.
*/
void validate();
/*! A string based associative array used for passing records around */
typedef QMap<QString, QString> RecordMap;
/*! Get a record from the srs.db or qgis.db backends, given an sql statment.
* @note only handles queries that return a single record.
* @note it will first try the system srs.db then the users qgis.db!
* @param QString The sql query to execute
* @return QMap An associative array of field name <-> value pairs
*/
RecordMap getRecord(QString theSql);
// Accessors -----------------------------------
/*! Get the SrsId
/*! Get the SrsId - if possible
* @return long theSrsId The internal sqlite3 srs.db primary key for this srs
*/
long srsid() const;
/*! Get the Postgis SRID - if possible.
* @return long theSRID The internal postgis SRID for this SRS
*/
long srid() const;
/*! Get the Description
* @return QString the Description A textual description of the srs.