[symbology] When rendering features, split the geometry fetching

and preparation stage from the symbol layer rendering stage, and
ensure that QgsSymbolLayer::startFeatureRender and ::stopFeatureRender
is correctly called in the right sequence when rendering multi-layer
symbols

This fixes issues with symbol layers which rely on startFeatureRender
and stopFeatureRender to correctly render, e.g. the Random Marker Fill
symbol layer.

Before this fix, the logic looked like:

- for every symbol layer in the symbol, call startFeatureRender
- for each part in polygon, prepare the part geometry and then render each symbol layer
- for every symbol layer in the symbol, call stopFeatureRender

The issue with this approach is that symbol layers which defer
rendering to the stopFeatureRender stage are always rendered
after ALL other symbol layers in the symbol, regardless of the actual
order of the symbol layers. Ultimately this causes Random Marker Fill
layers to always render on the top of symbols.

The new logic is:
- for each part in polygon, prepare the geometry and store the result
- for each symbol layer in the symbol:
   - call startFeatureRender
   - render the layer using each of the previously prepared parts
   - call stopFeatureRender

This results in correct stacking of the random marker fill in multi
layer symbols, because the stopFeatureRender call is correctly called
before the next layer's startFeatureRender and renderPolygon calls

Also, use QVector instead of QList for rings for improved efficiency
This commit is contained in:
Nyall Dawson 2020-05-19 08:17:53 +10:00
parent ea4f2bbfb9
commit ef97e8c6fc
20 changed files with 277 additions and 117 deletions

View File

@ -45,7 +45,7 @@ Caller takes ownership of the returned symbol layer.
virtual void stopRender( QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual QgsStringMap properties() const;
@ -214,7 +214,7 @@ Caller takes ownership of the returned symbol layer.
virtual void stopRender( QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual QgsStringMap properties() const;
@ -374,7 +374,7 @@ Caller takes ownership of the returned symbol layer.
virtual void stopRender( QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual QgsStringMap properties() const;
@ -686,7 +686,7 @@ Base class for polygon renderers generating texture images*
public:
QgsImageFillSymbolLayer();
virtual void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual QgsSymbol *subSymbol();
@ -806,7 +806,7 @@ Used internally when reading/writing symbols.
virtual QString layerType() const;
virtual void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void startRender( QgsSymbolRenderContext &context );
@ -1952,7 +1952,7 @@ Caller takes ownership of the returned symbol layer.
virtual void stopRender( QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual QgsStringMap properties() const;
@ -2139,7 +2139,7 @@ Caller takes ownership of the returned symbol layer.
virtual void stopRender( QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual QgsStringMap properties() const;

View File

@ -52,7 +52,7 @@ Creates a new QgsSimpleLineSymbolLayer from an SLD XML DOM ``element``.
virtual void renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context );
virtual void renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual QgsStringMap properties() const;
@ -506,7 +506,7 @@ calculating individual symbol angles.
virtual void renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context ) ${SIP_FINAL};
virtual void renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) ${SIP_FINAL};
virtual void renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) ${SIP_FINAL};
virtual QgsUnitTypes::RenderUnit outputUnit() const ${SIP_FINAL};

View File

@ -548,7 +548,7 @@ If ``correctRingOrientation`` is ``True`` then the ring will be oriented to matc
clockwise for exterior rings and counter-clockwise for interior rings.
%End
static void _getPolygon( QPolygonF &pts, QList<QPolygonF> &holes, QgsRenderContext &context, const QgsPolygon &polygon, bool clipToExtent = true, bool correctRingOrientation = false );
static void _getPolygon( QPolygonF &pts, QVector<QPolygonF> &holes, QgsRenderContext &context, const QgsPolygon &polygon, bool clipToExtent = true, bool correctRingOrientation = false );
%Docstring
Creates a polygon in screen coordinates from a QgsPolygonXYin map coordinates
@ -1206,7 +1206,7 @@ Ownership of the ``layers`` are transferred to the symbol.
%End
void setAngle( double angle );
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layer = -1, bool selected = false );
void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layer = -1, bool selected = false );
%Docstring
Renders the symbol using the given render ``context``.

View File

@ -979,7 +979,7 @@ Renders the line symbol layer along the line joining ``points``, using the given
.. seealso:: :py:func:`renderPolygonStroke`
%End
virtual void renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
%Docstring
Renders the line symbol layer along the outline of polygon, using the given render ``context``.
@ -1167,9 +1167,11 @@ class QgsFillSymbolLayer : QgsSymbolLayer
virtual void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) = 0;
virtual void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) = 0;
%Docstring
QgsFillSymbolLayer cannot be copied
Renders the fill symbol layer for the polygon whose outer ring is defined by ``points``, using the given render ``context``.
The ``rings`` argument optionally specifies a list of polygon rings to render as holes.
%End
virtual void drawPreviewIcon( QgsSymbolRenderContext &context, QSize size );
@ -1180,7 +1182,7 @@ QgsFillSymbolLayer cannot be copied
protected:
QgsFillSymbolLayer( bool locked = false );
void _renderPolygon( QPainter *p, const QPolygonF &points, const QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
void _renderPolygon( QPainter *p, const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
%Docstring
Default method to render polygon
%End

View File

@ -713,7 +713,7 @@ Determines an SVG symbol's name from its ``path``.
Calculate the centroid point of a QPolygonF
%End
static QPointF polygonPointOnSurface( const QPolygonF &points, QList<QPolygonF> *rings = 0 );
static QPointF polygonPointOnSurface( const QPolygonF &points, const QVector<QPolygonF> *rings = 0 );
%Docstring
Calculate a point on the surface of a QPolygonF
%End

View File

@ -358,7 +358,7 @@ void QgsAnnotation::drawFrame( QgsRenderContext &context ) const
QPolygonF poly;
poly.reserve( 9 + ( mHasFixedMapPosition ? 3 : 0 ) );
QList<QPolygonF> rings; //empty list
QVector<QPolygonF> rings; //empty list
for ( int i = 0; i < 4; ++i )
{
QLineF currentSegment = segment( i, &context );

View File

@ -127,7 +127,7 @@ void QgsLayoutItemMapOverview::draw( QPainter *painter )
QPolygonF intersectPolygon;
intersectPolygon = mapTransform.map( intersectExtent );
QList<QPolygonF> rings; //empty list
QVector<QPolygonF> rings; //empty list
if ( !mInverted )
{
//Render the intersecting map extent

View File

@ -280,7 +280,7 @@ void QgsLayoutItemPage::draw( QgsLayoutItemRenderContext &context )
// round up
QPolygonF pagePolygon = QPolygonF( QRectF( maxBleedPixels, maxBleedPixels,
std::ceil( rect().width() * scale ) - 2 * maxBleedPixels, std::ceil( rect().height() * scale ) - 2 * maxBleedPixels ) );
QList<QPolygonF> rings; //empty list
QVector<QPolygonF> rings; //empty list
symbol->renderPolygon( pagePolygon, &rings, nullptr, context.renderContext() );
symbol->stopRender( context.renderContext() );

View File

@ -117,7 +117,7 @@ void QgsLayoutItemPolygon::_draw( QgsLayoutItemRenderContext &context, const QSt
double scale = context.renderContext().convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters );
QTransform t = QTransform::fromScale( scale, scale );
QList<QPolygonF> rings; //empty
QVector<QPolygonF> rings; //empty
QPainterPath polygonPath;
polygonPath.addPolygon( mPolygon );

View File

@ -217,7 +217,7 @@ void QgsLayoutItemShape::draw( QgsLayoutItemRenderContext &context )
}
}
QList<QPolygonF> rings; //empty list
QVector<QPolygonF> rings; //empty list
symbol()->startRender( context.renderContext() );
symbol()->renderPolygon( shapePolygon, &rings, nullptr, context.renderContext() );

View File

@ -263,7 +263,7 @@ void QgsSimpleFillSymbolLayer::stopRender( QgsSymbolRenderContext &context )
Q_UNUSED( context )
}
void QgsSimpleFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsSimpleFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
QPainter *p = context.renderContext().painter();
if ( !p )
@ -842,7 +842,7 @@ void QgsGradientFillSymbolLayer::stopRender( QgsSymbolRenderContext &context )
Q_UNUSED( context )
}
void QgsGradientFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsGradientFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
QPainter *p = context.renderContext().painter();
if ( !p )
@ -1129,7 +1129,7 @@ void QgsShapeburstFillSymbolLayer::stopRender( QgsSymbolRenderContext &context )
Q_UNUSED( context )
}
void QgsShapeburstFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsShapeburstFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
QPainter *p = context.renderContext().painter();
if ( !p )
@ -1560,7 +1560,7 @@ QgsImageFillSymbolLayer::QgsImageFillSymbolLayer()
setSubSymbol( new QgsLineSymbol() );
}
void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
QPainter *p = context.renderContext().painter();
if ( !p )
@ -1606,8 +1606,7 @@ void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPol
mStroke->renderPolyline( points, context.feature(), context.renderContext(), -1, SELECT_FILL_BORDER && context.selected() );
if ( rings )
{
QList<QPolygonF>::const_iterator ringIt = rings->constBegin();
for ( ; ringIt != rings->constEnd(); ++ringIt )
for ( auto ringIt = rings->constBegin(); ringIt != rings->constEnd(); ++ringIt )
{
mStroke->renderPolyline( *ringIt, context.feature(), context.renderContext(), -1, SELECT_FILL_BORDER && context.selected() );
}
@ -3507,7 +3506,7 @@ void QgsCentroidFillSymbolLayer::stopRender( QgsSymbolRenderContext &context )
mMarker->stopRender( context.renderContext() );
}
void QgsCentroidFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsCentroidFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
if ( !mPointOnAllParts )
{
@ -3758,7 +3757,7 @@ QString QgsRasterFillSymbolLayer::layerType() const
return QStringLiteral( "RasterFill" );
}
void QgsRasterFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsRasterFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
QPainter *p = context.renderContext().painter();
if ( !p )
@ -4009,7 +4008,7 @@ void QgsRandomMarkerFillSymbolLayer::stopRender( QgsSymbolRenderContext &context
mMarker->stopRender( context.renderContext() );
}
void QgsRandomMarkerFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsRandomMarkerFillSymbolLayer::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
Part part;
part.exterior = points;

View File

@ -65,7 +65,7 @@ class CORE_EXPORT QgsSimpleFillSymbolLayer : public QgsFillSymbolLayer
void stopRender( QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
QgsStringMap properties() const override;
@ -229,7 +229,7 @@ class CORE_EXPORT QgsGradientFillSymbolLayer : public QgsFillSymbolLayer
void stopRender( QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
QgsStringMap properties() const override;
@ -391,7 +391,7 @@ class CORE_EXPORT QgsShapeburstFillSymbolLayer : public QgsFillSymbolLayer
void stopRender( QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
QgsStringMap properties() const override;
@ -648,7 +648,7 @@ class CORE_EXPORT QgsImageFillSymbolLayer: public QgsFillSymbolLayer
public:
QgsImageFillSymbolLayer();
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
QgsSymbol *subSymbol() override { return mStroke.get(); }
bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ) override;
@ -754,7 +754,7 @@ class CORE_EXPORT QgsRasterFillSymbolLayer: public QgsImageFillSymbolLayer
// implemented from base classes
QString layerType() const override;
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
void startRender( QgsSymbolRenderContext &context ) override;
void stopRender( QgsSymbolRenderContext &context ) override;
QgsStringMap properties() const override;
@ -1759,7 +1759,7 @@ class CORE_EXPORT QgsRandomMarkerFillSymbolLayer : public QgsFillSymbolLayer
QString layerType() const override;
void startRender( QgsSymbolRenderContext &context ) override;
void stopRender( QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
QgsStringMap properties() const override;
QgsRandomMarkerFillSymbolLayer *clone() const override SIP_FACTORY;
@ -1895,7 +1895,7 @@ class CORE_EXPORT QgsRandomMarkerFillSymbolLayer : public QgsFillSymbolLayer
struct Part
{
QPolygonF exterior;
QList<QPolygonF> rings;
QVector<QPolygonF> rings;
};
QVector< Part > mCurrentParts;
@ -1942,7 +1942,7 @@ class CORE_EXPORT QgsCentroidFillSymbolLayer : public QgsFillSymbolLayer
void stopRender( QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
QgsStringMap properties() const override;

View File

@ -238,7 +238,7 @@ void QgsSimpleLineSymbolLayer::stopRender( QgsSymbolRenderContext &context )
Q_UNUSED( context )
}
void QgsSimpleLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsSimpleLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
QPainter *p = context.renderContext().painter();
if ( !p )
@ -263,8 +263,7 @@ void QgsSimpleLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, QLi
if ( rings )
{
//add polygon rings
QList<QPolygonF>::const_iterator it = rings->constBegin();
for ( ; it != rings->constEnd(); ++it )
for ( auto it = rings->constBegin(); it != rings->constEnd(); ++it )
{
QPolygonF ring = *it;
clipPath.addPolygon( ring );
@ -867,7 +866,7 @@ void QgsTemplatedLineSymbolLayerBase::renderPolyline( const QPolygonF &points, Q
context.renderContext().painter()->restore();
}
void QgsTemplatedLineSymbolLayerBase::renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsTemplatedLineSymbolLayerBase::renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
const QgsCurvePolygon *curvePolygon = dynamic_cast<const QgsCurvePolygon *>( context.renderContext().geometry() );

View File

@ -68,7 +68,7 @@ class CORE_EXPORT QgsSimpleLineSymbolLayer : public QgsLineSymbolLayer
void stopRender( QgsSymbolRenderContext &context ) override;
void renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context ) override;
//overridden so that clip path can be set when using draw inside polygon option
void renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
void renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
QgsStringMap properties() const override;
QgsSimpleLineSymbolLayer *clone() const override SIP_FACTORY;
void toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const override;
@ -467,7 +467,7 @@ class CORE_EXPORT QgsTemplatedLineSymbolLayerBase : public QgsLineSymbolLayer
const QgsMapUnitScale &averageAngleMapUnitScale() const { return mAverageAngleLengthMapUnitScale; }
void renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context ) FINAL;
void renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) FINAL;
void renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) FINAL;
QgsUnitTypes::RenderUnit outputUnit() const FINAL;
void setMapUnitScale( const QgsMapUnitScale &scale ) FINAL;
QgsMapUnitScale mapUnitScale() const FINAL;

View File

@ -214,15 +214,18 @@ QPolygonF QgsSymbol::_getPolygonRing( QgsRenderContext &context, const QgsCurve
return poly;
}
void QgsSymbol::_getPolygon( QPolygonF &pts, QList<QPolygonF> &holes, QgsRenderContext &context, const QgsPolygon &polygon, const bool clipToExtent, const bool correctRingOrientation )
void QgsSymbol::_getPolygon( QPolygonF &pts, QVector<QPolygonF> &holes, QgsRenderContext &context, const QgsPolygon &polygon, const bool clipToExtent, const bool correctRingOrientation )
{
holes.clear();
pts = _getPolygonRing( context, *polygon.exteriorRing(), clipToExtent, true, correctRingOrientation );
for ( int idx = 0; idx < polygon.numInteriorRings(); idx++ )
const int ringCount = polygon.numInteriorRings();
holes.reserve( ringCount );
for ( int idx = 0; idx < ringCount; idx++ )
{
const QPolygonF hole = _getPolygonRing( context, *( polygon.interiorRing( idx ) ), clipToExtent, false, correctRingOrientation );
if ( !hole.isEmpty() ) holes.append( hole );
if ( !hole.isEmpty() )
holes.append( hole );
}
}
@ -560,7 +563,7 @@ void QgsSymbol::drawPreviewIcon( QPainter *painter, QSize size, QgsRenderContext
for ( const QList< QPolygonF > &poly : polys )
{
QList< QPolygonF > rings;
QVector< QPolygonF > rings;
for ( int i = 1; i < poly.size(); ++i )
rings << poly.at( i );
lsl->renderPolygonStroke( poly.value( 0 ), &rings, symbolContext );
@ -878,8 +881,13 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
QgsGeometry renderedBoundsGeom;
startFeatureRender( feature, context, layer );
// Step 1 - collect the set of painter coordinate geometries to render.
// We do this upfront, because we only want to ever do this once, regardless how many symbol layers we need to render.
QVector< QPointF > pointsToRender;
QVector< QPolygonF > linesToRender;
QVector< QPolygonF > polygonsToRender;
QVector< QVector< QPolygonF > > polygonRingsToRender;
std::map<double, QList<unsigned int> > mapAreaToPartNum;
switch ( QgsWkbTypes::flatType( segmentizedGeometry.constGet()->wkbType() ) )
{
case QgsWkbTypes::Point:
@ -892,7 +900,8 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
const QgsPoint *point = static_cast< const QgsPoint * >( segmentizedGeometry.constGet() );
const QPointF pt = _getPoint( context, *point );
static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
pointsToRender << pt;
if ( context.hasRenderedFeatureHandlers() || context.testFlag( QgsRenderContext::DrawSymbolBounds ) )
{
@ -914,8 +923,9 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
{
markers << pt;
}
}
break;
}
case QgsWkbTypes::LineString:
{
if ( mType != QgsSymbol::Line )
@ -925,7 +935,7 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
}
const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *segmentizedGeometry.constGet() );
const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
linesToRender << pts;
if ( context.hasRenderedFeatureHandlers() )
renderedBoundsGeom = QgsGeometry::fromQPolygonF( pts );
@ -934,13 +944,14 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
{
markers = pts;
}
}
break;
}
case QgsWkbTypes::Polygon:
case QgsWkbTypes::Triangle:
{
QPolygonF pts;
QList<QPolygonF> holes;
QVector<QPolygonF> holes;
if ( mType != QgsSymbol::Fill )
{
QgsDebugMsg( QStringLiteral( "polygon can be drawn only with fill symbol!" ) );
@ -953,7 +964,8 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
break;
}
_getPolygon( pts, holes, context, polygon, !tileMapRendering && clipFeaturesToExtent(), mForceRHR );
static_cast<QgsFillSymbol *>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
polygonsToRender << pts;
polygonRingsToRender << holes;
if ( context.hasRenderedFeatureHandlers() )
renderedBoundsGeom = QgsGeometry::fromQPolygonF( pts ); // TODO - consider holes?
@ -968,8 +980,8 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
markers << hole;
}
}
}
break;
}
case QgsWkbTypes::MultiPoint:
{
@ -980,24 +992,13 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
}
const QgsMultiPoint &mp = static_cast< const QgsMultiPoint & >( *segmentizedGeometry.constGet() );
if ( drawVertexMarker && !usingSegmentizedGeometry )
{
markers.reserve( mp.numGeometries() );
}
for ( int i = 0; i < mp.numGeometries(); ++i )
{
if ( context.renderingStopped() )
break;
mSymbolRenderContext->setGeometryPartNum( i + 1 );
if ( needsExpressionContext )
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
const QgsPoint &point = static_cast< const QgsPoint & >( *mp.geometryN( i ) );
const QPointF pt = _getPoint( context, point );
static_cast<QgsMarkerSymbol *>( this )->renderPoint( pt, &feature, context, layer, selected );
pointsToRender << pt;
if ( context.hasRenderedFeatureHandlers() )
{
@ -1010,8 +1011,8 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
markers.append( pt );
}
}
}
break;
}
case QgsWkbTypes::MultiCurve:
case QgsWkbTypes::MultiLineString:
@ -1030,14 +1031,9 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
if ( context.renderingStopped() )
break;
mSymbolRenderContext->setGeometryPartNum( i + 1 );
if ( needsExpressionContext )
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
context.setGeometry( geomCollection.geometryN( i ) );
const QgsCurve &curve = dynamic_cast<const QgsCurve &>( *geomCollection.geometryN( i ) );
const QPolygonF pts = _getLineString( context, curve, !tileMapRendering && clipFeaturesToExtent() );
static_cast<QgsLineSymbol *>( this )->renderPolyline( pts, &feature, context, layer, selected );
linesToRender << pts;
if ( context.hasRenderedFeatureHandlers() )
{
@ -1049,8 +1045,8 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
markers << pts;
}
}
}
break;
}
case QgsWkbTypes::MultiSurface:
case QgsWkbTypes::MultiPolygon:
@ -1062,14 +1058,13 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
}
QPolygonF pts;
QList<QPolygonF> holes;
QVector<QPolygonF> holes;
const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
const unsigned int num = geomCollection.numGeometries();
// Sort components by approximate area (probably a bit faster than using
// area() )
std::map<double, QList<unsigned int> > mapAreaToPartNum;
for ( unsigned int i = 0; i < num; ++i )
{
const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *geomCollection.geometryN( i ) );
@ -1086,21 +1081,14 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
const QList<unsigned int> &listPartIndex = iter->second;
for ( int idx = 0; idx < listPartIndex.size(); ++idx )
{
if ( context.renderingStopped() )
break;
const unsigned i = listPartIndex[idx];
mSymbolRenderContext->setGeometryPartNum( i + 1 );
if ( needsExpressionContext )
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
context.setGeometry( geomCollection.geometryN( i ) );
const QgsPolygon &polygon = dynamic_cast<const QgsPolygon &>( *geomCollection.geometryN( i ) );
if ( !polygon.exteriorRing() )
break;
_getPolygon( pts, holes, context, polygon, !tileMapRendering && clipFeaturesToExtent(), mForceRHR );
static_cast<QgsFillSymbol *>( this )->renderPolygon( pts, ( !holes.isEmpty() ? &holes : nullptr ), &feature, context, layer, selected );
polygonsToRender << pts;
polygonRingsToRender << holes;
if ( context.hasRenderedFeatureHandlers() )
{
@ -1121,6 +1109,7 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
}
break;
}
case QgsWkbTypes::GeometryCollection:
{
const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
@ -1132,6 +1121,7 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
FALLTHROUGH
}
default:
QgsDebugMsg( QStringLiteral( "feature %1: unsupported wkb type %2/%3 for rendering" )
.arg( feature.id() )
@ -1139,7 +1129,175 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
.arg( geom.wkbType(), 0, 16 ) );
}
stopFeatureRender( feature, context, layer );
// step 2 - determine which layers to render
std::vector< int > layers;
if ( layer == -1 )
{
layers.reserve( mLayers.count() );
for ( int i = 0; i < mLayers.count(); ++i )
layers.emplace_back( i );
}
else
{
layers.emplace_back( layer );
}
// step 3 - render these geometries using the desired symbol layers.
if ( needsExpressionContext )
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_layer_count" ), mLayers.count(), true ) );
for ( const int symbolLayerIndex : layers )
{
QgsSymbolLayer *symbolLayer = mLayers.value( symbolLayerIndex );
if ( !symbolLayer || !symbolLayer->enabled() )
continue;
if ( needsExpressionContext )
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_layer_index" ), symbolLayerIndex + 1, true ) );
symbolLayer->startFeatureRender( feature, context );
switch ( QgsWkbTypes::flatType( segmentizedGeometry.constGet()->wkbType() ) )
{
case QgsWkbTypes::Point:
{
if ( pointsToRender.empty() )
{
break;
}
static_cast<QgsMarkerSymbol *>( this )->renderPoint( pointsToRender.at( 0 ), &feature, context, symbolLayerIndex, selected );
break;
}
case QgsWkbTypes::LineString:
{
if ( linesToRender.empty() )
{
break;
}
static_cast<QgsLineSymbol *>( this )->renderPolyline( linesToRender.at( 0 ), &feature, context, symbolLayerIndex, selected );
break;
}
case QgsWkbTypes::Polygon:
case QgsWkbTypes::Triangle:
{
if ( polygonsToRender.empty() )
{
break;
}
static_cast<QgsFillSymbol *>( this )->renderPolygon( polygonsToRender.at( 0 ), ( !polygonRingsToRender.at( 0 ).isEmpty() ? &polygonRingsToRender.at( 0 ) : nullptr ), &feature, context, symbolLayerIndex, selected );
break;
}
case QgsWkbTypes::MultiPoint:
{
if ( pointsToRender.empty() )
{
break;
}
const QgsMultiPoint &mp = static_cast< const QgsMultiPoint & >( *segmentizedGeometry.constGet() );
for ( int i = 0; i < mp.numGeometries(); ++i )
{
if ( context.renderingStopped() )
break;
mSymbolRenderContext->setGeometryPartNum( i + 1 );
if ( needsExpressionContext )
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
static_cast<QgsMarkerSymbol *>( this )->renderPoint( pointsToRender.at( i ), &feature, context, symbolLayerIndex, selected );
}
break;
}
case QgsWkbTypes::MultiCurve:
case QgsWkbTypes::MultiLineString:
{
if ( linesToRender.empty() )
{
break;
}
const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
const unsigned int num = geomCollection.numGeometries();
for ( unsigned int i = 0; i < num; ++i )
{
if ( context.renderingStopped() )
break;
mSymbolRenderContext->setGeometryPartNum( i + 1 );
if ( needsExpressionContext )
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
context.setGeometry( geomCollection.geometryN( i ) );
static_cast<QgsLineSymbol *>( this )->renderPolyline( linesToRender.at( 0 ), &feature, context, symbolLayerIndex, selected );
}
break;
}
case QgsWkbTypes::MultiSurface:
case QgsWkbTypes::MultiPolygon:
{
if ( polygonsToRender.empty() )
{
break;
}
// Draw starting with larger parts down to smaller parts, so that in
// case of a part being incorrectly inside another part, it is drawn
// on top of it (#15419)
std::map<double, QList<unsigned int> >::const_reverse_iterator iter = mapAreaToPartNum.rbegin();
int polyIndex = 0;
for ( ; iter != mapAreaToPartNum.rend(); ++iter )
{
const QList<unsigned int> &listPartIndex = iter->second;
for ( int idx = 0; idx < listPartIndex.size(); ++idx )
{
if ( context.renderingStopped() )
break;
const unsigned i = listPartIndex[idx];
mSymbolRenderContext->setGeometryPartNum( i + 1 );
if ( needsExpressionContext )
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1, true ) );
const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
context.setGeometry( geomCollection.geometryN( i ) );
static_cast<QgsFillSymbol *>( this )->renderPolygon( polygonsToRender.at( polyIndex ), ( !polygonRingsToRender.at( polyIndex ).isEmpty() ? &polygonRingsToRender.at( polyIndex ) : nullptr ), &feature, context, symbolLayerIndex, selected );
polyIndex++;
}
}
break;
}
case QgsWkbTypes::GeometryCollection:
{
const QgsGeometryCollection &geomCollection = dynamic_cast<const QgsGeometryCollection &>( *segmentizedGeometry.constGet() );
if ( geomCollection.numGeometries() == 0 )
{
// skip noise from empty geometry collections from simplification
break;
}
FALLTHROUGH
}
default:
QgsDebugMsg( QStringLiteral( "feature %1: unsupported wkb type %2/%3 for rendering" )
.arg( feature.id() )
.arg( QgsWkbTypes::displayString( geom.constGet()->wkbType() ) )
.arg( geom.wkbType(), 0, 16 ) );
}
symbolLayer->stopFeatureRender( feature, context );
}
if ( context.hasRenderedFeatureHandlers() )
{
@ -2055,7 +2213,7 @@ QgsFillSymbol::QgsFillSymbol( const QgsSymbolLayerList &layers )
mLayers.append( new QgsSimpleFillSymbolLayer() );
}
void QgsFillSymbol::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
void QgsFillSymbol::renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layerIdx, bool selected )
{
QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderUnknownUnit, mOpacity, selected, mRenderHints, f );
symbolContext.setOriginalGeometryType( QgsWkbTypes::PolygonGeometry );
@ -2091,7 +2249,7 @@ void QgsFillSymbol::renderPolygon( const QPolygonF &points, QList<QPolygonF> *ri
}
}
void QgsFillSymbol::renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsFillSymbol::renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
if ( layer->dataDefinedProperties().hasActiveProperties() && !layer->dataDefinedProperties().valueAsBool( QgsSymbolLayer::PropertyLayerEnabled, context.renderContext().expressionContext(), true ) )
return;
@ -2102,7 +2260,7 @@ void QgsFillSymbol::renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolyg
if ( effect && effect->enabled() )
{
QRectF bounds = polygonBounds( points, rings );
QList<QPolygonF> *translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
QVector<QPolygonF> *translatedRings = translateRings( rings, -bounds.left(), -bounds.top() );
QgsEffectPainter p( context.renderContext() );
p->translate( bounds.topLeft() );
@ -2130,13 +2288,12 @@ void QgsFillSymbol::renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolyg
}
}
QRectF QgsFillSymbol::polygonBounds( const QPolygonF &points, const QList<QPolygonF> *rings ) const
QRectF QgsFillSymbol::polygonBounds( const QPolygonF &points, const QVector<QPolygonF> *rings ) const
{
QRectF bounds = points.boundingRect();
if ( rings )
{
QList<QPolygonF>::const_iterator it = rings->constBegin();
for ( ; it != rings->constEnd(); ++it )
for ( auto it = rings->constBegin(); it != rings->constEnd(); ++it )
{
bounds = bounds.united( ( *it ).boundingRect() );
}
@ -2144,14 +2301,14 @@ QRectF QgsFillSymbol::polygonBounds( const QPolygonF &points, const QList<QPolyg
return bounds;
}
QList<QPolygonF> *QgsFillSymbol::translateRings( const QList<QPolygonF> *rings, double dx, double dy ) const
QVector<QPolygonF> *QgsFillSymbol::translateRings( const QVector<QPolygonF> *rings, double dx, double dy ) const
{
if ( !rings )
return nullptr;
QList<QPolygonF> *translatedRings = new QList<QPolygonF>;
QList<QPolygonF>::const_iterator it = rings->constBegin();
for ( ; it != rings->constEnd(); ++it )
QVector<QPolygonF> *translatedRings = new QVector<QPolygonF>;
translatedRings->reserve( rings->size() );
for ( auto it = rings->constBegin(); it != rings->constEnd(); ++it )
{
translatedRings->append( ( *it ).translated( dx, dy ) );
}

View File

@ -589,7 +589,7 @@ class CORE_EXPORT QgsSymbol
* clockwise for exterior rings and counter-clockwise for interior rings.
*
*/
static void _getPolygon( QPolygonF &pts, QList<QPolygonF> &holes, QgsRenderContext &context, const QgsPolygon &polygon, bool clipToExtent = true, bool correctRingOrientation = false );
static void _getPolygon( QPolygonF &pts, QVector<QPolygonF> &holes, QgsRenderContext &context, const QgsPolygon &polygon, bool clipToExtent = true, bool correctRingOrientation = false );
/**
* Retrieve a cloned list of all layers that make up this symbol.
@ -1242,17 +1242,17 @@ class CORE_EXPORT QgsFillSymbol : public QgsSymbol
* If \a selected is true then the symbol will be drawn using the "selected feature"
* style and colors instead of the symbol's normal style.
*/
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layer = -1, bool selected = false );
void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, const QgsFeature *f, QgsRenderContext &context, int layer = -1, bool selected = false );
QgsFillSymbol *clone() const override SIP_FACTORY;
private:
void renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
void renderPolygonUsingLayer( QgsSymbolLayer *layer, const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
//! Calculates the bounds of a polygon including rings
QRectF polygonBounds( const QPolygonF &points, const QList<QPolygonF> *rings ) const;
QRectF polygonBounds( const QPolygonF &points, const QVector<QPolygonF> *rings ) const;
//! Translates the rings in a polygon by a set distance
QList<QPolygonF> *translateRings( const QList<QPolygonF> *rings, double dx, double dy ) const;
QVector<QPolygonF> *translateRings( const QVector<QPolygonF> *rings, double dx, double dy ) const;
};
#endif

View File

@ -657,7 +657,7 @@ void QgsLineSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext &context, QSize
stopRender( context );
}
void QgsLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsLineSymbolLayer::renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
switch ( mRingFilter )
{
@ -712,7 +712,7 @@ void QgsFillSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext &context, QSize
for ( const QList< QPolygonF > &poly : polys )
{
QList< QPolygonF > rings;
QVector< QPolygonF > rings;
for ( int i = 1; i < poly.size(); ++i )
rings << poly.at( i );
renderPolygon( poly.value( 0 ), &rings, context );
@ -723,7 +723,7 @@ void QgsFillSymbolLayer::drawPreviewIcon( QgsSymbolRenderContext &context, QSize
stopRender( context );
}
void QgsFillSymbolLayer::_renderPolygon( QPainter *p, const QPolygonF &points, const QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
void QgsFillSymbolLayer::_renderPolygon( QPainter *p, const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
if ( !p )
{
@ -757,8 +757,7 @@ void QgsFillSymbolLayer::_renderPolygon( QPainter *p, const QPolygonF &points, c
if ( rings )
{
QList<QPolygonF>::const_iterator it = rings->constBegin();
for ( ; it != rings->constEnd(); ++it )
for ( auto it = rings->constBegin(); it != rings->constEnd(); ++it )
{
QPolygonF ring = *it;
path.addPolygon( ring );

View File

@ -929,7 +929,7 @@ class CORE_EXPORT QgsLineSymbolLayer : public QgsSymbolLayer
*
* \see renderPolyline()
*/
virtual void renderPolygonStroke( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual void renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
/**
* Sets the \a width of the line symbol layer.
@ -1098,7 +1098,12 @@ class CORE_EXPORT QgsFillSymbolLayer : public QgsSymbolLayer
//! QgsFillSymbolLayer cannot be copied
QgsFillSymbolLayer &operator=( const QgsFillSymbolLayer &other ) = delete;
virtual void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) = 0;
/**
* Renders the fill symbol layer for the polygon whose outer ring is defined by \a points, using the given render \a context.
*
* The \a rings argument optionally specifies a list of polygon rings to render as holes.
*/
virtual void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) = 0;
void drawPreviewIcon( QgsSymbolRenderContext &context, QSize size ) override;
@ -1108,7 +1113,7 @@ class CORE_EXPORT QgsFillSymbolLayer : public QgsSymbolLayer
protected:
QgsFillSymbolLayer( bool locked = false );
//! Default method to render polygon
void _renderPolygon( QPainter *p, const QPolygonF &points, const QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
void _renderPolygon( QPainter *p, const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context );
double mAngle = 0.0;

View File

@ -4008,7 +4008,7 @@ QPointF QgsSymbolLayerUtils::polygonCentroid( const QPolygonF &points )
return QPointF( cx, cy );
}
QPointF QgsSymbolLayerUtils::polygonPointOnSurface( const QPolygonF &points, QList<QPolygonF> *rings )
QPointF QgsSymbolLayerUtils::polygonPointOnSurface( const QPolygonF &points, const QVector<QPolygonF> *rings )
{
QPointF centroid = QgsSymbolLayerUtils::polygonCentroid( points );
@ -4022,8 +4022,7 @@ QPointF QgsSymbolLayerUtils::polygonPointOnSurface( const QPolygonF &points, QLi
{
if ( rings )
{
QList<QPolygonF>::const_iterator ringIt = rings->constBegin();
for ( ; ringIt != rings->constEnd(); ++ringIt )
for ( auto ringIt = rings->constBegin(); ringIt != rings->constEnd(); ++ringIt )
{
pointCount = ( *ringIt ).count();
QgsPolylineXY polyline( pointCount );

View File

@ -643,7 +643,7 @@ class CORE_EXPORT QgsSymbolLayerUtils
static QPointF polygonCentroid( const QPolygonF &points );
//! Calculate a point on the surface of a QPolygonF
static QPointF polygonPointOnSurface( const QPolygonF &points, QList<QPolygonF> *rings = nullptr );
static QPointF polygonPointOnSurface( const QPolygonF &points, const QVector<QPolygonF> *rings = nullptr );
//! Calculate whether a point is within of a QPolygonF
static bool pointInPolygon( const QPolygonF &points, QPointF point );