Skip to content

Commit

Permalink
[api] Add z range filtering option to QgsMapSettings/QgsRenderContext…
Browse files Browse the repository at this point in the history
…/QgsMapCanvas

Allows for map renders to be filtered by a z or elevation range,
such that only parts of the layer which are considered within
this range will be rendered.

Implements qgis/QGIS-Enhancement-Proposals#201

*Requires support for respecting the QgsRenderContext zRange to be added
to the relevant map layer renderers
  • Loading branch information
nyalldawson committed Nov 25, 2020
1 parent 95fa338 commit f6f03cd
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 2 deletions.
18 changes: 18 additions & 0 deletions python/core/auto_generated/qgsmapsettings.sip.in
Expand Up @@ -773,6 +773,24 @@ Returns the list of rendered feature handlers to use while rendering the map set
.. seealso:: :py:func:`addRenderedFeatureHandler`

.. versionadded:: 3.10
%End

QgsDoubleRange zRange() const;
%Docstring
Returns the range of z-values which will be visible in the map.

.. seealso:: :py:func:`setZRange`

.. versionadded:: 3.18
%End

void setZRange( const QgsDoubleRange &range );
%Docstring
Sets the ``range`` of z-values which will be visible in the map.

.. seealso:: :py:func:`zRange`

.. versionadded:: 3.18
%End

protected:
Expand Down
18 changes: 18 additions & 0 deletions python/core/auto_generated/qgsrendercontext.sip.in
Expand Up @@ -864,6 +864,24 @@ rendering using QBrush objects.
.. seealso:: :py:func:`textureOrigin`

.. versionadded:: 3.16
%End

QgsDoubleRange zRange() const;
%Docstring
Returns the range of z-values which should be rendered.

.. seealso:: :py:func:`setZRange`

.. versionadded:: 3.18
%End

void setZRange( const QgsDoubleRange &range );
%Docstring
Sets the ``range`` of z-values which should be rendered.

.. seealso:: :py:func:`zRange`

.. versionadded:: 3.18
%End

};
Expand Down
18 changes: 18 additions & 0 deletions python/gui/auto_generated/qgsmapcanvas.sip.in
Expand Up @@ -971,6 +971,24 @@ Set a list of resolutions (map units per pixel) to which to "snap to" when zoomi
.. seealso:: :py:func:`setZoomResolutions`

.. versionadded:: 3.12
%End

QgsDoubleRange zRange() const;
%Docstring
Returns the range of z-values which will be visible in the map.

.. seealso:: :py:func:`setZRange`

.. versionadded:: 3.18
%End

void setZRange( const QgsDoubleRange &range );
%Docstring
Sets the ``range`` of z-values which will be visible in the map.

.. seealso:: :py:func:`zRange`

.. versionadded:: 3.18
%End

signals:
Expand Down
10 changes: 10 additions & 0 deletions src/core/qgsmapsettings.cpp
Expand Up @@ -747,3 +747,13 @@ QList<QgsRenderedFeatureHandlerInterface *> QgsMapSettings::renderedFeatureHandl
{
return mRenderedFeatureHandlers;
}

QgsDoubleRange QgsMapSettings::zRange() const
{
return mZRange;
}

void QgsMapSettings::setZRange( const QgsDoubleRange &zRange )
{
mZRange = zRange;
}
19 changes: 19 additions & 0 deletions src/core/qgsmapsettings.h
Expand Up @@ -676,6 +676,22 @@ class CORE_EXPORT QgsMapSettings : public QgsTemporalRangeObject
*/
QList< QgsRenderedFeatureHandlerInterface * > renderedFeatureHandlers() const;

/**
* Returns the range of z-values which will be visible in the map.
*
* \see setZRange()
* \since QGIS 3.18
*/
QgsDoubleRange zRange() const;

/**
* Sets the \a range of z-values which will be visible in the map.
*
* \see zRange()
* \since QGIS 3.18
*/
void setZRange( const QgsDoubleRange &range );

protected:

double mDpi;
Expand Down Expand Up @@ -743,6 +759,9 @@ class CORE_EXPORT QgsMapSettings : public QgsTemporalRangeObject
QList< QgsLabelBlockingRegion > mLabelBlockingRegions;
QList< QgsMapClippingRegion > mClippingRegions;
QList< QgsRenderedFeatureHandlerInterface * > mRenderedFeatureHandlers;

QgsDoubleRange mZRange;

};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsMapSettings::Flags )
Expand Down
14 changes: 14 additions & 0 deletions src/core/qgsrendercontext.cpp
Expand Up @@ -70,6 +70,7 @@ QgsRenderContext::QgsRenderContext( const QgsRenderContext &rh )
, mClippingRegions( rh.mClippingRegions )
, mFeatureClipGeometry( rh.mFeatureClipGeometry )
, mTextureOrigin( rh.mTextureOrigin )
, mZRange( rh.mZRange )
#ifdef QGISDEBUG
, mHasTransformContext( rh.mHasTransformContext )
#endif
Expand Down Expand Up @@ -106,6 +107,7 @@ QgsRenderContext &QgsRenderContext::operator=( const QgsRenderContext &rh )
mClippingRegions = rh.mClippingRegions;
mFeatureClipGeometry = rh.mFeatureClipGeometry;
mTextureOrigin = rh.mTextureOrigin;
mZRange = rh.mZRange;
setIsTemporal( rh.isTemporal() );
if ( isTemporal() )
setTemporalRange( rh.temporalRange() );
Expand Down Expand Up @@ -238,6 +240,8 @@ QgsRenderContext QgsRenderContext::fromMapSettings( const QgsMapSettings &mapSet
if ( ctx.isTemporal() )
ctx.setTemporalRange( mapSettings.temporalRange() );

ctx.setZRange( mapSettings.zRange() );

ctx.mClippingRegions = mapSettings.clippingRegions();

return ctx;
Expand Down Expand Up @@ -547,4 +551,14 @@ void QgsRenderContext::setTextureOrigin( const QPointF &origin )
mTextureOrigin = origin;
}

QgsDoubleRange QgsRenderContext::zRange() const
{
return mZRange;
}

void QgsRenderContext::setZRange( const QgsDoubleRange &range )
{
mZRange = range;
}


18 changes: 18 additions & 0 deletions src/core/qgsrendercontext.h
Expand Up @@ -856,6 +856,22 @@ class CORE_EXPORT QgsRenderContext : public QgsTemporalRangeObject
*/
void setTextureOrigin( const QPointF &origin );

/**
* Returns the range of z-values which should be rendered.
*
* \see setZRange()
* \since QGIS 3.18
*/
QgsDoubleRange zRange() const;

/**
* Sets the \a range of z-values which should be rendered.
*
* \see zRange()
* \since QGIS 3.18
*/
void setZRange( const QgsDoubleRange &range );

private:

Flags mFlags;
Expand Down Expand Up @@ -952,6 +968,8 @@ class CORE_EXPORT QgsRenderContext : public QgsTemporalRangeObject

QPointF mTextureOrigin;

QgsDoubleRange mZRange;

#ifdef QGISDEBUG
bool mHasTransformContext = false;
#endif
Expand Down
10 changes: 10 additions & 0 deletions src/gui/qgsmapcanvas.cpp
Expand Up @@ -1326,6 +1326,16 @@ void QgsMapCanvas::zoomToSelected( QgsVectorLayer *layer )
zoomToFeatureExtent( rect );
}

QgsDoubleRange QgsMapCanvas::zRange() const
{
return mSettings.zRange();
}

void QgsMapCanvas::setZRange( const QgsDoubleRange &range )
{
mSettings.setZRange( range );
}

void QgsMapCanvas::zoomToFeatureExtent( QgsRectangle &rect )
{
// no selected features, only one selected point feature
Expand Down
16 changes: 16 additions & 0 deletions src/gui/qgsmapcanvas.h
Expand Up @@ -879,6 +879,22 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
*/
const QList<double> &zoomResolutions() const { return mZoomResolutions; }

/**
* Returns the range of z-values which will be visible in the map.
*
* \see setZRange()
* \since QGIS 3.18
*/
QgsDoubleRange zRange() const;

/**
* Sets the \a range of z-values which will be visible in the map.
*
* \see zRange()
* \since QGIS 3.18
*/
void setZRange( const QgsDoubleRange &range );

private slots:
//! called when current maptool is destroyed
void mapToolDestroyed();
Expand Down
4 changes: 4 additions & 0 deletions tests/src/core/testqgsmapsettings.cpp
Expand Up @@ -117,6 +117,10 @@ void TestQgsMapSettings::testGettersSetters()
simplify.setSimplifyHints( QgsVectorSimplifyMethod::GeometrySimplification );
ms.setSimplifyMethod( simplify );
QCOMPARE( ms.simplifyMethod().simplifyHints(), QgsVectorSimplifyMethod::GeometrySimplification );

QVERIFY( ms.zRange().isInfinite() );
ms.setZRange( QgsDoubleRange( 1, 10 ) );
QCOMPARE( ms.zRange(), QgsDoubleRange( 1, 10 ) );
}

void TestQgsMapSettings::testLabelingEngineSettings()
Expand Down
2 changes: 1 addition & 1 deletion tests/src/python/test_python_repr.py
Expand Up @@ -316,7 +316,7 @@ def testDoubleRange(self):
self.assertEqual(QgsDoubleRange(1, 10, False).__repr__(),
"<QgsDoubleRange: (1, 10]>")
self.assertEqual(QgsDoubleRange(1, 10, True, False).__repr__(),
"<QgsDoubleRange: [1, 10)>")
"<QgsDoubleRange: [1, 10)>")

def testIntRange(self):
self.assertEqual(QgsIntRange(1, 10).__repr__(), "<QgsIntRange: [1, 10]>")
Expand Down
13 changes: 12 additions & 1 deletion tests/src/python/test_qgsrendercontext.py
Expand Up @@ -25,7 +25,8 @@
QgsRenderedFeatureHandlerInterface,
QgsDateTimeRange,
QgsMapClippingRegion,
QgsGeometry)
QgsGeometry,
QgsDoubleRange)
from qgis.PyQt.QtCore import QSize, QDateTime
from qgis.PyQt.QtGui import QPainter, QImage
from qgis.testing import start_app, unittest
Expand Down Expand Up @@ -58,6 +59,10 @@ def testGettersSetters(self):
c.setMapExtent(QgsRectangle(1, 2, 3, 4))
self.assertEqual(c.mapExtent(), QgsRectangle(1, 2, 3, 4))

self.assertTrue(c.zRange().isInfinite())
c.setZRange(QgsDoubleRange(1, 10))
self.assertEqual(c.zRange(), QgsDoubleRange(1, 10))

def testCopyConstructor(self):
"""
Test the copy constructor
Expand All @@ -66,10 +71,12 @@ def testCopyConstructor(self):

c1.setTextRenderFormat(QgsRenderContext.TextFormatAlwaysText)
c1.setMapExtent(QgsRectangle(1, 2, 3, 4))
c1.setZRange(QgsDoubleRange(1, 10))

c2 = QgsRenderContext(c1)
self.assertEqual(c2.textRenderFormat(), QgsRenderContext.TextFormatAlwaysText)
self.assertEqual(c2.mapExtent(), QgsRectangle(1, 2, 3, 4))
self.assertEqual(c2.zRange(), QgsDoubleRange(1, 10))

c1.setTextRenderFormat(QgsRenderContext.TextFormatAlwaysOutlines)
c2 = QgsRenderContext(c1)
Expand Down Expand Up @@ -129,17 +136,21 @@ def testFromMapSettings(self):
ms.setFlag(QgsMapSettings.Antialiasing, True)
ms.setFlag(QgsMapSettings.LosslessImageRendering, True)
ms.setFlag(QgsMapSettings.Render3DMap, True)
ms.setZRange(QgsDoubleRange(1, 10))

ms.setTextRenderFormat(QgsRenderContext.TextFormatAlwaysText)
rc = QgsRenderContext.fromMapSettings(ms)
self.assertEqual(rc.textRenderFormat(), QgsRenderContext.TextFormatAlwaysText)
self.assertTrue(rc.testFlag(QgsRenderContext.Antialiasing))
self.assertTrue(rc.testFlag(QgsRenderContext.LosslessImageRendering))
self.assertTrue(rc.testFlag(QgsRenderContext.Render3DMap))
self.assertEqual(ms.zRange(), QgsDoubleRange(1, 10))

ms.setTextRenderFormat(QgsRenderContext.TextFormatAlwaysOutlines)
ms.setZRange(QgsDoubleRange())
rc = QgsRenderContext.fromMapSettings(ms)
self.assertEqual(rc.textRenderFormat(), QgsRenderContext.TextFormatAlwaysOutlines)
self.assertTrue(ms.zRange().isInfinite())

self.assertEqual(rc.mapExtent(), QgsRectangle(10000, 20000, 30000, 40000))

Expand Down

0 comments on commit f6f03cd

Please sign in to comment.