Skip to content

Commit 36e276f

Browse files
committed
[FEATURE] Point cluster renderer
Groups nearby points into a single rendered marker symbol. QgsPointDisplacementRenderer has been split into a new pure virtual QgsPointDistanceRenderer base class which handles the detection of clusters and grouping of points. The new cluster renderer reuses this base class to avoid code duplication. Additionally, some improvements have been made to the displacement renderer, specifically: - points are now assigned to the group which is "nearest" them, rather then just assigning them first group within the search distance. In some cases this was assigning features to a more distant cluster, resulting in less predictable cluster patterns - individual points are now correctly shown in their own selection state Lots of code cleanup + documentation too. Sponsored by: - Andreas Neumann - Qtibia Engineering (Tudor Barascu) - Karl-Magnus Jönsson - Geonesia (Nicolas Ponzo) - Plus numerous additional anonymous backers whose generous contributions are also highly valued!
1 parent 19585ee commit 36e276f

25 files changed

+1826
-735
lines changed

doc/api_break.dox

+6
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,12 @@ be used instead of a null pointer if no transformation is required.</li>
10841084
<li>createMapRenderer(): default implementation (which called plugin's draw() method) has been removed. Plugin layers must implement createMapRenderer().</li>
10851085
</ul>
10861086

1087+
\subsection qgis_api_break_3_0_QgsPointDisplacementRenderer QgsPointDisplacementRenderer
1088+
1089+
<ul>
1090+
<li>The deprecated method setDisplacementGroups() has been removed. This method has had no effect since QGIS 2.4</li>
1091+
</ul>
1092+
10871093
\subsection qgis_api_break_3_0_QgsPointLocator QgsPointLocator
10881094

10891095
<ul>

python/core/core.sip

+2
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,9 @@
294294
%Include symbology-ng/qgsinvertedpolygonrenderer.sip
295295
%Include symbology-ng/qgslegendsymbolitem.sip
296296
%Include symbology-ng/qgsnullsymbolrenderer.sip
297+
%Include symbology-ng/qgspointclusterrenderer.sip
297298
%Include symbology-ng/qgspointdisplacementrenderer.sip
299+
%Include symbology-ng/qgspointdistancerenderer.sip
298300
%Include symbology-ng/qgsrenderer.sip
299301
%Include symbology-ng/qgsrendererregistry.sip
300302
%Include symbology-ng/qgsrulebasedrenderer.sip
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/** \class QgsPointClusterRenderer
2+
* \ingroup core
3+
* A renderer that automatically clusters points with the same geographic position.
4+
* \note added in QGIS 3.0
5+
*/
6+
class QgsPointClusterRenderer : QgsPointDistanceRenderer
7+
{
8+
%TypeHeaderCode
9+
#include <qgspointclusterrenderer.h>
10+
%End
11+
public:
12+
13+
QgsPointClusterRenderer();
14+
15+
virtual QgsPointClusterRenderer* clone() const /Factory/;
16+
virtual void startRender( QgsRenderContext& context, const QgsFields& fields );
17+
void stopRender( QgsRenderContext& context );
18+
QDomElement save( QDomDocument& doc );
19+
20+
//! Create a renderer from XML element
21+
static QgsFeatureRenderer* create( QDomElement& symbologyElem ) /Factory/;
22+
23+
/** Returns the symbol used for rendering clustered groups (but not ownership of the symbol).
24+
* @see setClusterSymbol()
25+
*/
26+
QgsMarkerSymbol* clusterSymbol();
27+
28+
/** Sets the symbol for rendering clustered groups.
29+
* @param symbol new cluster symbol. Ownership is transferred to the renderer.
30+
* @see clusterSymbol()
31+
*/
32+
void setClusterSymbol( QgsMarkerSymbol* symbol /Transfer/ );
33+
34+
/** Creates a QgsPointDisplacementRenderer from an existing renderer.
35+
* @note added in 2.5
36+
* @returns a new renderer if the conversion was possible, otherwise nullptr.
37+
*/
38+
static QgsPointClusterRenderer* convertFromRenderer( const QgsFeatureRenderer *renderer ) /Factory/;
39+
40+
private:
41+
QgsPointClusterRenderer( const QgsPointClusterRenderer & );
42+
QgsPointClusterRenderer & operator=( const QgsPointClusterRenderer & );
43+
44+
void drawGroup( QPointF centerPoint, QgsRenderContext& context, const QgsPointDistanceRenderer::ClusteredGroup& group );
45+
};
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
class QgsPointDisplacementRenderer : QgsFeatureRenderer
1+
/** \class QgsPointDisplacementRenderer
2+
* \ingroup core
3+
* A renderer that automatically displaces points with the same geographic location.
4+
*/
5+
class QgsPointDisplacementRenderer : QgsPointDistanceRenderer
26
{
37
%TypeHeaderCode
48
#include <qgspointdisplacementrenderer.h>
@@ -13,88 +17,56 @@ class QgsPointDisplacementRenderer : QgsFeatureRenderer
1317
ConcentricRings /*!< Place points in concentric rings around group*/
1418
};
1519

16-
QgsPointDisplacementRenderer( const QString& labelAttributeName = "" );
17-
~QgsPointDisplacementRenderer();
18-
19-
virtual QgsPointDisplacementRenderer* clone() const /Factory/;
20-
21-
virtual void toSld( QDomDocument& doc, QDomElement &element ) const;
22-
23-
/** Reimplemented from QgsFeatureRenderer*/
24-
bool renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false );
25-
26-
/** Partial proxy that will call this method on the embedded renderer. */
27-
virtual QList<QString> usedAttributes();
28-
/** Proxy that will call this method on the embedded renderer. */
29-
virtual QgsFeatureRenderer::Capabilities capabilities();
30-
/** Proxy that will call this method on the embedded renderer.
31-
@note available in python as symbols2
32-
*/
33-
virtual QgsSymbolList symbols( QgsRenderContext& context );
34-
/** Proxy that will call this method on the embedded renderer.
35-
@note available in python as symbolForFeature2
20+
/** Constructor for QgsPointDisplacementRenderer.
21+
* @param labelAttributeName optional attribute name for labeling points
3622
*/
37-
virtual QgsSymbol* symbolForFeature( QgsFeature& feature, QgsRenderContext& context );
38-
/** Proxy that will call this method on the embedded renderer.
39-
@note available in python as originalSymbolForFeature2
40-
*/
41-
virtual QgsSymbol* originalSymbolForFeature( QgsFeature& feat, QgsRenderContext& context );
42-
/** Proxy that will call this method on the embedded renderer.
43-
@note available in python as symbolsForFeature2
44-
*/
45-
virtual QgsSymbolList symbolsForFeature( QgsFeature& feat, QgsRenderContext& context );
46-
/** Proxy that will call this method on the embedded renderer.
47-
@note available in python as originalSymbolsForFeature2
48-
*/
49-
virtual QgsSymbolList originalSymbolsForFeature( QgsFeature& feat, QgsRenderContext& context );
50-
/** Proxy that will call this method on the embedded renderer.
51-
@note available in python as willRenderFeature2
52-
*/
53-
virtual bool willRenderFeature( QgsFeature& feat, QgsRenderContext& context );
23+
QgsPointDisplacementRenderer( const QString& labelAttributeName = QString() );
5424

25+
virtual QgsPointDisplacementRenderer* clone() const /Factory/;
5526
virtual void startRender( QgsRenderContext& context, const QgsFields& fields );
56-
5727
void stopRender( QgsRenderContext& context );
58-
59-
//! create a renderer from XML element
60-
static QgsFeatureRenderer* create( QDomElement& symbologyElem ) /Factory/;
6128
QDomElement save( QDomDocument& doc );
6229

63-
QgsLegendSymbologyList legendSymbologyItems( QSize iconSize );
64-
65-
//! @note not available in python bindings
66-
// QgsLegendSymbolList legendSymbolItems();
67-
68-
void setLabelAttributeName( const QString& name );
69-
QString labelAttributeName() const;
70-
71-
void setEmbeddedRenderer( QgsFeatureRenderer* r /Transfer/ );
72-
const QgsFeatureRenderer* embeddedRenderer() const;
73-
74-
virtual void setLegendSymbolItem( const QString& key, QgsSymbol* symbol );
75-
76-
virtual bool legendSymbolItemsCheckable() const;
77-
virtual bool legendSymbolItemChecked( const QString& key );
78-
virtual void checkLegendSymbolItem( const QString& key, bool state = true );
30+
//! Create a renderer from XML element
31+
static QgsFeatureRenderer* create( QDomElement& symbologyElem ) /Factory/;
7932

80-
void setLabelFont( const QFont& f );
81-
QFont labelFont() const;
33+
/** Sets the line width for the displacement group circle.
34+
* @param width line width in mm
35+
* @see circleWidth()
36+
* @see setCircleColor()
37+
*/
38+
void setCircleWidth( double width );
8239

83-
void setCircleWidth( double w );
40+
/** Returns the line width for the displacement group circle in mm.
41+
* @see setCircleWidth()
42+
* @see circleColor()
43+
*/
8444
double circleWidth() const;
8545

86-
void setCircleColor( const QColor& c );
46+
/** Sets the color used for drawing the displacement group circle.
47+
* @param color circle color
48+
* @see circleColor()
49+
* @see setCircleWidth()
50+
*/
51+
void setCircleColor( const QColor& color );
52+
53+
/** Returns the color used for drawing the displacement group circle.
54+
* @see setCircleColor()
55+
* @see circleWidth()
56+
*/
8757
QColor circleColor() const;
8858

89-
void setLabelColor( const QColor& c );
90-
QColor labelColor() const;
59+
/** Sets a factor for increasing the ring size of displacement groups.
60+
* @param distance addition factor
61+
* @see circleRadiusAddition()
62+
*/
63+
void setCircleRadiusAddition( double distance );
9164

92-
void setCircleRadiusAddition( double d );
65+
/** Returns the factor for increasing the ring size of displacement groups.
66+
* @see setCircleRadiusAddition()
67+
*/
9368
double circleRadiusAddition() const;
9469

95-
void setMaxLabelScaleDenominator( double d );
96-
double maxLabelScaleDenominator() const;
97-
9870
/** Returns the placement method used for dispersing the points.
9971
* @see setPlacement()
10072
* @note added in QGIS 2.12
@@ -108,62 +80,27 @@ class QgsPointDisplacementRenderer : QgsFeatureRenderer
10880
*/
10981
void setPlacement( Placement placement );
11082

111-
/** Returns the symbol for the center of a displacement group (but _not_ ownership of the symbol)*/
83+
/** Returns the symbol for the center of a displacement group (but not ownership of the symbol).
84+
* @see setCenterSymbol()
85+
*/
11286
QgsMarkerSymbol* centerSymbol();
113-
/** Sets the center symbol (takes ownership)*/
114-
void setCenterSymbol( QgsMarkerSymbol* symbol /Transfer/ );
115-
116-
/** Sets the tolerance distance for grouping points. Units are specified using
117-
* setToleranceUnit().
118-
* @param t tolerance distance
119-
* @see tolerance()
120-
* @see setToleranceUnit()
121-
*/
122-
void setTolerance( double t );
123-
124-
/** Returns the tolerance distance for grouping points. Units are retrieved using
125-
* toleranceUnit().
126-
* @see setTolerance()
127-
* @see toleranceUnit()
128-
*/
129-
double tolerance() const;
13087

131-
/** Sets the units for the tolerance distance.
132-
* @param unit tolerance distance units
133-
* @see setTolerance()
134-
* @see toleranceUnit()
135-
* @note added in QGIS 2.12
136-
*/
137-
void setToleranceUnit( QgsUnitTypes::RenderUnit unit );
138-
139-
/** Returns the units for the tolerance distance.
140-
* @see tolerance()
141-
* @see setToleranceUnit()
142-
* @note added in QGIS 2.12
143-
*/
144-
QgsUnitTypes::RenderUnit toleranceUnit() const;
145-
146-
/** Sets the map unit scale object for the distance tolerance. This is only used if the
147-
* toleranceUnit() is set to QgsSymbol::MapUnit.
148-
* @param scale scale for distance tolerance
149-
* @see toleranceMapUnitScale()
150-
* @see setToleranceUnit()
151-
*/
152-
void setToleranceMapUnitScale( const QgsMapUnitScale& scale );
88+
/** Sets the center symbol for a displacement group.
89+
* @param symbol new center symbol. Ownership is transferred to the renderer.
90+
* @see centerSymbol()
91+
*/
92+
void setCenterSymbol( QgsMarkerSymbol* symbol /Transfer/ );
15393

154-
/** Returns the map unit scale object for the distance tolerance. This is only used if the
155-
* toleranceUnit() is set to QgsSymbol::MapUnit.
156-
* @see setToleranceMapUnitScale()
157-
* @see toleranceUnit()
94+
/** Creates a QgsPointDisplacementRenderer from an existing renderer.
95+
* @note added in 2.5
96+
* @returns a new renderer if the conversion was possible, otherwise nullptr.
15897
*/
159-
const QgsMapUnitScale& toleranceMapUnitScale() const;
160-
161-
//! creates a QgsPointDisplacementRenderer from an existing renderer.
162-
//! @note added in 2.5
163-
//! @returns a new renderer if the conversion was possible, otherwise 0.
164-
static QgsPointDisplacementRenderer* convertFromRenderer(const QgsFeatureRenderer *renderer ) /Factory/;
98+
static QgsPointDisplacementRenderer* convertFromRenderer( const QgsFeatureRenderer *renderer ) /Factory/;
16599

166100
private:
167101
QgsPointDisplacementRenderer( const QgsPointDisplacementRenderer & );
168102
QgsPointDisplacementRenderer & operator=( const QgsPointDisplacementRenderer & );
103+
104+
void drawGroup( QPointF centerPoint, QgsRenderContext& context, const QgsPointDistanceRenderer::ClusteredGroup& group );
105+
169106
};

0 commit comments

Comments
 (0)