Skip to content

Commit

Permalink
Add API to skip identification of CRS created from proj strings
Browse files Browse the repository at this point in the history
The identification can be time consuming, so in the rare cases that
we are SURE that the definition doesn't correspond to a known or
user CRS, we can optionally skip it to save some time.
  • Loading branch information
nyalldawson committed May 19, 2020
1 parent a2e8cde commit 0acb7fc
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 32 deletions.
Expand Up @@ -474,6 +474,9 @@ We try to match the Proj string to internal QGIS CRS ID using the following logi
- if none of the above match, use the Proj string to create the CRS and do not associated an internal CRS ID to it.

:param projString: A Proj format string
:param identify: if ``False``, no attempts will be made to match the proj string against known CRS authorities. This is much
faster, but should only ever be used when it is known in advance that the definition does not correspond to a known or user CRS. This
argument is not available in Python.

:return: ``True`` on success else ``False``

Expand Down
73 changes: 41 additions & 32 deletions src/core/qgscoordinatereferencesystem.cpp
Expand Up @@ -897,7 +897,7 @@ bool QgsCoordinateReferenceSystem::createFromProj4( const QString &proj4String )
return createFromProj( proj4String );
}

bool QgsCoordinateReferenceSystem::createFromProj( const QString &projString )
bool QgsCoordinateReferenceSystem::createFromProj( const QString &projString, const bool identify )
{
d.detach();

Expand Down Expand Up @@ -937,51 +937,60 @@ bool QgsCoordinateReferenceSystem::createFromProj( const QString &projString )
d->mIsValid = false;
d->mWktPreferred.clear();
#if PROJ_VERSION_MAJOR>=6
// first, try to use proj to do this for us...
const QString projCrsString = myProj4String + ( myProj4String.contains( QStringLiteral( "+type=crs" ) ) ? QString() : QStringLiteral( " +type=crs" ) );
QgsProjUtils::proj_pj_unique_ptr crs( proj_create( QgsProjContext::get(), projCrsString.toLatin1().constData() ) );
if ( crs )
if ( identify )
{
QString authName;
QString authCode;
if ( QgsProjUtils::identifyCrs( crs.get(), authName, authCode, QgsProjUtils::FlagMatchBoundCrsToUnderlyingSourceCrs ) )
// first, try to use proj to do this for us...
const QString projCrsString = myProj4String + ( myProj4String.contains( QStringLiteral( "+type=crs" ) ) ? QString() : QStringLiteral( " +type=crs" ) );
QgsProjUtils::proj_pj_unique_ptr crs( proj_create( QgsProjContext::get(), projCrsString.toLatin1().constData() ) );
if ( crs )
{
const QString authid = QStringLiteral( "%1:%2" ).arg( authName, authCode );
if ( createFromOgcWmsCrs( authid ) )
QString authName;
QString authCode;
if ( QgsProjUtils::identifyCrs( crs.get(), authName, authCode, QgsProjUtils::FlagMatchBoundCrsToUnderlyingSourceCrs ) )
{
locker.changeMode( QgsReadWriteLocker::Write );
if ( !sDisableProjCache )
sProj4Cache()->insert( projString, *this );
return true;
const QString authid = QStringLiteral( "%1:%2" ).arg( authName, authCode );
if ( createFromOgcWmsCrs( authid ) )
{
locker.changeMode( QgsReadWriteLocker::Write );
if ( !sDisableProjCache )
sProj4Cache()->insert( projString, *this );
return true;
}
}
}
}

// 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() )
{
id = myRecord[QStringLiteral( "srs_id" )].toLong();
if ( id >= USER_CRS_START_ID )
// 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() )
{
createFromSrsId( id );
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.
setProjString( 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 );
}
}
}
if ( id < USER_CRS_START_ID )
else
{
// no direct matches, so go ahead and create a new proj object based on the proj string alone.
setProjString( 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 );
}
}

#else
Q_UNUSED( identify )

QRegExp myProjRegExp( "\\+proj=(\\S+)" );
int myStart = myProjRegExp.indexIn( myProj4String );
if ( myStart == -1 )
Expand Down
8 changes: 8 additions & 0 deletions src/core/qgscoordinatereferencesystem.h
Expand Up @@ -451,13 +451,21 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
* - if none of the above match, use the Proj string to create the CRS and do not associated an internal CRS ID to it.
*
* \param projString A Proj format string
* \param identify if FALSE, no attempts will be made to match the proj string against known CRS authorities. This is much
* faster, but should only ever be used when it is known in advance that the definition does not correspond to a known or user CRS. This
* argument is not available in Python.
*
* \returns TRUE on success else FALSE
* \note Some members may be left blank if no match can be found in CRS database.
* \note This method uses an internal cache. Call invalidateCache() to clear the cache.
* \see fromProj()
* \since QGIS 3.10.3
*/
#ifndef SIP_RUN
bool createFromProj( const QString &projString, bool identify = true );
#else
bool createFromProj( const QString &projString );
#endif

/**
* Set up this CRS from a string definition.
Expand Down

0 comments on commit 0acb7fc

Please sign in to comment.