QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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"
30 #include "qgspainteffectregistry.h"
31 #include "qgsproperty.h"
32 #include "qgsstyleentityvisitor.h"
33 
34 #include <QDomDocument>
35 #include <QDomElement>
36 
38  : QgsFeatureRenderer( QStringLiteral( "singleSymbol" ) )
39  , mSymbol( symbol )
40 {
41  Q_ASSERT( symbol );
42 }
43 
45 
47 {
48  return mSymbol.get();
49 }
50 
52 {
53  Q_UNUSED( context )
54  Q_UNUSED( feature )
55  return mSymbol.get();
56 }
57 
59 {
60  QgsFeatureRenderer::startRender( context, fields );
61 
62  if ( !mSymbol )
63  return;
64 
65  mSymbol->startRender( context, fields );
66 }
67 
69 {
71 
72  if ( !mSymbol )
73  return;
74 
75  mSymbol->stopRender( context );
76 }
77 
78 QSet<QString> QgsSingleSymbolRenderer::usedAttributes( const QgsRenderContext &context ) const
79 {
80  QSet<QString> attributes;
81  if ( mSymbol )
82  attributes.unite( mSymbol->usedAttributes( context ) );
83  return attributes;
84 }
85 
87 {
88  if ( mSymbol )
89  {
90  QgsStyleSymbolEntity entity( mSymbol.get() );
91  return visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) );
92  }
93  return true;
94 }
95 
97 {
98  return mSymbol.get();
99 }
100 
102 {
103  Q_ASSERT( s );
104  mSymbol.reset( s );
105 }
106 
108 {
109  return mSymbol ? QStringLiteral( "SINGLE: %1" ).arg( mSymbol->dump() ) : QString();
110 }
111 
113 {
117  copyRendererData( r );
118  return r;
119 }
120 
121 void QgsSingleSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
122 {
123  QVariantMap newProps = props;
124 
125  QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
126  element.appendChild( ruleElem );
127 
128  QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
129  nameElem.appendChild( doc.createTextNode( QStringLiteral( "Single symbol" ) ) );
130  ruleElem.appendChild( nameElem );
131 
132  QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, newProps );
133 
134  if ( mSymbol ) mSymbol->toSld( doc, ruleElem, newProps );
135 }
136 
138 {
139  Q_UNUSED( context )
140  QgsSymbolList lst;
141  lst.append( mSymbol.get() );
142  return lst;
143 }
144 
145 
147 {
148  QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
149  if ( symbolsElem.isNull() )
150  return nullptr;
151 
152  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
153 
154  if ( !symbolMap.contains( QStringLiteral( "0" ) ) )
155  return nullptr;
156 
157  QgsSingleSymbolRenderer *r = new QgsSingleSymbolRenderer( symbolMap.take( QStringLiteral( "0" ) ) );
158 
159  // delete symbols if there are any more
161 
162  QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
163  if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
164  {
165  convertSymbolRotation( r->mSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
166  }
167 
168  QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
169  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
170  {
172  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
173  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
174  }
175 
176  QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
177  if ( !ddsLegendSizeElem.isNull() )
178  {
179  r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
180  }
181 
182  // TODO: symbol levels
183  return r;
184 }
185 
187 {
188  // XXX this renderer can handle only one Rule!
189 
190  // get the first Rule element
191  QDomElement ruleElem = element.firstChildElement( QStringLiteral( "Rule" ) );
192  if ( ruleElem.isNull() )
193  {
194  QgsDebugMsg( QStringLiteral( "no Rule elements found!" ) );
195  return nullptr;
196  }
197 
198  QString label, description;
199  QgsSymbolLayerList layers;
200 
201  // retrieve the Rule element child nodes
202  QDomElement childElem = ruleElem.firstChildElement();
203  while ( !childElem.isNull() )
204  {
205  if ( childElem.localName() == QLatin1String( "Name" ) )
206  {
207  // <se:Name> tag contains the rule identifier,
208  // so prefer title tag for the label property value
209  if ( label.isEmpty() )
210  label = childElem.firstChild().nodeValue();
211  }
212  else if ( childElem.localName() == QLatin1String( "Description" ) )
213  {
214  // <se:Description> can contains a title and an abstract
215  QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
216  if ( !titleElem.isNull() )
217  {
218  label = titleElem.firstChild().nodeValue();
219  }
220 
221  QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
222  if ( !abstractElem.isNull() )
223  {
224  description = abstractElem.firstChild().nodeValue();
225  }
226  }
227  else if ( childElem.localName() == QLatin1String( "Abstract" ) )
228  {
229  // <sld:Abstract> (v1.0)
230  description = childElem.firstChild().nodeValue();
231  }
232  else if ( childElem.localName() == QLatin1String( "Title" ) )
233  {
234  // <sld:Title> (v1.0)
235  label = childElem.firstChild().nodeValue();
236  }
237  else if ( childElem.localName().endsWith( QLatin1String( "Symbolizer" ) ) )
238  {
239  // create symbol layers for this symbolizer
240  QgsSymbolLayerUtils::createSymbolLayerListFromSld( childElem, geomType, layers );
241  }
242 
243  childElem = childElem.nextSiblingElement();
244  }
245 
246  if ( layers.isEmpty() )
247  return nullptr;
248 
249  // now create the symbol
250  std::unique_ptr< QgsSymbol > symbol;
251  switch ( geomType )
252  {
254  symbol = qgis::make_unique< QgsLineSymbol >( layers );
255  break;
256 
258  symbol = qgis::make_unique< QgsFillSymbol >( layers );
259  break;
260 
262  symbol = qgis::make_unique< QgsMarkerSymbol >( layers );
263  break;
264 
265  default:
266  QgsDebugMsg( QStringLiteral( "invalid geometry type: found %1" ).arg( geomType ) );
267  return nullptr;
268  }
269 
270  // and finally return the new renderer
271  return new QgsSingleSymbolRenderer( symbol.release() );
272 }
273 
274 QDomElement QgsSingleSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
275 {
276  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
277  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "singleSymbol" ) );
278  rendererElem.setAttribute( QStringLiteral( "symbollevels" ), ( mUsingSymbolLevels ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
279  rendererElem.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
280 
282  symbols[QStringLiteral( "0" )] = mSymbol.get();
283  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
284  rendererElem.appendChild( symbolsElem );
285 
286  QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
287  rendererElem.appendChild( rotationElem );
288 
289  QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
290  rendererElem.appendChild( sizeScaleElem );
291 
293  mPaintEffect->saveProperties( doc, rendererElem );
294 
295  if ( !mOrderBy.isEmpty() )
296  {
297  QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
298  mOrderBy.save( orderBy );
299  rendererElem.appendChild( orderBy );
300  }
301  rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
302 
304  {
305  QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
306  mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
307  rendererElem.appendChild( ddsLegendElem );
308  }
309 
310  return rendererElem;
311 }
312 
314 {
316  {
317  const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( mSymbol.get() );
318  QgsProperty sizeDD( symbol->dataDefinedSize() );
319  if ( sizeDD && sizeDD.isActive() )
320  {
322  ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSymbol.get() ), sizeDD );
323  return ddSizeLegend.legendSymbolList();
324  }
325  }
326 
328  lst << QgsLegendSymbolItem( mSymbol.get(), QString(), QStringLiteral( "0" ) );
329  return lst;
330 }
331 
332 QSet< QString > QgsSingleSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
333 {
334  Q_UNUSED( feature )
335  Q_UNUSED( context )
336  return QSet< QString >() << QStringLiteral( "0" );
337 }
338 
339 void QgsSingleSymbolRenderer::setLegendSymbolItem( const QString &key, QgsSymbol *symbol )
340 {
341  Q_UNUSED( key )
342  setSymbol( symbol );
343 }
344 
346 {
347  QgsSingleSymbolRenderer *r = nullptr;
348  if ( renderer->type() == QLatin1String( "singleSymbol" ) )
349  {
350  r = dynamic_cast<QgsSingleSymbolRenderer *>( renderer->clone() );
351  }
352  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
353  {
354  const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
355  if ( pointDistanceRenderer )
356  r = convertFromRenderer( pointDistanceRenderer->embeddedRenderer() );
357  }
358  else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
359  {
360  const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
361  if ( invertedPolygonRenderer )
362  r = convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
363  }
364 
365  if ( !r )
366  {
367  QgsRenderContext context;
368  QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
369  if ( !symbols.isEmpty() )
370  {
371  r = new QgsSingleSymbolRenderer( symbols.at( 0 )->clone() );
372  }
373  }
374 
375  if ( r )
376  {
377  r->setOrderBy( renderer->orderBy() );
378  r->setOrderByEnabled( renderer->orderByEnabled() );
379  }
380 
381  return r;
382 }
383 
385 {
386  mDataDefinedSizeLegend.reset( settings );
387 }
388 
390 {
391  return mDataDefinedSizeLegend.get();
392 }
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.
void setOrderBy(const QgsFeatureRequest::OrderBy &orderBy)
Define the order in which features shall be processed by this renderer.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
void setOrderByEnabled(bool enabled)
Sets whether custom ordering should be applied before features are processed by this renderer.
static void convertSymbolSizeScale(QgsSymbol *symbol, QgsSymbol::ScaleMethod method, const QString &field)
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QgsPaintEffect * mPaintEffect
Definition: qgsrenderer.h:529
QString type() const
Definition: qgsrenderer.h:141
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:50
bool usingSymbolLevels() const
Definition: qgsrenderer.h:283
void setUsingSymbolLevels(bool usingSymbolLevels)
Definition: qgsrenderer.h:284
bool orderByEnabled() const
Returns whether custom ordering will be applied before features are processed by this renderer.
static void convertSymbolRotation(QgsSymbol *symbol, const QString &field)
QgsFeatureRequest::OrderBy mOrderBy
Definition: qgsrenderer.h:545
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
Definition: qgsrenderer.cpp:94
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
Container of fields for a vector layer.
Definition: qgsfields.h:45
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.
Definition: qgssymbol.h:1004
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
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.
Definition: qgsproperty.h:232
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
store renderer info to XML element
QgsSymbol * symbol() const
Returns the symbol which will be rendered for every feature.
void setSymbol(QgsSymbol *s)
Sets the symbol which will be rendered for every feature.
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...
static QgsFeatureRenderer * createFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType)
Creates a new single symbol renderer from an SLD element.
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:1201
static bool createSymbolLayerListFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType, QgsSymbolLayerList &layers)
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 void clearSymbolMap(QgsSymbolMap &symbols)
static QgsSymbol::ScaleMethod decodeScaleMethod(const QString &str)
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:65
@ Marker
Marker symbol.
Definition: qgssymbol.h:88
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
#define RENDERER_TAG_NAME
Definition: qgsrenderer.h:51
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition: qgsrenderer.h:46
QList< QgsSymbol * > QgsSymbolList
Definition: qgsrenderer.h:45
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:54
Contains information relating to the style entity currently being visited.