QGIS API Documentation  3.2.0-Bonn (bc43194)
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 <cmath>
26 
28  : QgsPointDistanceRenderer( QStringLiteral( "pointCluster" ) )
29 {
30  mClusterSymbol.reset( new QgsMarkerSymbol() );
31  mClusterSymbol->setSize( 4 );
32  mClusterSymbol->setColor( QColor( 245, 75, 80 ) );
33 
35  fm->setFontFamily( QFont().defaultFamily() );
36  fm->setColor( QColor( 255, 255, 255 ) );
37  fm->setSize( 3.2 );
38  fm->setOffset( QPointF( 0, -0.4 ) );
40  mClusterSymbol->insertSymbolLayer( 1, fm );
41 }
42 
44 {
46  if ( mRenderer )
47  r->setEmbeddedRenderer( mRenderer->clone() );
54  if ( mClusterSymbol )
55  {
56  r->setClusterSymbol( mClusterSymbol->clone() );
57  }
58  copyRendererData( r );
59  return r;
60 }
61 
62 void QgsPointClusterRenderer::drawGroup( QPointF centerPoint, QgsRenderContext &context, const ClusteredGroup &group )
63 {
64  if ( group.size() > 1 )
65  {
66  mClusterSymbol->renderPoint( centerPoint, &( group.at( 0 ).feature ), context, -1, false );
67  }
68  else
69  {
70  //single isolated symbol, draw it untouched
71  QgsMarkerSymbol *symbol = group.at( 0 ).symbol();
72  symbol->startRender( context );
73  symbol->renderPoint( centerPoint, &( group.at( 0 ).feature ), context, -1, group.at( 0 ).isSelected );
74  symbol->stopRender( context );
75  }
76 }
77 
79 {
80  if ( mClusterSymbol )
81  {
82  mClusterSymbol->startRender( context, fields );
83  }
84  QgsPointDistanceRenderer::startRender( context, fields );
85 }
86 
88 {
90  if ( mClusterSymbol )
91  {
92  mClusterSymbol->stopRender( context );
93  }
94 }
95 
96 QgsFeatureRenderer *QgsPointClusterRenderer::create( QDomElement &symbologyElem, const QgsReadWriteContext &context )
97 {
99  r->setTolerance( symbologyElem.attribute( QStringLiteral( "tolerance" ), QStringLiteral( "0.00001" ) ).toDouble() );
100  r->setToleranceUnit( QgsUnitTypes::decodeRenderUnit( symbologyElem.attribute( QStringLiteral( "toleranceUnit" ), QStringLiteral( "MapUnit" ) ) ) );
101  r->setToleranceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( symbologyElem.attribute( QStringLiteral( "toleranceUnitScale" ) ) ) );
102 
103  //look for an embedded renderer <renderer-v2>
104  QDomElement embeddedRendererElem = symbologyElem.firstChildElement( QStringLiteral( "renderer-v2" ) );
105  if ( !embeddedRendererElem.isNull() )
106  {
107  r->setEmbeddedRenderer( QgsFeatureRenderer::load( embeddedRendererElem, context ) );
108  }
109 
110  //center symbol
111  QDomElement centerSymbolElem = symbologyElem.firstChildElement( QStringLiteral( "symbol" ) );
112  if ( !centerSymbolElem.isNull() )
113  {
114  r->setClusterSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( centerSymbolElem, context ) );
115  }
116  return r;
117 }
118 
120 {
121  return mClusterSymbol.get();
122 }
123 
124 QDomElement QgsPointClusterRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
125 {
126  QDomElement rendererElement = doc.createElement( RENDERER_TAG_NAME );
127  rendererElement.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
128  rendererElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "pointCluster" ) );
129  rendererElement.setAttribute( QStringLiteral( "tolerance" ), QString::number( mTolerance ) );
130  rendererElement.setAttribute( QStringLiteral( "toleranceUnit" ), QgsUnitTypes::encodeUnit( mToleranceUnit ) );
131  rendererElement.setAttribute( QStringLiteral( "toleranceUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mToleranceMapUnitScale ) );
132 
133  if ( mRenderer )
134  {
135  QDomElement embeddedRendererElem = mRenderer->save( doc, context );
136  rendererElement.appendChild( embeddedRendererElem );
137  }
138  if ( mClusterSymbol )
139  {
140  QDomElement centerSymbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "centerSymbol" ), mClusterSymbol.get(), doc, context );
141  rendererElement.appendChild( centerSymbolElem );
142  }
143 
145  mPaintEffect->saveProperties( doc, rendererElement );
146 
147  if ( !mOrderBy.isEmpty() )
148  {
149  QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
150  mOrderBy.save( orderBy );
151  rendererElement.appendChild( orderBy );
152  }
153  rendererElement.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
154 
155  return rendererElement;
156 }
157 
158 QSet<QString> QgsPointClusterRenderer::usedAttributes( const QgsRenderContext &context ) const
159 {
160  QSet<QString> attr = QgsPointDistanceRenderer::usedAttributes( context );
161  if ( mClusterSymbol )
162  attr.unite( mClusterSymbol->usedAttributes( context ) );
163  return attr;
164 }
165 
167 {
168  mClusterSymbol.reset( symbol );
169 }
170 
172 {
173  if ( renderer->type() == QLatin1String( "pointCluster" ) )
174  {
175  return dynamic_cast<QgsPointClusterRenderer *>( renderer->clone() );
176  }
177  else if ( renderer->type() == QLatin1String( "singleSymbol" ) ||
178  renderer->type() == QLatin1String( "categorizedSymbol" ) ||
179  renderer->type() == QLatin1String( "graduatedSymbol" ) ||
180  renderer->type() == QLatin1String( "RuleRenderer" ) )
181  {
182  QgsPointClusterRenderer *pointRenderer = new QgsPointClusterRenderer();
183  pointRenderer->setEmbeddedRenderer( renderer->clone() );
184  return pointRenderer;
185  }
186  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) )
187  {
188  QgsPointClusterRenderer *pointRenderer = new QgsPointClusterRenderer();
189  const QgsPointDisplacementRenderer *displacementRenderer = static_cast< const QgsPointDisplacementRenderer * >( renderer );
190  if ( displacementRenderer->embeddedRenderer() )
191  pointRenderer->setEmbeddedRenderer( displacementRenderer->embeddedRenderer()->clone() );
192  pointRenderer->setTolerance( displacementRenderer->tolerance() );
193  pointRenderer->setToleranceUnit( displacementRenderer->toleranceUnit() );
194  pointRenderer->setToleranceMapUnitScale( displacementRenderer->toleranceMapUnitScale() );
195  if ( const_cast< QgsPointDisplacementRenderer * >( displacementRenderer )->centerSymbol() )
196  pointRenderer->setClusterSymbol( const_cast< QgsPointDisplacementRenderer * >( displacementRenderer )->centerSymbol()->clone() );
197  return pointRenderer;
198  }
199  else
200  {
201  return nullptr;
202  }
203 }
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.
QgsUnitTypes::RenderUnit mToleranceUnit
Unit for distance tolerance.
QgsFeatureRequest::OrderBy mOrderBy
Definition: qgsrenderer.h:526
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:49
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:510
QgsUnitTypes::RenderUnit toleranceUnit() const
Returns the units for the tolerance distance.
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:396
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)
Definition: qgssymbol.cpp:1475
static QgsPointClusterRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
Creates a QgsPointClusterRenderer from an existing renderer.
QString type() const
Definition: qgsrenderer.h:129
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
void setSize(double size)
Sets the symbol size.
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.
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
static QDomElement saveSymbol(const QString &symbolName, QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:48
void setFontFamily(const QString &family)
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:418
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.