QGIS API Documentation 3.99.0-Master (21b3aa880ba)
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
19#include "qgsfeature.h"
20#include "qgsfillsymbol.h"
22#include "qgslinesymbol.h"
23#include "qgslogger.h"
24#include "qgsmarkersymbol.h"
25#include "qgsogcutils.h"
26#include "qgspainteffect.h"
29#include "qgsproperty.h"
30#include "qgssldexportcontext.h"
32#include "qgssymbol.h"
33#include "qgssymbollayer.h"
34#include "qgssymbollayerutils.h"
35#include "qgsvectorlayer.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 QgsSldExportContext context;
134 context.setExtraProperties( props );
135 toSld( doc, element, context );
136}
137
138bool QgsSingleSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, QgsSldExportContext &context ) const
139{
140 const QVariantMap oldProps = context.extraProperties();
141 QVariantMap newProps = oldProps;
142
143 QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
144 element.appendChild( ruleElem );
145
146 QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
147 nameElem.appendChild( doc.createTextNode( QStringLiteral( "Single symbol" ) ) );
148 ruleElem.appendChild( nameElem );
149
150 QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, newProps );
151
152 context.setExtraProperties( newProps );
153 if ( mSymbol )
154 mSymbol->toSld( doc, ruleElem, context );
155
156 context.setExtraProperties( oldProps );
157 return true;
158}
159
161{
162 Q_UNUSED( context )
163 QgsSymbolList lst;
164 lst.append( mSymbol.get() );
165 return lst;
166}
167
168
170{
171 QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
172 if ( symbolsElem.isNull() )
173 return nullptr;
174
175 QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
176
177 if ( !symbolMap.contains( QStringLiteral( "0" ) ) )
178 return nullptr;
179
180 QgsSingleSymbolRenderer *r = new QgsSingleSymbolRenderer( symbolMap.take( QStringLiteral( "0" ) ) );
181
182 // delete symbols if there are any more
184
185 const QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
186 if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
187 {
188 convertSymbolRotation( r->mSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
189 }
190
191 const QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
192 if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
193 {
195 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
196 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
197 }
198
199 const QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
200 if ( !ddsLegendSizeElem.isNull() )
201 {
202 r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
203 }
204
205 // TODO: symbol levels
206 return r;
207}
208
210{
211 // XXX this renderer can handle only one Rule!
212
213 // get the first Rule element
214 const QDomElement ruleElem = element.firstChildElement( QStringLiteral( "Rule" ) );
215 if ( ruleElem.isNull() )
216 {
217 QgsDebugError( QStringLiteral( "no Rule elements found!" ) );
218 return nullptr;
219 }
220
221 QString label, description;
222 QgsSymbolLayerList layers;
223
224 // retrieve the Rule element child nodes
225 QDomElement childElem = ruleElem.firstChildElement();
226 while ( !childElem.isNull() )
227 {
228 if ( childElem.localName() == QLatin1String( "Name" ) )
229 {
230 // <se:Name> tag contains the rule identifier,
231 // so prefer title tag for the label property value
232 if ( label.isEmpty() )
233 label = childElem.firstChild().nodeValue();
234 }
235 else if ( childElem.localName() == QLatin1String( "Description" ) )
236 {
237 // <se:Description> can contains a title and an abstract
238 const QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
239 if ( !titleElem.isNull() )
240 {
241 label = titleElem.firstChild().nodeValue();
242 }
243
244 const QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
245 if ( !abstractElem.isNull() )
246 {
247 description = abstractElem.firstChild().nodeValue();
248 }
249 }
250 else if ( childElem.localName() == QLatin1String( "Abstract" ) )
251 {
252 // <sld:Abstract> (v1.0)
253 description = childElem.firstChild().nodeValue();
254 }
255 else if ( childElem.localName() == QLatin1String( "Title" ) )
256 {
257 // <sld:Title> (v1.0)
258 label = childElem.firstChild().nodeValue();
259 }
260 else if ( childElem.localName().endsWith( QLatin1String( "Symbolizer" ) ) )
261 {
262 // create symbol layers for this symbolizer
263 QgsSymbolLayerUtils::createSymbolLayerListFromSld( childElem, geomType, layers );
264 }
265
266 childElem = childElem.nextSiblingElement();
267 }
268
269 if ( layers.isEmpty() )
270 return nullptr;
271
272 // now create the symbol
273 std::unique_ptr< QgsSymbol > symbol;
274 switch ( geomType )
275 {
277 symbol = std::make_unique< QgsLineSymbol >( layers );
278 break;
279
281 symbol = std::make_unique< QgsFillSymbol >( layers );
282 break;
283
285 symbol = std::make_unique< QgsMarkerSymbol >( layers );
286 break;
287
288 default:
289 QgsDebugError( QStringLiteral( "invalid geometry type: found %1" ).arg( qgsEnumValueToKey( geomType ) ) );
290 return nullptr;
291 }
292
293 // and finally return the new renderer
294 return new QgsSingleSymbolRenderer( symbol.release() );
295}
296
297QDomElement QgsSingleSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
298{
299 QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
300 rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "singleSymbol" ) );
301
303 symbols[QStringLiteral( "0" )] = mSymbol.get();
304 const QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
305 rendererElem.appendChild( symbolsElem );
306
307 const QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
308 rendererElem.appendChild( rotationElem );
309
310 const QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
311 rendererElem.appendChild( sizeScaleElem );
312
314 {
315 QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
316 mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
317 rendererElem.appendChild( ddsLegendElem );
318 }
319
320 saveRendererData( doc, rendererElem, context );
321
322 return rendererElem;
323}
324
326{
328 {
329 const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( mSymbol.get() );
330 const QgsProperty sizeDD( symbol->dataDefinedSize() );
331 if ( sizeDD && sizeDD.isActive() )
332 {
334 ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSymbol.get() ), sizeDD );
335 return ddSizeLegend.legendSymbolList();
336 }
337 }
338
340 lst << QgsLegendSymbolItem( mSymbol.get(), QString(), QStringLiteral( "0" ) );
341 return lst;
342}
343
344QSet< QString > QgsSingleSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
345{
346 Q_UNUSED( feature )
347 Q_UNUSED( context )
348 return QSet< QString >() << QStringLiteral( "0" );
349}
350
351QString QgsSingleSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *, bool &ok ) const
352{
353 if ( key == QLatin1String( "0" ) )
354 {
355 ok = true;
356 return QStringLiteral( "TRUE" );
357 }
358 else
359 {
360 ok = false;
361 return QString();
362 }
363}
364
366{
367 Q_UNUSED( key )
368 setSymbol( symbol );
369}
370
372{
373 QgsSingleSymbolRenderer *r = nullptr;
374 if ( renderer->type() == QLatin1String( "singleSymbol" ) )
375 {
376 r = dynamic_cast<QgsSingleSymbolRenderer *>( renderer->clone() );
377 }
378 else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
379 {
380 const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
381 if ( pointDistanceRenderer )
382 r = convertFromRenderer( pointDistanceRenderer->embeddedRenderer() );
383 }
384 else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
385 {
386 const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
387 if ( invertedPolygonRenderer )
388 r = convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
389 }
390
391 if ( !r )
392 {
393 QgsRenderContext context;
394 const QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
395 if ( !symbols.isEmpty() )
396 {
397 r = new QgsSingleSymbolRenderer( symbols.at( 0 )->clone() );
398 }
399 }
400
401 if ( r )
402 {
403 renderer->copyRendererData( r );
404 }
405
406 return r;
407}
408
413
QFlags< FeatureRendererFlag > FeatureRendererFlags
Flags controlling behavior of vector feature renderers.
Definition qgis.h:838
@ AffectsLabeling
If present, indicates that the renderer will participate in the map labeling problem.
Definition qgis.h:829
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:358
@ Point
Points.
Definition qgis.h:359
@ Line
Lines.
Definition qgis.h:360
@ Polygon
Polygons.
Definition qgis.h:361
@ Marker
Marker symbol.
Definition qgis.h:611
@ AffectsLabeling
If present, indicates that the symbol will participate in the map labeling problem.
Definition qgis.h:849
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.
QgsFeatureRenderer(const QString &type)
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)
Converts old rotation expressions to symbol level data defined angles.
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)
Converts old sizeScale expressions to symbol level data defined sizes.
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
A polygon-only feature renderer used to display features inverted.
Stores information about one class/rule of a vector layer renderer in a unified way that can be used ...
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.
A container for the context for various read/write operations on 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.
Q_DECL_DEPRECATED 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.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
QVariantMap extraProperties() const
Returns the open ended set of properties that can drive/inform the SLD encoding.
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:1397
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 dataset.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6798
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define QgsDebugError(str)
Definition qgslogger.h:57
#define RENDERER_TAG_NAME
Definition qgsrenderer.h:55
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition qgsrenderer.h:50
QList< QgsSymbol * > QgsSymbolList
Definition qgsrenderer.h:49
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30
Contains information relating to the style entity currently being visited.