diff --git a/python/PyQt6/core/auto_generated/qgsrendercontext.sip.in b/python/PyQt6/core/auto_generated/qgsrendercontext.sip.in index f7fa86048893..aefdaa5ecdad 100644 --- a/python/PyQt6/core/auto_generated/qgsrendercontext.sip.in +++ b/python/PyQt6/core/auto_generated/qgsrendercontext.sip.in @@ -635,7 +635,7 @@ Sets whether the rendering optimization (geometry simplification) should be exec .. seealso:: :py:func:`useRenderingOptimization` %End - const QgsVectorSimplifyMethod &vectorSimplifyMethod() const; + QgsVectorSimplifyMethod &vectorSimplifyMethod(); %Docstring Returns the simplification settings to use when rendering vector layers. @@ -646,6 +646,7 @@ The default is to use no simplification. .. versionadded:: 2.4 %End + void setVectorSimplifyMethod( const QgsVectorSimplifyMethod &simplifyMethod ); %Docstring Sets the simplification setting to use when rendering vector layers. diff --git a/python/core/auto_generated/qgsrendercontext.sip.in b/python/core/auto_generated/qgsrendercontext.sip.in index f7fa86048893..aefdaa5ecdad 100644 --- a/python/core/auto_generated/qgsrendercontext.sip.in +++ b/python/core/auto_generated/qgsrendercontext.sip.in @@ -635,7 +635,7 @@ Sets whether the rendering optimization (geometry simplification) should be exec .. seealso:: :py:func:`useRenderingOptimization` %End - const QgsVectorSimplifyMethod &vectorSimplifyMethod() const; + QgsVectorSimplifyMethod &vectorSimplifyMethod(); %Docstring Returns the simplification settings to use when rendering vector layers. @@ -646,6 +646,7 @@ The default is to use no simplification. .. versionadded:: 2.4 %End + void setVectorSimplifyMethod( const QgsVectorSimplifyMethod &simplifyMethod ); %Docstring Sets the simplification setting to use when rendering vector layers. diff --git a/src/core/qgsrendercontext.h b/src/core/qgsrendercontext.h index dbadfab2ef7d..b60f01ebfb9a 100644 --- a/src/core/qgsrendercontext.h +++ b/src/core/qgsrendercontext.h @@ -653,7 +653,16 @@ class CORE_EXPORT QgsRenderContext : public QgsTemporalRangeObject * \see setVectorSimplifyMethod() * \since QGIS 2.4 */ - const QgsVectorSimplifyMethod &vectorSimplifyMethod() const { return mVectorSimplifyMethod; } + QgsVectorSimplifyMethod &vectorSimplifyMethod() { return mVectorSimplifyMethod; } + + /** + * Returns the simplification settings to use when rendering vector layers. + * + * The default is to use no simplification. + * + * \see setVectorSimplifyMethod() + */ + const QgsVectorSimplifyMethod &vectorSimplifyMethod() const SIP_SKIP { return mVectorSimplifyMethod; } /** * Sets the simplification setting to use when rendering vector layers. diff --git a/src/core/symbology/qgsmergedfeaturerenderer.cpp b/src/core/symbology/qgsmergedfeaturerenderer.cpp index 6ede529624eb..d8493a9246f5 100644 --- a/src/core/symbology/qgsmergedfeaturerenderer.cpp +++ b/src/core/symbology/qgsmergedfeaturerenderer.cpp @@ -26,6 +26,7 @@ #include "qgspainteffect.h" #include "qgspainteffectregistry.h" #include "qgsstyleentityvisitor.h" +#include "qgsmaptopixelgeometrysimplifier.h" #include #include @@ -232,6 +233,20 @@ bool QgsMergedFeatureRenderer::renderFeature( const QgsFeature &feature, QgsRend } QgsGeometry geom = feature.geometry(); + // Simplify the geometry, if needed. + if ( context.vectorSimplifyMethod().forceLocalOptimization() ) + { + const int simplifyHints = context.vectorSimplifyMethod().simplifyHints(); + const QgsMapToPixelSimplifier simplifier( simplifyHints, context.vectorSimplifyMethod().tolerance(), + context.vectorSimplifyMethod().simplifyAlgorithm() ); + + QgsGeometry simplified( simplifier.simplify( geom ) ); + if ( !simplified.isEmpty() ) + { + geom = simplified; + } + } + QgsCoordinateTransform xform = context.coordinateTransform(); if ( xform.isValid() ) { @@ -366,7 +381,11 @@ void QgsMergedFeatureRenderer::stopRender( QgsRenderContext &context ) if ( feat.hasGeometry() ) { mContext.expressionContext().setFeature( feat ); + const bool prevSimplify = context.vectorSimplifyMethod().forceLocalOptimization(); + // we've already simplified, no need to re-do simplification + mContext.vectorSimplifyMethod().setForceLocalOptimization( false ); mSubRenderer->renderFeature( feat, mContext ); + mContext.vectorSimplifyMethod().setForceLocalOptimization( prevSimplify ); } } diff --git a/tests/src/core/testqgsinvertedpolygonrenderer.cpp b/tests/src/core/testqgsinvertedpolygonrenderer.cpp index 52d3f6bfd0ac..b9279cc6949a 100644 --- a/tests/src/core/testqgsinvertedpolygonrenderer.cpp +++ b/tests/src/core/testqgsinvertedpolygonrenderer.cpp @@ -28,7 +28,9 @@ #include #include #include "qgsrenderer.h" - +#include "qgsfillsymbol.h" +#include "qgsinvertedpolygonrenderer.h" +#include "qgssinglesymbolrenderer.h" //qgis test includes #include "qgsmultirenderchecker.h" @@ -41,7 +43,7 @@ class TestQgsInvertedPolygon : public QgsTest Q_OBJECT public: - TestQgsInvertedPolygon() : QgsTest( QStringLiteral( "Inverted Polygon Renderer Tests" ) ) {} + TestQgsInvertedPolygon() : QgsTest( QStringLiteral( "Inverted Polygon Renderer Tests" ), QStringLiteral( "symbol_invertedpolygon" ) ) {} private slots: void initTestCase();// will be called before the first testfunction is executed. @@ -52,6 +54,7 @@ class TestQgsInvertedPolygon : public QgsTest void checkSymbolItem(); void preprocess(); void projectionTest(); + void projectionWithSimplificationTest(); void curvedPolygons(); void rotationTest(); @@ -136,6 +139,34 @@ void TestQgsInvertedPolygon::projectionTest() mMapSettings.setDestinationCrs( mpPolysLayer->crs() ); } +void TestQgsInvertedPolygon::projectionWithSimplificationTest() +{ + std::unique_ptr< QgsVectorLayer > polyLayer = std::make_unique< QgsVectorLayer >( testDataPath( "polys.shp" ), QStringLiteral( "polys" ) ); + QVERIFY( polyLayer->isValid() ); + QgsMapSettings mapSettings; + mapSettings.setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) ); + mapSettings.setLayers( QList() << polyLayer.get() ); + mapSettings.setOutputDpi( 96 ); + + QgsFillSymbol *fill = QgsFillSymbol::createSimple( QVariantMap( {{"color", "#fdbf6f"}, {"outline_color", "black"}, + { "outline_width", "1"}} ) ); + QgsInvertedPolygonRenderer *renderer = new QgsInvertedPolygonRenderer(); + QgsSingleSymbolRenderer *singleSymbolRenderer = new QgsSingleSymbolRenderer( fill ); + renderer->setEmbeddedRenderer( singleSymbolRenderer ); + polyLayer->setRenderer( renderer ); + + mapSettings.setExtent( QgsRectangle( -119.552, 25.255, -109.393, 32.651 ) ); + + QgsVectorSimplifyMethod simplifyMethod; + simplifyMethod.setSimplifyHints( QgsVectorSimplifyMethod::GeometrySimplification ); + simplifyMethod.setForceLocalOptimization( true ); + simplifyMethod.setSimplifyAlgorithm( QgsVectorSimplifyMethod::SnappedToGridGlobal ); + simplifyMethod.setThreshold( 0.1f ); + mapSettings.setSimplifyMethod( simplifyMethod ); + + QGSVERIFYRENDERMAPSETTINGSCHECK( QStringLiteral( "inverted_polys_projection_simplification" ), QStringLiteral( "inverted_polys_projection_simplification" ), mapSettings ); +} + void TestQgsInvertedPolygon::curvedPolygons() { const QString myCurvedPolysFileName = mTestDataDir + "curved_polys.gpkg"; diff --git a/tests/testdata/control_images/symbol_invertedpolygon/expected_inverted_polys_projection_simplification/expected_inverted_polys_projection_simplification.png b/tests/testdata/control_images/symbol_invertedpolygon/expected_inverted_polys_projection_simplification/expected_inverted_polys_projection_simplification.png new file mode 100644 index 000000000000..18bfbc7c9005 Binary files /dev/null and b/tests/testdata/control_images/symbol_invertedpolygon/expected_inverted_polys_projection_simplification/expected_inverted_polys_projection_simplification.png differ