Skip to content

Commit

Permalink
Ensure that proj strings in different parameter order are matched
Browse files Browse the repository at this point in the history
to user CRS on proj 6 builds
  • Loading branch information
nyalldawson committed Dec 20, 2019
1 parent a2c6bb9 commit 3f0af6e
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 5 deletions.
89 changes: 84 additions & 5 deletions src/core/qgscoordinatereferencesystem.cpp
Expand Up @@ -831,14 +831,25 @@ bool QgsCoordinateReferenceSystem::createFromProj( const QString &projString )
}
}
}
#endif

#if PROJ_VERSION_MAJOR>=6
// try to match against known user crses
// try a direct match against user crses
QgsCoordinateReferenceSystem::RecordMap myRecord = getRecord( "select * from tbl_srs where parameters=" + QgsSqliteUtils::quotedString( myProj4String ) + " order by deprecated" );
long id = 0;
if ( !myRecord.empty() )
{
long id = myRecord[QStringLiteral( "srs_id" )].toLong();
id = myRecord[QStringLiteral( "srs_id" )].toLong();
if ( id >= USER_CRS_START_ID )
{
createFromSrsId( id );
}
}
if ( id < USER_CRS_START_ID )
{
// no direct matches, so go ahead and create a new proj object based on the proj string alone.
setProj4String( myProj4String );

// lastly, try a tolerant match of the created proj object against all user CRSes (allowing differences in parameter order during the comparison)
id = matchToUserCrs();
if ( id >= USER_CRS_START_ID )
{
createFromSrsId( id );
Expand Down Expand Up @@ -1006,7 +1017,6 @@ bool QgsCoordinateReferenceSystem::createFromProj( const QString &projString )
d->mIsValid = false;
}
}
#endif

// if we failed to look up the projection in database, don't worry. we can still use it :)
if ( !d->mIsValid )
Expand All @@ -1015,6 +1025,7 @@ bool QgsCoordinateReferenceSystem::createFromProj( const QString &projString )
//setProj4String will set mIsValidFlag to true if there is no issue
setProjString( myProj4String );
}
#endif

locker.changeMode( QgsReadWriteLocker::Write );
if ( !sDisableProjCache )
Expand Down Expand Up @@ -2348,6 +2359,74 @@ bool QgsCoordinateReferenceSystem::loadFromAuthCode( const QString &auth, const

return true;
}

QList<long> QgsCoordinateReferenceSystem::userSrsIds()
{
QList<long> results;
// check user defined projection database
const QString db = QgsApplication::qgisUserDatabaseFilePath();

QFileInfo myInfo( db );
if ( !myInfo.exists() )
{
QgsDebugMsg( "failed : " + db + " does not exist!" );
return results;
}

sqlite3_database_unique_ptr database;
sqlite3_statement_unique_ptr statement;

//check the db is available
int result = openDatabase( db, database );
if ( result != SQLITE_OK )
{
QgsDebugMsg( "failed : " + db + " could not be opened!" );
return results;
}

QString sql = QStringLiteral( "select srs_id from tbl_srs where srs_id >= %1" ).arg( USER_CRS_START_ID );
int rc;
statement = database.prepare( sql, rc );
while ( true )
{
int ret = statement.step();

if ( ret == SQLITE_DONE )
{
// there are no more rows to fetch - we can stop looping
break;
}

if ( ret == SQLITE_ROW )
{
results.append( statement.columnAsInt64( 0 ) );
}
else
{
QgsMessageLog::logMessage( QObject::tr( "SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( database.get() ) ), QObject::tr( "SpatiaLite" ) );
break;
}
}

return results;
}

long QgsCoordinateReferenceSystem::matchToUserCrs() const
{
if ( !d->mPj )
return 0;

const QList< long > ids = userSrsIds();
for ( long id : ids )
{
QgsCoordinateReferenceSystem candidate = QgsCoordinateReferenceSystem::fromSrsId( id );
if ( candidate.projObject() && proj_is_equivalent_to( d->mPj.get(), candidate.projObject(), PJ_COMP_EQUIVALENT ) )
{
return id;
}
}
return 0;
}
#endif

#if PROJ_VERSION_MAJOR<6
Expand Down
14 changes: 14 additions & 0 deletions src/core/qgscoordinatereferencesystem.h
Expand Up @@ -931,6 +931,20 @@ class CORE_EXPORT QgsCoordinateReferenceSystem

#if PROJ_VERSION_MAJOR>=6
bool loadFromAuthCode( const QString &auth, const QString &code );

/**
* Returns a list of all users SRS IDs present in the CRS database.
*/
static QList< long > userSrsIds();

/**
* Tries to match the current definition of the CRS to user CRSes.
*
* Uses proj's equivalent testing API so that matches are tolerant to differences in
* parameter order and naming for proj or WKT strings (internally, uses the PJ_COMP_EQUIVALENT
* criteria).
*/
long matchToUserCrs() const;
#endif

/**
Expand Down
8 changes: 8 additions & 0 deletions tests/src/core/testqgscoordinatereferencesystem.cpp
Expand Up @@ -1410,6 +1410,14 @@ void TestQgsCoordinateReferenceSystem::customProjString()
QCOMPARE( crs.toWkt(), QStringLiteral( R"""(COMPD_CS["unknown",PROJCS["unknown",GEOGCS["unknown",DATUM["Unknown_based_on_Bessel_1841_ellipsoid",SPHEROID["Bessel 1841",6377397.155,299.1528128],TOWGS84[595.75,121.09,515.5,8.227,-1.5193,5.5971,-2.6729]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Oblique_Stereographic"],PARAMETER["latitude_of_origin",47.4860018439082],PARAMETER["central_meridian",19.0491441390302],PARAMETER["scale_factor",1],PARAMETER["false_easting",500000],PARAMETER["false_northing",500000],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH]],VERT_CS["unknown",VERT_DATUM["unknown",2005],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Gravity-related height",UP]]])""" ) );
QCOMPARE( crs.authid(), QStringLiteral( "USER:%1" ).arg( id ) );

// make sure it matches to user crs when parameter order is different
QgsCoordinateReferenceSystem::invalidateCache();
crs = QgsCoordinateReferenceSystem::fromProj4( QStringLiteral( "+proj=sterea +lon_0=19.0491441390302 +lat_0=47.4860018439082 +k=1 +y_0=500000 +ellps=bessel +x_0=500000 +towgs84=595.75,121.09,515.50,8.2270,-1.5193,5.5971,-2.6729 +units=m +vunits=m +no_defs" ) );
QVERIFY( crs.isValid() );
QCOMPARE( crs.authid(), QStringLiteral( "USER:%1" ).arg( id ) );
QCOMPARE( crs.toProj4(), QStringLiteral( "+proj=sterea +lat_0=47.4860018439082 +lon_0=19.0491441390302 +k=1 +x_0=500000 +y_0=500000 +ellps=bessel +towgs84=595.75,121.09,515.50,8.2270,-1.5193,5.5971,-2.6729 +units=m +vunits=m +no_defs" ) );
QCOMPARE( crs.toWkt(), QStringLiteral( R"""(COMPD_CS["unknown",PROJCS["unknown",GEOGCS["unknown",DATUM["Unknown_based_on_Bessel_1841_ellipsoid",SPHEROID["Bessel 1841",6377397.155,299.1528128],TOWGS84[595.75,121.09,515.5,8.227,-1.5193,5.5971,-2.6729]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Oblique_Stereographic"],PARAMETER["latitude_of_origin",47.4860018439082],PARAMETER["central_meridian",19.0491441390302],PARAMETER["scale_factor",1],PARAMETER["false_easting",500000],PARAMETER["false_northing",500000],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH]],VERT_CS["unknown",VERT_DATUM["unknown",2005],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Gravity-related height",UP]]])""" ) );

#endif
}

Expand Down

0 comments on commit 3f0af6e

Please sign in to comment.