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