Skip to content

Commit

Permalink
Automatically adds projections previously unknown to QGIS (but still …
Browse files Browse the repository at this point in the history
…valid) as a Custom CRS. This can later be edited for name etc. No user interaction required, one new text to translate. Fixes #418.

git-svn-id: http://svn.osgeo.org/qgis/trunk@11366 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
homann committed Aug 13, 2009
1 parent eb02422 commit 93d5bd2
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 8 deletions.
171 changes: 163 additions & 8 deletions src/core/qgscoordinatereferencesystem.cpp
Expand Up @@ -31,6 +31,7 @@
#include "qgsmessageoutput.h"
#include "qgis.h" //const vals declared here

#include <cassert>
#include <sqlite3.h>

//gdal and ogr includes (needed for == operator)
Expand Down Expand Up @@ -349,18 +350,20 @@ bool QgsCoordinateReferenceSystem::createFromProj4( const QString theProj4String
* have been set if this method has been delegated to from createFromWkt.
* Normally we wouldnt expect this to work, but its worth trying first
* as its quicker than methods below..
*/
*/
long mySrsId = 0;
QgsCoordinateReferenceSystem::RecordMap myRecord;
if ( !mDescription.trimmed().isEmpty() )
{
myRecord = getRecord( "select * from tbl_srs where description='" + mDescription.trimmed() + "'" );
}

// *** Matching on descriptions feels iffy. Different projs can have same description. Homann ***
// if ( !mDescription.trimmed().isEmpty() )
//{
// myRecord = getRecord( "select * from tbl_srs where description='" + mDescription.trimmed() + "'" );
//}

/*
* - if the above does not match perform a whole text search on proj4 string (if not null)
*/
QgsDebugMsg( "wholetext match on name failed, trying proj4string match" );
// QgsDebugMsg( "wholetext match on name failed, trying proj4string match" );
myRecord = getRecord( "select * from tbl_srs where parameters='" + theProj4String.trimmed() + "'" );
if ( !myRecord.empty() )
{
Expand Down Expand Up @@ -434,7 +437,34 @@ bool QgsCoordinateReferenceSystem::createFromProj4( const QString theProj4String
// if we failed to look up the projection in database, don't worry. we can still use it :)
if ( !mIsValidFlag )
{
QgsDebugMsg( "Projection is not found in databases." );
setProj4String( theProj4String );
// Is the SRS is valid now, we know it's a decent +proj string that can be entered into the srs.db
if ( mIsValidFlag )
{
// Try to save. If not possible, set to invalid. Problems on read only systems?
QgsDebugMsg( "Projection appears to be valid. Save to database!" );
mIsValidFlag = saveAsUserCRS();
// The srsid is not set, we should do that now.
if ( mIsValidFlag )
{
myRecord = getRecord( "select * from tbl_srs where parameters='" + theProj4String.trimmed() + "'" );
if ( !myRecord.empty() )
{
mySrsId = myRecord["srs_id"].toLong();
QgsDebugMsg( "proj4string match search for srsid returned srsid: " + QString::number( mySrsId ) );
if ( mySrsId > 0 )
{
createFromSrsId( mySrsId );
}
else
{
QgsDebugMsg( "Couldn't find newly added proj string?" );
mIsValidFlag = false;
}
}
}
}
}


Expand Down Expand Up @@ -610,7 +640,8 @@ QString QgsCoordinateReferenceSystem::toProj4() const
toProj4 = proj4src;
CPLFree( proj4src );

return toProj4;
// Stray spaces at the end?
return toProj4.trimmed();
}

bool QgsCoordinateReferenceSystem::geographicFlag() const
Expand Down Expand Up @@ -740,7 +771,7 @@ long QgsCoordinateReferenceSystem::findMatchingProj()
QgsDebugMsg( "entered." );
if ( mEllipsoidAcronym.isNull() || mProjectionAcronym.isNull() || !mIsValidFlag )
{
QgsLogger::warning( "QgsCoordinateReferenceSystem::findMatchingProj will only work if prj acr ellipsoid acr and proj4string are set!..." );
QgsDebugMsg( "QgsCoordinateReferenceSystem::findMatchingProj will only work if prj acr ellipsoid acr and proj4string are set!..." );
return 0;
}

Expand Down Expand Up @@ -1122,3 +1153,127 @@ QString QgsCoordinateReferenceSystem::validationHint()
{
return mValidationHint;
}

/// Copied from QgsCustomProjectionDialog ///
/// Please refactor into SQL handler !!! ///

bool QgsCoordinateReferenceSystem::saveAsUserCRS()
{

if ( ! mIsValidFlag )
{
QgsDebugMsg( "Can't save an invalid CRS!" );
return false;
}

QString mySql;
QString myName = QString( " * %1 (%2)" )
.arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ))
.arg( toProj4() );

//if this is the first record we need to ensure that its srs_id is 10000. For
//any rec after that sqlite3 will take care of the autonumering
//this was done to support sqlite 3.0 as it does not yet support
//the autoinc related system tables.
if ( getRecordCount() == 0 )
{
mySql = QString( "insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) " )
+ " values (" + QString::number( USER_CRS_START_ID ) + ",'"
+ sqlSafeString( myName ) + "','" + projectionAcronym()
+ "','" + ellipsoidAcronym() + "','" + sqlSafeString( toProj4() )
+ "',0)"; // <-- is_geo shamelessly hard coded for now
}
else
{
mySql = "insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ('"
+ sqlSafeString( myName ) + "','" + projectionAcronym()
+ "','" + ellipsoidAcronym() + "','" + sqlSafeString( toProj4() )
+ "',0)"; // <-- is_geo shamelessly hard coded for now
}
sqlite3 *myDatabase;
const char *myTail;
sqlite3_stmt *myPreparedStatement;
int myResult;
//check the db is available
myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
if ( myResult != SQLITE_OK )
{
QgsDebugMsg( QString( "Can't open database: %1 \n please notify QGIS developers of this error \n %2 (file name) " ).arg( sqlite3_errmsg( myDatabase ) ).arg( QgsApplication::qgisUserDbFilePath() ) );
// XXX This will likely never happen since on open, sqlite creates the
// database if it does not exist.
assert( myResult == SQLITE_OK );
}
QgsDebugMsg( QString( "Update or insert sql \n%1" ).arg( mySql ) );
myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.length(), &myPreparedStatement, &myTail );
sqlite3_step( myPreparedStatement );
// XXX Need to free memory from the error msg if one is set
return myResult == SQLITE_OK;

}

long QgsCoordinateReferenceSystem::getRecordCount()
{
sqlite3 *myDatabase;
const char *myTail;
sqlite3_stmt *myPreparedStatement;
int myResult;
long myRecordCount = 0;
//check the db is available
myResult = sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().data(), &myDatabase );
if ( myResult != SQLITE_OK )
{
QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
// XXX This will likely never happen since on open, sqlite creates the
// database if it does not exist.
assert( myResult == SQLITE_OK );
}
// Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
QString mySql = "select count(*) from tbl_srs";
myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.length(), &myPreparedStatement, &myTail );
// XXX Need to free memory from the error msg if one is set
if ( myResult == SQLITE_OK )
{
if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
{
QString myRecordCountString = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 0 ) );
myRecordCount = myRecordCountString.toLong();
}
}
// close the sqlite3 statement
sqlite3_finalize( myPreparedStatement );
sqlite3_close( myDatabase );
return myRecordCount;

}

const QString QgsCoordinateReferenceSystem::sqlSafeString( const QString theSQL )
{

QString myRetval;
QChar *it = ( QChar * )theSQL.unicode();
for ( int i = 0; i < theSQL.length(); i++ )
{
if ( *it == '\"' )
{
myRetval += "\\\"";
}
else if ( *it == '\'' )
{
myRetval += "\\'";
}
else if ( *it == '\\' )
{
myRetval += "\\\\";
}
else if ( *it == '%' )
{
myRetval += "\\%";
}
else
{
myRetval += *it;
}
it++;
}
return myRetval;
}
9 changes: 9 additions & 0 deletions src/core/qgscoordinatereferencesystem.h
Expand Up @@ -387,6 +387,15 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
//! Work out the projection units and set the appropriate local variable
void setMapUnits();

//! Save the proj4-string as a custom CRS
bool saveAsUserCRS();

//! Helper for getting number of user CRS already in db
long getRecordCount();

//! Helper for sql-safin strings
const QString sqlSafeString( const QString theSQL );

void *mCRS;

bool loadFromDb( QString db, QString field, long id );
Expand Down

0 comments on commit 93d5bd2

Please sign in to comment.