Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Avoid some crs db lookups on proj 6 builds
  • Loading branch information
nyalldawson committed Jun 4, 2019
1 parent 0b52a37 commit 8a4d306
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 68 deletions.
268 changes: 201 additions & 67 deletions src/core/qgscoordinatereferencesystem.cpp
Expand Up @@ -383,6 +383,27 @@ bool QgsCoordinateReferenceSystem::createFromOgcWmsCrs( const QString &crs )
}
}

#if PROJ_VERSION_MAJOR>=6
// first chance for proj 6 - scan through legacy systems and try to use authid directly
const QString legacyKey = wmsCrs.toLower();
for ( auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
{
if ( it.key().compare( legacyKey, Qt::CaseInsensitive ) == 0 )
{
const QStringList parts = it.key().split( ':' );
const QString auth = parts.at( 0 );
const QString code = parts.at( 1 );
if ( loadFromAuthCode( auth, code ) )
{
sOgcLock.lockForWrite();
sOgcCache.insert( crs, *this );
sOgcLock.unlock();
return true;
}
}
}
#endif

if ( loadFromDatabase( QgsApplication::srsDatabaseFilePath(), QStringLiteral( "lower(auth_name||':'||auth_id)" ), wmsCrs.toLower() ) )
{
sOgcLock.lockForWrite();
Expand Down Expand Up @@ -463,6 +484,27 @@ bool QgsCoordinateReferenceSystem::createFromSrid( const long id )
}
sSrIdCacheLock.unlock();

#if PROJ_VERSION_MAJOR>=6
// first chance for proj 6 - scan through legacy systems and try to use authid directly
for ( auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
{
if ( it.value().endsWith( QStringLiteral( ",%1" ).arg( id ) ) )
{
const QStringList parts = it.key().split( ':' );
const QString auth = parts.at( 0 );
const QString code = parts.at( 1 );
if ( loadFromAuthCode( auth, code ) )
{
sSrIdCacheLock.lockForWrite();
sSrIdCache.insert( id, *this );
sSrIdCacheLock.unlock();

return true;
}
}
}
#endif

bool result = loadFromDatabase( QgsApplication::srsDatabaseFilePath(), QStringLiteral( "srid" ), QString::number( id ) );

sSrIdCacheLock.lockForWrite();
Expand All @@ -485,6 +527,27 @@ bool QgsCoordinateReferenceSystem::createFromSrsId( const long id )
}
sCRSSrsIdLock.unlock();

#if PROJ_VERSION_MAJOR>=6
// first chance for proj 6 - scan through legacy systems and try to use authid directly
for ( auto it = sAuthIdToQgisSrsIdMap.constBegin(); it != sAuthIdToQgisSrsIdMap.constEnd(); ++it )
{
if ( it.value().startsWith( QString::number( id ) + ',' ) )
{
const QStringList parts = it.key().split( ':' );
const QString auth = parts.at( 0 );
const QString code = parts.at( 1 );
if ( loadFromAuthCode( auth, code ) )
{
sCRSSrsIdLock.lockForWrite();
sSrsIdCache.insert( id, *this );
sCRSSrsIdLock.unlock();

return true;
}
}
}
#endif

bool result = loadFromDatabase( id < USER_CRS_START_ID ? QgsApplication::srsDatabaseFilePath() :
QgsApplication::qgisUserDatabaseFilePath(),
QStringLiteral( "srs_id" ), QString::number( id ) );
Expand Down Expand Up @@ -696,12 +759,13 @@ bool QgsCoordinateReferenceSystem::createFromWkt( const QString &wkt )
const QString authCode( proj_get_id_code( d->mPj.get(), 0 ) );
if ( !authName.isEmpty() && !authCode.isEmpty() )
{
const QString authid = QStringLiteral( "%1:%2" ).arg( authName, authCode );
bool result = createFromOgcWmsCrs( authid );
sCRSWktLock.lockForWrite();
sWktCache.insert( wkt, *this );
sCRSWktLock.unlock();
return result;
if ( loadFromAuthCode( authName, authCode ) )
{
sCRSWktLock.lockForWrite();
sWktCache.insert( wkt, *this );
sCRSWktLock.unlock();
return true;
}
}
}
#else
Expand Down Expand Up @@ -874,11 +938,13 @@ bool QgsCoordinateReferenceSystem::createFromProj4( const QString &proj4String )
if ( !authName.isEmpty() && !authCode.isEmpty() )
{
const QString authid = QStringLiteral( "%1:%2" ).arg( authName, authCode );
const bool result = createFromOgcWmsCrs( authid );
sProj4CacheLock.lockForWrite();
sProj4Cache.insert( proj4String, *this );
sProj4CacheLock.unlock();
return result;
if ( createFromOgcWmsCrs( authid ) )
{
sProj4CacheLock.lockForWrite();
sProj4Cache.insert( proj4String, *this );
sProj4CacheLock.unlock();
return true;
}
}
}
}
Expand Down Expand Up @@ -2064,6 +2130,127 @@ long QgsCoordinateReferenceSystem::getRecordCount()
return myRecordCount;
}

#if PROJ_VERSION_MAJOR>=6
bool testIsGeographic( PJ *crs )
{
PJ_CONTEXT *pjContext = QgsProjContext::get();
bool isGeographic = false;
QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( pjContext, crs ) );
if ( coordinateSystem )
{
const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
if ( axisCount > 0 )
{
const char *outUnitAuthName = nullptr;
const char *outUnitAuthCode = nullptr;
// Read only first axis
proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
&outUnitAuthName,
&outUnitAuthCode );

if ( outUnitAuthName && outUnitAuthCode )
{
const char *unitCategory = nullptr;
if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode, nullptr, nullptr, &unitCategory ) )
{
isGeographic = QString( unitCategory ).compare( QLatin1String( "angular" ), Qt::CaseInsensitive ) == 0;
}
}
}
}
return isGeographic;
}

void getOperationAndEllipsoidFromProjString( const QString &proj, QString &operation, QString &ellipsoid )
{
QRegExp projRegExp( "\\+proj=(\\S+)" );
if ( projRegExp.indexIn( proj ) < 0 )
{
QgsDebugMsgLevel( QStringLiteral( "no +proj argument found [%2]" ).arg( proj ), 2 );
return;
}
operation = projRegExp.cap( 1 );

QRegExp ellipseRegExp( "\\+(?:ellps|datum)=(\\S+)" );
QString ellps;
if ( ellipseRegExp.indexIn( proj ) >= 0 )
{
ellipsoid = ellipseRegExp.cap( 1 );
}
else
{
// satisfy not null constraint on ellipsoid_acronym field
// possibly we should drop the constraint, yet the crses with missing ellipsoid_acronym are malformed
// and will result in oddities within other areas of QGIS (e.g. project ellipsoid won't be correctly
// set for these CRSes). Better just hack around and make the constraint happy for now,
// and hope that the definitions get corrected in future.
ellipsoid = "";
}
}


bool QgsCoordinateReferenceSystem::loadFromAuthCode( const QString &auth, const QString &code )
{
d.detach();
d->mIsValid = false;
d->mWkt.clear();

PJ_CONTEXT *pjContext = QgsProjContext::get();
QgsProjUtils::proj_pj_unique_ptr crs( proj_create_from_database( pjContext, auth.toUtf8().constData(), code.toUtf8().constData(), PJ_CATEGORY_CRS, false, nullptr ) );
if ( !crs )
{
return false;
}

switch ( proj_get_type( crs.get() ) )
{
case PJ_TYPE_VERTICAL_CRS:
return false;

default:
break;
}

crs = QgsProjUtils::crsToSingleCrs( crs.get() );

QString proj4 = getFullProjString( crs.get() );
proj4.replace( QStringLiteral( "+type=crs" ), QString() );
proj4 = proj4.trimmed();

d->mIsValid = true;
d->mProj4 = proj4;
d->mDescription = QString( proj_get_name( crs.get() ) );
d->mAuthId = QStringLiteral( "%1:%2" ).arg( auth, code );
d->mIsGeographic = testIsGeographic( crs.get() );
d->mAxisInvertedDirty = true;
QString operation;
QString ellipsoid;
getOperationAndEllipsoidFromProjString( proj4, operation, ellipsoid );
d->mProjectionAcronym = operation;
d->mEllipsoidAcronym = ellipsoid;
d->mPj = std::move( crs );

const QString dbVals = sAuthIdToQgisSrsIdMap.value( QStringLiteral( "%1:%2" ).arg( auth, code ).toUpper() );
QString srsId;
QString srId;
if ( !dbVals.isEmpty() )
{
const QStringList parts = dbVals.split( ',' );
d->mSrsId = parts.at( 0 ).toInt();
d->mSRID = parts.at( 1 ).toInt();
}

setMapUnits();

return true;
}
#endif

#if PROJ_VERSION_MAJOR<6
// adapted from gdal/ogr/ogr_srs_dict.cpp
bool QgsCoordinateReferenceSystem::loadWkts( QHash<int, QString> &wkts, const char *filename )
Expand Down Expand Up @@ -2333,63 +2520,10 @@ int QgsCoordinateReferenceSystem::syncDatabase()
}
else
{
// ideally we'd be getting these using the proj api -- but that's not possible

QRegExp projRegExp( "\\+proj=(\\S+)" );
if ( projRegExp.indexIn( proj4 ) < 0 )
{
QgsDebugMsg( QStringLiteral( "%1:%2: no +proj argument found [%2]" ).arg( authority, code, proj4 ) );
continue;
}
const QString operation = projRegExp.cap( 1 );

QRegExp ellipseRegExp( "\\+ellps=(\\S+)" );
QString operation;
QString ellps;
if ( ellipseRegExp.indexIn( proj4 ) >= 0 )
{
ellps = ellipseRegExp.cap( 1 );
}
else
{
// satisfy not null constraint on ellipsoid_acronym field
// possibly we should drop the constraint, yet the crses with missing ellipsoid_acronym are malformed
// and will result in oddities within other areas of QGIS (e.g. project ellipsoid won't be correctly
// set for these CRSes). Better just hack around and make the constraint happy for now,
// and hope that the definitions get corrected in future.
ellps = "";
}


bool isGeographic = false;

QgsProjUtils::proj_pj_unique_ptr coordinateSystem( proj_crs_get_coordinate_system( pjContext, crs.get() ) );
if ( coordinateSystem )
{
const int axisCount = proj_cs_get_axis_count( pjContext, coordinateSystem.get() );
if ( axisCount > 0 )
{
const char *outUnitAuthName = nullptr;
const char *outUnitAuthCode = nullptr;
// Read only first axis
proj_cs_get_axis_info( pjContext, coordinateSystem.get(), 0,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
&outUnitAuthName,
&outUnitAuthCode );

if ( outUnitAuthName && outUnitAuthCode )
{
const char *unitCategory = nullptr;
if ( proj_uom_get_info_from_database( pjContext, outUnitAuthName, outUnitAuthCode, nullptr, nullptr, &unitCategory ) )
{
isGeographic = QString( unitCategory ).compare( QLatin1String( "angular" ), Qt::CaseInsensitive ) == 0;
}
}
}
}
getOperationAndEllipsoidFromProjString( proj4, operation, ellps );
const bool isGeographic = testIsGeographic( crs.get() );

// work out srid and srsid
const QString dbVals = sAuthIdToQgisSrsIdMap.value( QStringLiteral( "%1:%2" ).arg( authority, code ) );
Expand Down
4 changes: 4 additions & 0 deletions src/core/qgscoordinatereferencesystem.h
Expand Up @@ -781,6 +781,10 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
//! Helper for getting number of user CRS already in db
long getRecordCount();

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

/**
* Initialize the CRS object by looking up CRS database in path given in db argument,
* using first CRS entry where expression = 'value'
Expand Down
2 changes: 1 addition & 1 deletion tests/src/core/testqgscoordinatereferencesystem.cpp
Expand Up @@ -701,7 +701,7 @@ void TestQgsCoordinateReferenceSystem::ellipsoidAcronym()
myCrs.createFromSrid( GEOSRID );
QString myAcronym = myCrs.ellipsoidAcronym();
debugPrint( myCrs );
QVERIFY( myAcronym == "WGS84" );
QCOMPARE( myAcronym, QStringLiteral( "WGS84" ) );
}
void TestQgsCoordinateReferenceSystem::toWkt()
{
Expand Down

0 comments on commit 8a4d306

Please sign in to comment.