Skip to content

Commit

Permalink
Merge pull request #3331 from nyalldawson/crs
Browse files Browse the repository at this point in the history
QgsCoordinateReferenceSystem - API fixes + internal caching
  • Loading branch information
nyalldawson committed Jul 25, 2016
2 parents 2b8b979 + 6dac8e1 commit bc2c2b2
Show file tree
Hide file tree
Showing 87 changed files with 795 additions and 768 deletions.
8 changes: 8 additions & 0 deletions doc/api_break.dox
Expand Up @@ -24,6 +24,9 @@ This page tries to maintain a list with incompatible changes that happened in pr
<li>QgsLabel and QgsLabelAttributes. Replaced by labeling based on PAL library, see QgsLabelingEngineV2.</li>
<li>QgsMapCanvasMap. It is an internal class used by map canvas.</li>
<li>QgsMapRenderer. It has been replaced by QgsMapRendererJob with subclasses and QgsMapSettings.</li>
<li>QgsCRSCache was removed. QgsCoordinateReferenceSystem now internally uses a cache for CRS creation,
so there is no longer a need for the separate cache class. Code which previously called QgsCRSCache::updateCRSCache()
should now call QgsCoordinateReferenceSystem::invalidateCache() and QgsCoordinateTransformCache::instance()->invalidateCrs( authid ).</li>
</ul>

\subsection qgis_api_break_3_0_global General changes
Expand Down Expand Up @@ -103,9 +106,14 @@ qgsPermissiveToInt()</li>
\subsection qgis_api_break_3_0_QgsCoordinateReferenceSystem QgsCoordinateReferenceSystem

<ul>
<li>QgsCoordinateReferenceSystem now uses internal caches to avoid expensive database lookups
when CRS objects are initialized. This is handled internally, but invalidateCache() must be
called if changes are made to the CRS database.</li>
<li>setCustomSrsValidation() has been renamed to setCustomCrsValidation()</li>
<li>saveAsUserCRS() has been renamed to saveAsUserCrs()</li>
<li>geographicCRSAuthId() has been renamed to geographicCrsAuthId()</li>
<li>geographicFlag() was renamed to isGeographic()</li>
<li>axisInverted() was renamed to hasAxisInverted()</li>
</ul>

\subsection qgis_api_break_3_0_QgsCoordinateTransform QgsCoordinateTransform
Expand Down
76 changes: 58 additions & 18 deletions python/core/qgscoordinatereferencesystem.sip
Expand Up @@ -119,19 +119,12 @@
* constructor that automatically recognizes definition format from the given string.
*
* Creation of CRS object involves some queries in a local SQLite database, which may
* be potentially expensive. It is therefore recommended to use QgsCRSCache methods
* that return possibly cached CRS objects instead of constructing new instances that
* involve the lookup overhead.
* be potentially expensive. Consequently, CRS creation methods use an internal cache to avoid
* unnecessary database lookups. If the CRS database is modified, then it is necessary to call
* invalidateCache() to ensure that outdated records are not being returned from the cache.
*
* Since QGIS 2.16 QgsCoordinateReferenceSystem objects are implicitly shared.
*
* The following table summarizes equivalents for non-cached and cached CRS lookup:
*
* Definition | Non-cached | Cached
* ----------- | --------------------- | ------------------------------
* Auth + Code | createFromOgcWmsCrs() | QgsCRSCache::crsByOgcWmsCrs()
* PROJ.4 | createFromProj4() | QgsCRSCache::crsByProj4()
* WKT | createFromWkt() | QgsCRSCache::crsByWkt()
*
* Caveats
* =======
Expand All @@ -140,7 +133,7 @@
* used by ESRI. They look very similar, but they are not the same. QGIS is able to consume
* both flavours.
*
* \see QgsCoordinateTransform, QgsCRSCache
* \see QgsCoordinateTransform
*/
class QgsCoordinateReferenceSystem
{
Expand Down Expand Up @@ -190,6 +183,47 @@ class QgsCoordinateReferenceSystem
// TODO QGIS 3: remove theType and always use EPSG code
QgsCoordinateReferenceSystem( const long theId, CrsType theType = PostgisCrsId );

// static creators

/** Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
* @param ogcCrs OGR compliant CRS definition, eg "EPSG:4326"
* @returns matching CRS, or an invalid CRS if string could not be matched
* @note added in QGIS 3.0
* @see createFromOgcWmsCrs()
*/
static QgsCoordinateReferenceSystem fromOgcWmsCrs( const QString& ogcCrs );

/** Creates a CRS from a given EPSG ID.
* @param epsg epsg CRS ID
* @returns matching CRS, or an invalid CRS if string could not be matched
* @note added in QGIS 3.0
*/
static QgsCoordinateReferenceSystem fromEpsgId( long epsg );

/** Creates a CRS from a proj4 style formatted string.
* @param proj4 proj4 format string
* @returns matching CRS, or an invalid CRS if string could not be matched
* @note added in QGIS 3.0
* @see createFromProj4()
*/
static QgsCoordinateReferenceSystem fromProj4( const QString& proj4 );

/** Creates a CRS from a WKT spatial ref sys definition string.
* @param wkt WKT for the desired spatial reference system.
* @returns matching CRS, or an invalid CRS if string could not be matched
* @note added in QGIS 3.0
* @see createFromWkt()
*/
static QgsCoordinateReferenceSystem fromWkt( const QString& wkt );

/** Creates a 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 3.0
* @see createFromSrsId()
*/
static QgsCoordinateReferenceSystem fromSrsId( long srsId );

// Misc helper functions -----------------------

/**
Expand All @@ -207,7 +241,7 @@ class QgsCoordinateReferenceSystem
* Accepts both "<auth>:<code>" format and OGC URN "urn:ogc:def:crs:<auth>:[<version>]:<code>".
* It also recognizes "QGIS", "USER", "CUSTOM" authorities, which all have the same meaning
* and refer to QGIS internal CRS IDs.
* @note this method is expensive. Consider using QgsCRSCache::crsByOgcWmsCrs() instead.
* @note this method uses an internal cache. Call invalidateCache() to clear the cache.
* @return True on success else false
*/
// TODO QGIS 3: remove "QGIS" and "CUSTOM", only support "USER" (also returned by authid())
Expand All @@ -227,7 +261,7 @@ class QgsCoordinateReferenceSystem
* Otherwise the WKT will be converted to a proj4 string and createFromProj4()
* set up the object.
* @note Some members may be left blank if no match can be found in CRS database.
* @note this method is expensive. Consider using QgsCRSCache::crsByWkt() instead.
* @note this method uses an internal cache. Call invalidateCache() to clear the cache.
* @param theWkt The WKT for the desired spatial reference system.
* @return True on success else false
*/
Expand All @@ -237,7 +271,7 @@ class QgsCoordinateReferenceSystem
*
* If the srsid is < USER_CRS_START_ID, system CRS database is used, otherwise
* user's local CRS database from home directory is used.
* @note this method is expensive. Consider using QgsCRSCache::crsBySrsId() instead.
* @note this method uses an internal cache. Call invalidateCache() to clear the cache.
* @param theSrsId The internal QGIS CRS ID for the desired spatial reference system.
* @return True on success else false
*/
Expand All @@ -260,7 +294,7 @@ class QgsCoordinateReferenceSystem
* - if none of the above match, use findMatchingProj()
*
* @note Some members may be left blank if no match can be found in CRS database.
* @note this method is expensive. Consider using QgsCRSCache::crsByProj4() instead.
* @note this method uses an internal cache. Call invalidateCache() to clear the cache.
* @param theProjString A proj4 format string
* @return True on success else false
*/
Expand Down Expand Up @@ -436,13 +470,12 @@ class QgsCoordinateReferenceSystem
/** Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
* @returns true if CRS is geographic, or false if it is a projected CRS
*/
//TODO QGIS 3.0 - rename to isGeographic
bool geographicFlag() const;
bool isGeographic() const;

/** Returns whether axis is inverted (eg. for WMS 1.3) for the CRS.
* @returns true if CRS axis is inverted
*/
bool axisInverted() const;
bool hasAxisInverted() const;

/** Returns the units for the projection used by the CRS.
*/
Expand Down Expand Up @@ -479,4 +512,11 @@ class QgsCoordinateReferenceSystem
* @note added in QGIS 2.7
*/
static QStringList recentProjections();

/** Clears the internal cache used to initialise QgsCoordinateReferenceSystem objects.
* This should be called whenever the srs database has been modified in order to ensure
* that outdated CRS objects are not created.
* @note added in QGIS 3.0
*/
static void invalidateCache();
};
78 changes: 0 additions & 78 deletions python/core/qgscrscache.sip
Expand Up @@ -25,81 +25,3 @@ class QgsCoordinateTransformCache
QgsCoordinateTransformCache( const QgsCoordinateTransformCache& rh );
};

/** \ingroup core
* \class QgsCrsCache
* \brief Caches QgsCoordinateReferenceSystem construction, which may be expensive.
*
* QgsCRSCache maintains a cache of previously constructed coordinate systems, so that
* creating a new CRS from the cache can reuse previously calculated parameters. The
* constructors for QgsCoordinateReferenceSystem can be expensive, so it's recommended
* to use QgsCRSCache instead of directly calling the QgsCoordinateReferenceSystem
* constructors.
*/

class QgsCrsCache
{
%TypeHeaderCode
#include <qgscrscache.h>
%End

public:

//! Returns a pointer to the QgsCRSCache singleton
static QgsCrsCache* instance();

/** Returns the CRS for authid, e.g. 'EPSG:4326' (or an invalid CRS in case of error)
* @deprecated use crsByOgcWmsCrs() instead
*/
QgsCoordinateReferenceSystem crsByAuthId( const QString& authid ) /Deprecated/;

/** Returns the CRS from a given OGC WMS-format Coordinate Reference System string.
* @param ogcCrs OGR compliant CRS definition, eg "EPSG:4326"
* @returns matching CRS, or an invalid CRS if string could not be matched
* @note added in QGIS 2.16
* @see QgsCoordinateReferenceSystem::createFromOgcWmsCrs()
*/
QgsCoordinateReferenceSystem crsByOgcWmsCrs( const QString& ogcCrs ) const;

/** Returns the CRS from a given EPSG ID.
* @param epsg epsg CRS ID
* @returns matching CRS, or an invalid CRS if string could not be matched
*/
QgsCoordinateReferenceSystem crsByEpsgId( long epsg ) const;

/** Returns the CRS from a proj4 style formatted string.
* @param proj4 proj4 format string
* @returns matching CRS, or an invalid CRS if string could not be matched
* @note added in QGIS 2.16
* @see QgsCoordinateReferenceSystem::createFromProj4()
*/
QgsCoordinateReferenceSystem crsByProj4( const QString& proj4 ) const;

/** Returns the CRS from a WKT spatial ref sys definition string.
* @param wkt WKT for the desired spatial reference system.
* @returns matching CRS, or an invalid CRS if string could not be matched
* @note added in QGIS 2.16
* @see QgsCoordinateReferenceSystem::createFromWkt()
*/
QgsCoordinateReferenceSystem crsByWkt( const QString& wkt ) 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"
*/
void updateCrsCache( const QString& authid );

protected:
QgsCrsCache();

private:

QgsCrsCache( const QgsCrsCache& other );
};
3 changes: 1 addition & 2 deletions src/app/gps/qgsgpsinformationwidget.cpp
Expand Up @@ -35,7 +35,6 @@
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "qgswkbptr.h"
#include "qgscrscache.h"

// QWT Charting widget

Expand Down Expand Up @@ -229,7 +228,7 @@ QgsGPSInformationWidget::QgsGPSInformationWidget( QgsMapCanvas * thepCanvas, QWi
radRecenterWhenNeeded->setChecked( true );
}

mWgs84CRS = QgsCrsCache::instance()->crsByOgcWmsCrs( "EPSG:4326" );
mWgs84CRS = QgsCoordinateReferenceSystem::fromOgcWmsCrs( "EPSG:4326" );

mBtnDebug->setVisible( mySettings.value( "/gps/showDebug", "false" ).toBool() ); // use a registry setting to control - power users/devs could set it

Expand Down
3 changes: 1 addition & 2 deletions src/app/gps/qgsgpsmarker.cpp
Expand Up @@ -18,14 +18,13 @@
#include "qgsgpsmarker.h"
#include "qgscoordinatetransform.h"
#include "qgsmapcanvas.h"
#include "qgscrscache.h"
#include "qgscsexception.h"

QgsGpsMarker::QgsGpsMarker( QgsMapCanvas* mapCanvas )
: QgsMapCanvasItem( mapCanvas )
{
mSize = 16;
mWgs84CRS = QgsCrsCache::instance()->crsByOgcWmsCrs( "EPSG:4326" );
mWgs84CRS = QgsCoordinateReferenceSystem::fromOgcWmsCrs( "EPSG:4326" );
mSvg.load( QString( ":/images/north_arrows/gpsarrow2.svg" ) );
if ( ! mSvg.isValid() )
{
Expand Down
3 changes: 1 addition & 2 deletions src/app/ogr/qgsvectorlayersaveasdialog.cpp
Expand Up @@ -16,7 +16,6 @@
* *
***************************************************************************/
#include "qgslogger.h"
#include "qgscrscache.h"
#include "qgsvectorlayersaveasdialog.h"
#include "qgsgenericprojectionselector.h"
#include "qgsvectordataprovider.h"
Expand Down Expand Up @@ -102,7 +101,7 @@ void QgsVectorLayerSaveAsDialog::setup()
idx = 0;
}

QgsCoordinateReferenceSystem srs = QgsCrsCache::instance()->crsBySrsId( mCRS );
QgsCoordinateReferenceSystem srs = QgsCoordinateReferenceSystem::fromSrsId( mCRS );
mCrsSelector->setCrs( srs );
mCrsSelector->setLayerCrs( srs );
mCrsSelector->dialog()->setMessage( tr( "Select the coordinate reference system for the vector file. "
Expand Down
5 changes: 2 additions & 3 deletions src/app/openstreetmap/qgsosmdownloaddialog.cpp
Expand Up @@ -21,7 +21,6 @@

#include "qgis.h"
#include "qgisapp.h"
#include "qgscrscache.h"
#include "qgsmapcanvas.h"
#include "qgsmaplayer.h"
#include "qgsmaplayerregistry.h"
Expand Down Expand Up @@ -104,7 +103,7 @@ void QgsOSMDownloadDialog::onExtentCanvas()

if ( QgisApp::instance()->mapCanvas()->hasCrsTransformEnabled() )
{
QgsCoordinateReferenceSystem dst = QgsCrsCache::instance()->crsBySrsId( GEOCRS_ID );
QgsCoordinateReferenceSystem dst = QgsCoordinateReferenceSystem::fromSrsId( GEOCRS_ID );

QgsCoordinateTransform ct( QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs(), dst );
r = ct.transformBoundingBox( r );
Expand Down Expand Up @@ -143,7 +142,7 @@ void QgsOSMDownloadDialog::onCurrentLayerChanged( int index )
if ( !layer )
return;

QgsCoordinateReferenceSystem dst = QgsCrsCache::instance()->crsBySrsId( GEOCRS_ID );
QgsCoordinateReferenceSystem dst = QgsCoordinateReferenceSystem::fromSrsId( GEOCRS_ID );

QgsCoordinateTransform ct( layer->crs(), dst );
QgsRectangle rect( ct.transformBoundingBox( layer->extent() ) );
Expand Down
11 changes: 5 additions & 6 deletions src/app/qgisapp.cpp
Expand Up @@ -127,7 +127,6 @@
#include "qgscoordinatetransform.h"
#include "qgscoordinateutils.h"
#include "qgscredentialdialog.h"
#include "qgscrscache.h"
#include "qgscursors.h"
#include "qgscustomization.h"
#include "qgscustomlayerorderwidget.h"
Expand Down Expand Up @@ -513,7 +512,7 @@ void QgisApp::validateCrs( QgsCoordinateReferenceSystem &srs )
if ( authid.isNull() )
authid = QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs().authid();

QgsCoordinateReferenceSystem defaultCrs = QgsCrsCache::instance()->crsByOgcWmsCrs( authid );
QgsCoordinateReferenceSystem defaultCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( authid );
if ( defaultCrs.isValid() )
{
mySelector->setSelectedCrsId( defaultCrs.srsid() );
Expand Down Expand Up @@ -4413,7 +4412,7 @@ void QgisApp::fileNew( bool thePromptToSaveFlag, bool forceBlank )

// set project CRS
QString defCrs = settings.value( "/Projections/projectDefaultCrs", GEO_EPSG_CRS_AUTHID ).toString();
QgsCoordinateReferenceSystem srs = QgsCrsCache::instance()->crsByOgcWmsCrs( defCrs );
QgsCoordinateReferenceSystem srs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( defCrs );
mMapCanvas->setDestinationCrs( srs );
// write the projections _proj string_ to project settings
prj->writeEntry( "SpatialRefSys", "/ProjectCRSProj4String", srs.toProj4() );
Expand Down Expand Up @@ -6171,7 +6170,7 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer* vlayer, bool symbologyOpt
QgsWKBTypes::Type forcedGeometryType = dialog->geometryType();

QgsCoordinateTransform ct;
destCRS = QgsCrsCache::instance()->crsBySrsId( dialog->crs() );
destCRS = QgsCoordinateReferenceSystem::fromSrsId( dialog->crs() );

if ( destCRS.isValid() && destCRS != vlayer->crs() )
{
Expand Down Expand Up @@ -8469,7 +8468,7 @@ void QgisApp::setLayerCrs()
return;
}

QgsCoordinateReferenceSystem crs = QgsCrsCache::instance()->crsBySrsId( mySelector.selectedCrsId() );
QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromSrsId( mySelector.selectedCrsId() );

Q_FOREACH ( QgsLayerTreeNode* node, mLayerTreeView->selectedNodes() )
{
Expand Down Expand Up @@ -8626,7 +8625,7 @@ void QgisApp::legendGroupSetCrs()
return;
}

QgsCoordinateReferenceSystem crs = QgsCrsCache::instance()->crsBySrsId( mySelector.selectedCrsId() );
QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromSrsId( mySelector.selectedCrsId() );
Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, currentGroup->findLayers() )
{
if ( nodeLayer->layer() )
Expand Down
3 changes: 1 addition & 2 deletions src/app/qgsbookmarks.cpp
Expand Up @@ -21,7 +21,6 @@
#include "qgsmapcanvas.h"
#include "qgsproject.h"
#include "qgsmessagelog.h"
#include "qgscrscache.h"

#include "qgslogger.h"

Expand Down Expand Up @@ -232,7 +231,7 @@ void QgsBookmarks::zoomToBookmark()
if ( srid > 0 &&
srid != QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs().srsid() )
{
QgsCoordinateTransform ct( QgsCrsCache::instance()->crsBySrsId( srid ),
QgsCoordinateTransform ct( QgsCoordinateReferenceSystem::fromSrsId( srid ),
QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs() );
rect = ct.transform( rect );
if ( rect.isEmpty() )
Expand Down

0 comments on commit bc2c2b2

Please sign in to comment.