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