QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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
27#include <QPainter>
28#include <cmath>
29
31 : QgsPointDistanceRenderer( QStringLiteral( "pointDisplacement" ), labelAttributeName )
32 , mCircleColor( QColor( 125, 125, 125 ) )
33{
34 mCenterSymbol.reset( new QgsMarkerSymbol() );
35}
36
38{
40 if ( mRenderer )
41 r->setEmbeddedRenderer( mRenderer->clone() );
42 r->setCircleWidth( mCircleWidth );
43 r->setCircleColor( mCircleColor );
46 r->setPlacement( mPlacement );
47 r->setCircleRadiusAddition( mCircleRadiusAddition );
48 r->setLabelDistanceFactor( mLabelDistanceFactor );
53 if ( mCenterSymbol )
54 {
55 r->setCenterSymbol( mCenterSymbol->clone() );
56 }
58 return r;
59}
60
61void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderContext &context, const ClusteredGroup &group ) const
62{
63
64 //calculate max diagonal size from all symbols in group
65 double diagonal = 0;
66 QVector<double> diagonals( group.size() );
67 double currentDiagonal;
68
69 int groupPosition = 0;
70 for ( const GroupedFeature &feature : group )
71 {
72 if ( QgsMarkerSymbol *symbol = feature.symbol() )
73 {
74 currentDiagonal = M_SQRT2 * symbol->size( context );
75 diagonals[groupPosition] = currentDiagonal;
76 diagonal = std::max( diagonal, currentDiagonal );
77
78 }
79 else
80 {
81 diagonals[groupPosition] = 0.0;
82 }
83 groupPosition++;
84 }
85
86 QgsSymbolRenderContext symbolContext( context, Qgis::RenderUnit::Millimeters, 1.0, false );
87
88 QList<QPointF> symbolPositions;
89 QList<QPointF> labelPositions;
90 double circleRadius = -1.0;
91 double gridRadius = -1.0;
92 int gridSize = -1;
93
94 calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius, gridRadius, gridSize, diagonals );
95
96 //only draw circle/grid if there's a pen present - otherwise skip drawing transparent grids
97 if ( mCircleColor.isValid() && mCircleColor.alpha() > 0 )
98 {
99 switch ( mPlacement )
100 {
101 case Ring:
102 case ConcentricRings:
103 drawCircle( circleRadius, symbolContext, centerPoint, group.size() );
104 break;
105 case Grid:
106 drawGrid( gridSize, symbolContext, symbolPositions, group.size() );
107 break;
108 }
109 }
110
111 if ( group.size() > 1 )
112 {
113 //draw mid point
114 const QgsFeature firstFeature = group.at( 0 ).feature;
115 if ( mCenterSymbol )
116 {
117 mCenterSymbol->renderPoint( centerPoint, &firstFeature, context, -1, false );
118 }
119 else
120 {
121 const double rectSize = symbolContext.renderContext().convertToPainterUnits( 1, Qgis::RenderUnit::Millimeters );
122 context.painter()->drawRect( QRectF( centerPoint.x() - rectSize, centerPoint.y() - rectSize, rectSize * 2, rectSize * 2 ) );
123 }
124 }
125
126 //draw symbols on the circle
127 drawSymbols( group, context, symbolPositions );
128 //and also the labels
129 if ( mLabelIndex >= 0 )
130 {
131 drawLabels( centerPoint, symbolContext, labelPositions, group );
132 }
133}
134
135
137{
138 if ( mCenterSymbol )
139 {
140 mCenterSymbol->startRender( context, fields );
141 }
142
143 QgsPointDistanceRenderer::startRender( context, fields );
144}
145
147{
149 if ( mCenterSymbol )
150 {
151 mCenterSymbol->stopRender( context );
152 }
153}
154
156{
158 r->setLabelAttributeName( symbologyElem.attribute( QStringLiteral( "labelAttributeName" ) ) );
159 QFont labelFont;
160 if ( !QgsFontUtils::setFromXmlChildNode( labelFont, symbologyElem, QStringLiteral( "labelFontProperties" ) ) )
161 {
162 labelFont.fromString( symbologyElem.attribute( QStringLiteral( "labelFont" ), QString() ) );
163 }
165 r->setPlacement( static_cast< Placement >( symbologyElem.attribute( QStringLiteral( "placement" ), QStringLiteral( "0" ) ).toInt() ) );
166 r->setCircleWidth( symbologyElem.attribute( QStringLiteral( "circleWidth" ), QStringLiteral( "0.4" ) ).toDouble() );
167 r->setCircleColor( QgsSymbolLayerUtils::decodeColor( symbologyElem.attribute( QStringLiteral( "circleColor" ), QString() ) ) );
168 r->setLabelColor( QgsSymbolLayerUtils::decodeColor( symbologyElem.attribute( QStringLiteral( "labelColor" ), QString() ) ) );
169 r->setCircleRadiusAddition( symbologyElem.attribute( QStringLiteral( "circleRadiusAddition" ), QStringLiteral( "0.0" ) ).toDouble() );
170 r->setLabelDistanceFactor( symbologyElem.attribute( QStringLiteral( "labelDistanceFactor" ), QStringLiteral( "0.5" ) ).toDouble() );
171 r->setMinimumLabelScale( symbologyElem.attribute( QStringLiteral( "maxLabelScaleDenominator" ), QStringLiteral( "-1" ) ).toDouble() );
172 r->setTolerance( symbologyElem.attribute( QStringLiteral( "tolerance" ), QStringLiteral( "0.00001" ) ).toDouble() );
173 r->setToleranceUnit( QgsUnitTypes::decodeRenderUnit( symbologyElem.attribute( QStringLiteral( "toleranceUnit" ), QStringLiteral( "MapUnit" ) ) ) );
174 r->setToleranceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( symbologyElem.attribute( QStringLiteral( "toleranceUnitScale" ) ) ) );
175
176 //look for an embedded renderer <renderer-v2>
177 QDomElement embeddedRendererElem = symbologyElem.firstChildElement( QStringLiteral( "renderer-v2" ) );
178 if ( !embeddedRendererElem.isNull() )
179 {
180 r->setEmbeddedRenderer( QgsFeatureRenderer::load( embeddedRendererElem, context ) );
181 }
182
183 //center symbol
184 const QDomElement centerSymbolElem = symbologyElem.firstChildElement( QStringLiteral( "symbol" ) );
185 if ( !centerSymbolElem.isNull() )
186 {
187 r->setCenterSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( centerSymbolElem, context ) );
188 }
189 return r;
190}
191
193{
194 return mCenterSymbol.get();
195}
196
197QDomElement QgsPointDisplacementRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
198{
199 QDomElement rendererElement = doc.createElement( RENDERER_TAG_NAME );
200 rendererElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "pointDisplacement" ) );
201 rendererElement.setAttribute( QStringLiteral( "labelAttributeName" ), mLabelAttributeName );
202 rendererElement.appendChild( QgsFontUtils::toXmlElement( mLabelFont, doc, QStringLiteral( "labelFontProperties" ) ) );
203 rendererElement.setAttribute( QStringLiteral( "circleWidth" ), QString::number( mCircleWidth ) );
204 rendererElement.setAttribute( QStringLiteral( "circleColor" ), QgsSymbolLayerUtils::encodeColor( mCircleColor ) );
205 rendererElement.setAttribute( QStringLiteral( "labelColor" ), QgsSymbolLayerUtils::encodeColor( mLabelColor ) );
206 rendererElement.setAttribute( QStringLiteral( "circleRadiusAddition" ), QString::number( mCircleRadiusAddition ) );
207 rendererElement.setAttribute( QStringLiteral( "labelDistanceFactor" ), QString::number( mLabelDistanceFactor ) );
208 rendererElement.setAttribute( QStringLiteral( "placement" ), static_cast< int >( mPlacement ) );
209 rendererElement.setAttribute( QStringLiteral( "maxLabelScaleDenominator" ), QString::number( mMinLabelScale ) );
210 rendererElement.setAttribute( QStringLiteral( "tolerance" ), QString::number( mTolerance ) );
211 rendererElement.setAttribute( QStringLiteral( "toleranceUnit" ), QgsUnitTypes::encodeUnit( mToleranceUnit ) );
212 rendererElement.setAttribute( QStringLiteral( "toleranceUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mToleranceMapUnitScale ) );
213
214 if ( mRenderer )
215 {
216 const QDomElement embeddedRendererElem = mRenderer->save( doc, context );
217 rendererElement.appendChild( embeddedRendererElem );
218 }
219 if ( mCenterSymbol )
220 {
221 const QDomElement centerSymbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "centerSymbol" ), mCenterSymbol.get(), doc, context );
222 rendererElement.appendChild( centerSymbolElem );
223 }
224
225 saveRendererData( doc, rendererElement, context );
226
227 return rendererElement;
228}
229
231{
232 QSet<QString> attr = QgsPointDistanceRenderer::usedAttributes( context );
233 if ( mCenterSymbol )
234 attr.unite( mCenterSymbol->usedAttributes( context ) );
235 return attr;
236}
237
239{
240 if ( !QgsPointDistanceRenderer::accept( visitor ) )
241 return false;
242
243 if ( mCenterSymbol )
244 {
245 QgsStyleSymbolEntity entity( mCenterSymbol.get() );
246 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "center" ), QObject::tr( "Center Symbol" ) ) ) )
247 return false;
248 }
249
250 return true;
251}
252
254{
255 mCenterSymbol.reset( symbol );
256}
257
258void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition,
259 double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius, double &gridRadius,
260 int &gridSize, QVector<double> &diagonals ) const
261{
262 symbolPositions.clear();
263 labelShifts.clear();
264
265 if ( nPosition < 1 )
266 {
267 return;
268 }
269 else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position
270 {
271 const double side = std::sqrt( std::pow( symbolDiagonal, 2 ) / 2.0 );
272 symbolPositions.append( centerPoint );
273 labelShifts.append( QPointF( side * mLabelDistanceFactor, -side * mLabelDistanceFactor ) );
274 return;
275 }
276
277 const double circleAdditionPainterUnits = symbolContext.renderContext().convertToPainterUnits( mCircleRadiusAddition, Qgis::RenderUnit::Millimeters );
278
279 switch ( mPlacement )
280 {
281 case Ring:
282 {
283 const double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI );
284 const double radius = std::max( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits;
285
286 const double angleStep = 2 * M_PI / nPosition;
287 double currentAngle = 0.0;
288 for ( int featureIndex = 0; featureIndex < nPosition; currentAngle += angleStep, featureIndex++ )
289 {
290 const double sinusCurrentAngle = std::sin( currentAngle );
291 const double cosinusCurrentAngle = std::cos( currentAngle );
292 const QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
293
294 const QPointF labelShift( ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
295 symbolPositions.append( centerPoint + positionShift );
296 labelShifts.append( labelShift );
297 }
298 circleRadius = radius;
299 break;
300 }
301 case ConcentricRings:
302 {
303 const double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
304
305 int pointsRemaining = nPosition;
306 int ringNumber = 1;
307 const double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0;
308 int featureIndex = 0;
309 while ( pointsRemaining > 0 )
310 {
311 const double radiusCurrentRing = std::max( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 );
312 const int maxPointsCurrentRing = std::max( std::floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 );
313 const int actualPointsCurrentRing = std::min( maxPointsCurrentRing, pointsRemaining );
314
315 const double angleStep = 2 * M_PI / actualPointsCurrentRing;
316 double currentAngle = 0.0;
317 for ( int i = 0; i < actualPointsCurrentRing; ++i )
318 {
319 const double sinusCurrentAngle = std::sin( currentAngle );
320 const double cosinusCurrentAngle = std::cos( currentAngle );
321 const QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle );
322 const QPointF labelShift( ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
323 symbolPositions.append( centerPoint + positionShift );
324 labelShifts.append( labelShift );
325 currentAngle += angleStep;
326 featureIndex++;
327 }
328
329 pointsRemaining -= actualPointsCurrentRing;
330 ringNumber++;
331 circleRadius = radiusCurrentRing;
332 }
333 break;
334 }
335 case Grid:
336 {
337 const double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
338 int pointsRemaining = nPosition;
339 gridSize = std::ceil( std::sqrt( pointsRemaining ) );
340 if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )
341 gridSize -= 1;
342 const double originalPointRadius = ( ( centerDiagonal / 2.0 + symbolDiagonal / 2.0 ) + symbolDiagonal ) / 2;
343 const double userPointRadius = originalPointRadius + circleAdditionPainterUnits;
344
345 int yIndex = 0;
346 while ( pointsRemaining > 0 )
347 {
348 for ( int xIndex = 0; xIndex < gridSize && pointsRemaining > 0; ++xIndex )
349 {
350 const QPointF positionShift( userPointRadius * xIndex, userPointRadius * yIndex );
351 symbolPositions.append( centerPoint + positionShift );
352 pointsRemaining--;
353 }
354 yIndex++;
355 }
356
357 centralizeGrid( symbolPositions, userPointRadius, gridSize );
358
359 int xFactor;
360 int yFactor;
361 double side = 0;
362 for ( int symbolIndex = 0; symbolIndex < symbolPositions.size(); ++symbolIndex )
363 {
364 if ( symbolPositions.at( symbolIndex ).x() < centerPoint.x() )
365 {
366 xFactor = -1;
367 }
368 else
369 {
370 xFactor = 1;
371 }
372
373 if ( symbolPositions.at( symbolIndex ).y() < centerPoint.y() )
374 {
375 yFactor = 1;
376 }
377 else
378 {
379 yFactor = -1;
380 }
381
382 side = std::sqrt( std::pow( diagonals.at( symbolIndex ), 2 ) / 2.0 );
383 const QPointF labelShift( ( side * mLabelDistanceFactor * xFactor ), ( -side * mLabelDistanceFactor * yFactor ) );
384 labelShifts.append( symbolPositions.at( symbolIndex ) - centerPoint + labelShift );
385 }
386
387 gridRadius = userPointRadius;
388 break;
389 }
390 }
391}
392
393void QgsPointDisplacementRenderer::centralizeGrid( QList<QPointF> &pointSymbolPositions, double radius, int size ) const
394{
395 const double shiftAmount = -radius * ( size - 1.0 ) / 2.0;
396 const QPointF centralShift( shiftAmount, shiftAmount );
397 for ( int i = 0; i < pointSymbolPositions.size(); ++i )
398 {
399 pointSymbolPositions[i] += centralShift;
400 }
401}
402
403void QgsPointDisplacementRenderer::drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context,
404 QList<QPointF> pointSymbolPositions, int nSymbols ) const
405{
406 QPainter *p = context.renderContext().painter();
407 if ( nSymbols < 2 || !p ) //draw grid only if multiple features
408 {
409 return;
410 }
411
412 QPen gridPen( mCircleColor );
413 gridPen.setWidthF( context.renderContext().convertToPainterUnits( mCircleWidth, Qgis::RenderUnit::Millimeters ) );
414 p->setPen( gridPen );
415
416 for ( int i = 0; i < pointSymbolPositions.size(); ++i )
417 {
418 if ( i + 1 < pointSymbolPositions.size() && 0 != ( i + 1 ) % gridSizeUnits )
419 {
420 const QLineF gridLineRow( pointSymbolPositions[i], pointSymbolPositions[i + 1] );
421 p->drawLine( gridLineRow );
422 }
423
424 if ( i + gridSizeUnits < pointSymbolPositions.size() )
425 {
426 const QLineF gridLineColumn( pointSymbolPositions[i], pointSymbolPositions[i + gridSizeUnits] );
427 p->drawLine( gridLineColumn );
428 }
429 }
430}
431
432void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols ) const
433{
434 QPainter *p = context.renderContext().painter();
435 if ( nSymbols < 2 || !p ) //draw circle only if multiple features
436 {
437 return;
438 }
439
440 //draw Circle
441 QPen circlePen( mCircleColor );
442 circlePen.setWidthF( context.renderContext().convertToPainterUnits( mCircleWidth, Qgis::RenderUnit::Millimeters ) );
443 p->setPen( circlePen );
444 p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 );
445}
446
447void QgsPointDisplacementRenderer::drawSymbols( const ClusteredGroup &group, QgsRenderContext &context, const QList<QPointF> &symbolPositions ) const
448{
449 QList<QPointF>::const_iterator symbolPosIt = symbolPositions.constBegin();
450 ClusteredGroup::const_iterator groupIt = group.constBegin();
451 for ( ; symbolPosIt != symbolPositions.constEnd() && groupIt != group.constEnd();
452 ++symbolPosIt, ++groupIt )
453 {
454 context.expressionContext().setFeature( groupIt->feature );
455 groupIt->symbol()->startRender( context );
456 groupIt->symbol()->renderPoint( *symbolPosIt, &( groupIt->feature ), context, -1, groupIt->isSelected );
457 if ( context.hasRenderedFeatureHandlers() )
458 {
459 const QgsGeometry bounds( QgsGeometry::fromRect( QgsRectangle( groupIt->symbol()->bounds( *symbolPosIt, context, groupIt->feature ) ) ) );
460 const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
462 for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
463 handler->handleRenderedFeature( groupIt->feature, bounds, featureContext );
464 }
465 groupIt->symbol()->stopRender( context );
466 }
467}
468
470{
471 if ( renderer->type() == QLatin1String( "pointDisplacement" ) )
472 {
473 return dynamic_cast<QgsPointDisplacementRenderer *>( renderer->clone() );
474 }
475 else if ( renderer->type() == QLatin1String( "singleSymbol" ) ||
476 renderer->type() == QLatin1String( "categorizedSymbol" ) ||
477 renderer->type() == QLatin1String( "graduatedSymbol" ) ||
478 renderer->type() == QLatin1String( "RuleRenderer" ) )
479 {
481 pointRenderer->setEmbeddedRenderer( renderer->clone() );
482 renderer->copyRendererData( pointRenderer );
483 return pointRenderer;
484 }
485 else if ( renderer->type() == QLatin1String( "pointCluster" ) )
486 {
488 const QgsPointClusterRenderer *clusterRenderer = static_cast< const QgsPointClusterRenderer * >( renderer );
489 if ( clusterRenderer->embeddedRenderer() )
490 pointRenderer->setEmbeddedRenderer( clusterRenderer->embeddedRenderer()->clone() );
491 pointRenderer->setTolerance( clusterRenderer->tolerance() );
492 pointRenderer->setToleranceUnit( clusterRenderer->toleranceUnit() );
493 pointRenderer->setToleranceMapUnitScale( clusterRenderer->toleranceMapUnitScale() );
494 if ( const_cast< QgsPointClusterRenderer * >( clusterRenderer )->clusterSymbol() )
495 pointRenderer->setCenterSymbol( const_cast< QgsPointClusterRenderer * >( clusterRenderer )->clusterSymbol()->clone() );
496 renderer->copyRendererData( pointRenderer );
497 return pointRenderer;
498 }
499 else
500 {
501 return nullptr;
502 }
503}
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:164
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
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:1341
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QColor decodeColor(const QString &str)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static QString encodeColor(const QColor &color)
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.