From 9cf2ff31d86e6b7671aaca137a60a7b7a975ef62 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 22 Jan 2019 13:29:00 +1000 Subject: [PATCH] Fix evaluation of data defined properties for subsymbols of subsymbols Fixes #18384 --- .../symbology/qgsarrowsymbollayer.sip.in | 2 + .../symbology/qgsfillsymbollayer.sip.in | 8 +++ .../qgsgeometrygeneratorsymbollayer.sip.in | 2 + .../symbology/qgslinesymbollayer.sip.in | 2 + .../symbology/qgsmarkersymbollayer.sip.in | 2 + .../symbology/qgssymbollayer.sip.in | 7 +++ .../qgsvectorfieldsymbollayer.sip.in | 2 + src/core/dxf/qgsdxfexport.cpp | 2 +- src/core/symbology/qgsarrowsymbollayer.cpp | 8 +++ src/core/symbology/qgsarrowsymbollayer.h | 1 + src/core/symbology/qgsfillsymbollayer.cpp | 36 +++++++++++++ src/core/symbology/qgsfillsymbollayer.h | 4 ++ .../qgsgeometrygeneratorsymbollayer.cpp | 8 +++ .../qgsgeometrygeneratorsymbollayer.h | 1 + src/core/symbology/qgslinesymbollayer.cpp | 9 ++++ src/core/symbology/qgslinesymbollayer.h | 1 + src/core/symbology/qgsmarkersymbollayer.cpp | 9 ++++ src/core/symbology/qgsmarkersymbollayer.h | 1 + src/core/symbology/qgssymbol.cpp | 7 +-- src/core/symbology/qgssymbollayer.cpp | 5 ++ src/core/symbology/qgssymbollayer.h | 7 +++ .../symbology/qgsvectorfieldsymbollayer.cpp | 9 ++++ .../symbology/qgsvectorfieldsymbollayer.h | 1 + .../python/test_qgsmarkerlinesymbollayer.py | 51 ++++++++++++++++-- .../expected_part_count_variable.png | Bin 0 -> 1198 bytes .../expected_part_num_variable.png | Bin 0 -> 1041 bytes 26 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 tests/testdata/control_images/symbol_markerline/expected_part_count_variable/expected_part_count_variable.png create mode 100644 tests/testdata/control_images/symbol_markerline/expected_part_num_variable/expected_part_num_variable.png diff --git a/python/core/auto_generated/symbology/qgsarrowsymbollayer.sip.in b/python/core/auto_generated/symbology/qgsarrowsymbollayer.sip.in index c146edd4f74e..d9317cefffc4 100644 --- a/python/core/auto_generated/symbology/qgsarrowsymbollayer.sip.in +++ b/python/core/auto_generated/symbology/qgsarrowsymbollayer.sip.in @@ -43,6 +43,8 @@ Create a new QgsArrowSymbolLayer virtual QSet usedAttributes( const QgsRenderContext &context ) const; + virtual bool hasDataDefinedProperties() const; + double arrowWidth() const; %Docstring diff --git a/python/core/auto_generated/symbology/qgsfillsymbollayer.sip.in b/python/core/auto_generated/symbology/qgsfillsymbollayer.sip.in index da212aa4eecb..420e84540b64 100644 --- a/python/core/auto_generated/symbology/qgsfillsymbollayer.sip.in +++ b/python/core/auto_generated/symbology/qgsfillsymbollayer.sip.in @@ -734,6 +734,8 @@ Returns the stroke width map unit scale. virtual QSet usedAttributes( const QgsRenderContext &context ) const; + virtual bool hasDataDefinedProperties() const; + protected: @@ -1563,6 +1565,8 @@ Returns the map unit scale for the pattern's line offset. virtual QSet usedAttributes( const QgsRenderContext &context ) const; + virtual bool hasDataDefinedProperties() const; + protected: @@ -1727,6 +1731,8 @@ Returns the units for the vertical displacement between rows in the pattern. virtual QSet usedAttributes( const QgsRenderContext &context ) const; + virtual bool hasDataDefinedProperties() const; + virtual void setColor( const QColor &c ); virtual QColor color() const; @@ -1798,6 +1804,8 @@ class QgsCentroidFillSymbolLayer : QgsFillSymbolLayer virtual QSet usedAttributes( const QgsRenderContext &context ) const; + virtual bool hasDataDefinedProperties() const; + void setPointOnSurface( bool pointOnSurface ); bool pointOnSurface() const; diff --git a/python/core/auto_generated/symbology/qgsgeometrygeneratorsymbollayer.sip.in b/python/core/auto_generated/symbology/qgsgeometrygeneratorsymbollayer.sip.in index fef091fa993e..13b39c1fc068 100644 --- a/python/core/auto_generated/symbology/qgsgeometrygeneratorsymbollayer.sip.in +++ b/python/core/auto_generated/symbology/qgsgeometrygeneratorsymbollayer.sip.in @@ -70,6 +70,8 @@ Gets the expression to generate this geometry. virtual QSet usedAttributes( const QgsRenderContext &context ) const; + virtual bool hasDataDefinedProperties() const; + virtual bool isCompatibleWithSymbol( QgsSymbol *symbol ) const; diff --git a/python/core/auto_generated/symbology/qgslinesymbollayer.sip.in b/python/core/auto_generated/symbology/qgslinesymbollayer.sip.in index 61d9bce9ac6f..b0d244f46260 100644 --- a/python/core/auto_generated/symbology/qgslinesymbollayer.sip.in +++ b/python/core/auto_generated/symbology/qgslinesymbollayer.sip.in @@ -378,6 +378,8 @@ Returns the units for the interval between markers. virtual QSet usedAttributes( const QgsRenderContext &context ) const; + virtual bool hasDataDefinedProperties() const; + virtual void setDataDefinedProperty( QgsSymbolLayer::Property key, const QgsProperty &property ); diff --git a/python/core/auto_generated/symbology/qgsmarkersymbollayer.sip.in b/python/core/auto_generated/symbology/qgsmarkersymbollayer.sip.in index ad1ae3cb2f61..b86dcd53d446 100644 --- a/python/core/auto_generated/symbology/qgsmarkersymbollayer.sip.in +++ b/python/core/auto_generated/symbology/qgsmarkersymbollayer.sip.in @@ -505,6 +505,8 @@ Creates a new QgsFilledMarkerSymbolLayer. virtual QSet usedAttributes( const QgsRenderContext &context ) const; + virtual bool hasDataDefinedProperties() const; + virtual void setColor( const QColor &c ); virtual QColor color() const; diff --git a/python/core/auto_generated/symbology/qgssymbollayer.sip.in b/python/core/auto_generated/symbology/qgssymbollayer.sip.in index 6959813abe65..53fe6df6c8ba 100644 --- a/python/core/auto_generated/symbology/qgssymbollayer.sip.in +++ b/python/core/auto_generated/symbology/qgssymbollayer.sip.in @@ -403,6 +403,13 @@ Sets the symbol layer's property collection, used for data defined overrides. .. seealso:: :py:func:`properties` .. versionadded:: 3.0 +%End + + virtual bool hasDataDefinedProperties() const; +%Docstring +Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties. + +.. versionadded:: 3.4.5 %End protected: diff --git a/python/core/auto_generated/symbology/qgsvectorfieldsymbollayer.sip.in b/python/core/auto_generated/symbology/qgsvectorfieldsymbollayer.sip.in index 5366a6ad7407..25dd488bbfe0 100644 --- a/python/core/auto_generated/symbology/qgsvectorfieldsymbollayer.sip.in +++ b/python/core/auto_generated/symbology/qgsvectorfieldsymbollayer.sip.in @@ -74,6 +74,8 @@ A symbol layer class for displaying displacement arrows based on point layer att virtual QSet usedAttributes( const QgsRenderContext &context ) const; + virtual bool hasDataDefinedProperties() const; + void setXAttribute( const QString &attribute ); QString xAttribute() const; diff --git a/src/core/dxf/qgsdxfexport.cpp b/src/core/dxf/qgsdxfexport.cpp index 179a2428fbe7..82b8042c16c8 100644 --- a/src/core/dxf/qgsdxfexport.cpp +++ b/src/core/dxf/qgsdxfexport.cpp @@ -4253,7 +4253,7 @@ bool QgsDxfExport::hasDataDefinedProperties( const QgsSymbolLayer *sl, const Qgs return true; } - return sl->dataDefinedProperties().hasActiveProperties(); + return sl->hasDataDefinedProperties(); } double QgsDxfExport::dashSize() const diff --git a/src/core/symbology/qgsarrowsymbollayer.cpp b/src/core/symbology/qgsarrowsymbollayer.cpp index 7d67461651ec..8669cf4e03a1 100644 --- a/src/core/symbology/qgsarrowsymbollayer.cpp +++ b/src/core/symbology/qgsarrowsymbollayer.cpp @@ -165,6 +165,14 @@ QSet QgsArrowSymbolLayer::usedAttributes( const QgsRenderContext &conte return attributes; } +bool QgsArrowSymbolLayer::hasDataDefinedProperties() const +{ + if ( QgsSymbolLayer::hasDataDefinedProperties() ) + return true; + if ( mSymbol && mSymbol->hasDataDefinedProperties() ) + return true; + return false; +} void QgsArrowSymbolLayer::startRender( QgsSymbolRenderContext &context ) { diff --git a/src/core/symbology/qgsarrowsymbollayer.h b/src/core/symbology/qgsarrowsymbollayer.h index a8dc7fe5d6e6..6fc487498d82 100644 --- a/src/core/symbology/qgsarrowsymbollayer.h +++ b/src/core/symbology/qgsarrowsymbollayer.h @@ -47,6 +47,7 @@ class CORE_EXPORT QgsArrowSymbolLayer : public QgsLineSymbolLayer QgsSymbol *subSymbol() override { return mSymbol.get(); } bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ) override; QSet usedAttributes( const QgsRenderContext &context ) const override; + bool hasDataDefinedProperties() const override; //! Gets current arrow width double arrowWidth() const { return mArrowWidth; } diff --git a/src/core/symbology/qgsfillsymbollayer.cpp b/src/core/symbology/qgsfillsymbollayer.cpp index d423eab07dad..807b8c1d48f9 100644 --- a/src/core/symbology/qgsfillsymbollayer.cpp +++ b/src/core/symbology/qgsfillsymbollayer.cpp @@ -1707,6 +1707,15 @@ QSet QgsImageFillSymbolLayer::usedAttributes( const QgsRenderContext &c return attr; } +bool QgsImageFillSymbolLayer::hasDataDefinedProperties() const +{ + if ( QgsSymbolLayer::hasDataDefinedProperties() ) + return true; + if ( mStroke && mStroke->hasDataDefinedProperties() ) + return true; + return false; +} + //QgsSVGFillSymbolLayer @@ -2326,6 +2335,15 @@ QSet QgsLinePatternFillSymbolLayer::usedAttributes( const QgsRenderCont return attr; } +bool QgsLinePatternFillSymbolLayer::hasDataDefinedProperties() const +{ + if ( QgsSymbolLayer::hasDataDefinedProperties() ) + return true; + if ( mFillLineSymbol && mFillLineSymbol->hasDataDefinedProperties() ) + return true; + return false; +} + double QgsLinePatternFillSymbolLayer::estimateMaxBleed( const QgsRenderContext & ) const { return 0; @@ -3337,6 +3355,15 @@ QSet QgsPointPatternFillSymbolLayer::usedAttributes( const QgsRenderCon return attributes; } +bool QgsPointPatternFillSymbolLayer::hasDataDefinedProperties() const +{ + if ( QgsSymbolLayer::hasDataDefinedProperties() ) + return true; + if ( mMarkerSymbol && mMarkerSymbol->hasDataDefinedProperties() ) + return true; + return false; +} + void QgsPointPatternFillSymbolLayer::setColor( const QColor &c ) { mColor = c; @@ -3516,6 +3543,15 @@ QSet QgsCentroidFillSymbolLayer::usedAttributes( const QgsRenderContext return attributes; } +bool QgsCentroidFillSymbolLayer::hasDataDefinedProperties() const +{ + if ( QgsSymbolLayer::hasDataDefinedProperties() ) + return true; + if ( mMarker && mMarker->hasDataDefinedProperties() ) + return true; + return false; +} + void QgsCentroidFillSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit ) { if ( mMarker ) diff --git a/src/core/symbology/qgsfillsymbollayer.h b/src/core/symbology/qgsfillsymbollayer.h index 1e347ed4122e..44246418aef0 100644 --- a/src/core/symbology/qgsfillsymbollayer.h +++ b/src/core/symbology/qgsfillsymbollayer.h @@ -677,6 +677,7 @@ class CORE_EXPORT QgsImageFillSymbolLayer: public QgsFillSymbolLayer QColor dxfColor( QgsSymbolRenderContext &context ) const override; Qt::PenStyle dxfPenStyle() const override; QSet usedAttributes( const QgsRenderContext &context ) const override; + bool hasDataDefinedProperties() const override; protected: QBrush mBrush; @@ -1406,6 +1407,7 @@ class CORE_EXPORT QgsLinePatternFillSymbolLayer: public QgsImageFillSymbolLayer bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ) override; QgsSymbol *subSymbol() override; QSet usedAttributes( const QgsRenderContext &context ) const override; + bool hasDataDefinedProperties() const override; protected: @@ -1560,6 +1562,7 @@ class CORE_EXPORT QgsPointPatternFillSymbolLayer: public QgsImageFillSymbolLayer QgsMapUnitScale mapUnitScale() const override; QSet usedAttributes( const QgsRenderContext &context ) const override; + bool hasDataDefinedProperties() const override; void setColor( const QColor &c ) override; QColor color() const override; @@ -1632,6 +1635,7 @@ class CORE_EXPORT QgsCentroidFillSymbolLayer : public QgsFillSymbolLayer QgsMapUnitScale mapUnitScale() const override; QSet usedAttributes( const QgsRenderContext &context ) const override; + bool hasDataDefinedProperties() const override; void setPointOnSurface( bool pointOnSurface ) { mPointOnSurface = pointOnSurface; } bool pointOnSurface() const { return mPointOnSurface; } diff --git a/src/core/symbology/qgsgeometrygeneratorsymbollayer.cpp b/src/core/symbology/qgsgeometrygeneratorsymbollayer.cpp index a0faabd0000e..450d1fccde5f 100644 --- a/src/core/symbology/qgsgeometrygeneratorsymbollayer.cpp +++ b/src/core/symbology/qgsgeometrygeneratorsymbollayer.cpp @@ -182,6 +182,14 @@ QSet QgsGeometryGeneratorSymbolLayer::usedAttributes( const QgsRenderCo + mExpression->referencedColumns(); } +bool QgsGeometryGeneratorSymbolLayer::hasDataDefinedProperties() const +{ + // we treat geometry generator layers like they have data defined properties, + // since the WHOLE layer is based on expressions and requires the full expression + // context + return true; +} + bool QgsGeometryGeneratorSymbolLayer::isCompatibleWithSymbol( QgsSymbol *symbol ) const { Q_UNUSED( symbol ) diff --git a/src/core/symbology/qgsgeometrygeneratorsymbollayer.h b/src/core/symbology/qgsgeometrygeneratorsymbollayer.h index cb9046c9f6bc..42fe4d083fde 100644 --- a/src/core/symbology/qgsgeometrygeneratorsymbollayer.h +++ b/src/core/symbology/qgsgeometrygeneratorsymbollayer.h @@ -73,6 +73,7 @@ class CORE_EXPORT QgsGeometryGeneratorSymbolLayer : public QgsSymbolLayer bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ) override; QSet usedAttributes( const QgsRenderContext &context ) const override; + bool hasDataDefinedProperties() const override; /** * Will always return true. diff --git a/src/core/symbology/qgslinesymbollayer.cpp b/src/core/symbology/qgslinesymbollayer.cpp index 7dbb8fab9cfc..63864db7e5a9 100644 --- a/src/core/symbology/qgslinesymbollayer.cpp +++ b/src/core/symbology/qgslinesymbollayer.cpp @@ -1664,6 +1664,15 @@ QSet QgsMarkerLineSymbolLayer::usedAttributes( const QgsRenderContext & return attr; } +bool QgsMarkerLineSymbolLayer::hasDataDefinedProperties() const +{ + if ( QgsSymbolLayer::hasDataDefinedProperties() ) + return true; + if ( mMarker && mMarker->hasDataDefinedProperties() ) + return true; + return false; +} + double QgsMarkerLineSymbolLayer::estimateMaxBleed( const QgsRenderContext &context ) const { return context.convertToPainterUnits( ( mMarker->size() / 2.0 ), mMarker->sizeUnit(), mMarker->sizeMapUnitScale() ) + diff --git a/src/core/symbology/qgslinesymbollayer.h b/src/core/symbology/qgslinesymbollayer.h index 82219fb66183..157cc4f019a2 100644 --- a/src/core/symbology/qgslinesymbollayer.h +++ b/src/core/symbology/qgslinesymbollayer.h @@ -356,6 +356,7 @@ class CORE_EXPORT QgsMarkerLineSymbolLayer : public QgsLineSymbolLayer QgsMapUnitScale mapUnitScale() const override; QSet usedAttributes( const QgsRenderContext &context ) const override; + bool hasDataDefinedProperties() const override; void setDataDefinedProperty( QgsSymbolLayer::Property key, const QgsProperty &property ) override; diff --git a/src/core/symbology/qgsmarkersymbollayer.cpp b/src/core/symbology/qgsmarkersymbollayer.cpp index 644dcdf12425..f737484b8c64 100644 --- a/src/core/symbology/qgsmarkersymbollayer.cpp +++ b/src/core/symbology/qgsmarkersymbollayer.cpp @@ -1645,6 +1645,15 @@ QSet QgsFilledMarkerSymbolLayer::usedAttributes( const QgsRenderContext return attr; } +bool QgsFilledMarkerSymbolLayer::hasDataDefinedProperties() const +{ + if ( QgsSymbolLayer::hasDataDefinedProperties() ) + return true; + if ( mFill && mFill->hasDataDefinedProperties() ) + return true; + return false; +} + void QgsFilledMarkerSymbolLayer::setColor( const QColor &c ) { mColor = c; diff --git a/src/core/symbology/qgsmarkersymbollayer.h b/src/core/symbology/qgsmarkersymbollayer.h index ce7d3b8c4dee..bf5621e68992 100644 --- a/src/core/symbology/qgsmarkersymbollayer.h +++ b/src/core/symbology/qgsmarkersymbollayer.h @@ -456,6 +456,7 @@ class CORE_EXPORT QgsFilledMarkerSymbolLayer : public QgsSimpleMarkerSymbolLayer bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ) override; double estimateMaxBleed( const QgsRenderContext &context ) const override; QSet usedAttributes( const QgsRenderContext &context ) const override; + bool hasDataDefinedProperties() const override; void setColor( const QColor &c ) override; QColor color() const override; diff --git a/src/core/symbology/qgssymbol.cpp b/src/core/symbology/qgssymbol.cpp index 495f0177f7c5..841b6160a921 100644 --- a/src/core/symbology/qgssymbol.cpp +++ b/src/core/symbology/qgssymbol.cpp @@ -677,12 +677,7 @@ bool QgsSymbol::hasDataDefinedProperties() const { Q_FOREACH ( QgsSymbolLayer *layer, mLayers ) { - if ( layer->dataDefinedProperties().hasActiveProperties() ) - return true; - // we treat geometry generator layers like they have data defined properties, - // since the WHOLE layer is based on expressions and requires the full expression - // context - if ( layer->layerType() == QLatin1String( "GeometryGenerator" ) ) + if ( layer->hasDataDefinedProperties() ) return true; } return false; diff --git a/src/core/symbology/qgssymbollayer.cpp b/src/core/symbology/qgssymbollayer.cpp index b0c7c5aad3c3..9aa851cbfe6e 100644 --- a/src/core/symbology/qgssymbollayer.cpp +++ b/src/core/symbology/qgssymbollayer.cpp @@ -193,6 +193,11 @@ void QgsSymbolLayer::prepareExpressions( const QgsSymbolRenderContext &context ) } } +bool QgsSymbolLayer::hasDataDefinedProperties() const +{ + return mDataDefinedProperties.hasActiveProperties(); +} + const QgsPropertiesDefinition &QgsSymbolLayer::propertyDefinitions() { QgsSymbolLayer::initPropertyDefinitions(); diff --git a/src/core/symbology/qgssymbollayer.h b/src/core/symbology/qgssymbollayer.h index f78c65e6e12c..619961249fe6 100644 --- a/src/core/symbology/qgssymbollayer.h +++ b/src/core/symbology/qgssymbollayer.h @@ -398,6 +398,13 @@ class CORE_EXPORT QgsSymbolLayer */ void setDataDefinedProperties( const QgsPropertyCollection &collection ) { mDataDefinedProperties = collection; } + /** + * Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties. + * + * \since QGIS 3.4.5 + */ + virtual bool hasDataDefinedProperties() const; + protected: QgsSymbolLayer( QgsSymbol::SymbolType type, bool locked = false ); diff --git a/src/core/symbology/qgsvectorfieldsymbollayer.cpp b/src/core/symbology/qgsvectorfieldsymbollayer.cpp index 30b054b20373..c7feb6e02308 100644 --- a/src/core/symbology/qgsvectorfieldsymbollayer.cpp +++ b/src/core/symbology/qgsvectorfieldsymbollayer.cpp @@ -284,6 +284,15 @@ QSet QgsVectorFieldSymbolLayer::usedAttributes( const QgsRenderContext return attributes; } +bool QgsVectorFieldSymbolLayer::hasDataDefinedProperties() const +{ + if ( QgsSymbolLayer::hasDataDefinedProperties() ) + return true; + if ( mLineSymbol && mLineSymbol->hasDataDefinedProperties() ) + return true; + return false; +} + void QgsVectorFieldSymbolLayer::convertPolarToCartesian( double length, double angle, double &x, double &y ) const { //convert angle to degree and to north orientation diff --git a/src/core/symbology/qgsvectorfieldsymbollayer.h b/src/core/symbology/qgsvectorfieldsymbollayer.h index b591ecf99abf..0cc96a09dd7f 100644 --- a/src/core/symbology/qgsvectorfieldsymbollayer.h +++ b/src/core/symbology/qgsvectorfieldsymbollayer.h @@ -72,6 +72,7 @@ class CORE_EXPORT QgsVectorFieldSymbolLayer: public QgsMarkerSymbolLayer void drawPreviewIcon( QgsSymbolRenderContext &context, QSize size ) override; QSet usedAttributes( const QgsRenderContext &context ) const override; + bool hasDataDefinedProperties() const override; //setters and getters void setXAttribute( const QString &attribute ) { mXAttribute = attribute; } diff --git a/tests/src/python/test_qgsmarkerlinesymbollayer.py b/tests/src/python/test_qgsmarkerlinesymbollayer.py index 8b1f725b35b9..e5ffb55f41e3 100644 --- a/tests/src/python/test_qgsmarkerlinesymbollayer.py +++ b/tests/src/python/test_qgsmarkerlinesymbollayer.py @@ -42,7 +42,14 @@ QgsSimpleMarkerSymbolLayer, QgsLineSymbolLayer, QgsMarkerLineSymbolLayer, - QgsMarkerSymbol + QgsMarkerSymbol, + QgsGeometryGeneratorSymbolLayer, + QgsSymbol, + QgsFontMarkerSymbolLayer, + QgsFontUtils, + QgsLineSymbol, + QgsSymbolLayer, + QgsProperty ) from qgis.testing import unittest, start_app @@ -63,7 +70,6 @@ def tearDown(self): def testRingFilter(self): # test filtering rings during rendering - s = QgsFillSymbol() s.deleteSymbolLayer(0) @@ -107,7 +113,41 @@ def testRingFilter(self): rendered_image = self.renderGeometry(s3, g) assert self.imageCheck('markerline_interioronly', 'markerline_interioronly', rendered_image) - def renderGeometry(self, symbol, geom): + def testPartNum(self): + # test geometry_part_num variable + s = QgsLineSymbol() + s.deleteSymbolLayer(0) + + sym_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'segments_to_lines($geometry)'}) + sym_layer.setSymbolType(QgsSymbol.Line) + s.appendSymbolLayer(sym_layer) + + marker_line = QgsMarkerLineSymbolLayer(False) + marker_line.setPlacement(QgsMarkerLineSymbolLayer.FirstVertex) + f = QgsFontUtils.getStandardTestFont('Bold', 24) + marker = QgsFontMarkerSymbolLayer(f.family(), 'x', 24, QColor(255, 255, 0)) + marker.setDataDefinedProperty(QgsSymbolLayer.PropertyCharacter, QgsProperty.fromExpression('@geometry_part_num')) + marker_symbol = QgsMarkerSymbol() + marker_symbol.changeSymbolLayer(0, marker) + marker_line.setSubSymbol(marker_symbol) + line_symbol = QgsLineSymbol() + line_symbol.changeSymbolLayer(0, marker_line) + sym_layer.setSubSymbol(line_symbol) + + # rendering test + g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + rendered_image = self.renderGeometry(s, g, buffer=4) + assert self.imageCheck('part_num_variable', 'part_num_variable', rendered_image) + + marker.setDataDefinedProperty(QgsSymbolLayer.PropertyCharacter, + QgsProperty.fromExpression('@geometry_part_count')) + + # rendering test + g = QgsGeometry.fromWkt('LineString(0 0, 10 0, 10 10, 0 10)') + rendered_image = self.renderGeometry(s, g, buffer=4) + assert self.imageCheck('part_count_variable', 'part_count_variable', rendered_image) + + def renderGeometry(self, symbol, geom, buffer=20): f = QgsFeature() f.setGeometry(geom) @@ -118,15 +158,16 @@ def renderGeometry(self, symbol, geom): extent = geom.get().boundingBox() # buffer extent by 10% if extent.width() > 0: - extent = extent.buffered((extent.height() + extent.width()) / 20.0) + extent = extent.buffered((extent.height() + extent.width()) / buffer) else: - extent = extent.buffered(10) + extent = extent.buffered(buffer / 2) ms.setExtent(extent) ms.setOutputSize(image.size()) context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI + context.expressionContext().setFeature(f) painter.begin(image) try: diff --git a/tests/testdata/control_images/symbol_markerline/expected_part_count_variable/expected_part_count_variable.png b/tests/testdata/control_images/symbol_markerline/expected_part_count_variable/expected_part_count_variable.png new file mode 100644 index 0000000000000000000000000000000000000000..56453d41106f6990e143e541db6025cb9305a839 GIT binary patch literal 1198 zcmY*Xdo+{@6rWgI#_=lC#BMpU#7y|Z$wph&cw|Q8^?g1==*!Fsd6(E(wn&&Fk3q7k z=^-=U#MiKi+1gXs8Dqyv$YVGRO_?;pBu4BwyMNR@=XZbi-gE9f_f_EUcUT{5hQ(ko z`ebj9Kn)8wutiIwEnJ*M8q!Vj4o$^i4B9uaiA6N{27~!3itOPQe70s*+M6)4-$=(l z16^MiOE+u3W1lh`p1k7tEVVYr=F#K3HdJ4w>4_%`*;d~R)MihzvXosNN)zG* z^@&bd2{+8|0*^7k%MZFK`k9!KAo?%cglSahxuwG*7d9rLe)uNRO^7!Y$~elu(Rs?e ziICt1pf17%vZN<+*T=Skv;_qJX`&dm!nuS|=StWjb@Bkie>MxrK?F-~=*mcn!)0eM zuul##6?Y)Aj_+7yzYkiP0(c+PJG2~txO=Aipb}b;5xf1gc$wzpW1knQIkO<2L1#VuW2Jh>{OD>Bn8|U)8o>`sO8psyEFNp;_dU4o+fc#xz(M&i$ah|j|@<4WKeTyhRJhE>3XkR>dC|EPWX zxC{Xq#;@A4mlSft8oOo@p%Gdd-&}mSRd9Y$%=uGS#urd(uyx`x;G9T(6}Nn(7Qvb@ z3%^`qFCWUd-@2gJ#rY8pw6ob$xrh5Uan`WZc zGyX^&UB#&d%D7L7eRZbGc0$fk)Lxo-I1S_#o_;fMARarvOKOI%1fH8JKV`QJg|9iJ z&{-~P2TFbmLh9l}arx^qp`T)aWy{q{MYPrL(H}x_HX65KwKN*I1zk_h*q@LI(h6Bq zmmyLf(q+P=el{!n2#V~yB)-z$4bwhmb7HRdcjJmfpuWL?t%pciL287wYrVRPs!l&M zh``s0f-)+nYI{rtAgrHL-^xmUS+I$A$S`7abhDiNI#=1)R7eNtk0$Iy7rDU_DPjH? zb)UUGH?PAYhtu}=Y6%(}o(BHnwU=l1lQJ)Wx=&J+h;(j0dkv$s{(Vm7hWcH^_io_-$pNm1wj1>}wmBsjUBd)9$&HXqKF1ALl|-pb~P0F}YmNPB@J7`tzRSi^HP%TD>dRuRXHx!lPQvQoWNxK$Dc5B3w8? zhA8SNwQSvefv=ehUxa(`~C#M-=CYX3(tEb!vh zp!R+d-Fw?FKX1;uo}9bn`BwfzQTHcgXRg`UwX3%Gs-=FSsA$xl^3&cCu9n&xHTZaB8$!##J=8y|0661?`d+Rt@g-uu__&37XrRz?OygvMyD z2?>&y;W}cg;q#sr%AS_iR=Ep7)^c z-HYRAtKv50G?&bnCmr&4eUo??=jQuqZ{_`M-^{FBdro{7BT`gCm6FxqI%oxOSOJmJfq?L%uD-JQ1Kn`o|gMD*#csya%4;u1^$ z->=+d_ta+o#ItKBCd&RlKVj{mM}GTm%JXYmG{hc`NLKBOKq8q-rUykWq)4Y%h&wvcSUlMn1pJ(lTr)N6CDC@??KZy fP!JSv4Y_}r93~u8`SN)3D-hq))z4*}Q$iB}=zZPx literal 0 HcmV?d00001