QGIS API Documentation 3.43.0-Master (ac9f54ad1f7)
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#include "qgssldexportcontext.h"
37
38#include <QDomDocument>
39#include <QDomElement>
40
42 : QgsFeatureRenderer( QStringLiteral( "singleSymbol" ) )
43 , mSymbol( symbol )
44{
45 Q_ASSERT( symbol );
46}
47
55
57
62
64{
65 Q_UNUSED( context )
66 Q_UNUSED( feature )
67 return mSymbol.get();
68}
69
71{
72 QgsFeatureRenderer::startRender( context, fields );
73
74 if ( !mSymbol )
75 return;
76
77 mSymbol->startRender( context, fields );
78}
79
81{
83
84 if ( !mSymbol )
85 return;
86
87 mSymbol->stopRender( context );
88}
89
90QSet<QString> QgsSingleSymbolRenderer::usedAttributes( const QgsRenderContext &context ) const
91{
92 QSet<QString> attributes;
93 if ( mSymbol )
94 attributes.unite( mSymbol->usedAttributes( context ) );
95 return attributes;
96}
97
99{
100 if ( mSymbol )
101 {
102 QgsStyleSymbolEntity entity( mSymbol.get() );
103 return visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) );
104 }
105 return true;
106}
107
109{
110 return mSymbol.get();
111}
112
114{
115 Q_ASSERT( s );
116 mSymbol.reset( s );
117}
118
120{
121 return mSymbol ? QStringLiteral( "SINGLE: %1" ).arg( mSymbol->dump() ) : QString();
122}
123
131
132void QgsSingleSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
133{
134 QgsSldExportContext context;
135 context.setExtraProperties( props );
136 toSld( doc, element, context );
137}
138
139bool QgsSingleSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, QgsSldExportContext &context ) const
140{
141 const QVariantMap oldProps = context.extraProperties();
142 QVariantMap newProps = oldProps;
143
144 QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
145 element.appendChild( ruleElem );
146
147 QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
148 nameElem.appendChild( doc.createTextNode( QStringLiteral( "Single symbol" ) ) );
149 ruleElem.appendChild( nameElem );
150
151 QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, newProps );
152
153 context.setExtraProperties( newProps );
154 if ( mSymbol )
155 mSymbol->toSld( doc, ruleElem, context );
156
157 context.setExtraProperties( oldProps );
158 return true;
159}
160
162{
163 Q_UNUSED( context )
164 QgsSymbolList lst;
165 lst.append( mSymbol.get() );
166 return lst;
167}
168
169
171{
172 QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
173 if ( symbolsElem.isNull() )
174 return nullptr;
175
176 QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
177
178 if ( !symbolMap.contains( QStringLiteral( "0" ) ) )
179 return nullptr;
180
181 QgsSingleSymbolRenderer *r = new QgsSingleSymbolRenderer( symbolMap.take( QStringLiteral( "0" ) ) );
182
183 // delete symbols if there are any more
185
186 const QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
187 if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
188 {
189 convertSymbolRotation( r->mSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
190 }
191
192 const QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
193 if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
194 {
196 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
197 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
198 }
199
200 const QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
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( QStringLiteral( "Rule" ) );
216 if ( ruleElem.isNull() )
217 {
218 QgsDebugError( QStringLiteral( "no Rule elements found!" ) );
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() == QLatin1String( "Name" ) )
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() == QLatin1String( "Description" ) )
237 {
238 // <se:Description> can contains a title and an abstract
239 const QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
240 if ( !titleElem.isNull() )
241 {
242 label = titleElem.firstChild().nodeValue();
243 }
244
245 const QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
246 if ( !abstractElem.isNull() )
247 {
248 description = abstractElem.firstChild().nodeValue();
249 }
250 }
251 else if ( childElem.localName() == QLatin1String( "Abstract" ) )
252 {
253 // <sld:Abstract> (v1.0)
254 description = childElem.firstChild().nodeValue();
255 }
256 else if ( childElem.localName() == QLatin1String( "Title" ) )
257 {
258 // <sld:Title> (v1.0)
259 label = childElem.firstChild().nodeValue();
260 }
261 else if ( childElem.localName().endsWith( QLatin1String( "Symbolizer" ) ) )
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( QStringLiteral( "invalid geometry type: found %1" ).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( QStringLiteral( "type" ), QStringLiteral( "singleSymbol" ) );
302
304 symbols[QStringLiteral( "0" )] = mSymbol.get();
305 const QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
306 rendererElem.appendChild( symbolsElem );
307
308 const QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
309 rendererElem.appendChild( rotationElem );
310
311 const QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
312 rendererElem.appendChild( sizeScaleElem );
313
315 {
316 QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
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(), QStringLiteral( "0" ) );
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 >() << QStringLiteral( "0" );
350}
351
352QString QgsSingleSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *, bool &ok ) const
353{
354 if ( key == QLatin1String( "0" ) )
355 {
356 ok = true;
357 return QStringLiteral( "TRUE" );
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() == QLatin1String( "singleSymbol" ) )
376 {
377 r = dynamic_cast<QgsSingleSymbolRenderer *>( renderer->clone() );
378 }
379 else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
380 {
381 const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
382 if ( pointDistanceRenderer )
383 r = convertFromRenderer( pointDistanceRenderer->embeddedRenderer() );
384 }
385 else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
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:802
@ 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)
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.
A feature renderer which renders all features with the same symbol.
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:6493
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define QgsDebugError(str)
Definition qgslogger.h:40
#define RENDERER_TAG_NAME
Definition qgsrenderer.h:54
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition qgsrenderer.h:49
QList< QgsSymbol * > QgsSymbolList
Definition qgsrenderer.h:48
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition qgssymbol.h:30
Contains information relating to the style entity currently being visited.