QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgspointclusterrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspointclusterrenderer.cpp
3  ---------------------------
4  begin : February 2016
5  copyright : (C) 2016 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
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 
20 #include "qgssymbollayerutils.h"
21 #include "qgspainteffectregistry.h"
22 #include "qgspainteffect.h"
23 #include "qgsmarkersymbollayer.h"
24 #include "qgsproperty.h"
25 #include "qgsstyleentityvisitor.h"
26 #include <cmath>
27 
29  : QgsPointDistanceRenderer( QStringLiteral( "pointCluster" ) )
30 {
31  mClusterSymbol.reset( new QgsMarkerSymbol() );
32  mClusterSymbol->setSize( 4 );
33  mClusterSymbol->setColor( QColor( 245, 75, 80 ) );
34 
36  fm->setFontFamily( QFont().defaultFamily() );
37  fm->setColor( QColor( 255, 255, 255 ) );
38  fm->setSize( 3.2 );
39  fm->setOffset( QPointF( 0, -0.4 ) );
41  mClusterSymbol->insertSymbolLayer( 1, fm );
42 }
43 
45 {
47  if ( mRenderer )
48  r->setEmbeddedRenderer( mRenderer->clone() );
55  if ( mClusterSymbol )
56  {
57  r->setClusterSymbol( mClusterSymbol->clone() );
58  }
59  copyRendererData( r );
60  return r;
61 }
62 
63 void QgsPointClusterRenderer::drawGroup( QPointF centerPoint, QgsRenderContext &context, const ClusteredGroup &group )
64 {
65  if ( group.size() > 1 )
66  {
67  mClusterSymbol->renderPoint( centerPoint, &( group.at( 0 ).feature ), context, -1, false );
68  }
69  else
70  {
71  //single isolated symbol, draw it untouched
72  QgsMarkerSymbol *symbol = group.at( 0 ).symbol();
73  symbol->startRender( context );
74  symbol->renderPoint( centerPoint, &( group.at( 0 ).feature ), context, -1, group.at( 0 ).isSelected );
75  symbol->stopRender( context );
76  }
77 }
78 
80 {
81  if ( mClusterSymbol )
82  {
83  mClusterSymbol->startRender( context, fields );
84  }
85  QgsPointDistanceRenderer::startRender( context, fields );
86 }
87 
89 {
91  if ( mClusterSymbol )
92  {
93  mClusterSymbol->stopRender( context );
94  }
95 }
96 
97 QgsFeatureRenderer *QgsPointClusterRenderer::create( QDomElement &symbologyElem, const QgsReadWriteContext &context )
98 {
100  r->setTolerance( symbologyElem.attribute( QStringLiteral( "tolerance" ), QStringLiteral( "0.00001" ) ).toDouble() );
101  r->setToleranceUnit( QgsUnitTypes::decodeRenderUnit( symbologyElem.attribute( QStringLiteral( "toleranceUnit" ), QStringLiteral( "MapUnit" ) ) ) );
102  r->setToleranceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( symbologyElem.attribute( QStringLiteral( "toleranceUnitScale" ) ) ) );
103 
104  //look for an embedded renderer <renderer-v2>
105  QDomElement embeddedRendererElem = symbologyElem.firstChildElement( QStringLiteral( "renderer-v2" ) );
106  if ( !embeddedRendererElem.isNull() )
107  {
108  r->setEmbeddedRenderer( QgsFeatureRenderer::load( embeddedRendererElem, context ) );
109  }
110 
111  //center symbol
112  QDomElement centerSymbolElem = symbologyElem.firstChildElement( QStringLiteral( "symbol" ) );
113  if ( !centerSymbolElem.isNull() )
114  {
115  r->setClusterSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( centerSymbolElem, context ) );
116  }
117  return r;
118 }
119 
121 {
122  return mClusterSymbol.get();
123 }
124 
125 QDomElement QgsPointClusterRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
126 {
127  QDomElement rendererElement = doc.createElement( RENDERER_TAG_NAME );
128  rendererElement.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
129  rendererElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "pointCluster" ) );
130  rendererElement.setAttribute( QStringLiteral( "tolerance" ), QString::number( mTolerance ) );
131  rendererElement.setAttribute( QStringLiteral( "toleranceUnit" ), QgsUnitTypes::encodeUnit( mToleranceUnit ) );
132  rendererElement.setAttribute( QStringLiteral( "toleranceUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mToleranceMapUnitScale ) );
133 
134  if ( mRenderer )
135  {
136  QDomElement embeddedRendererElem = mRenderer->save( doc, context );
137  rendererElement.appendChild( embeddedRendererElem );
138  }
139  if ( mClusterSymbol )
140  {
141  QDomElement centerSymbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "centerSymbol" ), mClusterSymbol.get(), doc, context );
142  rendererElement.appendChild( centerSymbolElem );
143  }
144 
146  mPaintEffect->saveProperties( doc, rendererElement );
147 
148  if ( !mOrderBy.isEmpty() )
149  {
150  QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
151  mOrderBy.save( orderBy );
152  rendererElement.appendChild( orderBy );
153  }
154  rendererElement.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
155 
156  return rendererElement;
157 }
158 
159 QSet<QString> QgsPointClusterRenderer::usedAttributes( const QgsRenderContext &context ) const
160 {
161  QSet<QString> attr = QgsPointDistanceRenderer::usedAttributes( context );
162  if ( mClusterSymbol )
163  attr.unite( mClusterSymbol->usedAttributes( context ) );
164  return attr;
165 }
166 
168 {
169  if ( !QgsPointDistanceRenderer::accept( visitor ) )
170  return false;
171 
172  if ( mClusterSymbol )
173  {
174  QgsStyleSymbolEntity entity( mClusterSymbol.get() );
175  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "cluster" ), QObject::tr( "Cluster Symbol" ) ) ) )
176  return false;
177  }
178 
179  return true;
180 }
181 
183 {
184  mClusterSymbol.reset( symbol );
185 }
186 
188 {
189  if ( renderer->type() == QLatin1String( "pointCluster" ) )
190  {
191  return dynamic_cast<QgsPointClusterRenderer *>( renderer->clone() );
192  }
193  else if ( renderer->type() == QLatin1String( "singleSymbol" ) ||
194  renderer->type() == QLatin1String( "categorizedSymbol" ) ||
195  renderer->type() == QLatin1String( "graduatedSymbol" ) ||
196  renderer->type() == QLatin1String( "RuleRenderer" ) )
197  {
198  QgsPointClusterRenderer *pointRenderer = new QgsPointClusterRenderer();
199  pointRenderer->setEmbeddedRenderer( renderer->clone() );
200  return pointRenderer;
201  }
202  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) )
203  {
204  QgsPointClusterRenderer *pointRenderer = new QgsPointClusterRenderer();
205  const QgsPointDisplacementRenderer *displacementRenderer = static_cast< const QgsPointDisplacementRenderer * >( renderer );
206  if ( displacementRenderer->embeddedRenderer() )
207  pointRenderer->setEmbeddedRenderer( displacementRenderer->embeddedRenderer()->clone() );
208  pointRenderer->setTolerance( displacementRenderer->tolerance() );
209  pointRenderer->setToleranceUnit( displacementRenderer->toleranceUnit() );
210  pointRenderer->setToleranceMapUnitScale( displacementRenderer->toleranceMapUnitScale() );
211  if ( const_cast< QgsPointDisplacementRenderer * >( displacementRenderer )->centerSymbol() )
212  pointRenderer->setClusterSymbol( const_cast< QgsPointDisplacementRenderer * >( displacementRenderer )->centerSymbol()->clone() );
213  return pointRenderer;
214  }
215  else
216  {
217  return nullptr;
218  }
219 }
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
QgsPaintEffect * mPaintEffect
Definition: qgsrenderer.h:529
QString type() const
Definition: qgsrenderer.h:141
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:50
static QgsFeatureRenderer * load(QDomElement &symbologyElem, const QgsReadWriteContext &context)
create a renderer from XML element
QgsFeatureRequest::OrderBy mOrderBy
Definition: qgsrenderer.h:545
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.
Container of fields for a vector layer.
Definition: qgsfields.h:45
void setFontFamily(const QString &family)
Sets the font family for the font which will be used to render the point.
virtual void setSize(double size)
Sets the symbol size.
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:1004
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:2036
void renderPoint(QPointF point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Renders the symbol at the specified point, using the given render context.
Definition: qgssymbol.cpp:1973
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.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
QgsPointClusterRenderer * clone() const override
Create a deep copy of this renderer.
void setClusterSymbol(QgsMarkerSymbol *symbol)
Sets the symbol for rendering clustered groups.
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
store renderer info to XML element
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
static QgsFeatureRenderer * create(QDomElement &symbologyElem, const QgsReadWriteContext &context)
Creates a renderer from XML element.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
QgsMarkerSymbol * clusterSymbol()
Returns the symbol used for rendering clustered groups (but not ownership of the symbol).
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
static QgsPointClusterRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
Creates a QgsPointClusterRenderer from an existing renderer.
A renderer that automatically displaces points with the same geographic location.
QgsMarkerSymbol * centerSymbol()
Returns the symbol for the center of a displacement group (but not ownership of the symbol).
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.
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.
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.
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...
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
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:1201
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.
@ PropertyCharacter
Character, eg for font marker symbol layers.
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
virtual void setColor(const QColor &color)
The fill color.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:507
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:480
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.
#define RENDERER_TAG_NAME
Definition: qgsrenderer.h:51
Contains information relating to the style entity currently being visited.