Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgspointdistancerenderer.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 : : 18 : : #ifndef QGSPOINTDISTANCERENDERER_H 19 : : #define QGSPOINTDISTANCERENDERER_H 20 : : 21 : : #include "qgis_core.h" 22 : : #include "qgis.h" 23 : : #include "qgsrenderer.h" 24 : : #include <QFont> 25 : : 26 : : class QgsSpatialIndex; 27 : : 28 : : /** 29 : : * \class QgsPointDistanceRenderer 30 : : * \ingroup core 31 : : * \brief An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers). 32 : : * QgsPointDistanceRenderer handles calculation of point clusters using a distance based threshold. 33 : : * Subclasses must implement drawGroup() to handle the rendering of individual point clusters 34 : : * in the desired style. 35 : : * \since QGIS 3.0 36 : : */ 37 : : 38 : 0 : class CORE_EXPORT QgsPointDistanceRenderer: public QgsFeatureRenderer 39 : : { 40 : : public: 41 : : 42 : : //! Contains properties for a feature within a clustered group. 43 : 0 : struct GroupedFeature 44 : : { 45 : : 46 : : /** 47 : : * Constructor for GroupedFeature. 48 : : * \param feature feature 49 : : * \param symbol base symbol for rendering feature (owned by GroupedFeature) 50 : : * \param isSelected set to TRUE if feature is selected and should be rendered in a selected state 51 : : * \param label optional label text, or empty string for no label 52 : : */ 53 : 0 : GroupedFeature( const QgsFeature &feature, QgsMarkerSymbol *symbol SIP_TRANSFER, bool isSelected, const QString &label = QString() ) 54 : 0 : : feature( feature ) 55 : 0 : , isSelected( isSelected ) 56 : 0 : , label( label ) 57 : 0 : , mSymbol( symbol ) 58 : 0 : {} 59 : : 60 : : //! Feature 61 : : QgsFeature feature; 62 : : 63 : : //! Base symbol for rendering feature 64 : 0 : QgsMarkerSymbol *symbol() const { return mSymbol.get(); } 65 : : 66 : : //! True if feature is selected and should be rendered in a selected state 67 : : bool isSelected; 68 : : 69 : : //! Optional label text 70 : : QString label; 71 : : 72 : : private: 73 : : std::shared_ptr< QgsMarkerSymbol > mSymbol; 74 : : }; 75 : : 76 : : //! A group of clustered points (ie features within the distance tolerance). 77 : : typedef QList< QgsPointDistanceRenderer::GroupedFeature > ClusteredGroup; 78 : : 79 : : /** 80 : : * Constructor for QgsPointDistanceRenderer. 81 : : * \param rendererName name of renderer for registry 82 : : * \param labelAttributeName optional attribute for labeling points 83 : : */ 84 : : QgsPointDistanceRenderer( const QString &rendererName, const QString &labelAttributeName = QString() ); 85 : : 86 : : void toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props = QVariantMap() ) const override; 87 : : bool renderFeature( const QgsFeature &feature, QgsRenderContext &context, int layer = -1, bool selected = false, bool drawVertexMarker = false ) override SIP_THROW( QgsCsException ); 88 : : QSet<QString> usedAttributes( const QgsRenderContext &context ) const override; 89 : : bool filterNeedsGeometry() const override; 90 : : QgsFeatureRenderer::Capabilities capabilities() override; 91 : : QgsSymbolList symbols( QgsRenderContext &context ) const override; 92 : : QgsSymbol *symbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override; 93 : : QgsSymbol *originalSymbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override; 94 : : QgsSymbolList symbolsForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override; 95 : : QgsSymbolList originalSymbolsForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override; 96 : : QSet< QString > legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override; 97 : : bool willRenderFeature( const QgsFeature &feature, QgsRenderContext &context ) const override; 98 : : void startRender( QgsRenderContext &context, const QgsFields &fields ) override; 99 : : void stopRender( QgsRenderContext &context ) override; 100 : : QgsLegendSymbolList legendSymbolItems() const override; 101 : : void setEmbeddedRenderer( QgsFeatureRenderer *r SIP_TRANSFER ) override; 102 : : const QgsFeatureRenderer *embeddedRenderer() const override; 103 : : void setLegendSymbolItem( const QString &key, QgsSymbol *symbol SIP_TRANSFER ) override; 104 : : bool legendSymbolItemsCheckable() const override; 105 : : bool legendSymbolItemChecked( const QString &key ) override; 106 : : void checkLegendSymbolItem( const QString &key, bool state ) override; 107 : : QString filter( const QgsFields &fields = QgsFields() ) override; 108 : : bool accept( QgsStyleEntityVisitorInterface *visitor ) const override; 109 : : 110 : : /** 111 : : * Sets the attribute name for labeling points. 112 : : * \param name attribute name, or empty string to avoid labeling features by the renderer 113 : : * \see labelAttributeName() 114 : : * \see setLabelFont() 115 : : * \see setLabelColor() 116 : : * \see setMinimumLabelScale() 117 : : */ 118 : 0 : void setLabelAttributeName( const QString &name ) { mLabelAttributeName = name; } 119 : : 120 : : /** 121 : : * Returns the attribute name used for labeling points, or an empty string if no labeling 122 : : * will be done by the renderer. 123 : : * \see setLabelAttributeName() 124 : : * \see labelFont() 125 : : * \see minimumLabelScale() 126 : : * \see labelColor() 127 : : */ 128 : : QString labelAttributeName() const { return mLabelAttributeName; } 129 : : 130 : : /** 131 : : * Sets the font used for labeling points. 132 : : * \param font label font 133 : : * \see labelFont() 134 : : * \see setLabelAttributeName() 135 : : * \see setLabelColor() 136 : : */ 137 : 0 : void setLabelFont( const QFont &font ) { mLabelFont = font; } 138 : : 139 : : /** 140 : : * Returns the font used for labeling points. 141 : : * \see setLabelFont() 142 : : * \see labelAttributeName() 143 : : * \see labelColor() 144 : : */ 145 : : QFont labelFont() const { return mLabelFont;} 146 : : 147 : : /** 148 : : * Sets the minimum map \a scale (i.e. most "zoomed out") at which points should be labeled by the renderer. 149 : : * The \a scale value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map. 150 : : * \see minimumLabelScale() 151 : : * \see setLabelAttributeName() 152 : : */ 153 : 0 : void setMinimumLabelScale( double scale ) { mMinLabelScale = scale; } 154 : : 155 : : /** 156 : : * Returns the minimum map scale (i.e. most "zoomed out") at which points should be labeled by the renderer. 157 : : * The scale value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map. 158 : : * \see setMinimumLabelScale() 159 : : * \see labelAttributeName() 160 : : */ 161 : : double minimumLabelScale() const { return mMinLabelScale; } 162 : : 163 : : /** 164 : : * Sets the color to use for for labeling points. 165 : : * \param color label color 166 : : * \see labelColor() 167 : : * \see setLabelAttributeName() 168 : : * \see setLabelFont() 169 : : */ 170 : 0 : void setLabelColor( const QColor &color ) { mLabelColor = color;} 171 : : 172 : : /** 173 : : * Returns the color used for for labeling points. 174 : : * \see setLabelColor() 175 : : * \see labelAttributeName() 176 : : * \see labelFont() 177 : : */ 178 : : QColor labelColor() const { return mLabelColor; } 179 : : 180 : : /** 181 : : * Sets the tolerance distance for grouping points. Units are specified using 182 : : * setToleranceUnit(). 183 : : * \param distance tolerance distance 184 : : * \see tolerance() 185 : : * \see setToleranceUnit() 186 : : */ 187 : 0 : void setTolerance( double distance ) { mTolerance = distance; } 188 : : 189 : : /** 190 : : * Returns the tolerance distance for grouping points. Units are retrieved using 191 : : * toleranceUnit(). 192 : : * \see setTolerance() 193 : : * \see toleranceUnit() 194 : : */ 195 : 0 : double tolerance() const { return mTolerance; } 196 : : 197 : : /** 198 : : * Sets the units for the tolerance distance. 199 : : * \param unit tolerance distance units 200 : : * \see setTolerance() 201 : : * \see toleranceUnit() 202 : : * \since QGIS 2.12 203 : : */ 204 : 0 : void setToleranceUnit( QgsUnitTypes::RenderUnit unit ) { mToleranceUnit = unit; } 205 : : 206 : : /** 207 : : * Returns the units for the tolerance distance. 208 : : * \see tolerance() 209 : : * \see setToleranceUnit() 210 : : * \since QGIS 2.12 211 : : */ 212 : 0 : QgsUnitTypes::RenderUnit toleranceUnit() const { return mToleranceUnit; } 213 : : 214 : : /** 215 : : * Sets the map unit scale object for the distance tolerance. This is only used if the 216 : : * toleranceUnit() is set to QgsUnitTypes::RenderMapUnits. 217 : : * \param scale scale for distance tolerance 218 : : * \see toleranceMapUnitScale() 219 : : * \see setToleranceUnit() 220 : : */ 221 : 0 : void setToleranceMapUnitScale( const QgsMapUnitScale &scale ) { mToleranceMapUnitScale = scale; } 222 : : 223 : : /** 224 : : * Returns the map unit scale object for the distance tolerance. This is only used if the 225 : : * toleranceUnit() is set to QgsUnitTypes::RenderMapUnits. 226 : : * \see setToleranceMapUnitScale() 227 : : * \see toleranceUnit() 228 : : */ 229 : 0 : const QgsMapUnitScale &toleranceMapUnitScale() const { return mToleranceMapUnitScale; } 230 : : 231 : : protected: 232 : : 233 : : //! Embedded base renderer. This can be used for rendering individual, isolated points. 234 : : std::unique_ptr< QgsFeatureRenderer > mRenderer; 235 : : 236 : : //! Attribute name for labeling. An empty string indicates that no labels should be rendered. 237 : : QString mLabelAttributeName; 238 : : 239 : : //! Label attribute index (or -1 if none). This index is not stored, it is requested in the startRender() method. 240 : : int mLabelIndex; 241 : : 242 : : //! Distance tolerance. Points that are closer together than this distance are considered clustered. 243 : : double mTolerance; 244 : : //! Unit for distance tolerance. 245 : : QgsUnitTypes::RenderUnit mToleranceUnit; 246 : : //! Map unit scale for distance tolerance. 247 : : QgsMapUnitScale mToleranceMapUnitScale; 248 : : 249 : : //! Label font. 250 : : QFont mLabelFont; 251 : : //! Label text color. 252 : : QColor mLabelColor; 253 : : //! Whether labels should be drawn for points. This is set internally from startRender() depending on scale denominator. 254 : : bool mDrawLabels; 255 : : //! Maximum scale denominator for label display. A zero value indicates no scale limitation. 256 : : double mMinLabelScale = 0; 257 : : 258 : : //! Groups of features that are considered clustered together. 259 : : QList<ClusteredGroup> mClusteredGroups; 260 : : 261 : : //! Mapping of feature ID to the feature's group index. 262 : : QMap<QgsFeatureId, int> mGroupIndex; 263 : : 264 : : //! Mapping of feature ID to approximate group location 265 : : QMap<QgsFeatureId, QgsPointXY > mGroupLocations; 266 : : 267 : : //! Spatial index for fast lookup of nearby points. 268 : : QgsSpatialIndex *mSpatialIndex = nullptr; 269 : : 270 : : /** 271 : : * Renders the labels for a group. 272 : : * \param centerPoint center point of group 273 : : * \param context destination render context 274 : : * \param labelShifts displacement for individual label positions 275 : : * \param group group of clustered features to label 276 : : * \note may not be available in Python bindings on some platforms 277 : : */ 278 : : void drawLabels( QPointF centerPoint, QgsSymbolRenderContext &context, const QList<QPointF> &labelShifts, const ClusteredGroup &group ); 279 : : 280 : : private: 281 : : 282 : : /** 283 : : * Draws a group of clustered points. 284 : : * \param centerPoint central point (geographic centroid) of all points contained within the cluster 285 : : * \param context destination render context 286 : : * \param group contents of group 287 : : */ 288 : : virtual void drawGroup( QPointF centerPoint, QgsRenderContext &context, const ClusteredGroup &group ) = 0 SIP_FORCE; 289 : : 290 : : //! Creates a search rectangle with specified distance tolerance. 291 : : QgsRectangle searchRect( const QgsPointXY &p, double distance ) const; 292 : : 293 : : //! Debugging function to check the entries in the clustered groups 294 : : void printGroupInfo() const; 295 : : 296 : : //! Returns the label text for a feature (using mLabelAttributeName as attribute field) 297 : : QString getLabel( const QgsFeature &feature ) const; 298 : : 299 : : //! Internal group rendering helper 300 : : void drawGroup( const ClusteredGroup &group, QgsRenderContext &context ); 301 : : 302 : : /** 303 : : * Returns first symbol from the embedded renderer for a feature or NULLPTR if none 304 : : * \param feature source feature 305 : : * \param context target render context 306 : : */ 307 : : QgsMarkerSymbol *firstSymbolForFeature( const QgsFeature &feature, QgsRenderContext &context ); 308 : : 309 : : /** 310 : : * Creates an expression context scope for a clustered group, with variables reflecting the group's properties. 311 : : * \param group clustered group 312 : : * \returns new expression context scope 313 : : */ 314 : : QgsExpressionContextScope *createGroupScope( const ClusteredGroup &group ) const; 315 : : 316 : : }; 317 : : 318 : : #endif // QGSPOINTDISTANCERENDERER_H