Skip to content

Commit

Permalink
When a geometry generator symbol layer is used as part of a
Browse files Browse the repository at this point in the history
SUBSYMBOL, the $geometry part of the expression must refer to
the shape which is being rendered by the parent symbol, and
not the original feature's geometry
  • Loading branch information
nyalldawson authored and github-actions[bot] committed Oct 23, 2021
1 parent c7102e8 commit 0838fd9
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 3 deletions.
6 changes: 4 additions & 2 deletions src/core/symbology/qgsgeometrygeneratorsymbollayer.cpp
Expand Up @@ -333,10 +333,12 @@ void QgsGeometryGeneratorSymbolLayer::render( QgsSymbolRenderContext &context, Q
QgsExpressionContext &expressionContext = context.renderContext().expressionContext();
QgsFeature f = expressionContext.feature();

if ( !context.feature() && points )
if ( ( !context.feature() || context.renderContext().flags() & Qgis::RenderContextFlag::RenderingSubSymbol ) && points )
{
// oh dear, we don't have a feature to work from... but that's ok, we are probably being rendered as a plain old symbol!
// in this case we need to build up a feature which represents the points being rendered
// in this case we need to build up a feature which represents the points being rendered.
// note that we also do this same logic when we are rendering a subsymbol. In that case the $geometry part of the
// expression should refer to the shape of the subsymbol being rendered, NOT the feature's original geometry
QgsGeometry drawGeometry;

// step 1 - convert points and rings to geometry
Expand Down
44 changes: 43 additions & 1 deletion tests/src/python/test_qgsgeometrygeneratorsymbollayer.py
Expand Up @@ -44,7 +44,8 @@
QgsRenderContext,
QgsRenderChecker,
QgsCoordinateReferenceSystem,
QgsCoordinateTransform
QgsCoordinateTransform,
QgsArrowSymbolLayer
)

from qgis.testing import start_app, unittest
Expand Down Expand Up @@ -327,6 +328,47 @@ def test_no_feature_coordinate_transform(self):

self.assertTrue(self.imageCheck('geometrygenerator_nofeature', 'geometrygenerator_nofeature', image))

def test_subsymbol(self):
"""
Test rendering a generator in a subsymbol of another symbol
"""
sym = QgsLineSymbol()
arrow = QgsArrowSymbolLayer()
arrow.setIsRepeated(False)
arrow.setArrowStartWidth(10)
arrow.setArrowWidth(5)
arrow.setHeadLength(20)
arrow.setHeadThickness(10)

sym.changeSymbolLayer(0, arrow)

self.lines_layer.renderer().setSymbol(sym)

# here "$geometry" must refer to the created ARROW shape, NOT the original feature line geometry!
generator_layer = QgsGeometryGeneratorSymbolLayer.create(
{'geometryModifier': 'buffer($geometry, 3)'})
generator_layer.setSymbolType(QgsSymbol.Fill)
generator_layer.setUnits(QgsUnitTypes.RenderMillimeters)
self.assertIsNotNone(generator_layer.subSymbol())

generator_layer.subSymbol().symbolLayer(0).setColor(QColor(255, 255, 255))
generator_layer.subSymbol().symbolLayer(0).setStrokeColor(QColor(0, 0, 0))
generator_layer.subSymbol().symbolLayer(0).setStrokeWidth(2)

sub_symbol = QgsFillSymbol()
sub_symbol.changeSymbolLayer(0, generator_layer)
arrow.setSubSymbol(sub_symbol)

rendered_layers = [self.lines_layer]
self.mapsettings.setLayers(rendered_layers)

renderchecker = QgsMultiRenderChecker()
renderchecker.setMapSettings(self.mapsettings)
renderchecker.setControlName('expected_geometrygenerator_subsymbol')
res = renderchecker.runTest('geometrygenerator_subsymbol')
self.report += renderchecker.report()
self.assertTrue(res)

def imageCheck(self, name, reference_image, image):
self.report += "<h2>Render {}</h2>\n".format(name)
temp_dir = QDir.tempPath() + '/'
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 0838fd9

Please sign in to comment.