Skip to content

Commit

Permalink
Merge pull request #40444 from pblottiere/geographic-extent-store
Browse files Browse the repository at this point in the history
Geographic extent storing
  • Loading branch information
pblottiere committed Mar 10, 2021
2 parents 84b3cb1 + 1970df7 commit 3f5b165
Show file tree
Hide file tree
Showing 15 changed files with 249 additions and 42 deletions.
20 changes: 20 additions & 0 deletions python/core/auto_generated/qgsmaplayer.sip.in
Expand Up @@ -503,6 +503,18 @@ Returns new instance of :py:class:`QgsMapLayerRenderer` that will be used for re
virtual QgsRectangle extent() const;
%Docstring
Returns the extent of the layer.
%End

QgsRectangle wgs84Extent( bool forceRecalculate = false ) const;
%Docstring
Returns the WGS84 extent (EPSG:4326) of the layer according to
ReadFlag.FlagTrustLayerMetadata. If that flag is activated, then the
WGS84 extent read in the qgs project is returned. Otherwise, the actual
WGS84 extent is returned.

:param forceRecalculate: True to return the current WGS84 extent whatever the read flags

.. versionadded:: 3.20
%End

bool isValid() const;
Expand Down Expand Up @@ -1800,6 +1812,14 @@ Add error message
Sets error message
%End

void invalidateWgs84Extent();
%Docstring
Invalidates the WGS84 extent. If FlagTrustLayerMetadata is enabled,
the extent is not invalidated because we want to trust metadata whatever
happens.

.. versionadded:: 3.20
%End



Expand Down
11 changes: 10 additions & 1 deletion python/core/auto_generated/qgsxmlutils.sip.in
Expand Up @@ -50,7 +50,16 @@ Encodes a distance unit to a DOM element.
.. seealso:: :py:func:`readMapUnits`
%End

static QDomElement writeRectangle( const QgsRectangle &rect, QDomDocument &doc );
static QDomElement writeRectangle( const QgsRectangle &rect, QDomDocument &doc, const QString &elementName = QStringLiteral( "extent" ) );
%Docstring
Encodes a rectangle to a DOM element.

:param rect: rectangle to encode
:param doc: DOM document
:param elementName: name of the DOM element

:return: element containing encoded rectangle
%End

static QDomElement writeVariant( const QVariant &value, QDomDocument &doc );
%Docstring
Expand Down
1 change: 1 addition & 0 deletions src/core/annotations/qgsannotationlayer.cpp
Expand Up @@ -120,6 +120,7 @@ QgsRectangle QgsAnnotationLayer::extent() const
void QgsAnnotationLayer::setTransformContext( const QgsCoordinateTransformContext &context )
{
mTransformContext = context;
invalidateWgs84Extent();
}

bool QgsAnnotationLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext &context )
Expand Down
1 change: 1 addition & 0 deletions src/core/mesh/qgsmeshlayer.cpp
Expand Up @@ -539,6 +539,7 @@ void QgsMeshLayer::setTransformContext( const QgsCoordinateTransformContext &tra
{
if ( mDataProvider )
mDataProvider->setTransformContext( transformContext );
invalidateWgs84Extent();
}

QgsMeshDatasetIndex QgsMeshLayer::datasetIndexAtTime( const QgsDateTimeRange &timeRange, int datasetGroupIndex ) const
Expand Down
1 change: 1 addition & 0 deletions src/core/pointcloud/qgspointcloudlayer.cpp
Expand Up @@ -277,6 +277,7 @@ void QgsPointCloudLayer::setTransformContext( const QgsCoordinateTransformContex
{
if ( mDataProvider )
mDataProvider->setTransformContext( transformContext );
invalidateWgs84Extent();
}

void QgsPointCloudLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider,
Expand Down
61 changes: 59 additions & 2 deletions src/core/qgsmaplayer.cpp
Expand Up @@ -56,6 +56,7 @@
#include "qgsvectordataprovider.h"
#include "qgsxmlutils.h"
#include "qgsstringutils.h"
#include "qgsmessagelog.h"
#include "qgsmaplayertemporalproperties.h"
#include "qgsmaplayerelevationproperties.h"

Expand Down Expand Up @@ -392,6 +393,14 @@ bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteCon
setRefreshOnNofifyMessage( layerElement.attribute( QStringLiteral( "refreshOnNotifyMessage" ), QString() ) );
setRefreshOnNotifyEnabled( layerElement.attribute( QStringLiteral( "refreshOnNotifyEnabled" ), QStringLiteral( "0" ) ).toInt() );

// geographic extent is read only if necessary
if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
{
const QDomNode wgs84ExtentNode = layerElement.namedItem( QStringLiteral( "wgs84extent" ) );
if ( !wgs84ExtentNode.isNull() )
mWgs84Extent = QgsXmlUtils::readRectangle( wgs84ExtentNode.toElement() );
}

return ! layerError;
} // bool QgsMapLayer::readLayerXML

Expand All @@ -411,6 +420,7 @@ bool QgsMapLayer::writeLayerXml( QDomElement &layerElement, QDomDocument &docume
if ( !extent().isNull() )
{
layerElement.appendChild( QgsXmlUtils::writeRectangle( mExtent, document ) );
layerElement.appendChild( QgsXmlUtils::writeRectangle( wgs84Extent( true ), document, QStringLiteral( "wgs84extent" ) ) );
}

layerElement.setAttribute( QStringLiteral( "autoRefreshTime" ), QString::number( mRefreshTimer->interval() ) );
Expand Down Expand Up @@ -1899,9 +1909,9 @@ void QgsMapLayer::emitStyleChanged()
emit styleChanged();
}

void QgsMapLayer::setExtent( const QgsRectangle &r )
void QgsMapLayer::setExtent( const QgsRectangle &extent )
{
mExtent = r;
updateExtent( extent );
}

bool QgsMapLayer::isReadOnly() const
Expand Down Expand Up @@ -2001,3 +2011,50 @@ void QgsMapLayer::onNotified( const QString &message )
emit dataChanged();
}
}

QgsRectangle QgsMapLayer::wgs84Extent( bool forceRecalculate ) const
{
QgsRectangle wgs84Extent;

if ( ! forceRecalculate && ! mWgs84Extent.isNull() )
{
wgs84Extent = mWgs84Extent;
}
else if ( ! mExtent.isNull() )
{
const QgsCoordinateTransform transformer { crs(), QgsCoordinateReferenceSystem::fromOgcWmsCrs( geoEpsgCrsAuthId() ), transformContext() };
try
{
wgs84Extent = transformer.transformBoundingBox( mExtent );
}
catch ( const QgsCsException &cse )
{
QgsMessageLog::logMessage( tr( "Error transforming extent: %1" ).arg( cse.what() ) );
wgs84Extent = QgsRectangle();
}
}
return wgs84Extent;
}

void QgsMapLayer::updateExtent( const QgsRectangle &extent ) const
{
if ( extent == mExtent )
return;

mExtent = extent;

// do not update the wgs84 extent if we trust layer metadata
if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
return;

mWgs84Extent = wgs84Extent( true );
}

void QgsMapLayer::invalidateWgs84Extent()
{
// do not update the wgs84 extent if we trust layer metadata
if ( mReadFlags & QgsMapLayer::ReadFlag::FlagTrustLayerMetadata )
return;

mWgs84Extent = QgsRectangle();
}
30 changes: 28 additions & 2 deletions src/core/qgsmaplayer.h
Expand Up @@ -514,6 +514,16 @@ class CORE_EXPORT QgsMapLayer : public QObject
//! Returns the extent of the layer.
virtual QgsRectangle extent() const;

/**
* Returns the WGS84 extent (EPSG:4326) of the layer according to
* ReadFlag::FlagTrustLayerMetadata. If that flag is activated, then the
* WGS84 extent read in the qgs project is returned. Otherwise, the actual
* WGS84 extent is returned.
* \param forceRecalculate True to return the current WGS84 extent whatever the read flags
* \since QGIS 3.20
*/
QgsRectangle wgs84Extent( bool forceRecalculate = false ) const;

/**
* Returns the status of the layer. An invalid layer is one which has a bad datasource
* or other problem. Child classes set this flag when initialized.
Expand Down Expand Up @@ -1602,8 +1612,13 @@ class CORE_EXPORT QgsMapLayer : public QObject
//! Sets error message
void setError( const QgsError &error ) { mError = error;}

//! Extent of the layer
mutable QgsRectangle mExtent;
/**
* Invalidates the WGS84 extent. If FlagTrustLayerMetadata is enabled,
* the extent is not invalidated because we want to trust metadata whatever
* happens.
* \since QGIS 3.20
*/
void invalidateWgs84Extent();

//! Indicates if the layer is valid and can be drawn
bool mValid = false;
Expand Down Expand Up @@ -1685,6 +1700,9 @@ class CORE_EXPORT QgsMapLayer : public QObject
bool &resultFlag, StyleCategories categories = AllStyleCategories );
bool loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type );

// const method because extents are mutable
void updateExtent( const QgsRectangle &extent ) const;

/**
* This method returns TRUE by default but can be overwritten to specify
* that a certain layer is writable.
Expand Down Expand Up @@ -1742,6 +1760,12 @@ class CORE_EXPORT QgsMapLayer : public QObject
//! Renderer for 3D views
QgsAbstract3DRenderer *m3DRenderer = nullptr;

//! Extent of the layer
mutable QgsRectangle mExtent;

//! Extent of the layer in EPSG:4326
mutable QgsRectangle mWgs84Extent;

/**
* Stores the original XML properties of the layer when loaded from the project
*
Expand All @@ -1751,6 +1775,8 @@ class CORE_EXPORT QgsMapLayer : public QObject

//! To avoid firing multiple time repaintRequested signal on circular layer circular dependencies
bool mRepaintRequestedFired = false;

friend class QgsVectorLayer;
};

Q_DECLARE_METATYPE( QgsMapLayer * )
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgspluginlayer.cpp
Expand Up @@ -40,7 +40,7 @@ QString QgsPluginLayer::pluginLayerType()

void QgsPluginLayer::setExtent( const QgsRectangle &extent )
{
mExtent = extent;
QgsMapLayer::setExtent( extent );
static_cast<QgsPluginLayerDataProvider *>( mDataProvider )->setExtent( extent );
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/qgsxmlutils.cpp
Expand Up @@ -78,7 +78,7 @@ QDomElement QgsXmlUtils::writeMapUnits( QgsUnitTypes::DistanceUnit units, QDomDo
return unitsNode;
}

QDomElement QgsXmlUtils::writeRectangle( const QgsRectangle &rect, QDomDocument &doc )
QDomElement QgsXmlUtils::writeRectangle( const QgsRectangle &rect, QDomDocument &doc, const QString &elementName )
{
QDomElement xMin = doc.createElement( QStringLiteral( "xmin" ) );
QDomElement yMin = doc.createElement( QStringLiteral( "ymin" ) );
Expand All @@ -95,7 +95,7 @@ QDomElement QgsXmlUtils::writeRectangle( const QgsRectangle &rect, QDomDocument
xMax.appendChild( xMaxText );
yMax.appendChild( yMaxText );

QDomElement extentNode = doc.createElement( QStringLiteral( "extent" ) );
QDomElement extentNode = doc.createElement( elementName );
extentNode.appendChild( xMin );
extentNode.appendChild( yMin );
extentNode.appendChild( xMax );
Expand Down
9 changes: 8 additions & 1 deletion src/core/qgsxmlutils.h
Expand Up @@ -59,7 +59,14 @@ class CORE_EXPORT QgsXmlUtils
*/
static QDomElement writeMapUnits( QgsUnitTypes::DistanceUnit units, QDomDocument &doc );

static QDomElement writeRectangle( const QgsRectangle &rect, QDomDocument &doc );
/**
* Encodes a rectangle to a DOM element.
* \param rect rectangle to encode
* \param doc DOM document
* \param elementName name of the DOM element
* \returns element containing encoded rectangle
*/
static QDomElement writeRectangle( const QgsRectangle &rect, QDomDocument &doc, const QString &elementName = QStringLiteral( "extent" ) );

/**
* Write a QVariant to a QDomElement.
Expand Down
1 change: 1 addition & 0 deletions src/core/raster/qgsrasterlayer.cpp
Expand Up @@ -1759,6 +1759,7 @@ void QgsRasterLayer::setTransformContext( const QgsCoordinateTransformContext &t
{
if ( mDataProvider )
mDataProvider->setTransformContext( transformContext );
invalidateWgs84Extent();
}

QStringList QgsRasterLayer::subLayers() const
Expand Down
21 changes: 9 additions & 12 deletions src/core/vector/qgsvectorlayer.cpp
Expand Up @@ -848,23 +848,20 @@ QgsRectangle QgsVectorLayer::extent() const

if ( !mValidExtent && mLazyExtent && mDataProvider && !mDataProvider->hasMetadata() && mReadExtentFromXml && !mXmlExtent.isNull() )
{
mExtent = mXmlExtent;
updateExtent( mXmlExtent );
mValidExtent = true;
mLazyExtent = false;
}

if ( !mValidExtent && mLazyExtent && mDataProvider && mDataProvider->isValid() )
{
// get the extent
QgsRectangle mbr = mDataProvider->extent();

// show the extent
QgsDebugMsgLevel( QStringLiteral( "Extent of layer: %1" ).arg( mbr.toString() ), 3 );
// store the extent
updateExtent( mDataProvider->extent() );
mValidExtent = true;
mExtent = mbr;

mLazyExtent = false;

// show the extent
QgsDebugMsgLevel( QStringLiteral( "Extent of layer: %1" ).arg( mExtent.toString() ), 3 );
}

if ( mValidExtent )
Expand All @@ -886,7 +883,7 @@ QgsRectangle QgsVectorLayer::extent() const
// but only when there are some features already
if ( mDataProvider->featureCount() != 0 )
{
QgsRectangle r = mDataProvider->extent();
const QgsRectangle r = mDataProvider->extent();
rect.combineExtentWith( r );
}

Expand All @@ -897,7 +894,7 @@ QgsRectangle QgsVectorLayer::extent() const
{
if ( it->hasGeometry() )
{
QgsRectangle r = it->geometry().boundingBox();
const QgsRectangle r = it->geometry().boundingBox();
rect.combineExtentWith( r );
}
}
Expand All @@ -913,7 +910,7 @@ QgsRectangle QgsVectorLayer::extent() const
{
if ( fet.hasGeometry() && fet.geometry().type() != QgsWkbTypes::UnknownGeometry )
{
QgsRectangle bb = fet.geometry().boundingBox();
const QgsRectangle bb = fet.geometry().boundingBox();
rect.combineExtentWith( bb );
}
}
Expand All @@ -925,8 +922,8 @@ QgsRectangle QgsVectorLayer::extent() const
rect = QgsRectangle(); // use rectangle with zero coordinates
}

updateExtent( rect );
mValidExtent = true;
mExtent = rect;

// Send this (hopefully) up the chain to the map canvas
emit recalculateExtents();
Expand Down
1 change: 1 addition & 0 deletions src/core/vectortile/qgsvectortilelayer.cpp
Expand Up @@ -344,6 +344,7 @@ bool QgsVectorTileLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QStr
void QgsVectorTileLayer::setTransformContext( const QgsCoordinateTransformContext &transformContext )
{
Q_UNUSED( transformContext )
invalidateWgs84Extent();
}

QString QgsVectorTileLayer::loadDefaultStyle( bool &resultFlag )
Expand Down

0 comments on commit 3f5b165

Please sign in to comment.