Add clipping regions to QgsMapSettings/QgsRenderContext API

This commit is contained in:
Nyall Dawson 2020-06-30 13:21:46 +10:00
parent 04f51371fc
commit e38bb541a6
8 changed files with 124 additions and 3 deletions

View File

@ -667,6 +667,24 @@ Returns the list of regions to avoid placing labels within.
.. seealso:: :py:func:`labelBoundaryGeometry` .. seealso:: :py:func:`labelBoundaryGeometry`
.. versionadded:: 3.6 .. versionadded:: 3.6
%End
void addClippingRegion( const QgsMapClippingRegion &region );
%Docstring
Adds a new clipping ``region`` to the map settings.
.. seealso:: :py:func:`clippingRegions`
.. versionadded:: 3.16
%End
QList< QgsMapClippingRegion > clippingRegions() const;
%Docstring
Returns the list of clipping regions to apply to the map.
.. seealso:: :py:func:`addClippingRegion`
.. versionadded:: 3.16
%End %End
void setSimplifyMethod( const QgsVectorSimplifyMethod &method ); void setSimplifyMethod( const QgsVectorSimplifyMethod &method );

View File

@ -12,7 +12,6 @@
class QgsRenderContext : QgsTemporalRangeObject class QgsRenderContext : QgsTemporalRangeObject
{ {
%Docstring %Docstring
@ -27,6 +26,7 @@ to be rendered etc.
%End %End
public: public:
QgsRenderContext(); QgsRenderContext();
~QgsRenderContext();
QgsRenderContext( const QgsRenderContext &rh ); QgsRenderContext( const QgsRenderContext &rh );
@ -787,6 +787,15 @@ Clears the specified custom rendering flag.
.. seealso:: :py:func:`setCustomRenderingFlag` .. seealso:: :py:func:`setCustomRenderingFlag`
.. versionadded:: 3.12 .. versionadded:: 3.12
%End
QList< QgsMapClippingRegion > clippingRegions() const;
%Docstring
Returns the list of clipping regions to apply during the render.
These regions are always in the final destination CRS for the map.
.. versionadded:: 3.16
%End %End
}; };

View File

@ -682,6 +682,16 @@ void QgsMapSettings::setLabelBoundaryGeometry( const QgsGeometry &boundary )
mLabelBoundaryGeometry = boundary; mLabelBoundaryGeometry = boundary;
} }
void QgsMapSettings::addClippingRegion( const QgsMapClippingRegion &region )
{
mClippingRegions.append( region );
}
QList<QgsMapClippingRegion> QgsMapSettings::clippingRegions() const
{
return mClippingRegions;
}
void QgsMapSettings::addRenderedFeatureHandler( QgsRenderedFeatureHandlerInterface *handler ) void QgsMapSettings::addRenderedFeatureHandler( QgsRenderedFeatureHandlerInterface *handler )
{ {
mRenderedFeatureHandlers.append( handler ); mRenderedFeatureHandlers.append( handler );

View File

@ -33,6 +33,7 @@
#include "qgsmaplayer.h" #include "qgsmaplayer.h"
#include "qgsgeometry.h" #include "qgsgeometry.h"
#include "qgstemporalrangeobject.h" #include "qgstemporalrangeobject.h"
#include "qgsmapclippingregion.h"
class QPainter; class QPainter;
@ -578,6 +579,24 @@ class CORE_EXPORT QgsMapSettings : public QgsTemporalRangeObject
*/ */
QList< QgsLabelBlockingRegion > labelBlockingRegions() const { return mLabelBlockingRegions; } QList< QgsLabelBlockingRegion > labelBlockingRegions() const { return mLabelBlockingRegions; }
/**
* Adds a new clipping \a region to the map settings.
*
* \see clippingRegions()
*
* \since QGIS 3.16
*/
void addClippingRegion( const QgsMapClippingRegion &region );
/**
* Returns the list of clipping regions to apply to the map.
*
* \see addClippingRegion()
*
* \since QGIS 3.16
*/
QList< QgsMapClippingRegion > clippingRegions() const;
/** /**
* Sets the simplification setting to use when rendering vector layers. * Sets the simplification setting to use when rendering vector layers.
* *
@ -692,6 +711,7 @@ class CORE_EXPORT QgsMapSettings : public QgsTemporalRangeObject
private: private:
QList< QgsLabelBlockingRegion > mLabelBlockingRegions; QList< QgsLabelBlockingRegion > mLabelBlockingRegions;
QList< QgsMapClippingRegion > mClippingRegions;
QList< QgsRenderedFeatureHandlerInterface * > mRenderedFeatureHandlers; QList< QgsRenderedFeatureHandlerInterface * > mRenderedFeatureHandlers;
}; };

View File

@ -37,6 +37,8 @@ QgsRenderContext::QgsRenderContext()
mDistanceArea.setEllipsoid( mDistanceArea.sourceCrs().ellipsoidAcronym() ); mDistanceArea.setEllipsoid( mDistanceArea.sourceCrs().ellipsoidAcronym() );
} }
QgsRenderContext::~QgsRenderContext() = default;
QgsRenderContext::QgsRenderContext( const QgsRenderContext &rh ) QgsRenderContext::QgsRenderContext( const QgsRenderContext &rh )
: QgsTemporalRangeObject( rh ) : QgsTemporalRangeObject( rh )
, mFlags( rh.mFlags ) , mFlags( rh.mFlags )
@ -65,6 +67,7 @@ QgsRenderContext::QgsRenderContext( const QgsRenderContext &rh )
, mHasRenderedFeatureHandlers( rh.mHasRenderedFeatureHandlers ) , mHasRenderedFeatureHandlers( rh.mHasRenderedFeatureHandlers )
, mCustomRenderingFlags( rh.mCustomRenderingFlags ) , mCustomRenderingFlags( rh.mCustomRenderingFlags )
, mDisabledSymbolLayers() , mDisabledSymbolLayers()
, mClippingRegions( rh.mClippingRegions )
#ifdef QGISDEBUG #ifdef QGISDEBUG
, mHasTransformContext( rh.mHasTransformContext ) , mHasTransformContext( rh.mHasTransformContext )
#endif #endif
@ -98,6 +101,7 @@ QgsRenderContext &QgsRenderContext::operator=( const QgsRenderContext &rh )
mRenderedFeatureHandlers = rh.mRenderedFeatureHandlers; mRenderedFeatureHandlers = rh.mRenderedFeatureHandlers;
mHasRenderedFeatureHandlers = rh.mHasRenderedFeatureHandlers; mHasRenderedFeatureHandlers = rh.mHasRenderedFeatureHandlers;
mCustomRenderingFlags = rh.mCustomRenderingFlags; mCustomRenderingFlags = rh.mCustomRenderingFlags;
mClippingRegions = rh.mClippingRegions;
setIsTemporal( rh.isTemporal() ); setIsTemporal( rh.isTemporal() );
if ( isTemporal() ) if ( isTemporal() )
setTemporalRange( rh.temporalRange() ); setTemporalRange( rh.temporalRange() );
@ -209,6 +213,8 @@ QgsRenderContext QgsRenderContext::fromMapSettings( const QgsMapSettings &mapSet
if ( ctx.isTemporal() ) if ( ctx.isTemporal() )
ctx.setTemporalRange( mapSettings.temporalRange() ); ctx.setTemporalRange( mapSettings.temporalRange() );
ctx.mClippingRegions = mapSettings.clippingRegions();
return ctx; return ctx;
} }
@ -491,4 +497,9 @@ QList<QgsRenderedFeatureHandlerInterface *> QgsRenderContext::renderedFeatureHan
return mRenderedFeatureHandlers; return mRenderedFeatureHandlers;
} }
QList<QgsMapClippingRegion> QgsRenderContext::clippingRegions() const
{
return mClippingRegions;
}

View File

@ -43,8 +43,8 @@ class QgsLabelingEngine;
class QgsMapSettings; class QgsMapSettings;
class QgsRenderedFeatureHandlerInterface; class QgsRenderedFeatureHandlerInterface;
class QgsSymbolLayer; class QgsSymbolLayer;
class QgsMaskIdProvider; class QgsMaskIdProvider;
class QgsMapClippingRegion;
/** /**
@ -58,6 +58,7 @@ class CORE_EXPORT QgsRenderContext : public QgsTemporalRangeObject
{ {
public: public:
QgsRenderContext(); QgsRenderContext();
~QgsRenderContext() override;
QgsRenderContext( const QgsRenderContext &rh ); QgsRenderContext( const QgsRenderContext &rh );
QgsRenderContext &operator=( const QgsRenderContext &rh ); QgsRenderContext &operator=( const QgsRenderContext &rh );
@ -786,6 +787,15 @@ class CORE_EXPORT QgsRenderContext : public QgsTemporalRangeObject
*/ */
void clearCustomRenderingFlag( const QString &flag ) { mCustomRenderingFlags.remove( flag ); } void clearCustomRenderingFlag( const QString &flag ) { mCustomRenderingFlags.remove( flag ); }
/**
* Returns the list of clipping regions to apply during the render.
*
* These regions are always in the final destination CRS for the map.
*
* \since QGIS 3.16
*/
QList< QgsMapClippingRegion > clippingRegions() const;
private: private:
Flags mFlags; Flags mFlags;
@ -877,6 +887,8 @@ class CORE_EXPORT QgsRenderContext : public QgsTemporalRangeObject
QSet<const QgsSymbolLayer *> mDisabledSymbolLayers; QSet<const QgsSymbolLayer *> mDisabledSymbolLayers;
QList< QgsMapClippingRegion > mClippingRegions;
#ifdef QGISDEBUG #ifdef QGISDEBUG
bool mHasTransformContext = false; bool mHasTransformContext = false;
#endif #endif

View File

@ -61,6 +61,7 @@ class TestQgsMapSettings: public QObject
void testExpressionContext(); void testExpressionContext();
void testRenderedFeatureHandlers(); void testRenderedFeatureHandlers();
void testCustomRenderingFlags(); void testCustomRenderingFlags();
void testClippingRegions();
private: private:
QString toString( const QPolygonF &p, int decimalPlaces = 2 ) const; QString toString( const QPolygonF &p, int decimalPlaces = 2 ) const;
@ -588,5 +589,32 @@ void TestQgsMapSettings::testCustomRenderingFlags()
Q_NOWARN_DEPRECATED_POP Q_NOWARN_DEPRECATED_POP
} }
void TestQgsMapSettings::testClippingRegions()
{
QgsMapSettings settings;
QVERIFY( settings.clippingRegions().isEmpty() );
QgsMapClippingRegion region( QgsGeometry::fromWkt( QStringLiteral( "Polygon(( 0 0, 1 0 , 1 1 , 0 1, 0 0 ))" ) ) );
settings.addClippingRegion( region );
QCOMPARE( settings.clippingRegions().size(), 1 );
QCOMPARE( settings.clippingRegions().at( 0 ).geometry().asWkt(), QStringLiteral( "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))" ) );
QgsMapClippingRegion region2( QgsGeometry::fromWkt( QStringLiteral( "Polygon(( 10 0, 11 0 , 11 1 , 10 1, 10 0 ))" ) ) );
settings.addClippingRegion( region2 );
QCOMPARE( settings.clippingRegions().size(), 2 );
QCOMPARE( settings.clippingRegions().at( 0 ).geometry().asWkt(), QStringLiteral( "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))" ) );
QCOMPARE( settings.clippingRegions().at( 1 ).geometry().asWkt(), QStringLiteral( "Polygon ((10 0, 11 0, 11 1, 10 1, 10 0))" ) );
QgsMapSettings settings2( settings );
QCOMPARE( settings2.clippingRegions().size(), 2 );
QCOMPARE( settings2.clippingRegions().at( 0 ).geometry().asWkt(), QStringLiteral( "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))" ) );
QCOMPARE( settings2.clippingRegions().at( 1 ).geometry().asWkt(), QStringLiteral( "Polygon ((10 0, 11 0, 11 1, 10 1, 10 0))" ) );
QgsMapSettings settings3;
settings3 = settings;
QCOMPARE( settings3.clippingRegions().size(), 2 );
QCOMPARE( settings3.clippingRegions().at( 0 ).geometry().asWkt(), QStringLiteral( "Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))" ) );
QCOMPARE( settings3.clippingRegions().at( 1 ).geometry().asWkt(), QStringLiteral( "Polygon ((10 0, 11 0, 11 1, 10 1, 10 0))" ) ) ;
}
QGSTEST_MAIN( TestQgsMapSettings ) QGSTEST_MAIN( TestQgsMapSettings )
#include "testqgsmapsettings.moc" #include "testqgsmapsettings.moc"

View File

@ -23,7 +23,9 @@ from qgis.core import (QgsRenderContext,
QgsRectangle, QgsRectangle,
QgsVectorSimplifyMethod, QgsVectorSimplifyMethod,
QgsRenderedFeatureHandlerInterface, QgsRenderedFeatureHandlerInterface,
QgsDateTimeRange) QgsDateTimeRange,
QgsMapClippingRegion,
QgsGeometry)
from qgis.PyQt.QtCore import QSize, QDateTime from qgis.PyQt.QtCore import QSize, QDateTime
from qgis.PyQt.QtGui import QPainter, QImage from qgis.PyQt.QtGui import QPainter, QImage
from qgis.testing import start_app, unittest from qgis.testing import start_app, unittest
@ -507,6 +509,17 @@ class TestQgsRenderContext(unittest.TestCase):
self.assertEqual(rc.isTemporal(), False) self.assertEqual(rc.isTemporal(), False)
self.assertIsNotNone(rc.temporalRange()) self.assertIsNotNone(rc.temporalRange())
def testClippingRegion(self):
ms = QgsMapSettings()
rc = QgsRenderContext.fromMapSettings(ms)
self.assertFalse(rc.clippingRegions())
ms.addClippingRegion(QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon(( 0 0, 1 0 , 1 1 , 0 1, 0 0 ))')))
ms.addClippingRegion(QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon(( 10 0, 11 0 , 11 1 , 10 1, 10 0 ))')))
rc = QgsRenderContext.fromMapSettings(ms)
self.assertEqual(len(rc.clippingRegions()), 2)
self.assertEqual(rc.clippingRegions()[0].geometry().asWkt(), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))')
self.assertEqual(rc.clippingRegions()[1].geometry().asWkt(), 'Polygon ((10 0, 11 0, 11 1, 10 1, 10 0))')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()