From 73244580d219fd237cc24fd3df86dbd6d4c378c4 Mon Sep 17 00:00:00 2001 From: Julien Cabieces Date: Tue, 13 Sep 2022 18:03:41 +0200 Subject: [PATCH 1/3] Fixes #33755 : Fix legend when geometry generator is involved --- .../layertree/qgslayertreemodellegendnode.cpp | 47 ++++++---- tests/src/core/testqgslayertree.cpp | 90 ++++++++++++++++++- 2 files changed, 117 insertions(+), 20 deletions(-) diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp index 9817dde44c8..c0cf56e2c6a 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.cpp +++ b/src/core/layertree/qgslayertreemodellegendnode.cpp @@ -37,6 +37,7 @@ #include "qgsmarkersymbol.h" #include "qgsvariantutils.h" #include "qgslayertreelayer.h" +#include "qgsgeometrygeneratorsymbollayer.h" #include @@ -343,25 +344,36 @@ QSize QgsSymbolLegendNode::minimumIconSize( QgsRenderContext *context ) const const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 ); const int largeIconSize = QgsLayerTreeModel::scaleIconSize( 512 ); QSize minSz( iconSize, iconSize ); - if ( mItem.symbol() && mItem.symbol()->type() == Qgis::SymbolType::Marker ) + if ( mItem.symbol() && ( mItem.symbol()->type() == Qgis::SymbolType::Marker + || mItem.symbol()->type() == Qgis::SymbolType::Line ) ) { - // unusued width, height variables - double width = 0.0; - double height = 0.0; - const std::unique_ptr symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height ) ); + + bool hasRestrictedSizeSymbol = true; + for ( QgsSymbolLayer *sl : mItem.symbol()->symbolLayers() ) + if ( dynamic_cast( sl ) ) + hasRestrictedSizeSymbol = false; + + int maxSize = largeIconSize; + std::unique_ptr symbol; + if ( hasRestrictedSizeSymbol ) + { + // unusued width, height variables + double width = 0.0; + double height = 0.0; + symbol.reset( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height ) ); + } + else if ( context ) + { + // when it's not possible to get a restricted size symbol, we restrict + // pixmap target size to be sure it would fit MAXIMUM_SIZE + maxSize = static_cast( std::round( MAXIMUM_SIZE * context->scaleFactor() ) ); + } + + const QSize size( mItem.symbol()->type() == Qgis::SymbolType::Marker ? maxSize : minSz.width(), + maxSize ); + minSz = QgsImageOperation::nonTransparentImageRect( - QgsSymbolLayerUtils::symbolPreviewPixmap( symbol ? symbol.get() : mItem.symbol(), QSize( largeIconSize, largeIconSize ), 0, - context ).toImage(), - minSz, - true ).size(); - } - else if ( mItem.symbol() && mItem.symbol()->type() == Qgis::SymbolType::Line ) - { - double width = 0.0; - double height = 0.0; - const std::unique_ptr symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height ) ); - minSz = QgsImageOperation::nonTransparentImageRect( - QgsSymbolLayerUtils::symbolPreviewPixmap( symbol ? symbol.get() : mItem.symbol(), QSize( minSz.width(), largeIconSize ), 0, + QgsSymbolLayerUtils::symbolPreviewPixmap( symbol ? symbol.get() : mItem.symbol(), size, 0, context ).toImage(), minSz, true ).size(); @@ -1564,4 +1576,3 @@ void QgsVectorLabelLegendNode::textWidthHeight( double &width, double &height, Q height = QgsTextRenderer::textHeight( ctx, textFormat, 'A', true ); width = QgsTextRenderer::textWidth( ctx, textFormat, textLines, &fm ); } - diff --git a/tests/src/core/testqgslayertree.cpp b/tests/src/core/testqgslayertree.cpp index a421f306681..9ae241bb8ac 100644 --- a/tests/src/core/testqgslayertree.cpp +++ b/tests/src/core/testqgslayertree.cpp @@ -31,6 +31,9 @@ #include "qgslegendsettings.h" #include "qgsmarkersymbol.h" #include "qgsannotationlayer.h" +#include "qgsgeometrygeneratorsymbollayer.h" +#include "qgsfillsymbol.h" +#include "qgsfillsymbollayer.h" #include class TestQgsLayerTree : public QObject @@ -46,7 +49,10 @@ class TestQgsLayerTree : public QObject void testCheckStateHiearchical(); void testCheckStateMutuallyExclusive(); void testCheckStateMutuallyExclusiveEdgeCases(); + void testRestrictedSymbolSize_data(); void testRestrictedSymbolSize(); + void testRestrictedSymbolSizeWithGeometryGenerator_data(); + void testRestrictedSymbolSizeWithGeometryGenerator(); void testShowHideAllSymbolNodes(); void testFindLegendNode(); void testLegendSymbolCategorized(); @@ -304,10 +310,26 @@ void TestQgsLayerTree::testCheckStateMutuallyExclusiveEdgeCases() delete root3; } +void TestQgsLayerTree::testRestrictedSymbolSize_data() +{ + QTest::addColumn( "maxSize" ); + QTest::addColumn( "expectedSize" ); + + // QTest::newRow( "smaller than max" ) << 15. << 52; + QTest::newRow( "bigger than max" ) << 10. << 40; +} + void TestQgsLayerTree::testRestrictedSymbolSize() { + QFETCH( double, maxSize ); + QFETCH( int, expectedSize ); + + // to force re-read of max/min size in QgsSymbolLegendNode constructor + QgsSymbolLegendNode::MINIMUM_SIZE = -1; + QgsSymbolLegendNode::MAXIMUM_SIZE = -1; + QgsSettings settings; - settings.setValue( "/qgis/legendsymbolMaximumSize", 15.0 ); + settings.setValue( "/qgis/legendsymbolMaximumSize", maxSize ); //new memory layer QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "Point?field=col1:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ); @@ -337,7 +359,71 @@ void TestQgsLayerTree::testRestrictedSymbolSize() const QList nodes = m->layerLegendNodes( n ); const QSize minimumSize = static_cast< QgsSymbolLegendNode *>( nodes.at( 0 ) )->minimumIconSize(); - QCOMPARE( minimumSize.width(), 52 ); + QCOMPARE( minimumSize.width(), expectedSize ); + + //cleanup + delete m; + delete root; +} + +void TestQgsLayerTree::testRestrictedSymbolSizeWithGeometryGenerator_data() +{ + QTest::addColumn( "maxSize" ); + QTest::addColumn( "expectedSize" ); + + QTest::newRow( "smaller than max" ) << 15. << 42; + QTest::newRow( "bigger than max" ) << 10. << 38; +} + +void TestQgsLayerTree::testRestrictedSymbolSizeWithGeometryGenerator() +{ + QFETCH( double, maxSize ); + QFETCH( int, expectedSize ); + + // to force re-read of max/min size in QgsSymbolLegendNode constructor + QgsSymbolLegendNode::MINIMUM_SIZE = -1; + QgsSymbolLegendNode::MAXIMUM_SIZE = -1; + + QgsSettings settings; + settings.setValue( "/qgis/legendsymbolMaximumSize", maxSize ); + + //new memory layer + QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "Point?field=col1:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ); + QVERIFY( vl->isValid() ); + + QgsProject project; + project.addMapLayer( vl ); + + //create a categorized renderer with geometry generator for layer + + QVariantMap ggProps; + ggProps.insert( QStringLiteral( "SymbolType" ), QStringLiteral( "Fill" ) ); + ggProps.insert( QStringLiteral( "geometryModifier" ), QStringLiteral( "buffer( $geometry, 200 )" ) ); + QgsSymbolLayer *ggSymbolLayer = QgsGeometryGeneratorSymbolLayer::create( ggProps ); + QgsSymbolLayerList fillSymbolLayerList; + fillSymbolLayerList << new QgsSimpleFillSymbolLayer(); + ggSymbolLayer->setSubSymbol( new QgsFillSymbol( fillSymbolLayerList ) ); + QgsSymbolLayerList slList; + slList << ggSymbolLayer; + QgsMarkerSymbol *symbol = new QgsMarkerSymbol( slList ); + + QgsCategorizedSymbolRenderer *renderer = new QgsCategorizedSymbolRenderer(); + renderer->setClassAttribute( QStringLiteral( "col1" ) ); + renderer->setSourceSymbol( symbol->clone() ); + renderer->addCategory( QgsRendererCategory( "a", symbol->clone(), QStringLiteral( "a" ) ) ); + renderer->addCategory( QgsRendererCategory( "b", symbol->clone(), QStringLiteral( "b" ) ) ); + vl->setRenderer( renderer ); + + //create legend with symbology nodes for categorized renderer + QgsLayerTree *root = new QgsLayerTree(); + QgsLayerTreeLayer *n = new QgsLayerTreeLayer( vl ); + root->addChildNode( n ); + QgsLayerTreeModel *m = new QgsLayerTreeModel( root, nullptr ); + m->setLegendMapViewData( 10, 96, 10 ); + + const QList nodes = m->layerLegendNodes( n ); + const QSize minimumSize = static_cast< QgsSymbolLegendNode *>( nodes.at( 0 ) )->minimumIconSize(); + QCOMPARE( minimumSize.width(), expectedSize ); //cleanup delete m; From e24700df2d79385551c65f964c9d02a44de1c2ea Mon Sep 17 00:00:00 2001 From: Julien Cabieces Date: Thu, 15 Sep 2022 15:10:08 +0200 Subject: [PATCH 2/3] Move geom generator logic in QgsSymbolLayerUtils --- .../auto_generated/symbology/qgssymbol.sip.in | 3 +-- .../symbology/qgssymbollayerutils.sip.in | 10 ++++---- .../layertree/qgslayertreemodellegendnode.cpp | 24 +++++++------------ src/core/symbology/qgssymbol.h | 3 +-- src/core/symbology/qgssymbollayerutils.cpp | 24 +++++++++++++++---- src/core/symbology/qgssymbollayerutils.h | 10 ++++---- 6 files changed, 41 insertions(+), 33 deletions(-) diff --git a/python/core/auto_generated/symbology/qgssymbol.sip.in b/python/core/auto_generated/symbology/qgssymbol.sip.in index 1c9812bcf8d..520d234f263 100644 --- a/python/core/auto_generated/symbology/qgssymbol.sip.in +++ b/python/core/auto_generated/symbology/qgssymbol.sip.in @@ -125,7 +125,7 @@ Returns the symbol's type. %End - QgsSymbolLayerList symbolLayers(); + QgsSymbolLayerList symbolLayers() const; %Docstring Returns the list of symbol layers contained in the symbol. @@ -780,7 +780,6 @@ Render editing vertex marker at specified point QgsSymbol( const QgsSymbol & ); }; - /************************************************************************ * This file has been generated automatically from * * * diff --git a/python/core/auto_generated/symbology/qgssymbollayerutils.sip.in b/python/core/auto_generated/symbology/qgssymbollayerutils.sip.in index 54d4aa23926..afd3c43e23a 100644 --- a/python/core/auto_generated/symbology/qgssymbollayerutils.sip.in +++ b/python/core/auto_generated/symbology/qgssymbollayerutils.sip.in @@ -979,10 +979,14 @@ Creates a new symbol with size restricted to min/max size if original size is ou :param minSize: the minimum size in mm :param maxSize: the maximum size in mm :param context: the render context -:param width: expected width, can be changed by the function +:param width: expected width :param height: expected height, can be changed by this function + ``width`` and ``height`` are changed to 0 if no restricted size symbol is needed, -1 if it's not possible to + compute a restricted size symbol (geometry generator is involved for instance). -:return: 0 if size is within minSize/maxSize range. New symbol if size was out of min/max range. Caller takes ownership +:return: None if size is within minSize/maxSize range or if it's not possible to compute a + restricted size symbol. New symbol if size was out of min/max range. + Caller takes ownership %End static QgsStringMap evaluatePropertiesMap( const QMap &propertiesMap, const QgsExpressionContext &context ); @@ -997,8 +1001,6 @@ Evaluates a map of properties using the given ``context`` and returns a variant - - /************************************************************************ * This file has been generated automatically from * * * diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp index c0cf56e2c6a..c5c1f9d72e6 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.cpp +++ b/src/core/layertree/qgslayertreemodellegendnode.cpp @@ -347,24 +347,16 @@ QSize QgsSymbolLegendNode::minimumIconSize( QgsRenderContext *context ) const if ( mItem.symbol() && ( mItem.symbol()->type() == Qgis::SymbolType::Marker || mItem.symbol()->type() == Qgis::SymbolType::Line ) ) { - - bool hasRestrictedSizeSymbol = true; - for ( QgsSymbolLayer *sl : mItem.symbol()->symbolLayers() ) - if ( dynamic_cast( sl ) ) - hasRestrictedSizeSymbol = false; - int maxSize = largeIconSize; - std::unique_ptr symbol; - if ( hasRestrictedSizeSymbol ) + + // unusued width, height variables + double width = 0.0; + double height = 0.0; + std::unique_ptr symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height ) ); + + if ( width == -1 && height == -1 && context ) { - // unusued width, height variables - double width = 0.0; - double height = 0.0; - symbol.reset( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height ) ); - } - else if ( context ) - { - // when it's not possible to get a restricted size symbol, we restrict + // Tt's not possible to get a restricted size symbol, so we restrict // pixmap target size to be sure it would fit MAXIMUM_SIZE maxSize = static_cast( std::round( MAXIMUM_SIZE * context->scaleFactor() ) ); } diff --git a/src/core/symbology/qgssymbol.h b/src/core/symbology/qgssymbol.h index db3c6113900..d1a2f761899 100644 --- a/src/core/symbology/qgssymbol.h +++ b/src/core/symbology/qgssymbol.h @@ -160,7 +160,7 @@ class CORE_EXPORT QgsSymbol * \see symbolLayerCount * \since QGIS 2.7 */ - QgsSymbolLayerList symbolLayers() { return mLayers; } + QgsSymbolLayerList symbolLayers() const { return mLayers; } #ifndef SIP_RUN @@ -856,4 +856,3 @@ class CORE_EXPORT QgsSymbol }; #endif - diff --git a/src/core/symbology/qgssymbollayerutils.cpp b/src/core/symbology/qgssymbollayerutils.cpp index 66f3ef62840..b94108e3cb6 100644 --- a/src/core/symbology/qgssymbollayerutils.cpp +++ b/src/core/symbology/qgssymbollayerutils.cpp @@ -4998,9 +4998,11 @@ double QgsSymbolLayerUtils::rendererFrameRate( const QgsFeatureRenderer *rendere QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height ) { + height = width = -1; + if ( !s || !context ) { - return 0; + return nullptr; } double size; @@ -5008,6 +5010,16 @@ QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double const QgsLineSymbol *lineSymbol = dynamic_cast( s ); if ( markerSymbol ) { + const QgsSymbolLayerList sls = s->symbolLayers(); + for ( const QgsSymbolLayer *sl : std::as_const( sls ) ) + { + // geometry generators involved, there is no way to get a restricted size symbol + if ( sl->type() != Qgis::SymbolType::Marker ) + { + return nullptr; + } + } + size = markerSymbol->size( *context ); } else if ( lineSymbol ) @@ -5016,7 +5028,7 @@ QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double } else { - return 0; //not size restriction implemented for other symbol types + return nullptr; //not size restriction implemented for other symbol types } size /= context->scaleFactor(); @@ -5031,7 +5043,9 @@ QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double } else { - return 0; + // no need to restricted size symbol + height = width = 0; + return nullptr; } if ( markerSymbol ) @@ -5051,7 +5065,8 @@ QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double height = size; return ls; } - return 0; + + return nullptr; } QgsStringMap QgsSymbolLayerUtils::evaluatePropertiesMap( const QMap &propertiesMap, const QgsExpressionContext &context ) @@ -5064,4 +5079,3 @@ QgsStringMap QgsSymbolLayerUtils::evaluatePropertiesMap( const QMap offsetLine( QPolygonF polyline, double dist, QgsWkbTypes::GeometryType geometryType ) SIP_SKIP; #endif - - From dcf64e80fea14adb1285097202cc321416995132 Mon Sep 17 00:00:00 2001 From: Julien Cabieces Date: Wed, 21 Sep 2022 09:30:45 +0200 Subject: [PATCH 3/3] add an ok boolean to check if it exists a restricted symbol --- .../symbology/qgssymbollayerutils.sip.in | 10 +++++----- src/core/layertree/qgslayertreemodellegendnode.cpp | 7 ++++--- src/core/symbology/qgssymbollayerutils.cpp | 14 ++++++++++---- src/core/symbology/qgssymbollayerutils.h | 10 +++++----- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/python/core/auto_generated/symbology/qgssymbollayerutils.sip.in b/python/core/auto_generated/symbology/qgssymbollayerutils.sip.in index afd3c43e23a..1dbef61333c 100644 --- a/python/core/auto_generated/symbology/qgssymbollayerutils.sip.in +++ b/python/core/auto_generated/symbology/qgssymbollayerutils.sip.in @@ -971,7 +971,7 @@ Returns -1 if the ``renderer`` is not animated. .. versionadded:: 3.26 %End - static QgsSymbol *restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height ); + static QgsSymbol *restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height, bool *ok = 0 ); %Docstring Creates a new symbol with size restricted to min/max size if original size is out of min/max range @@ -979,10 +979,10 @@ Creates a new symbol with size restricted to min/max size if original size is ou :param minSize: the minimum size in mm :param maxSize: the maximum size in mm :param context: the render context -:param width: expected width -:param height: expected height, can be changed by this function - ``width`` and ``height`` are changed to 0 if no restricted size symbol is needed, -1 if it's not possible to - compute a restricted size symbol (geometry generator is involved for instance). +:param width: expected width, can be changed by the function +:param height: expected height, can be changed by the function +:param ok: if not None, ok is set to false if it's not possible to compute a restricted symbol (if geometry generators + are involved for instance) :return: None if size is within minSize/maxSize range or if it's not possible to compute a restricted size symbol. New symbol if size was out of min/max range. diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp index c5c1f9d72e6..cb29bb8197e 100644 --- a/src/core/layertree/qgslayertreemodellegendnode.cpp +++ b/src/core/layertree/qgslayertreemodellegendnode.cpp @@ -352,11 +352,12 @@ QSize QgsSymbolLegendNode::minimumIconSize( QgsRenderContext *context ) const // unusued width, height variables double width = 0.0; double height = 0.0; - std::unique_ptr symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height ) ); + bool ok; + std::unique_ptr symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height, &ok ) ); - if ( width == -1 && height == -1 && context ) + if ( !ok && context ) { - // Tt's not possible to get a restricted size symbol, so we restrict + // It's not possible to get a restricted size symbol, so we restrict // pixmap target size to be sure it would fit MAXIMUM_SIZE maxSize = static_cast( std::round( MAXIMUM_SIZE * context->scaleFactor() ) ); } diff --git a/src/core/symbology/qgssymbollayerutils.cpp b/src/core/symbology/qgssymbollayerutils.cpp index b94108e3cb6..e783c05a189 100644 --- a/src/core/symbology/qgssymbollayerutils.cpp +++ b/src/core/symbology/qgssymbollayerutils.cpp @@ -4996,15 +4996,16 @@ double QgsSymbolLayerUtils::rendererFrameRate( const QgsFeatureRenderer *rendere return visitor.refreshRate; } -QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height ) +QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height, bool *ok ) { - height = width = -1; - if ( !s || !context ) { return nullptr; } + if ( ok ) + *ok = true; + double size; const QgsMarkerSymbol *markerSymbol = dynamic_cast( s ); const QgsLineSymbol *lineSymbol = dynamic_cast( s ); @@ -5016,6 +5017,9 @@ QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double // geometry generators involved, there is no way to get a restricted size symbol if ( sl->type() != Qgis::SymbolType::Marker ) { + if ( ok ) + *ok = false; + return nullptr; } } @@ -5028,6 +5032,9 @@ QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double } else { + if ( ok ) + *ok = false; + return nullptr; //not size restriction implemented for other symbol types } @@ -5044,7 +5051,6 @@ QgsSymbol *QgsSymbolLayerUtils::restrictedSizeSymbol( const QgsSymbol *s, double else { // no need to restricted size symbol - height = width = 0; return nullptr; } diff --git a/src/core/symbology/qgssymbollayerutils.h b/src/core/symbology/qgssymbollayerutils.h index 51079f77bbb..31372ebcc60 100644 --- a/src/core/symbology/qgssymbollayerutils.h +++ b/src/core/symbology/qgssymbollayerutils.h @@ -880,15 +880,15 @@ class CORE_EXPORT QgsSymbolLayerUtils * \param minSize the minimum size in mm * \param maxSize the maximum size in mm * \param context the render context - * \param width expected width - * \param height expected height, can be changed by this function - * \a width and \a height are changed to 0 if no restricted size symbol is needed, -1 if it's not possible to - * compute a restricted size symbol (geometry generator is involved for instance). + * \param width expected width, can be changed by the function + * \param height expected height, can be changed by the function + * \param ok if not nullptr, ok is set to false if it's not possible to compute a restricted symbol (if geometry generators + * are involved for instance) * \return nullptr if size is within minSize/maxSize range or if it's not possible to compute a * restricted size symbol. New symbol if size was out of min/max range. * Caller takes ownership */ - static QgsSymbol *restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height ); + static QgsSymbol *restrictedSizeSymbol( const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height, bool *ok = nullptr ); /** * Evaluates a map of properties using the given \a context and returns a variant map with evaluated expressions from the properties.