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