QGIS API Documentation  3.20.0-Odense (decaadbb31)
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  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  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( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
198  rendererElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "pointDisplacement" ) );
199  rendererElement.setAttribute( QStringLiteral( "labelAttributeName" ), mLabelAttributeName );
200  rendererElement.appendChild( QgsFontUtils::toXmlElement( mLabelFont, doc, QStringLiteral( "labelFontProperties" ) ) );
201  rendererElement.setAttribute( QStringLiteral( "circleWidth" ), QString::number( mCircleWidth ) );
202  rendererElement.setAttribute( QStringLiteral( "circleColor" ), QgsSymbolLayerUtils::encodeColor( mCircleColor ) );
203  rendererElement.setAttribute( QStringLiteral( "labelColor" ), QgsSymbolLayerUtils::encodeColor( mLabelColor ) );
204  rendererElement.setAttribute( QStringLiteral( "circleRadiusAddition" ), QString::number( mCircleRadiusAddition ) );
205  rendererElement.setAttribute( QStringLiteral( "labelDistanceFactor" ), QString::number( mLabelDistanceFactor ) );
206  rendererElement.setAttribute( QStringLiteral( "placement" ), static_cast< int >( mPlacement ) );
207  rendererElement.setAttribute( QStringLiteral( "maxLabelScaleDenominator" ), QString::number( mMinLabelScale ) );
208  rendererElement.setAttribute( QStringLiteral( "tolerance" ), QString::number( mTolerance ) );
209  rendererElement.setAttribute( QStringLiteral( "toleranceUnit" ), QgsUnitTypes::encodeUnit( mToleranceUnit ) );
210  rendererElement.setAttribute( QStringLiteral( "toleranceUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mToleranceMapUnitScale ) );
211 
212  if ( mRenderer )
213  {
214  QDomElement embeddedRendererElem = mRenderer->save( doc, context );
215  rendererElement.appendChild( embeddedRendererElem );
216  }
217  if ( mCenterSymbol )
218  {
219  QDomElement centerSymbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "centerSymbol" ), mCenterSymbol.get(), doc, context );
220  rendererElement.appendChild( centerSymbolElem );
221  }
222 
224  mPaintEffect->saveProperties( doc, rendererElement );
225 
226  if ( !mOrderBy.isEmpty() )
227  {
228  QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
229  mOrderBy.save( orderBy );
230  rendererElement.appendChild( orderBy );
231  }
232  rendererElement.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
233 
234  return rendererElement;
235 }
236 
238 {
239  QSet<QString> attr = QgsPointDistanceRenderer::usedAttributes( context );
240  if ( mCenterSymbol )
241  attr.unite( mCenterSymbol->usedAttributes( context ) );
242  return attr;
243 }
244 
246 {
247  if ( !QgsPointDistanceRenderer::accept( visitor ) )
248  return false;
249 
250  if ( mCenterSymbol )
251  {
252  QgsStyleSymbolEntity entity( mCenterSymbol.get() );
253  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "center" ), QObject::tr( "Center Symbol" ) ) ) )
254  return false;
255  }
256 
257  return true;
258 }
259 
261 {
262  mCenterSymbol.reset( symbol );
263 }
264 
265 void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition,
266  double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius, double &gridRadius,
267  int &gridSize, QVector<double> &diagonals ) const
268 {
269  symbolPositions.clear();
270  labelShifts.clear();
271 
272  if ( nPosition < 1 )
273  {
274  return;
275  }
276  else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position
277  {
278  const double side = std::sqrt( std::pow( symbolDiagonal, 2 ) / 2.0 );
279  symbolPositions.append( centerPoint );
280  labelShifts.append( QPointF( side * mLabelDistanceFactor, -side * mLabelDistanceFactor ) );
281  return;
282  }
283 
284  double circleAdditionPainterUnits = symbolContext.renderContext().convertToPainterUnits( mCircleRadiusAddition, QgsUnitTypes::RenderMillimeters );
285 
286  switch ( mPlacement )
287  {
288  case Ring:
289  {
290  const double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI );
291  const double radius = std::max( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits;
292 
293  const double angleStep = 2 * M_PI / nPosition;
294  double currentAngle = 0.0;
295  for ( int featureIndex = 0; featureIndex < nPosition; currentAngle += angleStep, featureIndex++ )
296  {
297  const double sinusCurrentAngle = std::sin( currentAngle );
298  const double cosinusCurrentAngle = std::cos( currentAngle );
299  const QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
300 
301  const QPointF labelShift( ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
302  symbolPositions.append( centerPoint + positionShift );
303  labelShifts.append( labelShift );
304  }
305  circleRadius = radius;
306  break;
307  }
308  case ConcentricRings:
309  {
310  double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
311 
312  int pointsRemaining = nPosition;
313  int ringNumber = 1;
314  double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0;
315  int featureIndex = 0;
316  while ( pointsRemaining > 0 )
317  {
318  double radiusCurrentRing = std::max( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 );
319  int maxPointsCurrentRing = std::max( std::floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 );
320  int actualPointsCurrentRing = std::min( maxPointsCurrentRing, pointsRemaining );
321 
322  double angleStep = 2 * M_PI / actualPointsCurrentRing;
323  double currentAngle = 0.0;
324  for ( int i = 0; i < actualPointsCurrentRing; ++i )
325  {
326  double sinusCurrentAngle = std::sin( currentAngle );
327  double cosinusCurrentAngle = std::cos( currentAngle );
328  QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle );
329  QPointF labelShift( ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
330  symbolPositions.append( centerPoint + positionShift );
331  labelShifts.append( labelShift );
332  currentAngle += angleStep;
333  featureIndex++;
334  }
335 
336  pointsRemaining -= actualPointsCurrentRing;
337  ringNumber++;
338  circleRadius = radiusCurrentRing;
339  }
340  break;
341  }
342  case Grid:
343  {
344  double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
345  int pointsRemaining = nPosition;
346  gridSize = std::ceil( std::sqrt( pointsRemaining ) );
347  if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )
348  gridSize -= 1;
349  double originalPointRadius = ( ( centerDiagonal / 2.0 + symbolDiagonal / 2.0 ) + symbolDiagonal ) / 2;
350  double userPointRadius = originalPointRadius + circleAdditionPainterUnits;
351 
352  int yIndex = 0;
353  while ( pointsRemaining > 0 )
354  {
355  for ( int xIndex = 0; xIndex < gridSize && pointsRemaining > 0; ++xIndex )
356  {
357  QPointF positionShift( userPointRadius * xIndex, userPointRadius * yIndex );
358  symbolPositions.append( centerPoint + positionShift );
359  pointsRemaining--;
360  }
361  yIndex++;
362  }
363 
364  centralizeGrid( symbolPositions, userPointRadius, gridSize );
365 
366  int xFactor;
367  int yFactor;
368  double side = 0;
369  for ( int symbolIndex = 0; symbolIndex < symbolPositions.size(); ++symbolIndex )
370  {
371  if ( symbolPositions.at( symbolIndex ).x() < centerPoint.x() )
372  {
373  xFactor = -1;
374  }
375  else
376  {
377  xFactor = 1;
378  }
379 
380  if ( symbolPositions.at( symbolIndex ).y() < centerPoint.y() )
381  {
382  yFactor = 1;
383  }
384  else
385  {
386  yFactor = -1;
387  }
388 
389  side = std::sqrt( std::pow( diagonals.at( symbolIndex ), 2 ) / 2.0 );
390  QPointF labelShift( ( side * mLabelDistanceFactor * xFactor ), ( -side * mLabelDistanceFactor * yFactor ) );
391  labelShifts.append( symbolPositions.at( symbolIndex ) - centerPoint + labelShift );
392  }
393 
394  gridRadius = userPointRadius;
395  break;
396  }
397  }
398 }
399 
400 void QgsPointDisplacementRenderer::centralizeGrid( QList<QPointF> &pointSymbolPositions, double radius, int size ) const
401 {
402  double shiftAmount = -radius * ( size - 1.0 ) / 2.0;
403  QPointF centralShift( shiftAmount, shiftAmount );
404  for ( int i = 0; i < pointSymbolPositions.size(); ++i )
405  {
406  pointSymbolPositions[i] += centralShift;
407  }
408 }
409 
410 void QgsPointDisplacementRenderer::drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context,
411  QList<QPointF> pointSymbolPositions, int nSymbols )
412 {
413  QPainter *p = context.renderContext().painter();
414  if ( nSymbols < 2 || !p ) //draw grid only if multiple features
415  {
416  return;
417  }
418 
419  QPen gridPen( mCircleColor );
420  gridPen.setWidthF( context.renderContext().convertToPainterUnits( mCircleWidth, QgsUnitTypes::RenderMillimeters ) );
421  p->setPen( gridPen );
422 
423  for ( int i = 0; i < pointSymbolPositions.size(); ++i )
424  {
425  if ( i + 1 < pointSymbolPositions.size() && 0 != ( i + 1 ) % gridSizeUnits )
426  {
427  QLineF gridLineRow( pointSymbolPositions[i], pointSymbolPositions[i + 1] );
428  p->drawLine( gridLineRow );
429  }
430 
431  if ( i + gridSizeUnits < pointSymbolPositions.size() )
432  {
433  QLineF gridLineColumn( pointSymbolPositions[i], pointSymbolPositions[i + gridSizeUnits] );
434  p->drawLine( gridLineColumn );
435  }
436  }
437 }
438 
439 void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols )
440 {
441  QPainter *p = context.renderContext().painter();
442  if ( nSymbols < 2 || !p ) //draw circle only if multiple features
443  {
444  return;
445  }
446 
447  //draw Circle
448  QPen circlePen( mCircleColor );
449  circlePen.setWidthF( context.renderContext().convertToPainterUnits( mCircleWidth, QgsUnitTypes::RenderMillimeters ) );
450  p->setPen( circlePen );
451  p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 );
452 }
453 
454 void QgsPointDisplacementRenderer::drawSymbols( const ClusteredGroup &group, QgsRenderContext &context, const QList<QPointF> &symbolPositions )
455 {
456  QList<QPointF>::const_iterator symbolPosIt = symbolPositions.constBegin();
457  ClusteredGroup::const_iterator groupIt = group.constBegin();
458  for ( ; symbolPosIt != symbolPositions.constEnd() && groupIt != group.constEnd();
459  ++symbolPosIt, ++groupIt )
460  {
461  context.expressionContext().setFeature( groupIt->feature );
462  groupIt->symbol()->startRender( context );
463  groupIt->symbol()->renderPoint( *symbolPosIt, &( groupIt->feature ), context, -1, groupIt->isSelected );
464  if ( context.hasRenderedFeatureHandlers() )
465  {
466  const QgsGeometry bounds( QgsGeometry::fromRect( QgsRectangle( groupIt->symbol()->bounds( *symbolPosIt, context, groupIt->feature ) ) ) );
467  const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
469  for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
470  handler->handleRenderedFeature( groupIt->feature, bounds, featureContext );
471  }
472  groupIt->symbol()->stopRender( context );
473  }
474 }
475 
477 {
478  if ( renderer->type() == QLatin1String( "pointDisplacement" ) )
479  {
480  return dynamic_cast<QgsPointDisplacementRenderer *>( renderer->clone() );
481  }
482  else if ( renderer->type() == QLatin1String( "singleSymbol" ) ||
483  renderer->type() == QLatin1String( "categorizedSymbol" ) ||
484  renderer->type() == QLatin1String( "graduatedSymbol" ) ||
485  renderer->type() == QLatin1String( "RuleRenderer" ) )
486  {
488  pointRenderer->setEmbeddedRenderer( renderer->clone() );
489  return pointRenderer;
490  }
491  else if ( renderer->type() == QLatin1String( "pointCluster" ) )
492  {
494  const QgsPointClusterRenderer *clusterRenderer = static_cast< const QgsPointClusterRenderer * >( renderer );
495  if ( clusterRenderer->embeddedRenderer() )
496  pointRenderer->setEmbeddedRenderer( clusterRenderer->embeddedRenderer()->clone() );
497  pointRenderer->setTolerance( clusterRenderer->tolerance() );
498  pointRenderer->setToleranceUnit( clusterRenderer->toleranceUnit() );
499  pointRenderer->setToleranceMapUnitScale( clusterRenderer->toleranceMapUnitScale() );
500  if ( const_cast< QgsPointClusterRenderer * >( clusterRenderer )->clusterSymbol() )
501  pointRenderer->setCenterSymbol( const_cast< QgsPointClusterRenderer * >( clusterRenderer )->clusterSymbol()->clone() );
502  return pointRenderer;
503  }
504  else
505  {
506  return nullptr;
507  }
508 }
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.
QgsPaintEffect * mPaintEffect
Definition: qgsrenderer.h:537
QString type() const
Definition: qgsrenderer.h:141
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
QgsFeatureRequest::OrderBy mOrderBy
Definition: qgsrenderer.h:553
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
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.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
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
store renderer info to 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.
QList< QgsRenderedFeatureHandlerInterface * > renderedFeatureHandlers() const
Returns the list of rendered feature handlers to use while rendering map layers.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
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:49
Contains information relating to the style entity currently being visited.