diff --git a/src/core/symbology/qgsfillsymbollayer.cpp b/src/core/symbology/qgsfillsymbollayer.cpp index c6cacf456a7..b5a0184f77e 100644 --- a/src/core/symbology/qgsfillsymbollayer.cpp +++ b/src/core/symbology/qgsfillsymbollayer.cpp @@ -3988,10 +3988,13 @@ void QgsRandomMarkerFillSymbolLayer::renderPolygon( const QPolygonF &points, QLi if ( mRenderingFeature ) { + // in the middle of rendering a possibly multi-part feature, so we collect all the parts and defer the actual rendering + // until after we've received the final part mCurrentParts << part; } else { + // not rendering a feature, so we can just render the polygon immediately render( context.renderContext(), QVector< Part>() << part, context.feature() ? *context.feature() : QgsFeature(), context.selected() ); } } @@ -4036,8 +4039,7 @@ void QgsRandomMarkerFillSymbolLayer::render( QgsRenderContext &context, const QV } } - QgsGeometry geom = QgsGeometry::unaryUnion( geometryParts ); - + const QgsGeometry geom = geometryParts.count() != 1 ? QgsGeometry::unaryUnion( geometryParts ) : geometryParts.at( 0 ); if ( clipPoints ) { @@ -4060,6 +4062,8 @@ void QgsRandomMarkerFillSymbolLayer::render( QgsRenderContext &context, const QV QVector< QgsPointXY > randomPoints = geom.randomPointsInPolygon( count, seed ); #if 0 + // in some cases rendering from top to bottom is nice (e.g. randomised tree markers), but in other cases it's not wanted.. + // TODO consider exposing this as an option std::sort( randomPoints.begin(), randomPoints.end(), []( const QgsPointXY & a, const QgsPointXY & b )->bool { return a.y() < b.y(); diff --git a/tests/src/python/test_qgsrandommarkersymbollayer.py b/tests/src/python/test_qgsrandommarkersymbollayer.py index 468af51fcb4..b98f78194f9 100644 --- a/tests/src/python/test_qgsrandommarkersymbollayer.py +++ b/tests/src/python/test_qgsrandommarkersymbollayer.py @@ -38,19 +38,8 @@ from qgis.core import (QgsGeometry, QgsReadWriteContext, QgsSymbolLayerUtils, QgsSimpleMarkerSymbolLayer, - QgsLineSymbolLayer, - QgsTemplatedLineSymbolLayerBase, - QgsMarkerLineSymbolLayer, + QgsSimpleFillSymbolLayer, QgsMarkerSymbol, - QgsGeometryGeneratorSymbolLayer, - QgsSymbol, - QgsFontMarkerSymbolLayer, - QgsFontUtils, - QgsLineSymbol, - QgsSymbolLayer, - QgsProperty, - QgsRectangle, - QgsUnitTypes, QgsRandomMarkerFillSymbolLayer ) @@ -142,6 +131,30 @@ class TestQgsRandomMarkerSymbolLayer(unittest.TestCase): random_fill = QgsRandomMarkerFillSymbolLayer.create({}) self.assertNotEqual(random_fill.seed(), 0) + def testMultipart(self): + """ + Test rendering a multi-part random marker fill symbol + """ + s = QgsFillSymbol() + s.deleteSymbolLayer(0) + + simple_fill = QgsSimpleFillSymbolLayer(color=QColor(255,255,255)) + s.appendSymbolLayer(simple_fill.clone()) + + random_fill = QgsRandomMarkerFillSymbolLayer(12, seed=481523) + marker = QgsSimpleMarkerSymbolLayer(QgsSimpleMarkerSymbolLayer.Triangle, 4) + marker.setColor(QColor(255, 0, 0)) + marker.setStrokeStyle(Qt.NoPen) + marker_symbol = QgsMarkerSymbol() + marker_symbol.changeSymbolLayer(0, marker) + random_fill.setSubSymbol(marker_symbol) + + s.appendSymbolLayer(random_fill.clone()) + + g = QgsGeometry.fromWkt('MultiPolygon(((0 0, 5 0, 5 10, 0 10, 0 0),(1 1, 1 9, 4 9, 4 1, 1 1)), ((6 0, 10 0, 10 5, 6 5, 6 0)), ((8 6, 10 6, 10 10, 8 10, 8 6)))') + rendered_image = self.renderGeometry(s, g) + self.assertTrue(self.imageCheck('randommarkerfill_multipoly', 'randommarkerfill_multipoly', rendered_image)) + def renderGeometry(self, symbol, geom, buffer=20): f = QgsFeature() f.setGeometry(geom) diff --git a/tests/testdata/control_images/symbol_randommarkerfill/expected_randommarkerfill_multipoly/expected_randommarkerfill_multipoly.png b/tests/testdata/control_images/symbol_randommarkerfill/expected_randommarkerfill_multipoly/expected_randommarkerfill_multipoly.png new file mode 100644 index 00000000000..9e76a8bc3c0 Binary files /dev/null and b/tests/testdata/control_images/symbol_randommarkerfill/expected_randommarkerfill_multipoly/expected_randommarkerfill_multipoly.png differ