QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgspointdisplacementrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointdisplacementrenderer.cpp
3 --------------------------------
4 begin : January 26, 2010
5 copyright : (C) 2010 by Marco Hugentobler
6 email : marco at hugis dot net
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19#include "qgssymbollayerutils.h"
20#include "qgsfontutils.h"
24#include "qgsmarkersymbol.h"
25#include "qgsunittypes.h"
26#include "qgscolorutils.h"
27
28#include <QPainter>
29#include <cmath>
30
32 : QgsPointDistanceRenderer( QStringLiteral( "pointDisplacement" ), labelAttributeName )
33 , mCircleColor( QColor( 125, 125, 125 ) )
34{
35 mCenterSymbol.reset( new QgsMarkerSymbol() );
36}
37
39{
41 if ( mRenderer )
42 r->setEmbeddedRenderer( mRenderer->clone() );
43 r->setCircleWidth( mCircleWidth );
44 r->setCircleColor( mCircleColor );
47 r->setPlacement( mPlacement );
48 r->setCircleRadiusAddition( mCircleRadiusAddition );
49 r->setLabelDistanceFactor( mLabelDistanceFactor );
54 if ( mCenterSymbol )
55 {
56 r->setCenterSymbol( mCenterSymbol->clone() );
57 }
59 return r;
60}
61
62void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderContext &context, const ClusteredGroup &group ) const
63{
64
65 //calculate max diagonal size from all symbols in group
66 double diagonal = 0;
67 QVector<double> diagonals( group.size() );
68 double currentDiagonal;
69
70 int groupPosition = 0;
71 for ( const GroupedFeature &feature : group )
72 {
73 if ( QgsMarkerSymbol *symbol = feature.symbol() )
74 {
75 currentDiagonal = M_SQRT2 * symbol->size( context );
76 diagonals[groupPosition] = currentDiagonal;
77 diagonal = std::max( diagonal, currentDiagonal );
78
79 }
80 else
81 {
82 diagonals[groupPosition] = 0.0;
83 }
84 groupPosition++;
85 }
86
87 QgsSymbolRenderContext symbolContext( context, Qgis::RenderUnit::Millimeters, 1.0, false );
88
89 QList<QPointF> symbolPositions;
90 QList<QPointF> labelPositions;
91 double circleRadius = -1.0;
92 double gridRadius = -1.0;
93 int gridSize = -1;
94
95 calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius, gridRadius, gridSize, diagonals );
96
97 //only draw circle/grid if there's a pen present - otherwise skip drawing transparent grids
98 if ( mCircleColor.isValid() && mCircleColor.alpha() > 0 )
99 {
100 switch ( mPlacement )
101 {
102 case Ring:
103 case ConcentricRings:
104 drawCircle( circleRadius, symbolContext, centerPoint, group.size() );
105 break;
106 case Grid:
107 drawGrid( gridSize, symbolContext, symbolPositions, group.size() );
108 break;
109 }
110 }
111
112 if ( group.size() > 1 )
113 {
114 //draw mid point
115 const QgsFeature firstFeature = group.at( 0 ).feature;
116 if ( mCenterSymbol )
117 {
118 mCenterSymbol->renderPoint( centerPoint, &firstFeature, context, -1, false );
119 }
120 else
121 {
122 const double rectSize = symbolContext.renderContext().convertToPainterUnits( 1, Qgis::RenderUnit::Millimeters );
123 context.painter()->drawRect( QRectF( centerPoint.x() - rectSize, centerPoint.y() - rectSize, rectSize * 2, rectSize * 2 ) );
124 }
125 }
126
127 //draw symbols on the circle
128 drawSymbols( group, context, symbolPositions );
129 //and also the labels
130 if ( mLabelIndex >= 0 )
131 {
132 drawLabels( centerPoint, symbolContext, labelPositions, group );
133 }
134}
135
136
138{
139 if ( mCenterSymbol )
140 {
141 mCenterSymbol->startRender( context, fields );
142 }
143
144 QgsPointDistanceRenderer::startRender( context, fields );
145}
146
148{
150 if ( mCenterSymbol )
151 {
152 mCenterSymbol->stopRender( context );
153 }
154}
155
157{
159 r->setLabelAttributeName( symbologyElem.attribute( QStringLiteral( "labelAttributeName" ) ) );
160 QFont labelFont;
161 if ( !QgsFontUtils::setFromXmlChildNode( labelFont, symbologyElem, QStringLiteral( "labelFontProperties" ) ) )
162 {
163 labelFont.fromString( symbologyElem.attribute( QStringLiteral( "labelFont" ), QString() ) );
164 }
166 r->setPlacement( static_cast< Placement >( symbologyElem.attribute( QStringLiteral( "placement" ), QStringLiteral( "0" ) ).toInt() ) );
167 r->setCircleWidth( symbologyElem.attribute( QStringLiteral( "circleWidth" ), QStringLiteral( "0.4" ) ).toDouble() );
168 r->setCircleColor( QgsColorUtils::colorFromString( symbologyElem.attribute( QStringLiteral( "circleColor" ), QString() ) ) );
169 r->setLabelColor( QgsColorUtils::colorFromString( symbologyElem.attribute( QStringLiteral( "labelColor" ), QString() ) ) );
170 r->setCircleRadiusAddition( symbologyElem.attribute( QStringLiteral( "circleRadiusAddition" ), QStringLiteral( "0.0" ) ).toDouble() );
171 r->setLabelDistanceFactor( symbologyElem.attribute( QStringLiteral( "labelDistanceFactor" ), QStringLiteral( "0.5" ) ).toDouble() );
172 r->setMinimumLabelScale( symbologyElem.attribute( QStringLiteral( "maxLabelScaleDenominator" ), QStringLiteral( "-1" ) ).toDouble() );
173 r->setTolerance( symbologyElem.attribute( QStringLiteral( "tolerance" ), QStringLiteral( "0.00001" ) ).toDouble() );
174 r->setToleranceUnit( QgsUnitTypes::decodeRenderUnit( symbologyElem.attribute( QStringLiteral( "toleranceUnit" ), QStringLiteral( "MapUnit" ) ) ) );
175 r->setToleranceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( symbologyElem.attribute( QStringLiteral( "toleranceUnitScale" ) ) ) );
176
177 //look for an embedded renderer <renderer-v2>
178 QDomElement embeddedRendererElem = symbologyElem.firstChildElement( QStringLiteral( "renderer-v2" ) );
179 if ( !embeddedRendererElem.isNull() )
180 {
181 r->setEmbeddedRenderer( QgsFeatureRenderer::load( embeddedRendererElem, context ) );
182 }
183
184 //center symbol
185 const QDomElement centerSymbolElem = symbologyElem.firstChildElement( QStringLiteral( "symbol" ) );
186 if ( !centerSymbolElem.isNull() )
187 {
188 r->setCenterSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( centerSymbolElem, context ) );
189 }
190 return r;
191}
192
194{
195 return mCenterSymbol.get();
196}
197
198QDomElement QgsPointDisplacementRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
199{
200 QDomElement rendererElement = doc.createElement( RENDERER_TAG_NAME );
201 rendererElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "pointDisplacement" ) );
202 rendererElement.setAttribute( QStringLiteral( "labelAttributeName" ), mLabelAttributeName );
203 rendererElement.appendChild( QgsFontUtils::toXmlElement( mLabelFont, doc, QStringLiteral( "labelFontProperties" ) ) );
204 rendererElement.setAttribute( QStringLiteral( "circleWidth" ), QString::number( mCircleWidth ) );
205 rendererElement.setAttribute( QStringLiteral( "circleColor" ), QgsColorUtils::colorToString( mCircleColor ) );
206 rendererElement.setAttribute( QStringLiteral( "labelColor" ), QgsColorUtils::colorToString( mLabelColor ) );
207 rendererElement.setAttribute( QStringLiteral( "circleRadiusAddition" ), QString::number( mCircleRadiusAddition ) );
208 rendererElement.setAttribute( QStringLiteral( "labelDistanceFactor" ), QString::number( mLabelDistanceFactor ) );
209 rendererElement.setAttribute( QStringLiteral( "placement" ), static_cast< int >( mPlacement ) );
210 rendererElement.setAttribute( QStringLiteral( "maxLabelScaleDenominator" ), QString::number( mMinLabelScale ) );
211 rendererElement.setAttribute( QStringLiteral( "tolerance" ), QString::number( mTolerance ) );
212 rendererElement.setAttribute( QStringLiteral( "toleranceUnit" ), QgsUnitTypes::encodeUnit( mToleranceUnit ) );
213 rendererElement.setAttribute( QStringLiteral( "toleranceUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mToleranceMapUnitScale ) );
214
215 if ( mRenderer )
216 {
217 const QDomElement embeddedRendererElem = mRenderer->save( doc, context );
218 rendererElement.appendChild( embeddedRendererElem );
219 }
220 if ( mCenterSymbol )
221 {
222 const QDomElement centerSymbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "centerSymbol" ), mCenterSymbol.get(), doc, context );
223 rendererElement.appendChild( centerSymbolElem );
224 }
225
226 saveRendererData( doc, rendererElement, context );
227
228 return rendererElement;
229}
230
232{
233 QSet<QString> attr = QgsPointDistanceRenderer::usedAttributes( context );
234 if ( mCenterSymbol )
235 attr.unite( mCenterSymbol->usedAttributes( context ) );
236 return attr;
237}
238
240{
241 if ( !QgsPointDistanceRenderer::accept( visitor ) )
242 return false;
243
244 if ( mCenterSymbol )
245 {
246 QgsStyleSymbolEntity entity( mCenterSymbol.get() );
247 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "center" ), QObject::tr( "Center Symbol" ) ) ) )
248 return false;
249 }
250
251 return true;
252}
253
255{
256 mCenterSymbol.reset( symbol );
257}
258
259void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition,
260 double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius, double &gridRadius,
261 int &gridSize, QVector<double> &diagonals ) const
262{
263 symbolPositions.clear();
264 labelShifts.clear();
265
266 if ( nPosition < 1 )
267 {
268 return;
269 }
270 else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position
271 {
272 const double side = std::sqrt( std::pow( symbolDiagonal, 2 ) / 2.0 );
273 symbolPositions.append( centerPoint );
274 labelShifts.append( QPointF( side * mLabelDistanceFactor, -side * mLabelDistanceFactor ) );
275 return;
276 }
277
278 const double circleAdditionPainterUnits = symbolContext.renderContext().convertToPainterUnits( mCircleRadiusAddition, Qgis::RenderUnit::Millimeters );
279
280 switch ( mPlacement )
281 {
282 case Ring:
283 {
284 const double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI );
285 const double radius = std::max( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits;
286
287 const double angleStep = 2 * M_PI / nPosition;
288 double currentAngle = 0.0;
289 for ( int featureIndex = 0; featureIndex < nPosition; currentAngle += angleStep, featureIndex++ )
290 {
291 const double sinusCurrentAngle = std::sin( currentAngle );
292 const double cosinusCurrentAngle = std::cos( currentAngle );
293 const QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
294
295 const QPointF labelShift( ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
296 symbolPositions.append( centerPoint + positionShift );
297 labelShifts.append( labelShift );
298 }
299 circleRadius = radius;
300 break;
301 }
302 case ConcentricRings:
303 {
304 const double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
305
306 int pointsRemaining = nPosition;
307 int ringNumber = 1;
308 const double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0;
309 int featureIndex = 0;
310 while ( pointsRemaining > 0 )
311 {
312 const double radiusCurrentRing = std::max( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 );
313 const int maxPointsCurrentRing = std::max( std::floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 );
314 const int actualPointsCurrentRing = std::min( maxPointsCurrentRing, pointsRemaining );
315
316 const double angleStep = 2 * M_PI / actualPointsCurrentRing;
317 double currentAngle = 0.0;
318 for ( int i = 0; i < actualPointsCurrentRing; ++i )
319 {
320 const double sinusCurrentAngle = std::sin( currentAngle );
321 const double cosinusCurrentAngle = std::cos( currentAngle );
322 const QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle );
323 const QPointF labelShift( ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
324 symbolPositions.append( centerPoint + positionShift );
325 labelShifts.append( labelShift );
326 currentAngle += angleStep;
327 featureIndex++;
328 }
329
330 pointsRemaining -= actualPointsCurrentRing;
331 ringNumber++;
332 circleRadius = radiusCurrentRing;
333 }
334 break;
335 }
336 case Grid:
337 {
338 const double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
339 int pointsRemaining = nPosition;
340 gridSize = std::ceil( std::sqrt( pointsRemaining ) );
341 if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )
342 gridSize -= 1;
343 const double originalPointRadius = ( ( centerDiagonal / 2.0 + symbolDiagonal / 2.0 ) + symbolDiagonal ) / 2;
344 const double userPointRadius = originalPointRadius + circleAdditionPainterUnits;
345
346 int yIndex = 0;
347 while ( pointsRemaining > 0 )
348 {
349 for ( int xIndex = 0; xIndex < gridSize && pointsRemaining > 0; ++xIndex )
350 {
351 const QPointF positionShift( userPointRadius * xIndex, userPointRadius * yIndex );
352 symbolPositions.append( centerPoint + positionShift );
353 pointsRemaining--;
354 }
355 yIndex++;
356 }
357
358 centralizeGrid( symbolPositions, userPointRadius, gridSize );
359
360 int xFactor;
361 int yFactor;
362 double side = 0;
363 for ( int symbolIndex = 0; symbolIndex < symbolPositions.size(); ++symbolIndex )
364 {
365 if ( symbolPositions.at( symbolIndex ).x() < centerPoint.x() )
366 {
367 xFactor = -1;
368 }
369 else
370 {
371 xFactor = 1;
372 }
373
374 if ( symbolPositions.at( symbolIndex ).y() < centerPoint.y() )
375 {
376 yFactor = 1;
377 }
378 else
379 {
380 yFactor = -1;
381 }
382
383 side = std::sqrt( std::pow( diagonals.at( symbolIndex ), 2 ) / 2.0 );
384 const QPointF labelShift( ( side * mLabelDistanceFactor * xFactor ), ( -side * mLabelDistanceFactor * yFactor ) );
385 labelShifts.append( symbolPositions.at( symbolIndex ) - centerPoint + labelShift );
386 }
387
388 gridRadius = userPointRadius;
389 break;
390 }
391 }
392}
393
394void QgsPointDisplacementRenderer::centralizeGrid( QList<QPointF> &pointSymbolPositions, double radius, int size ) const
395{
396 const double shiftAmount = -radius * ( size - 1.0 ) / 2.0;
397 const QPointF centralShift( shiftAmount, shiftAmount );
398 for ( int i = 0; i < pointSymbolPositions.size(); ++i )
399 {
400 pointSymbolPositions[i] += centralShift;
401 }
402}
403
404void QgsPointDisplacementRenderer::drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context,
405 QList<QPointF> pointSymbolPositions, int nSymbols ) const
406{
407 QPainter *p = context.renderContext().painter();
408 if ( nSymbols < 2 || !p ) //draw grid only if multiple features
409 {
410 return;
411 }
412
413 QPen gridPen( mCircleColor );
414 gridPen.setWidthF( context.renderContext().convertToPainterUnits( mCircleWidth, Qgis::RenderUnit::Millimeters ) );
415 p->setPen( gridPen );
416
417 for ( int i = 0; i < pointSymbolPositions.size(); ++i )
418 {
419 if ( i + 1 < pointSymbolPositions.size() && 0 != ( i + 1 ) % gridSizeUnits )
420 {
421 const QLineF gridLineRow( pointSymbolPositions[i], pointSymbolPositions[i + 1] );
422 p->drawLine( gridLineRow );
423 }
424
425 if ( i + gridSizeUnits < pointSymbolPositions.size() )
426 {
427 const QLineF gridLineColumn( pointSymbolPositions[i], pointSymbolPositions[i + gridSizeUnits] );
428 p->drawLine( gridLineColumn );
429 }
430 }
431}
432
433void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols ) const
434{
435 QPainter *p = context.renderContext().painter();
436 if ( nSymbols < 2 || !p ) //draw circle only if multiple features
437 {
438 return;
439 }
440
441 //draw Circle
442 QPen circlePen( mCircleColor );
443 circlePen.setWidthF( context.renderContext().convertToPainterUnits( mCircleWidth, Qgis::RenderUnit::Millimeters ) );
444 p->setPen( circlePen );
445 p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 );
446}
447
448void QgsPointDisplacementRenderer::drawSymbols( const ClusteredGroup &group, QgsRenderContext &context, const QList<QPointF> &symbolPositions ) const
449{
450 QList<QPointF>::const_iterator symbolPosIt = symbolPositions.constBegin();
451 ClusteredGroup::const_iterator groupIt = group.constBegin();
452 for ( ; symbolPosIt != symbolPositions.constEnd() && groupIt != group.constEnd();
453 ++symbolPosIt, ++groupIt )
454 {
455 context.expressionContext().setFeature( groupIt->feature );
456 groupIt->symbol()->startRender( context );
457 groupIt->symbol()->renderPoint( *symbolPosIt, &( groupIt->feature ), context, -1, groupIt->isSelected );
458 if ( context.hasRenderedFeatureHandlers() )
459 {
460 const QgsGeometry bounds( QgsGeometry::fromRect( QgsRectangle( groupIt->symbol()->bounds( *symbolPosIt, context, groupIt->feature ) ) ) );
461 const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
463 for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
464 handler->handleRenderedFeature( groupIt->feature, bounds, featureContext );
465 }
466 groupIt->symbol()->stopRender( context );
467 }
468}
469
471{
472 if ( renderer->type() == QLatin1String( "pointDisplacement" ) )
473 {
474 return dynamic_cast<QgsPointDisplacementRenderer *>( renderer->clone() );
475 }
476 else if ( renderer->type() == QLatin1String( "singleSymbol" ) ||
477 renderer->type() == QLatin1String( "categorizedSymbol" ) ||
478 renderer->type() == QLatin1String( "graduatedSymbol" ) ||
479 renderer->type() == QLatin1String( "RuleRenderer" ) )
480 {
482 pointRenderer->setEmbeddedRenderer( renderer->clone() );
483 renderer->copyRendererData( pointRenderer );
484 return pointRenderer;
485 }
486 else if ( renderer->type() == QLatin1String( "pointCluster" ) )
487 {
489 const QgsPointClusterRenderer *clusterRenderer = static_cast< const QgsPointClusterRenderer * >( renderer );
490 if ( clusterRenderer->embeddedRenderer() )
491 pointRenderer->setEmbeddedRenderer( clusterRenderer->embeddedRenderer()->clone() );
492 pointRenderer->setTolerance( clusterRenderer->tolerance() );
493 pointRenderer->setToleranceUnit( clusterRenderer->toleranceUnit() );
494 pointRenderer->setToleranceMapUnitScale( clusterRenderer->toleranceMapUnitScale() );
495 if ( const_cast< QgsPointClusterRenderer * >( clusterRenderer )->clusterSymbol() )
496 pointRenderer->setCenterSymbol( const_cast< QgsPointClusterRenderer * >( clusterRenderer )->clusterSymbol()->clone() );
497 renderer->copyRendererData( pointRenderer );
498 return pointRenderer;
499 }
500 else
501 {
502 return nullptr;
503 }
504}
@ Millimeters
Millimeters.
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QString type() const
Definition: qgsrenderer.h:142
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:46
static QgsFeatureRenderer * load(QDomElement &symbologyElem, const QgsReadWriteContext &context)
create a renderer from XML element
void saveRendererData(QDomDocument &doc, QDomElement &element, const QgsReadWriteContext &context)
Saves generic renderer data into the specified element.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
Container of fields for a vector layer.
Definition: qgsfields.h:45
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:162
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
A marker symbol type, for rendering Point and MultiPoint geometries.
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
A renderer that automatically clusters points with the same geographic position.
QgsMarkerSymbol * clusterSymbol()
Returns the symbol used for rendering clustered groups (but not ownership of the symbol).
A renderer that automatically displaces points with the same geographic location.
QgsPointDisplacementRenderer(const QString &labelAttributeName=QString())
Constructor for QgsPointDisplacementRenderer.
void setPlacement(Placement placement)
Sets the placement method used for dispersing the points.
void setLabelDistanceFactor(double factor)
Sets a factor for increasing the label distances from the symbol.
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
Stores renderer properties to an XML element.
QgsPointDisplacementRenderer * clone() const override
Create a deep copy of this renderer.
void setCircleColor(const QColor &color)
Sets the color used for drawing the displacement group circle.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
static QgsFeatureRenderer * create(QDomElement &symbologyElem, const QgsReadWriteContext &context)
Create a renderer from XML element.
void setCenterSymbol(QgsMarkerSymbol *symbol)
Sets the center symbol for a displacement group.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
Placement
Placement methods for dispersing points.
@ ConcentricRings
Place points in concentric rings around group.
@ Ring
Place points in a single ring around group.
@ Grid
Place points in a grid around group.
void setCircleRadiusAddition(double distance)
Sets a factor for increasing the ring size of displacement groups.
QgsMarkerSymbol * centerSymbol()
Returns the symbol for the center of a displacement group (but not ownership of the symbol).
void setCircleWidth(double width)
Sets the line width for the displacement group circle.
static QgsPointDisplacementRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
Creates a QgsPointDisplacementRenderer from an existing renderer.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
void setLabelColor(const QColor &color)
Sets the color to use for for labeling points.
double mMinLabelScale
Maximum scale denominator for label display. A zero value indicates no scale limitation.
int mLabelIndex
Label attribute index (or -1 if none). This index is not stored, it is requested in the startRender()...
QColor mLabelColor
Label text color.
QgsMapUnitScale mToleranceMapUnitScale
Map unit scale for distance tolerance.
void setLabelFont(const QFont &font)
Sets the font used for labeling points.
void setToleranceUnit(Qgis::RenderUnit unit)
Sets the units for the tolerance distance.
void drawLabels(QPointF centerPoint, QgsSymbolRenderContext &context, const QList< QPointF > &labelShifts, const ClusteredGroup &group) const
Renders the labels for a group.
void setMinimumLabelScale(double scale)
Sets the minimum map scale (i.e.
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
double tolerance() const
Returns the tolerance distance for grouping points.
QFont labelFont() const
Returns the font used for labeling points.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
const QgsMapUnitScale & toleranceMapUnitScale() const
Returns the map unit scale object for the distance tolerance.
void setEmbeddedRenderer(QgsFeatureRenderer *r) override
Sets an embedded renderer (subrenderer) for this feature renderer.
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
QString mLabelAttributeName
Attribute name for labeling. An empty string indicates that no labels should be rendered.
void setLabelAttributeName(const QString &name)
Sets the attribute name for labeling points.
double mTolerance
Distance tolerance. Points that are closer together than this distance are considered clustered.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
std::unique_ptr< QgsFeatureRenderer > mRenderer
Embedded base renderer. This can be used for rendering individual, isolated points.
Qgis::RenderUnit toleranceUnit() const
Returns the units for the tolerance distance.
void setToleranceMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the distance tolerance.
void setTolerance(double distance)
Sets the tolerance distance for grouping points.
Qgis::RenderUnit mToleranceUnit
Unit for distance tolerance.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
The class is used as a container of context for various read/write operations on other objects.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
Contains information about the context of a rendering operation.
bool hasRenderedFeatureHandlers() const
Returns true if the context has any rendered feature handlers.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
QList< QgsRenderedFeatureHandlerInterface * > renderedFeatureHandlers() const
Returns the list of rendered feature handlers to use while rendering map layers.
An interface for classes which provider custom handlers for features rendered as part of a map render...
An interface for classes which can visit style entity (e.g.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1372
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
#define RENDERER_TAG_NAME
Definition: qgsrenderer.h:50
Contains information relating to the style entity currently being visited.