QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 }
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
void setOffset(QPointF offset)
Sets the marker&#39;s offset, which is the horizontal and vertical displacement which the rendered marker...
The class is used as a container of context for various read/write operations on other objects...
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:971
QgsUnitTypes::RenderUnit mToleranceUnit
Unit for distance tolerance.
QgsFeatureRequest::OrderBy mOrderBy
Definition: qgsrenderer.h:533
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the 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.
void setLabelFont(const QFont &font)
Sets the font used for labeling points.
QgsMarkerSymbol * clusterSymbol()
Returns the symbol used for rendering clustered groups (but not ownership of the symbol).
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
void setTolerance(double distance)
Sets the tolerance distance for grouping points.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
void setLabelColor(const QColor &color)
Sets the color to use for for labeling points.
void setToleranceMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the distance tolerance.
void setToleranceUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the tolerance distance.
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Container of fields for a vector layer.
Definition: qgsfields.h:42
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
#define RENDERER_TAG_NAME
Definition: qgsrenderer.h:50
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
QgsPaintEffect * mPaintEffect
Definition: qgsrenderer.h:517
An interface for classes which can visit style entity (e.g.
QgsUnitTypes::RenderUnit toleranceUnit() const
Returns the units for the tolerance distance.
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:860
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:426
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
double mMinLabelScale
Maximum scale denominator for label display. A zero value indicates no scale limitation.
virtual void setColor(const QColor &color)
The fill color.
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:1647
static QgsPointClusterRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
Creates a QgsPointClusterRenderer from an existing renderer.
QString type() const
Definition: qgsrenderer.h:130
double mTolerance
Distance tolerance. Points that are closer together than this distance are considered clustered...
static QgsFeatureRenderer * load(QDomElement &symbologyElem, const QgsReadWriteContext &context)
create a renderer from XML element
static QgsFeatureRenderer * create(QDomElement &symbologyElem, const QgsReadWriteContext &context)
Creates a renderer from XML element.
A renderer that automatically clusters points with the same geographic position.
QColor mLabelColor
Label text color.
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.
Character, eg for font marker symbol layers.
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
QgsMapUnitScale mToleranceMapUnitScale
Map unit scale for distance tolerance.
double tolerance() const
Returns the tolerance distance for grouping points.
const QgsMapUnitScale & toleranceMapUnitScale() const
Returns the map unit scale object for the distance tolerance.
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
A renderer that automatically displaces points with the same geographic location. ...
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
Contains information about the context of a rendering operation.
void setMinimumLabelScale(double scale)
Sets the minimum map scale (i.e.
std::unique_ptr< QgsFeatureRenderer > mRenderer
Embedded base renderer. This can be used for rendering individual, isolated points.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
virtual void setSize(double size)
Sets the symbol size.
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:49
void setFontFamily(const QString &family)
Sets the font family for the font which will be used to render the point.
QList< QgsPointDistanceRenderer::GroupedFeature > ClusteredGroup
A group of clustered points (ie features within the distance tolerance).
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
void setEmbeddedRenderer(QgsFeatureRenderer *r) override
Sets an embedded renderer (subrenderer) for this feature renderer.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:449
Contains information relating to the style entity currently being visited.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.