QGIS API Documentation 3.39.0-Master (d85f3c2a281)
Loading...
Searching...
No Matches
qgssinglesymbolrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgssinglesymbolrenderer.cpp
3 ---------------------
4 begin : November 2009
5 copyright : (C) 2009 by Martin Dobias
6 email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgssymbol.h"
19#include "qgssymbollayerutils.h"
20
22#include "qgslogger.h"
23#include "qgsfeature.h"
24#include "qgsvectorlayer.h"
25#include "qgssymbollayer.h"
26#include "qgsogcutils.h"
29#include "qgspainteffect.h"
31#include "qgsproperty.h"
33#include "qgslinesymbol.h"
34#include "qgsmarkersymbol.h"
35#include "qgsfillsymbol.h"
36
37#include <QDomDocument>
38#include <QDomElement>
39
41 : QgsFeatureRenderer( QStringLiteral( "singleSymbol" ) )
42 , mSymbol( symbol )
43{
44 Q_ASSERT( symbol );
45}
46
54
56
61
63{
64 Q_UNUSED( context )
65 Q_UNUSED( feature )
66 return mSymbol.get();
67}
68
70{
71 QgsFeatureRenderer::startRender( context, fields );
72
73 if ( !mSymbol )
74 return;
75
76 mSymbol->startRender( context, fields );
77}
78
80{
82
83 if ( !mSymbol )
84 return;
85
86 mSymbol->stopRender( context );
87}
88
89QSet<QString> QgsSingleSymbolRenderer::usedAttributes( const QgsRenderContext &context ) const
90{
91 QSet<QString> attributes;
92 if ( mSymbol )
93 attributes.unite( mSymbol->usedAttributes( context ) );
94 return attributes;
95}
96
98{
99 if ( mSymbol )
100 {
101 QgsStyleSymbolEntity entity( mSymbol.get() );
102 return visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) );
103 }
104 return true;
105}
106
108{
109 return mSymbol.get();
110}
111
113{
114 Q_ASSERT( s );
115 mSymbol.reset( s );
116}
117
119{
120 return mSymbol ? QStringLiteral( "SINGLE: %1" ).arg( mSymbol->dump() ) : QString();
121}
122
130
131void QgsSingleSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
132{
133 QVariantMap newProps = props;
134
135 QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
136 element.appendChild( ruleElem );
137
138 QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
139 nameElem.appendChild( doc.createTextNode( QStringLiteral( "Single symbol" ) ) );
140 ruleElem.appendChild( nameElem );
141
142 QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, newProps );
143
144 if ( mSymbol ) mSymbol->toSld( doc, ruleElem, newProps );
145}
146
148{
149 Q_UNUSED( context )
150 QgsSymbolList lst;
151 lst.append( mSymbol.get() );
152 return lst;
153}
154
155
157{
158 QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
159 if ( symbolsElem.isNull() )
160 return nullptr;
161
162 QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
163
164 if ( !symbolMap.contains( QStringLiteral( "0" ) ) )
165 return nullptr;
166
167 QgsSingleSymbolRenderer *r = new QgsSingleSymbolRenderer( symbolMap.take( QStringLiteral( "0" ) ) );
168
169 // delete symbols if there are any more
171
172 const QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
173 if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
174 {
175 convertSymbolRotation( r->mSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
176 }
177
178 const QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
179 if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
180 {
182 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
183 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
184 }
185
186 const QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
187 if ( !ddsLegendSizeElem.isNull() )
188 {
189 r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
190 }
191
192 // TODO: symbol levels
193 return r;
194}
195
197{
198 // XXX this renderer can handle only one Rule!
199
200 // get the first Rule element
201 const QDomElement ruleElem = element.firstChildElement( QStringLiteral( "Rule" ) );
202 if ( ruleElem.isNull() )
203 {
204 QgsDebugError( QStringLiteral( "no Rule elements found!" ) );
205 return nullptr;
206 }
207
208 QString label, description;
209 QgsSymbolLayerList layers;
210
211 // retrieve the Rule element child nodes
212 QDomElement childElem = ruleElem.firstChildElement();
213 while ( !childElem.isNull() )
214 {
215 if ( childElem.localName() == QLatin1String( "Name" ) )
216 {
217 // <se:Name> tag contains the rule identifier,
218 // so prefer title tag for the label property value
219 if ( label.isEmpty() )
220 label = childElem.firstChild().nodeValue();
221 }
222 else if ( childElem.localName() == QLatin1String( "Description" ) )
223 {
224 // <se:Description> can contains a title and an abstract
225 const QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
226 if ( !titleElem.isNull() )
227 {
228 label = titleElem.firstChild().nodeValue();
229 }
230
231 const QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
232 if ( !abstractElem.isNull() )
233 {
234 description = abstractElem.firstChild().nodeValue();
235 }
236 }
237 else if ( childElem.localName() == QLatin1String( "Abstract" ) )
238 {
239 // <sld:Abstract> (v1.0)
240 description = childElem.firstChild().nodeValue();
241 }
242 else if ( childElem.localName() == QLatin1String( "Title" ) )
243 {
244 // <sld:Title> (v1.0)
245 label = childElem.firstChild().nodeValue();
246 }
247 else if ( childElem.localName().endsWith( QLatin1String( "Symbolizer" ) ) )
248 {
249 // create symbol layers for this symbolizer
250 QgsSymbolLayerUtils::createSymbolLayerListFromSld( childElem, geomType, layers );
251 }
252
253 childElem = childElem.nextSiblingElement();
254 }
255
256 if ( layers.isEmpty() )
257 return nullptr;
258
259 // now create the symbol
260 std::unique_ptr< QgsSymbol > symbol;
261 switch ( geomType )
262 {
264 symbol = std::make_unique< QgsLineSymbol >( layers );
265 break;
266
268 symbol = std::make_unique< QgsFillSymbol >( layers );
269 break;
270
272 symbol = std::make_unique< QgsMarkerSymbol >( layers );
273 break;
274
275 default:
276 QgsDebugError( QStringLiteral( "invalid geometry type: found %1" ).arg( qgsEnumValueToKey( geomType ) ) );
277 return nullptr;
278 }
279
280 // and finally return the new renderer
281 return new QgsSingleSymbolRenderer( symbol.release() );
282}
283
284QDomElement QgsSingleSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
285{
286 QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
287 rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "singleSymbol" ) );
288
290 symbols[QStringLiteral( "0" )] = mSymbol.get();
291 const QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
292 rendererElem.appendChild( symbolsElem );
293
294 const QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
295 rendererElem.appendChild( rotationElem );
296
297 const QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
298 rendererElem.appendChild( sizeScaleElem );
299
301 {
302 QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
303 mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
304 rendererElem.appendChild( ddsLegendElem );
305 }
306
307 saveRendererData( doc, rendererElem, context );
308
309 return rendererElem;
310}
311
313{
315 {
316 const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( mSymbol.get() );
317 const QgsProperty sizeDD( symbol->dataDefinedSize() );
318 if ( sizeDD && sizeDD.isActive() )
319 {
321 ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSymbol.get() ), sizeDD );
322 return ddSizeLegend.legendSymbolList();
323 }
324 }
325
327 lst << QgsLegendSymbolItem( mSymbol.get(), QString(), QStringLiteral( "0" ) );
328 return lst;
329}
330
331QSet< QString > QgsSingleSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
332{
333 Q_UNUSED( feature )
334 Q_UNUSED( context )
335 return QSet< QString >() << QStringLiteral( "0" );
336}
337
338QString QgsSingleSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *, bool &ok ) const
339{
340 if ( key == QLatin1String( "0" ) )
341 {
342 ok = true;
343 return QStringLiteral( "TRUE" );
344 }
345 else
346 {
347 ok = false;
348 return QString();
349 }
350}
351
353{
354 Q_UNUSED( key )
355 setSymbol( symbol );
356}
357
359{
360 QgsSingleSymbolRenderer *r = nullptr;
361 if ( renderer->type() == QLatin1String( "singleSymbol" ) )
362 {
363 r = dynamic_cast<QgsSingleSymbolRenderer *>( renderer->clone() );
364 }
365 else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
366 {
367 const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
368 if ( pointDistanceRenderer )
369 r = convertFromRenderer( pointDistanceRenderer->embeddedRenderer() );
370 }
371 else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
372 {
373 const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
374 if ( invertedPolygonRenderer )
375 r = convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
376 }
377
378 if ( !r )
379 {
380 QgsRenderContext context;
381 const QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
382 if ( !symbols.isEmpty() )
383 {
384 r = new QgsSingleSymbolRenderer( symbols.at( 0 )->clone() );
385 }
386 }
387
388 if ( r )
389 {
390 renderer->copyRendererData( r );
391 }
392
393 return r;
394}
395
400
QFlags< FeatureRendererFlag > FeatureRendererFlags
Flags controlling behavior of vector feature renderers.
Definition qgis.h:772
@ AffectsLabeling
If present, indicates that the renderer will participate in the map labeling problem.
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:337
@ Polygon
Polygons.
@ Marker
Marker symbol.
@ AffectsLabeling
If present, indicates that the symbol will participate in the map labeling problem.
Object that keeps configuration of appearance of marker symbol's data-defined size in legend.
static QgsDataDefinedSizeLegend * readXml(const QDomElement &elem, const QgsReadWriteContext &context) SIP_FACTORY
Creates instance from given element and returns it (caller takes ownership). Returns nullptr on error...
void updateFromSymbolAndProperty(const QgsMarkerSymbol *symbol, const QgsProperty &ddSize)
Updates the list of classes, source symbol and title label from given symbol and property.
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
Abstract base class for all 2D vector feature renderers.
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QString type() const
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
static void convertSymbolRotation(QgsSymbol *symbol, const QString &field)
void saveRendererData(QDomDocument &doc, QDomElement &element, const QgsReadWriteContext &context)
Saves generic renderer data into the specified element.
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
static void convertSymbolSizeScale(QgsSymbol *symbol, Qgis::ScaleMethod method, const QString &field)
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
Container of fields for a vector layer.
Definition qgsfields.h:46
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted,...
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
A marker symbol type, for rendering Point and MultiPoint geometries.
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
A store for object properties.
bool isActive() const
Returns whether the property is currently active.
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.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
Stores renderer properties to an XML element.
QgsSymbol * symbol() const
Returns the symbol which will be rendered for every feature.
Qgis::FeatureRendererFlags flags() const override
Returns flags associated with the renderer.
QString legendKeyToExpression(const QString &key, QgsVectorLayer *layer, bool &ok) const override
Attempts to convert the specified legend rule key to a QGIS expression matching the features displaye...
void setSymbol(QgsSymbol *s)
Sets the symbol which will be rendered for every feature.
static QgsFeatureRenderer * createFromSld(QDomElement &element, Qgis::GeometryType geomType)
Creates a new single symbol renderer from an SLD element.
std::unique_ptr< QgsSymbol > mSymbol
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates a new single symbol renderer from an XML element, using the supplied read/write context.
~QgsSingleSymbolRenderer() override
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend when renderer is configured to use data-defined size for marker symbo...
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend when using data-defined size for marker symbols.
std::unique_ptr< QgsDataDefinedSizeLegend > mDataDefinedSizeLegend
QgsSymbol * originalSymbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns symbol for feature.
static QgsSingleSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
Creates a new single symbol renderer from an existing renderer.
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
To be overridden.
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
QgsSingleSymbolRenderer * clone() const override
Create a deep copy of this renderer.
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
QString dump() const override
Returns debug information about this renderer.
QgsSingleSymbolRenderer(QgsSymbol *symbol)
Constructor for QgsSingleSymbolRenderer.
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:1396
static void applyScaleDependency(QDomDocument &doc, QDomElement &ruleElem, QVariantMap &props)
Checks if the properties contain scaleMinDenom and scaleMaxDenom, if available, they are added into t...
static bool createSymbolLayerListFromSld(QDomElement &element, Qgis::GeometryType geomType, QList< QgsSymbolLayer * > &layers)
Creates a symbol layer list from a DOM element.
static Qgis::ScaleMethod decodeScaleMethod(const QString &str)
Decodes a symbol scale method from a string.
static void clearSymbolMap(QgsSymbolMap &symbols)
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
Represents a vector layer which manages a vector based data sets.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6048
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define QgsDebugError(str)
Definition qgslogger.h:38
#define RENDERER_TAG_NAME
Definition qgsrenderer.h:53
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition qgsrenderer.h:48
QList< QgsSymbol * > QgsSymbolList
Definition qgsrenderer.h:47
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30
Contains information relating to the style entity currently being visited.