QGIS API Documentation 4.1.0-Master (60fea48833c)
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#include <QString>
40
41using namespace Qt::StringLiterals;
42
44 : QgsFeatureRenderer( u"singleSymbol"_s )
45 , mSymbol( symbol )
46{
47 Q_ASSERT( symbol );
48}
49
57
59
64
66{
67 Q_UNUSED( context )
68 Q_UNUSED( feature )
69 return mSymbol.get();
70}
71
73{
74 QgsFeatureRenderer::startRender( context, fields );
75
76 if ( !mSymbol )
77 return;
78
79 mSymbol->startRender( context, fields );
80}
81
83{
85
86 if ( !mSymbol )
87 return;
88
89 mSymbol->stopRender( context );
90}
91
92QSet<QString> QgsSingleSymbolRenderer::usedAttributes( const QgsRenderContext &context ) const
93{
94 QSet<QString> attributes;
95 if ( mSymbol )
96 attributes.unite( mSymbol->usedAttributes( context ) );
97 return attributes;
98}
99
101{
102 if ( mSymbol )
103 {
104 QgsStyleSymbolEntity entity( mSymbol.get() );
105 return visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) );
106 }
107 return true;
108}
109
111{
112 return mSymbol.get();
113}
114
116{
117 Q_ASSERT( s );
118 mSymbol.reset( s );
119}
120
122{
123 return mSymbol ? u"SINGLE: %1"_s.arg( mSymbol->dump() ) : QString();
124}
125
133
134void QgsSingleSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
135{
136 QgsSldExportContext context;
137 context.setExtraProperties( props );
138 toSld( doc, element, context );
139}
140
141bool QgsSingleSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, QgsSldExportContext &context ) const
142{
143 const QVariantMap oldProps = context.extraProperties();
144 QVariantMap newProps = oldProps;
145
146 QDomElement ruleElem = doc.createElement( u"se:Rule"_s );
147 element.appendChild( ruleElem );
148
149 QDomElement nameElem = doc.createElement( u"se:Name"_s );
150 nameElem.appendChild( doc.createTextNode( u"Single symbol"_s ) );
151 ruleElem.appendChild( nameElem );
152
153 QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, newProps );
154
155 context.setExtraProperties( newProps );
156 if ( mSymbol )
157 mSymbol->toSld( doc, ruleElem, context );
158
159 context.setExtraProperties( oldProps );
160 return true;
161}
162
164{
165 Q_UNUSED( context )
166 QgsSymbolList lst;
167 lst.append( mSymbol.get() );
168 return lst;
169}
170
171
173{
174 QDomElement symbolsElem = element.firstChildElement( u"symbols"_s );
175 if ( symbolsElem.isNull() )
176 return nullptr;
177
178 QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
179
180 if ( !symbolMap.contains( u"0"_s ) )
181 return nullptr;
182
183 QgsSingleSymbolRenderer *r = new QgsSingleSymbolRenderer( symbolMap.take( u"0"_s ) );
184
185 // delete symbols if there are any more
187
188 const QDomElement rotationElem = element.firstChildElement( u"rotation"_s );
189 if ( !rotationElem.isNull() && !rotationElem.attribute( u"field"_s ).isEmpty() )
190 {
191 convertSymbolRotation( r->mSymbol.get(), rotationElem.attribute( u"field"_s ) );
192 }
193
194 const QDomElement sizeScaleElem = element.firstChildElement( u"sizescale"_s );
195 if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( u"field"_s ).isEmpty() )
196 {
197 convertSymbolSizeScale( r->mSymbol.get(), QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( u"scalemethod"_s ) ), sizeScaleElem.attribute( u"field"_s ) );
198 }
199
200 const QDomElement ddsLegendSizeElem = element.firstChildElement( u"data-defined-size-legend"_s );
201 if ( !ddsLegendSizeElem.isNull() )
202 {
203 r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
204 }
205
206 // TODO: symbol levels
207 return r;
208}
209
211{
212 // XXX this renderer can handle only one Rule!
213
214 // get the first Rule element
215 const QDomElement ruleElem = element.firstChildElement( u"Rule"_s );
216 if ( ruleElem.isNull() )
217 {
218 QgsDebugError( u"no Rule elements found!"_s );
219 return nullptr;
220 }
221
222 QString label, description;
223 QgsSymbolLayerList layers;
224
225 // retrieve the Rule element child nodes
226 QDomElement childElem = ruleElem.firstChildElement();
227 while ( !childElem.isNull() )
228 {
229 if ( childElem.localName() == "Name"_L1 )
230 {
231 // <se:Name> tag contains the rule identifier,
232 // so prefer title tag for the label property value
233 if ( label.isEmpty() )
234 label = childElem.firstChild().nodeValue();
235 }
236 else if ( childElem.localName() == "Description"_L1 )
237 {
238 // <se:Description> can contains a title and an abstract
239 const QDomElement titleElem = childElem.firstChildElement( u"Title"_s );
240 if ( !titleElem.isNull() )
241 {
242 label = titleElem.firstChild().nodeValue();
243 }
244
245 const QDomElement abstractElem = childElem.firstChildElement( u"Abstract"_s );
246 if ( !abstractElem.isNull() )
247 {
248 description = abstractElem.firstChild().nodeValue();
249 }
250 }
251 else if ( childElem.localName() == "Abstract"_L1 )
252 {
253 // <sld:Abstract> (v1.0)
254 description = childElem.firstChild().nodeValue();
255 }
256 else if ( childElem.localName() == "Title"_L1 )
257 {
258 // <sld:Title> (v1.0)
259 label = childElem.firstChild().nodeValue();
260 }
261 else if ( childElem.localName().endsWith( "Symbolizer"_L1 ) )
262 {
263 // create symbol layers for this symbolizer
264 QgsSymbolLayerUtils::createSymbolLayerListFromSld( childElem, geomType, layers );
265 }
266
267 childElem = childElem.nextSiblingElement();
268 }
269
270 if ( layers.isEmpty() )
271 return nullptr;
272
273 // now create the symbol
274 std::unique_ptr< QgsSymbol > symbol;
275 switch ( geomType )
276 {
278 symbol = std::make_unique< QgsLineSymbol >( layers );
279 break;
280
282 symbol = std::make_unique< QgsFillSymbol >( layers );
283 break;
284
286 symbol = std::make_unique< QgsMarkerSymbol >( layers );
287 break;
288
289 default:
290 QgsDebugError( u"invalid geometry type: found %1"_s.arg( qgsEnumValueToKey( geomType ) ) );
291 return nullptr;
292 }
293
294 // and finally return the new renderer
295 return new QgsSingleSymbolRenderer( symbol.release() );
296}
297
298QDomElement QgsSingleSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
299{
300 QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
301 rendererElem.setAttribute( u"type"_s, u"singleSymbol"_s );
302
304 symbols[u"0"_s] = mSymbol.get();
305 const QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, u"symbols"_s, doc, context );
306 rendererElem.appendChild( symbolsElem );
307
308 const QDomElement rotationElem = doc.createElement( u"rotation"_s );
309 rendererElem.appendChild( rotationElem );
310
311 const QDomElement sizeScaleElem = doc.createElement( u"sizescale"_s );
312 rendererElem.appendChild( sizeScaleElem );
313
315 {
316 QDomElement ddsLegendElem = doc.createElement( u"data-defined-size-legend"_s );
317 mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
318 rendererElem.appendChild( ddsLegendElem );
319 }
320
321 saveRendererData( doc, rendererElem, context );
322
323 return rendererElem;
324}
325
327{
329 {
330 const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( mSymbol.get() );
331 const QgsProperty sizeDD( symbol->dataDefinedSize() );
332 if ( sizeDD && sizeDD.isActive() )
333 {
335 ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSymbol.get() ), sizeDD );
336 return ddSizeLegend.legendSymbolList();
337 }
338 }
339
341 lst << QgsLegendSymbolItem( mSymbol.get(), QString(), u"0"_s );
342 return lst;
343}
344
345QSet< QString > QgsSingleSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
346{
347 Q_UNUSED( feature )
348 Q_UNUSED( context )
349 return QSet< QString >() << u"0"_s;
350}
351
352QString QgsSingleSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *, bool &ok ) const
353{
354 if ( key == "0"_L1 )
355 {
356 ok = true;
357 return u"TRUE"_s;
358 }
359 else
360 {
361 ok = false;
362 return QString();
363 }
364}
365
367{
368 Q_UNUSED( key )
369 setSymbol( symbol );
370}
371
373{
374 QgsSingleSymbolRenderer *r = nullptr;
375 if ( renderer->type() == "singleSymbol"_L1 )
376 {
377 r = dynamic_cast<QgsSingleSymbolRenderer *>( renderer->clone() );
378 }
379 else if ( renderer->type() == "pointDisplacement"_L1 || renderer->type() == "pointCluster"_L1 )
380 {
381 const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
382 if ( pointDistanceRenderer )
383 r = convertFromRenderer( pointDistanceRenderer->embeddedRenderer() );
384 }
385 else if ( renderer->type() == "invertedPolygonRenderer"_L1 )
386 {
387 const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
388 if ( invertedPolygonRenderer )
389 r = convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
390 }
391
392 if ( !r )
393 {
394 QgsRenderContext context;
395 const QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
396 if ( !symbols.isEmpty() )
397 {
398 r = new QgsSingleSymbolRenderer( symbols.at( 0 )->clone() );
399 }
400 }
401
402 if ( r )
403 {
404 renderer->copyRendererData( r );
405 }
406
407 return r;
408}
409
414
QFlags< FeatureRendererFlag > FeatureRendererFlags
Flags controlling behavior of vector feature renderers.
Definition qgis.h:864
@ AffectsLabeling
If present, indicates that the renderer will participate in the map labeling problem.
Definition qgis.h:855
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:379
@ Point
Points.
Definition qgis.h:380
@ Line
Lines.
Definition qgis.h:381
@ Polygon
Polygons.
Definition qgis.h:382
@ Marker
Marker symbol.
Definition qgis.h:637
@ AffectsLabeling
If present, indicates that the symbol will participate in the map labeling problem.
Definition qgis.h:875
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:60
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:1393
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:227
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:7157
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define QgsDebugError(str)
Definition qgslogger.h:59
#define RENDERER_TAG_NAME
Definition qgsrenderer.h:57
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition qgsrenderer.h:52
QList< QgsSymbol * > QgsSymbolList
Definition qgsrenderer.h:51
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30
Contains information relating to the style entity currently being visited.