From 339d061693bac54cfa62659efa9d9642edfca96c Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 5 Jul 2016 13:35:01 +1000 Subject: [PATCH] Use QgsCRSCache instead of looking up CRS by srs id (refs #15193) --- python/core/qgscoordinatereferencesystem.sip | 1 + python/core/qgscrscache.sip | 8 ++++++++ src/core/qgscoordinatereferencesystem.h | 1 + src/core/qgscoordinatetransform.cpp | 2 +- src/core/qgscrscache.cpp | 20 +++++++++++++++++++- src/core/qgscrscache.h | 9 +++++++++ src/core/qgsdistancearea.cpp | 3 +-- src/gui/qgsprojectionselectionwidget.cpp | 9 +++------ tests/src/python/test_qgscrscache.py | 18 ++++++++++++++++++ 9 files changed, 61 insertions(+), 10 deletions(-) diff --git a/python/core/qgscoordinatereferencesystem.sip b/python/core/qgscoordinatereferencesystem.sip index a070eae3d96..e5b1ce46f13 100644 --- a/python/core/qgscoordinatereferencesystem.sip +++ b/python/core/qgscoordinatereferencesystem.sip @@ -77,6 +77,7 @@ class QgsCoordinateReferenceSystem * @note Any members will be overwritten during this process. * @param theSrsId The QGIS SrsId for the desired spatial reference system. * @return bool TRUE if success else false + * @note this method is expensive. Consider using QgsCRSCache::crsBySrsId() instead. */ bool createFromSrsId( const long theSrsId ); diff --git a/python/core/qgscrscache.sip b/python/core/qgscrscache.sip index 34065d656ed..b2c1b50292c 100644 --- a/python/core/qgscrscache.sip +++ b/python/core/qgscrscache.sip @@ -71,6 +71,14 @@ class QgsCRSCache */ QgsCoordinateReferenceSystem crsByProj4( const QString& proj4 ) const; + /** Returns the CRS from a specified QGIS SRS ID. + * @param srsId internal QGIS SRS ID + * @returns matching CRS, or an invalid CRS if ID could not be found + * @note added in QGIS 2.16 + * @see QgsCoordinateReferenceSystem::createFromSrsId() + */ + QgsCoordinateReferenceSystem crsBySrsId( long srsId ) const; + /** Updates the cached definition of a CRS. Should be called if the definition of a user-created * CRS has been changed. * @param authid CRS auth ID, eg "EPSG:4326" or "USER:100009" diff --git a/src/core/qgscoordinatereferencesystem.h b/src/core/qgscoordinatereferencesystem.h index 02097f831d3..697e7548bae 100644 --- a/src/core/qgscoordinatereferencesystem.h +++ b/src/core/qgscoordinatereferencesystem.h @@ -124,6 +124,7 @@ class CORE_EXPORT QgsCoordinateReferenceSystem * @note Any members will be overwritten during this process. * @param theSrsId The QGIS SrsId for the desired spatial reference system. * @return bool TRUE if success else false + * @note this method is expensive. Consider using QgsCRSCache::crsBySrsId() instead. */ bool createFromSrsId( const long theSrsId ); diff --git a/src/core/qgscoordinatetransform.cpp b/src/core/qgscoordinatetransform.cpp index f91530dc26e..110fa9e9f9e 100644 --- a/src/core/qgscoordinatetransform.cpp +++ b/src/core/qgscoordinatetransform.cpp @@ -152,7 +152,7 @@ void QgsCoordinateTransform::setDestCRS( const QgsCoordinateReferenceSystem& the void QgsCoordinateTransform::setDestCRSID( long theCRSID ) { //!todo Add some logic here to determine if the srsid is a system or user one - mDestCRS.createFromSrsId( theCRSID ); + mDestCRS = QgsCRSCache::instance()->crsBySrsId( theCRSID ); initialise(); } diff --git a/src/core/qgscrscache.cpp b/src/core/qgscrscache.cpp index 121193a47f0..028201de7ce 100644 --- a/src/core/qgscrscache.cpp +++ b/src/core/qgscrscache.cpp @@ -143,7 +143,7 @@ QgsCoordinateReferenceSystem QgsCRSCache::crsByEpsgId( long epsg ) const QgsCoordinateReferenceSystem QgsCRSCache::crsByProj4( const QString& proj4 ) const { - QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = mCRSProj4.find( proj4 ); + QHash< QString, QgsCoordinateReferenceSystem >::const_iterator crsIt = mCRSProj4.constFind( proj4 ); if ( crsIt == mCRSProj4.constEnd() ) { QgsCoordinateReferenceSystem s; @@ -158,3 +158,21 @@ QgsCoordinateReferenceSystem QgsCRSCache::crsByProj4( const QString& proj4 ) con return crsIt.value(); } } + +QgsCoordinateReferenceSystem QgsCRSCache::crsBySrsId( long srsId ) const +{ + QHash< long, QgsCoordinateReferenceSystem >::const_iterator crsIt = mCRSSrsId.constFind( srsId ); + if ( crsIt == mCRSSrsId.constEnd() ) + { + QgsCoordinateReferenceSystem s; + if ( ! s.createFromSrsId( srsId ) ) + { + return mCRSSrsId.insert( srsId, mInvalidCRS ).value(); + } + return mCRSSrsId.insert( srsId, s ).value(); + } + else + { + return crsIt.value(); + } +} diff --git a/src/core/qgscrscache.h b/src/core/qgscrscache.h index ec1eb025cfe..e3dbd2ea028 100644 --- a/src/core/qgscrscache.h +++ b/src/core/qgscrscache.h @@ -97,6 +97,14 @@ class CORE_EXPORT QgsCRSCache */ QgsCoordinateReferenceSystem crsByProj4( const QString& proj4 ) const; + /** Returns the CRS from a specified QGIS SRS ID. + * @param srsId internal QGIS SRS ID + * @returns matching CRS, or an invalid CRS if ID could not be found + * @note added in QGIS 2.16 + * @see QgsCoordinateReferenceSystem::createFromSrsId() + */ + QgsCoordinateReferenceSystem crsBySrsId( long srsId ) const; + /** Updates the cached definition of a CRS. Should be called if the definition of a user-created * CRS has been changed. * @param authid CRS auth ID, eg "EPSG:4326" or "USER:100009" @@ -110,6 +118,7 @@ class CORE_EXPORT QgsCRSCache mutable QHash< QString, QgsCoordinateReferenceSystem > mCRS; mutable QHash< QString, QgsCoordinateReferenceSystem > mCRSProj4; + mutable QHash< long, QgsCoordinateReferenceSystem > mCRSSrsId; /** CRS that is not initialized (returned in case of error)*/ QgsCoordinateReferenceSystem mInvalidCRS; diff --git a/src/core/qgsdistancearea.cpp b/src/core/qgsdistancearea.cpp index 340b004e760..e8c858a3169 100644 --- a/src/core/qgsdistancearea.cpp +++ b/src/core/qgsdistancearea.cpp @@ -106,8 +106,7 @@ bool QgsDistanceArea::willUseEllipsoid() const void QgsDistanceArea::setSourceCrs( long srsid ) { - QgsCoordinateReferenceSystem srcCRS; - srcCRS.createFromSrsId( srsid ); + QgsCoordinateReferenceSystem srcCRS = QgsCRSCache::instance()->crsBySrsId( srsid ); mCoordTransform->setSourceCrs( srcCRS ); } diff --git a/src/gui/qgsprojectionselectionwidget.cpp b/src/gui/qgsprojectionselectionwidget.cpp index 91ded03f8ca..335501554de 100644 --- a/src/gui/qgsprojectionselectionwidget.cpp +++ b/src/gui/qgsprojectionselectionwidget.cpp @@ -87,8 +87,7 @@ QgsCoordinateReferenceSystem QgsProjectionSelectionWidget::crs() const case QgsProjectionSelectionWidget::RecentCrs: { long srsid = mCrsComboBox->itemData( mCrsComboBox->currentIndex(), Qt::UserRole + 1 ).toLongLong(); - QgsCoordinateReferenceSystem crs; - crs.createFromSrsId( srsid ); + QgsCoordinateReferenceSystem crs = QgsCRSCache::instance()->crsBySrsId( srsid ); return crs; } } @@ -174,8 +173,7 @@ void QgsProjectionSelectionWidget::comboIndexChanged( int idx ) case QgsProjectionSelectionWidget::RecentCrs: { long srsid = mCrsComboBox->itemData( idx, Qt::UserRole + 1 ).toLongLong(); - QgsCoordinateReferenceSystem crs; - crs.createFromSrsId( srsid ); + QgsCoordinateReferenceSystem crs = QgsCRSCache::instance()->crsBySrsId( srsid ); emit crsChanged( crs ); return; } @@ -252,8 +250,7 @@ void QgsProjectionSelectionWidget::addRecentCrs() } i++; - QgsCoordinateReferenceSystem crs; - crs.createFromSrsId( srsid ); + QgsCoordinateReferenceSystem crs = QgsCRSCache::instance()->crsBySrsId( srsid ); if ( crs.isValid() ) { mCrsComboBox->addItem( tr( "%1 - %2" ).arg( crs.authid(), crs.description() ), QgsProjectionSelectionWidget::RecentCrs ); diff --git a/tests/src/python/test_qgscrscache.py b/tests/src/python/test_qgscrscache.py index 10d47bb30c8..f45b9e4c3e3 100644 --- a/tests/src/python/test_qgscrscache.py +++ b/tests/src/python/test_qgscrscache.py @@ -89,5 +89,23 @@ class TestQgsCRSCache(unittest.TestCase): crs = QgsCRSCache.instance().crsByProj4('asdasdasd') self.assertFalse(crs.isValid()) + def testcrsBySrsId(self): + """ test retrieving CRS from cache using srs id """ + + crs = QgsCRSCache.instance().crsBySrsId(3452) + self.assertTrue(crs.isValid()) + self.assertEqual(crs.authid(), 'EPSG:4326') + # a second time, so crs is fetched from cache + crs = QgsCRSCache.instance().crsBySrsId(3452) + self.assertTrue(crs.isValid()) + self.assertEqual(crs.authid(), 'EPSG:4326') + + # invalid + crs = QgsCRSCache.instance().crsBySrsId(-9999) + self.assertFalse(crs.isValid()) + # a second time, so invalid crs is fetched from cache + crs = QgsCRSCache.instance().crsBySrsId(-9999) + self.assertFalse(crs.isValid()) + if __name__ == '__main__': unittest.main()