Skip to content

Commit 0593a7b

Browse files
committedSep 22, 2021
Fix geometry generator when used as symbol for annotation item
1 parent 05778aa commit 0593a7b

File tree

10 files changed

+93
-40
lines changed

10 files changed

+93
-40
lines changed
 

‎python/core/auto_generated/symbology/qgsgeometrygeneratorsymbollayer.sip.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ This is a hybrid layer, it constructs its own geometry so it does not
120120
care about the geometry of its parents.
121121
%End
122122

123-
void render( QgsSymbolRenderContext &context, const QPolygonF *points = 0, const QVector<QPolygonF> *rings = 0 );
123+
void render( QgsSymbolRenderContext &context, QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::GeometryType::UnknownGeometry, const QPolygonF *points = 0, const QVector<QPolygonF> *rings = 0 );
124124
%Docstring
125125
Will render this symbol layer using the context.
126126
In comparison to other symbols there is no geometry passed in, since
@@ -129,14 +129,14 @@ which contains a :py:class:`QgsRenderContext` which in turn contains an expressi
129129
context which is available to the evaluated expression.
130130

131131
:param context: The rendering context which will be used to render and to construct a geometry.
132+
:param geometryType: type of original geometry being rendered by the parent symbol (since QGIS 3.22)
132133
:param points: optional list of original points which are being rendered by the parent symbol (since QGIS 3.22)
133134
:param rings: optional list of original rings which are being rendered by the parent symbol (since QGIS 3.22)
134135
%End
135136

136137
virtual void setColor( const QColor &color );
137138

138139

139-
140140
private:
141141
QgsGeometryGeneratorSymbolLayer( const QgsGeometryGeneratorSymbolLayer &copy );
142142
};

‎python/core/auto_generated/symbology/qgssymbol.sip.in

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ Retrieve a cloned list of all layers that make up this symbol.
677677
Ownership is transferred to the caller.
678678
%End
679679

680-
void renderUsingLayer( QgsSymbolLayer *layer, QgsSymbolRenderContext &context, const QPolygonF *points = 0, const QVector<QPolygonF> *rings = 0 );
680+
void renderUsingLayer( QgsSymbolLayer *layer, QgsSymbolRenderContext &context, QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::GeometryType::UnknownGeometry, const QPolygonF *points = 0, const QVector<QPolygonF> *rings = 0 );
681681
%Docstring
682682
Renders a context using a particular symbol layer without passing in a
683683
geometry. This is used as fallback, if the symbol being rendered is not
@@ -687,8 +687,8 @@ geometry passed to the layer will be empty.
687687
This is required for layers that generate their own geometry from other
688688
information in the rendering context.
689689

690-
Since QGIS 3.22, the optional ``points`` and ``rings`` arguments can specify the original
691-
points and rings in which are being rendered by the parent symbol.
690+
Since QGIS 3.22, the optional ``geometryType``, ``points`` and ``rings`` arguments can specify the original
691+
geometry type, points and rings in which are being rendered by the parent symbol.
692692
%End
693693

694694
void renderVertexMarker( QPointF pt, QgsRenderContext &context, Qgis::VertexMarkerType currentVertexMarkerType, double currentVertexMarkerSize );

‎src/core/symbology/qgsfillsymbol.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void QgsFillSymbol::renderPolygon( const QPolygonF &points, const QVector<QPolyg
5353
if ( symbolLayer->type() == Qgis::SymbolType::Fill || symbolLayer->type() == Qgis::SymbolType::Line )
5454
renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
5555
else
56-
renderUsingLayer( symbolLayer, symbolContext, &points, rings );
56+
renderUsingLayer( symbolLayer, symbolContext, QgsWkbTypes::PolygonGeometry, &points, rings );
5757
}
5858
return;
5959
}
@@ -70,7 +70,7 @@ void QgsFillSymbol::renderPolygon( const QPolygonF &points, const QVector<QPolyg
7070
if ( symbolLayer->type() == Qgis::SymbolType::Fill || symbolLayer->type() == Qgis::SymbolType::Line )
7171
renderPolygonUsingLayer( symbolLayer, points, rings, symbolContext );
7272
else
73-
renderUsingLayer( symbolLayer, symbolContext, &points, rings );
73+
renderUsingLayer( symbolLayer, symbolContext, QgsWkbTypes::PolygonGeometry, &points, rings );
7474
}
7575
}
7676

‎src/core/symbology/qgsgeometrygeneratorsymbollayer.cpp

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ bool QgsGeometryGeneratorSymbolLayer::isCompatibleWithSymbol( QgsSymbol *symbol
256256
Q_UNUSED( symbol )
257257
return true;
258258
}
259-
void QgsGeometryGeneratorSymbolLayer::render( QgsSymbolRenderContext &context, const QPolygonF *points, const QVector<QPolygonF> *rings )
259+
void QgsGeometryGeneratorSymbolLayer::render( QgsSymbolRenderContext &context, QgsWkbTypes::GeometryType geometryType, const QPolygonF *points, const QVector<QPolygonF> *rings )
260260
{
261261
if ( mRenderingFeature && mHasRenderedFeature )
262262
return;
@@ -271,27 +271,40 @@ void QgsGeometryGeneratorSymbolLayer::render( QgsSymbolRenderContext &context, c
271271
QgsGeometry drawGeometry;
272272

273273
// step 1 - convert points and rings to geometry
274-
if ( points->size() == 1 )
274+
switch ( geometryType )
275275
{
276-
drawGeometry = QgsGeometry::fromPointXY( points->at( 0 ) );
277-
}
278-
else if ( rings )
279-
{
280-
// polygon
281-
std::unique_ptr < QgsLineString > exterior( QgsLineString::fromQPolygonF( *points ) );
282-
std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
283-
polygon->setExteriorRing( exterior.release() );
284-
for ( const QPolygonF &ring : *rings )
276+
case QgsWkbTypes::PointGeometry:
285277
{
286-
polygon->addInteriorRing( QgsLineString::fromQPolygonF( ring ) );
278+
Q_ASSERT( points->size() == 1 );
279+
drawGeometry = QgsGeometry::fromPointXY( points->at( 0 ) );
280+
break;
287281
}
288-
drawGeometry = QgsGeometry( std::move( polygon ) );
289-
}
290-
else
291-
{
292-
// line
293-
std::unique_ptr < QgsLineString > ring( QgsLineString::fromQPolygonF( *points ) );
294-
drawGeometry = QgsGeometry( std::move( ring ) );
282+
case QgsWkbTypes::LineGeometry:
283+
{
284+
Q_ASSERT( !rings );
285+
std::unique_ptr < QgsLineString > ring( QgsLineString::fromQPolygonF( *points ) );
286+
drawGeometry = QgsGeometry( std::move( ring ) );
287+
break;
288+
}
289+
case QgsWkbTypes::PolygonGeometry:
290+
{
291+
std::unique_ptr < QgsLineString > exterior( QgsLineString::fromQPolygonF( *points ) );
292+
std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
293+
polygon->setExteriorRing( exterior.release() );
294+
if ( rings )
295+
{
296+
for ( const QPolygonF &ring : *rings )
297+
{
298+
polygon->addInteriorRing( QgsLineString::fromQPolygonF( ring ) );
299+
}
300+
}
301+
drawGeometry = QgsGeometry( std::move( polygon ) );
302+
break;
303+
}
304+
305+
case QgsWkbTypes::UnknownGeometry:
306+
case QgsWkbTypes::NullGeometry:
307+
return; // unreachable
295308
}
296309

297310
// step 2 - scale the draw geometry from PAINTER units to target units (e.g. millimeters)
@@ -311,9 +324,19 @@ void QgsGeometryGeneratorSymbolLayer::render( QgsSymbolRenderContext &context, c
311324
// step 5 - transform geometry back from target units to MAP units. We transform to map units here
312325
// as we'll ultimately be calling renderFeature, which excepts the feature has a geometry in map units.
313326
// Here we also scale the transform by the target unit to painter units factor to reverse that conversion
327+
geom.transform( painterToTargetUnits.inverted( ) );
314328
QTransform mapToPixel = context.renderContext().mapToPixel().transform();
315-
mapToPixel.scale( scale, scale );
316329
geom.transform( mapToPixel.inverted() );
330+
// also need to apply the coordinate transform from the render context
331+
try
332+
{
333+
geom.transform( context.renderContext().coordinateTransform(), QgsCoordinateTransform::ReverseTransform );
334+
}
335+
catch ( QgsCsException & )
336+
{
337+
QgsDebugMsg( QStringLiteral( "Could no transform generated geometry to layer CRS" ) );
338+
}
339+
317340
f.setGeometry( geom );
318341
}
319342
else if ( context.feature() )

‎src/core/symbology/qgsgeometrygeneratorsymbollayer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,14 @@ class CORE_EXPORT QgsGeometryGeneratorSymbolLayer : public QgsSymbolLayer
123123
* context which is available to the evaluated expression.
124124
*
125125
* \param context The rendering context which will be used to render and to construct a geometry.
126+
* \param geometryType type of original geometry being rendered by the parent symbol (since QGIS 3.22)
126127
* \param points optional list of original points which are being rendered by the parent symbol (since QGIS 3.22)
127128
* \param rings optional list of original rings which are being rendered by the parent symbol (since QGIS 3.22)
128129
*/
129-
void render( QgsSymbolRenderContext &context, const QPolygonF *points = nullptr, const QVector<QPolygonF> *rings = nullptr );
130+
void render( QgsSymbolRenderContext &context, QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::GeometryType::UnknownGeometry, const QPolygonF *points = nullptr, const QVector<QPolygonF> *rings = nullptr );
130131

131132
void setColor( const QColor &color ) override;
132133

133-
134134
private:
135135
QgsGeometryGeneratorSymbolLayer( const QString &expression );
136136

‎src/core/symbology/qgslinesymbol.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ void QgsLineSymbol::renderPolyline( const QPolygonF &points, const QgsFeature *f
223223
renderPolylineUsingLayer( lineLayer, points, symbolContext );
224224
}
225225
else
226-
renderUsingLayer( symbolLayer, symbolContext, &points );
226+
renderUsingLayer( symbolLayer, symbolContext, QgsWkbTypes::LineGeometry, &points );
227227
}
228228
return;
229229
}
@@ -244,7 +244,7 @@ void QgsLineSymbol::renderPolyline( const QPolygonF &points, const QgsFeature *f
244244
}
245245
else
246246
{
247-
renderUsingLayer( symbolLayer, symbolContext, &points );
247+
renderUsingLayer( symbolLayer, symbolContext, QgsWkbTypes::LineGeometry, &points );
248248
}
249249
}
250250

‎src/core/symbology/qgsmarkersymbol.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ void QgsMarkerSymbol::renderPoint( QPointF point, const QgsFeature *f, QgsRender
433433
{
434434
QPolygonF points;
435435
points.append( point );
436-
renderUsingLayer( symbolLayer, symbolContext, &points );
436+
renderUsingLayer( symbolLayer, symbolContext, QgsWkbTypes::PointGeometry, &points );
437437
}
438438
}
439439
return;
@@ -457,7 +457,7 @@ void QgsMarkerSymbol::renderPoint( QPointF point, const QgsFeature *f, QgsRender
457457
{
458458
QPolygonF points;
459459
points.append( point );
460-
renderUsingLayer( symbolLayer, symbolContext, &points );
460+
renderUsingLayer( symbolLayer, symbolContext, QgsWkbTypes::PointGeometry, &points );
461461
}
462462
}
463463
}

‎src/core/symbology/qgssymbol.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ QgsSymbolLayerList QgsSymbol::cloneLayers() const
778778
return lst;
779779
}
780780

781-
void QgsSymbol::renderUsingLayer( QgsSymbolLayer *layer, QgsSymbolRenderContext &context, const QPolygonF *points, const QVector<QPolygonF> *rings )
781+
void QgsSymbol::renderUsingLayer( QgsSymbolLayer *layer, QgsSymbolRenderContext &context, QgsWkbTypes::GeometryType geometryType, const QPolygonF *points, const QVector<QPolygonF> *rings )
782782
{
783783
Q_ASSERT( layer->type() == Qgis::SymbolType::Hybrid );
784784

@@ -791,11 +791,11 @@ void QgsSymbol::renderUsingLayer( QgsSymbolLayer *layer, QgsSymbolRenderContext
791791
if ( effect && effect->enabled() )
792792
{
793793
QgsEffectPainter p( context.renderContext(), effect );
794-
generatorLayer->render( context, points, rings );
794+
generatorLayer->render( context, geometryType, points, rings );
795795
}
796796
else
797797
{
798-
generatorLayer->render( context, points, rings );
798+
generatorLayer->render( context, geometryType, points, rings );
799799
}
800800
}
801801

‎src/core/symbology/qgssymbol.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -692,10 +692,10 @@ class CORE_EXPORT QgsSymbol
692692
* This is required for layers that generate their own geometry from other
693693
* information in the rendering context.
694694
*
695-
* Since QGIS 3.22, the optional \a points and \a rings arguments can specify the original
696-
* points and rings in which are being rendered by the parent symbol.
695+
* Since QGIS 3.22, the optional \a geometryType, \a points and \a rings arguments can specify the original
696+
* geometry type, points and rings in which are being rendered by the parent symbol.
697697
*/
698-
void renderUsingLayer( QgsSymbolLayer *layer, QgsSymbolRenderContext &context, const QPolygonF *points = nullptr, const QVector<QPolygonF> *rings = nullptr );
698+
void renderUsingLayer( QgsSymbolLayer *layer, QgsSymbolRenderContext &context, QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::GeometryType::UnknownGeometry, const QPolygonF *points = nullptr, const QVector<QPolygonF> *rings = nullptr );
699699

700700
/**
701701
* Render editing vertex marker at specified point

‎tests/src/python/test_qgsgeometrygeneratorsymbollayer.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@
4242
Qgis,
4343
QgsUnitTypes,
4444
QgsRenderContext,
45-
QgsRenderChecker
45+
QgsRenderChecker,
46+
QgsCoordinateReferenceSystem,
47+
QgsCoordinateTransform
4648
)
4749

4850
from qgis.testing import start_app, unittest
@@ -293,6 +295,34 @@ def test_no_feature(self):
293295

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

298+
def test_no_feature_coordinate_transform(self):
299+
"""
300+
Test rendering as a pure symbol, no feature associated, with coordinate transform
301+
"""
302+
buffer_layer = QgsGeometryGeneratorSymbolLayer.create({'geometryModifier': 'buffer($geometry, 5)'})
303+
buffer_layer.setSymbolType(QgsSymbol.Fill)
304+
buffer_layer.setUnits(QgsUnitTypes.RenderMillimeters)
305+
self.assertIsNotNone(buffer_layer.subSymbol())
306+
307+
symbol = QgsLineSymbol()
308+
symbol.changeSymbolLayer(0, buffer_layer)
309+
310+
image = QImage(400, 400, QImage.Format_RGB32)
311+
image.fill(QColor(255, 255, 255))
312+
painter = QPainter(image)
313+
314+
context = QgsRenderContext.fromQPainter(painter)
315+
context.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance().transformContext()))
316+
317+
symbol.startRender(context)
318+
319+
symbol.renderPolyline(QPolygonF([QPointF(50, 200), QPointF(100, 170), QPointF(350, 270)]), None, context)
320+
321+
symbol.stopRender(context)
322+
painter.end()
323+
324+
self.assertTrue(self.imageCheck('geometrygenerator_nofeature', 'geometrygenerator_nofeature', image))
325+
296326
def imageCheck(self, name, reference_image, image):
297327
self.report += "<h2>Render {}</h2>\n".format(name)
298328
temp_dir = QDir.tempPath() + '/'

0 commit comments

Comments
 (0)
Please sign in to comment.