QGIS API Documentation  3.21.0-Master (5b68dc587e)
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"
21 #include "qgspainteffectregistry.h"
22 #include "qgspainteffect.h"
24 #include "qgsstyleentityvisitor.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  }
58  copyRendererData( r );
59  return r;
60 }
61 
62 void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderContext &context, const ClusteredGroup &group )
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  }
161  r->setLabelFont( labelFont );
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 
194 QDomElement 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 
255 void 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 
390 void 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 
400 void QgsPointDisplacementRenderer::drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context,
401  QList<QPointF> pointSymbolPositions, int nSymbols )
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 
429 void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols )
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 
444 void QgsPointDisplacementRenderer::drawSymbols( const ClusteredGroup &group, QgsRenderContext &context, const QList<QPointF> &symbolPositions )
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();
458  const QgsRenderedFeatureHandlerInterface::RenderedFeatureContext featureContext( context );
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.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
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.
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:124
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 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.
const QgsMapUnitScale & toleranceMapUnitScale() const
Returns the map unit scale object for the distance tolerance.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
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 drawLabels(QPointF centerPoint, QgsSymbolRenderContext &context, const QList< QPointF > &labelShifts, const ClusteredGroup &group)
Renders the labels for a group.
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.
QgsExpressionContext & expressionContext()
Gets the expression context.
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).
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:1219
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.