QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsdiagramrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsdiagramrenderer.cpp
3 ---------------------
4 begin : March 2011
5 copyright : (C) 2011 by Marco Hugentobler
6 email : marco dot hugentobler at sourcepole dot ch
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#include "qgsdiagramrenderer.h"
16
17#include <memory>
18
24#include "qgsapplication.h"
25#include "qgscolorutils.h"
27#include "qgsfontutils.h"
29#include "qgslinesymbol.h"
30#include "qgsmarkersymbol.h"
31#include "qgspainteffect.h"
33#include "qgsrendercontext.h"
34#include "qgsscaleutils.h"
35#include "qgssymbollayerutils.h"
36#include "qgsunittypes.h"
37
38#include <QDomElement>
39#include <QPainter>
40
41QgsPropertiesDefinition QgsDiagramLayerSettings::sPropertyDefinitions;
42
43void QgsDiagramLayerSettings::initPropertyDefinitions()
44{
45 if ( !sPropertyDefinitions.isEmpty() )
46 return;
47
48 const QString origin = QStringLiteral( "diagram" );
49
50 sPropertyDefinitions = QgsPropertiesDefinition
51 {
52 { static_cast< int >( QgsDiagramLayerSettings::Property::BackgroundColor ), QgsPropertyDefinition( "backgroundColor", QObject::tr( "Background color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
53 { static_cast< int >( QgsDiagramLayerSettings::Property::StrokeColor ), QgsPropertyDefinition( "strokeColor", QObject::tr( "Stroke color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
54 { static_cast< int >( QgsDiagramLayerSettings::Property::StrokeWidth ), QgsPropertyDefinition( "strokeWidth", QObject::tr( "Stroke width" ), QgsPropertyDefinition::StrokeWidth, origin ) },
55 { static_cast< int >( QgsDiagramLayerSettings::Property::PositionX ), QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double, origin ) },
56 { static_cast< int >( QgsDiagramLayerSettings::Property::PositionY ), QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double, origin ) },
57 { static_cast< int >( QgsDiagramLayerSettings::Property::Distance ), QgsPropertyDefinition( "distance", QObject::tr( "Placement distance" ), QgsPropertyDefinition::DoublePositive, origin ) },
58 { static_cast< int >( QgsDiagramLayerSettings::Property::Priority ), QgsPropertyDefinition( "priority", QObject::tr( "Placement priority" ), QgsPropertyDefinition::DoublePositive, origin ) },
59 { static_cast< int >( QgsDiagramLayerSettings::Property::ZIndex ), QgsPropertyDefinition( "zIndex", QObject::tr( "Placement z-index" ), QgsPropertyDefinition::Double, origin ) },
60 { static_cast< int >( QgsDiagramLayerSettings::Property::IsObstacle ), QgsPropertyDefinition( "isObstacle", QObject::tr( "Diagram is an obstacle" ), QgsPropertyDefinition::Boolean, origin ) },
61 { static_cast< int >( QgsDiagramLayerSettings::Property::Show ), QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean, origin ) },
62 { static_cast< int >( QgsDiagramLayerSettings::Property::AlwaysShow ), QgsPropertyDefinition( "alwaysShow", QObject::tr( "Always show diagram" ), QgsPropertyDefinition::Boolean, origin ) },
63 { static_cast< int >( QgsDiagramLayerSettings::Property::StartAngle ), QgsPropertyDefinition( "startAngle", QObject::tr( "Pie chart start angle" ), QgsPropertyDefinition::Rotation, origin ) },
64 };
65}
66
68{
69 initPropertyDefinitions();
70 return sPropertyDefinitions;
71}
72
74{
75 initPropertyDefinitions();
76}
77
79//****** IMPORTANT! editing this? make sure you update the move constructor too! *****
80 : mCt( rh.mCt )
81 , mPlacement( rh.mPlacement )
82 , mPlacementFlags( rh.mPlacementFlags )
83 , mPriority( rh.mPriority )
84 , mZIndex( rh.mZIndex )
85 , mObstacle( rh.mObstacle )
86 , mDistance( rh.mDistance )
87 , mRenderer( rh.mRenderer ? rh.mRenderer->clone() : nullptr )
88 , mShowAll( rh.mShowAll )
89 , mDataDefinedProperties( rh.mDataDefinedProperties )
90 //****** IMPORTANT! editing this? make sure you update the move constructor too! *****
91{
92 initPropertyDefinitions();
93}
94
96 : mCt( std::move( rh.mCt ) )
97 , mPlacement( rh.mPlacement )
98 , mPlacementFlags( rh.mPlacementFlags )
99 , mPriority( rh.mPriority )
100 , mZIndex( rh.mZIndex )
101 , mObstacle( rh.mObstacle )
102 , mDistance( rh.mDistance )
103 , mRenderer( std::move( rh.mRenderer ) )
104 , mShowAll( rh.mShowAll )
105 , mDataDefinedProperties( std::move( rh.mDataDefinedProperties ) )
106{
107}
108
110{
111 if ( &rh == this )
112 return *this;
113
114 //****** IMPORTANT! editing this? make sure you update the move assignment operator too! *****
115 mPlacement = rh.mPlacement;
116 mPlacementFlags = rh.mPlacementFlags;
117 mPriority = rh.mPriority;
118 mZIndex = rh.mZIndex;
119 mObstacle = rh.mObstacle;
120 mDistance = rh.mDistance;
121 mRenderer.reset( rh.mRenderer ? rh.mRenderer->clone() : nullptr );
122 mCt = rh.mCt;
123 mShowAll = rh.mShowAll;
124 mDataDefinedProperties = rh.mDataDefinedProperties;
125 //****** IMPORTANT! editing this? make sure you update the move assignment operator too! *****
126 return *this;
127}
128
130{
131 if ( &rh == this )
132 return *this;
133
134 mPlacement = rh.mPlacement;
135 mPlacementFlags = rh.mPlacementFlags;
136 mPriority = rh.mPriority;
137 mZIndex = rh.mZIndex;
138 mObstacle = rh.mObstacle;
139 mDistance = rh.mDistance;
140 mRenderer = std::move( rh.mRenderer );
141 mCt = std::move( rh.mCt );
142 mShowAll = rh.mShowAll;
143 mDataDefinedProperties = std::move( rh.mDataDefinedProperties );
144 return *this;
145}
146
151
153{
154 if ( diagramRenderer == mRenderer.get() )
155 return;
156
157 mRenderer.reset( diagramRenderer );
158
159}
160
162{
163 mCt = transform;
164}
165
166void QgsDiagramLayerSettings::readXml( const QDomElement &elem )
167{
168 const QDomNodeList propertyElems = elem.elementsByTagName( QStringLiteral( "properties" ) );
169 if ( !propertyElems.isEmpty() )
170 {
171 ( void )mDataDefinedProperties.readXml( propertyElems.at( 0 ).toElement(), sPropertyDefinitions );
172 }
173 else
174 {
175 mDataDefinedProperties.clear();
176 }
177
178 mPlacement = static_cast< Placement >( elem.attribute( QStringLiteral( "placement" ) ).toInt() );
179 mPlacementFlags = static_cast< LinePlacementFlag >( elem.attribute( QStringLiteral( "linePlacementFlags" ) ).toInt() );
180 mPriority = elem.attribute( QStringLiteral( "priority" ) ).toInt();
181 mZIndex = elem.attribute( QStringLiteral( "zIndex" ) ).toDouble();
182 mObstacle = elem.attribute( QStringLiteral( "obstacle" ) ).toInt();
183 mDistance = elem.attribute( QStringLiteral( "dist" ) ).toDouble();
184 mShowAll = ( elem.attribute( QStringLiteral( "showAll" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
185}
186
187void QgsDiagramLayerSettings::writeXml( QDomElement &layerElem, QDomDocument &doc ) const
188{
189 QDomElement diagramLayerElem = doc.createElement( QStringLiteral( "DiagramLayerSettings" ) );
190 QDomElement propertiesElem = doc.createElement( QStringLiteral( "properties" ) );
191 ( void )mDataDefinedProperties.writeXml( propertiesElem, sPropertyDefinitions );
192 diagramLayerElem.appendChild( propertiesElem );
193 diagramLayerElem.setAttribute( QStringLiteral( "placement" ), mPlacement );
194 diagramLayerElem.setAttribute( QStringLiteral( "linePlacementFlags" ), mPlacementFlags );
195 diagramLayerElem.setAttribute( QStringLiteral( "priority" ), mPriority );
196 diagramLayerElem.setAttribute( QStringLiteral( "zIndex" ), mZIndex );
197 diagramLayerElem.setAttribute( QStringLiteral( "obstacle" ), mObstacle );
198 diagramLayerElem.setAttribute( QStringLiteral( "dist" ), QString::number( mDistance ) );
199 diagramLayerElem.setAttribute( QStringLiteral( "showAll" ), mShowAll );
200 layerElem.appendChild( diagramLayerElem );
201}
202
204{
205 return mDataDefinedProperties.prepare( context );
206}
207
209{
210 QSet< QString > referenced;
211 if ( mRenderer )
212 referenced = mRenderer->referencedFields( context );
213
214 //add the ones needed for data defined settings
215 referenced.unite( mDataDefinedProperties.referencedFields( context ) );
216
217 return referenced;
218}
219
220void QgsDiagramSettings::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
221{
222 enabled = ( elem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
223 if ( !QgsFontUtils::setFromXmlChildNode( font, elem, QStringLiteral( "fontProperties" ) ) )
224 {
225 font.fromString( elem.attribute( QStringLiteral( "font" ) ) );
226 }
227 backgroundColor.setNamedColor( elem.attribute( QStringLiteral( "backgroundColor" ) ) );
228 backgroundColor.setAlpha( elem.attribute( QStringLiteral( "backgroundAlpha" ) ).toInt() );
229 size.setWidth( elem.attribute( QStringLiteral( "width" ) ).toDouble() );
230 size.setHeight( elem.attribute( QStringLiteral( "height" ) ).toDouble() );
231 if ( elem.hasAttribute( QStringLiteral( "transparency" ) ) )
232 {
233 opacity = 1 - elem.attribute( QStringLiteral( "transparency" ), QStringLiteral( "0" ) ).toInt() / 255.0;
234 }
235 else
236 {
237 opacity = elem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1.00" ) ).toDouble();
238 }
239
240 penColor.setNamedColor( elem.attribute( QStringLiteral( "penColor" ) ) );
241 const int penAlpha = elem.attribute( QStringLiteral( "penAlpha" ), QStringLiteral( "255" ) ).toInt();
242 penColor.setAlpha( penAlpha );
243 penWidth = elem.attribute( QStringLiteral( "penWidth" ) ).toDouble();
244
245 mDirection = static_cast< Direction >( elem.attribute( QStringLiteral( "direction" ), QStringLiteral( "1" ) ).toInt() );
246
247 maximumScale = elem.attribute( QStringLiteral( "minScaleDenominator" ), QStringLiteral( "-1" ) ).toDouble();
248 minimumScale = elem.attribute( QStringLiteral( "maxScaleDenominator" ), QStringLiteral( "-1" ) ).toDouble();
249 if ( elem.hasAttribute( QStringLiteral( "scaleBasedVisibility" ) ) )
250 {
251 scaleBasedVisibility = ( elem.attribute( QStringLiteral( "scaleBasedVisibility" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
252 }
253 else
254 {
256 }
257
258 //diagram size unit type and scale
259 if ( elem.attribute( QStringLiteral( "sizeType" ) ) == QLatin1String( "MapUnits" ) )
260 {
261 //compatibility with pre-2.16 project files
263 }
264 else
265 {
266 sizeType = QgsUnitTypes::decodeRenderUnit( elem.attribute( QStringLiteral( "sizeType" ) ) );
267 }
268 sizeScale = QgsSymbolLayerUtils::decodeMapUnitScale( elem.attribute( QStringLiteral( "sizeScale" ) ) );
269
270 //line width unit type and scale
271 lineSizeUnit = QgsUnitTypes::decodeRenderUnit( elem.attribute( QStringLiteral( "lineSizeType" ) ) );
272 lineSizeScale = QgsSymbolLayerUtils::decodeMapUnitScale( elem.attribute( QStringLiteral( "lineSizeScale" ) ) );
273
274 mSpacing = elem.attribute( QStringLiteral( "spacing" ) ).toDouble();
275 mSpacingUnit = QgsUnitTypes::decodeRenderUnit( elem.attribute( QStringLiteral( "spacingUnit" ) ) );
276 mSpacingMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( elem.attribute( QStringLiteral( "spacingUnitScale" ) ) );
277
278 mStackedDiagramSpacing = elem.attribute( QStringLiteral( "stackedDiagramSpacing" ) ).toDouble();
279 mStackedDiagramSpacingUnit = QgsUnitTypes::decodeRenderUnit( elem.attribute( QStringLiteral( "stackedDiagramSpacingUnit" ) ) );
280 mStackedDiagramSpacingMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( elem.attribute( QStringLiteral( "stackedDiagramSpacingUnitScale" ) ) );
281
282 //label placement method
283 if ( elem.attribute( QStringLiteral( "labelPlacementMethod" ) ) == QLatin1String( "Height" ) )
284 {
286 }
287 else
288 {
290 }
291
292 // orientation
293 if ( elem.attribute( QStringLiteral( "diagramOrientation" ) ) == QLatin1String( "Left" ) )
294 {
296 }
297 else if ( elem.attribute( QStringLiteral( "diagramOrientation" ) ) == QLatin1String( "Right" ) )
298 {
300 }
301 else if ( elem.attribute( QStringLiteral( "diagramOrientation" ) ) == QLatin1String( "Down" ) )
302 {
304 }
305 else
306 {
308 }
309
310 // stacked mode
311 if ( elem.attribute( QStringLiteral( "stackedDiagramMode" ) ) == QLatin1String( "Horizontal" ) )
312 {
314 }
315 else if ( elem.attribute( QStringLiteral( "stackedDiagramMode" ) ) == QLatin1String( "Vertical" ) )
316 {
318 }
319
320 // scale dependency
321 if ( elem.attribute( QStringLiteral( "scaleDependency" ) ) == QLatin1String( "Diameter" ) )
322 {
323 scaleByArea = false;
324 }
325 else
326 {
327 scaleByArea = true;
328 }
329
330 barWidth = elem.attribute( QStringLiteral( "barWidth" ) ).toDouble();
331
332 if ( elem.hasAttribute( QStringLiteral( "angleOffset" ) ) )
333 rotationOffset = std::fmod( 360.0 - elem.attribute( QStringLiteral( "angleOffset" ) ).toInt() / 16.0, 360.0 );
334 else
335 rotationOffset = elem.attribute( QStringLiteral( "rotationOffset" ) ).toDouble();
336
337 minimumSize = elem.attribute( QStringLiteral( "minimumSize" ) ).toDouble();
338
339 const QDomNodeList axisSymbolNodes = elem.elementsByTagName( QStringLiteral( "axisSymbol" ) );
340 if ( axisSymbolNodes.count() > 0 )
341 {
342 const QDomElement axisSymbolElem = axisSymbolNodes.at( 0 ).toElement().firstChildElement();
343 mAxisLineSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( axisSymbolElem, context );
344 }
345 else
346 {
347 mAxisLineSymbol = std::make_unique< QgsLineSymbol >();
348 }
349
350 mShowAxis = elem.attribute( QStringLiteral( "showAxis" ), QStringLiteral( "0" ) ).toInt();
351
352 //colors
353 categoryColors.clear();
354 const QDomNodeList attributes = elem.elementsByTagName( QStringLiteral( "attribute" ) );
355
356
357 if ( attributes.length() > 0 )
358 {
359 for ( int i = 0; i < attributes.size(); i++ )
360 {
361 const QDomElement attrElem = attributes.at( i ).toElement();
362 QColor newColor( attrElem.attribute( QStringLiteral( "color" ) ) );
363 newColor.setAlphaF( attrElem.attribute( QStringLiteral( "colorOpacity" ), QStringLiteral( "1.0" ) ).toDouble() );
364 categoryColors.append( newColor );
365 categoryAttributes.append( attrElem.attribute( QStringLiteral( "field" ) ) );
366 categoryLabels.append( attrElem.attribute( QStringLiteral( "label" ) ) );
367 if ( categoryLabels.constLast().isEmpty() )
368 {
369 categoryLabels.back() = categoryAttributes.back();
370 }
371 }
372 }
373 else
374 {
375 // Restore old format attributes and colors
376
377 const QStringList colorList = elem.attribute( QStringLiteral( "colors" ) ).split( '/' );
378 QStringList::const_iterator colorIt = colorList.constBegin();
379 for ( ; colorIt != colorList.constEnd(); ++colorIt )
380 {
381 QColor newColor( *colorIt );
382 categoryColors.append( QColor( newColor ) );
383 }
384
385 //attribute indices
386 categoryAttributes.clear();
387 const QStringList catList = elem.attribute( QStringLiteral( "categories" ) ).split( '/' );
388 QStringList::const_iterator catIt = catList.constBegin();
389 for ( ; catIt != catList.constEnd(); ++catIt )
390 {
391 categoryAttributes.append( *catIt );
392 categoryLabels.append( *catIt );
393 }
394 }
395
396 const QDomElement effectElem = elem.firstChildElement( QStringLiteral( "effect" ) );
397 if ( !effectElem.isNull() )
398 setPaintEffect( QgsApplication::paintEffectRegistry()->createEffect( effectElem ) );
399 else
401}
402
403void QgsDiagramSettings::writeXml( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
404{
405 QDomElement categoryElem = doc.createElement( QStringLiteral( "DiagramCategory" ) );
406 categoryElem.setAttribute( QStringLiteral( "enabled" ), enabled );
407 categoryElem.appendChild( QgsFontUtils::toXmlElement( font, doc, QStringLiteral( "fontProperties" ) ) );
408 categoryElem.setAttribute( QStringLiteral( "backgroundColor" ), backgroundColor.name() );
409 categoryElem.setAttribute( QStringLiteral( "backgroundAlpha" ), backgroundColor.alpha() );
410 categoryElem.setAttribute( QStringLiteral( "width" ), QString::number( size.width() ) );
411 categoryElem.setAttribute( QStringLiteral( "height" ), QString::number( size.height() ) );
412 categoryElem.setAttribute( QStringLiteral( "penColor" ), penColor.name() );
413 categoryElem.setAttribute( QStringLiteral( "penAlpha" ), penColor.alpha() );
414 categoryElem.setAttribute( QStringLiteral( "penWidth" ), QString::number( penWidth ) );
415 categoryElem.setAttribute( QStringLiteral( "scaleBasedVisibility" ), scaleBasedVisibility );
416 categoryElem.setAttribute( QStringLiteral( "minScaleDenominator" ), QString::number( maximumScale ) );
417 categoryElem.setAttribute( QStringLiteral( "maxScaleDenominator" ), QString::number( minimumScale ) );
418 categoryElem.setAttribute( QStringLiteral( "opacity" ), QString::number( opacity ) );
419 categoryElem.setAttribute( QStringLiteral( "spacing" ), QString::number( mSpacing ) );
420 categoryElem.setAttribute( QStringLiteral( "spacingUnit" ), QgsUnitTypes::encodeUnit( mSpacingUnit ) );
421 categoryElem.setAttribute( QStringLiteral( "spacingUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mSpacingMapUnitScale ) );
422 categoryElem.setAttribute( QStringLiteral( "stackedDiagramSpacing" ), QString::number( mStackedDiagramSpacing ) );
423 categoryElem.setAttribute( QStringLiteral( "stackedDiagramSpacingUnit" ), QgsUnitTypes::encodeUnit( mStackedDiagramSpacingUnit ) );
424 categoryElem.setAttribute( QStringLiteral( "stackedDiagramSpacingUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mStackedDiagramSpacingMapUnitScale ) );
425 categoryElem.setAttribute( QStringLiteral( "direction" ), QString::number( mDirection ) );
426
427 //diagram size unit type and scale
428 categoryElem.setAttribute( QStringLiteral( "sizeType" ), QgsUnitTypes::encodeUnit( sizeType ) );
429 categoryElem.setAttribute( QStringLiteral( "sizeScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( sizeScale ) );
430
431 //line width unit type and scale
432 categoryElem.setAttribute( QStringLiteral( "lineSizeType" ), QgsUnitTypes::encodeUnit( lineSizeUnit ) );
433 categoryElem.setAttribute( QStringLiteral( "lineSizeScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( lineSizeScale ) );
434
435 // label placement method (text diagram)
437 {
438 categoryElem.setAttribute( QStringLiteral( "labelPlacementMethod" ), QStringLiteral( "Height" ) );
439 }
440 else
441 {
442 categoryElem.setAttribute( QStringLiteral( "labelPlacementMethod" ), QStringLiteral( "XHeight" ) );
443 }
444
445 if ( scaleByArea )
446 {
447 categoryElem.setAttribute( QStringLiteral( "scaleDependency" ), QStringLiteral( "Area" ) );
448 }
449 else
450 {
451 categoryElem.setAttribute( QStringLiteral( "scaleDependency" ), QStringLiteral( "Diameter" ) );
452 }
453
454 // orientation (histogram)
455 switch ( diagramOrientation )
456 {
457 case Left:
458 categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Left" ) );
459 break;
460
461 case Right:
462 categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Right" ) );
463 break;
464
465 case Down:
466 categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Down" ) );
467 break;
468
469 case Up:
470 categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Up" ) );
471 break;
472 }
473
474 // stacked mode
475 switch ( stackedDiagramMode )
476 {
477 case Horizontal:
478 categoryElem.setAttribute( QStringLiteral( "stackedDiagramMode" ), QStringLiteral( "Horizontal" ) );
479 break;
480
481 case Vertical:
482 categoryElem.setAttribute( QStringLiteral( "stackedDiagramMode" ), QStringLiteral( "Vertical" ) );
483 break;
484 }
485
486 categoryElem.setAttribute( QStringLiteral( "barWidth" ), QString::number( barWidth ) );
487 categoryElem.setAttribute( QStringLiteral( "minimumSize" ), QString::number( minimumSize ) );
488 categoryElem.setAttribute( QStringLiteral( "rotationOffset" ), QString::number( rotationOffset ) );
489
490 const int nCats = std::min( categoryColors.size(), categoryAttributes.size() );
491 for ( int i = 0; i < nCats; ++i )
492 {
493 QDomElement attributeElem = doc.createElement( QStringLiteral( "attribute" ) );
494
495 attributeElem.setAttribute( QStringLiteral( "field" ), categoryAttributes.at( i ) );
496 attributeElem.setAttribute( QStringLiteral( "color" ), categoryColors.at( i ).name() );
497 attributeElem.setAttribute( QStringLiteral( "colorOpacity" ), QString::number( categoryColors.at( i ).alphaF() ) );
498 attributeElem.setAttribute( QStringLiteral( "label" ), categoryLabels.at( i ) );
499 categoryElem.appendChild( attributeElem );
500 }
501
502 categoryElem.setAttribute( QStringLiteral( "showAxis" ), mShowAxis ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
503 QDomElement axisSymbolElem = doc.createElement( QStringLiteral( "axisSymbol" ) );
504 const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QString(), mAxisLineSymbol.get(), doc, context );
505 axisSymbolElem.appendChild( symbolElem );
506 categoryElem.appendChild( axisSymbolElem );
507
508 if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect.get() ) )
509 mPaintEffect->saveProperties( doc, categoryElem );
510
511 rendererElem.appendChild( categoryElem );
512}
513
515{
516 if ( mDiagram.get() == d )
517 return;
518
519 mDiagram.reset( d );
520}
521
527
529{
530 if ( &other == this )
531 return *this;
532
533 mDiagram.reset( other.mDiagram ? other.mDiagram->clone() : nullptr );
535 return *this;
536}
537
538void QgsDiagramRenderer::renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties ) const
539{
540 if ( !mDiagram )
541 {
542 return;
543 }
544
546 if ( !diagramSettings( feature, c, s ) )
547 {
548 return;
549 }
550
551 if ( properties.hasActiveProperties() )
552 {
553 c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( s.backgroundColor ) );
555 c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( s.penColor ) );
556 s.penColor = properties.valueAsColor( QgsDiagramLayerSettings::Property::StrokeColor, c.expressionContext(), s.penColor );
557 c.expressionContext().setOriginalValueVariable( s.penWidth );
558 s.penWidth = properties.valueAsDouble( QgsDiagramLayerSettings::Property::StrokeWidth, c.expressionContext(), s.penWidth );
559 c.expressionContext().setOriginalValueVariable( s.rotationOffset );
561 }
562
563 QgsPaintEffect *effect = s.paintEffect();
564 std::unique_ptr< QgsEffectPainter > effectPainter;
565 if ( effect && effect->enabled() )
566 {
567 effectPainter = std::make_unique< QgsEffectPainter >( c, effect );
568 }
569
570 mDiagram->renderDiagram( feature, c, s, pos );
571}
572
573QSizeF QgsDiagramRenderer::sizeMapUnits( const QgsFeature &feature, const QgsRenderContext &c ) const
574{
576 if ( !diagramSettings( feature, c, s ) || !s.enabled )
577 {
578 return QSizeF();
579 }
580
581 if ( s.scaleBasedVisibility )
582 {
583 // Note: scale might be a non-round number, so compare with qgsDoubleNear
584 const double rendererScale = c.rendererScale();
585
586 // maxScale is inclusive ( < --> no size )
587 double maxScale = s.maximumScale;
588 if ( maxScale > 0 && QgsScaleUtils::lessThanMaximumScale( rendererScale, maxScale ) )
589 {
590 return QSizeF();
591 }
592
593 // minScale is exclusive ( >= --> no size)
594 double minScale = s.minimumScale;
595 if ( minScale > 0 && QgsScaleUtils::equalToOrGreaterThanMinimumScale( rendererScale, minScale ) )
596 {
597 return QSizeF();
598 }
599 }
600
601 QSizeF size = diagramSize( feature, c );
602 if ( size.isValid() )
603 {
604 const double width = c.convertToMapUnits( size.width(), s.sizeType, s.sizeScale );
605 size.rheight() *= width / size.width();
606 size.setWidth( width );
607 }
608 return size;
609}
610
612{
613 QSet< QString > referenced;
614
615 if ( !mDiagram )
616 return referenced;
617
618 const auto constDiagramAttributes = diagramAttributes();
619 for ( const QString &att : constDiagramAttributes )
620 {
621 QgsExpression *expression = mDiagram->getExpression( att, context );
622 const auto constReferencedColumns = expression->referencedColumns();
623 for ( const QString &field : constReferencedColumns )
624 {
625 referenced << field;
626 }
627 }
628 return referenced;
629}
630
631void QgsDiagramRenderer::convertSizeToMapUnits( QSizeF &size, const QgsRenderContext &context ) const
632{
633 if ( !size.isValid() )
634 {
635 return;
636 }
637
638 const double pixelToMap = context.scaleFactor() * context.mapToPixel().mapUnitsPerPixel();
639 size.rwidth() *= pixelToMap;
640 size.rheight() *= pixelToMap;
641}
642
643int QgsDiagramRenderer::dpiPaintDevice( const QPainter *painter )
644{
645 if ( painter )
646 {
647 QPaintDevice *device = painter->device();
648 if ( device )
649 {
650 return device->logicalDpiX();
651 }
652 }
653 return -1;
654}
655
656void QgsDiagramRenderer::_readXml( const QDomElement &elem, const QgsReadWriteContext &context )
657{
658 Q_UNUSED( context )
659 mDiagram.reset();
660 const QString diagramType = elem.attribute( QStringLiteral( "diagramType" ) );
661 if ( diagramType == QgsPieDiagram::DIAGRAM_NAME_PIE )
662 {
663 mDiagram = std::make_unique<QgsPieDiagram>( );
664 }
665 else if ( diagramType == QgsTextDiagram::DIAGRAM_NAME_TEXT )
666 {
667 mDiagram = std::make_unique<QgsTextDiagram>( );
668 }
669 else if ( diagramType == QgsHistogramDiagram::DIAGRAM_NAME_HISTOGRAM )
670 {
671 mDiagram = std::make_unique<QgsHistogramDiagram>( );
672 }
673 else if ( diagramType == QgsStackedBarDiagram::DIAGRAM_NAME_STACKED_BAR )
674 {
675 mDiagram = std::make_unique<QgsStackedBarDiagram>( );
676 }
677 else if ( diagramType == QgsStackedDiagram::DIAGRAM_NAME_STACKED )
678 {
679 mDiagram = std::make_unique<QgsStackedDiagram>( );
680 }
681 else
682 {
683 // unknown diagram type -- default to histograms
684 mDiagram = std::make_unique<QgsHistogramDiagram>( );
685 }
686 mShowAttributeLegend = ( elem.attribute( QStringLiteral( "attributeLegend" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
687}
688
689void QgsDiagramRenderer::_writeXml( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
690{
691 Q_UNUSED( doc )
692 Q_UNUSED( context )
693
694 if ( mDiagram )
695 {
696 rendererElem.setAttribute( QStringLiteral( "diagramType" ), mDiagram->diagramName() );
697 }
698 rendererElem.setAttribute( QStringLiteral( "attributeLegend" ), mShowAttributeLegend );
699}
700
701const QString QgsSingleCategoryDiagramRenderer::DIAGRAM_RENDERER_NAME_SINGLE_CATEGORY = QStringLiteral( "SingleCategory" );
702
707
709{
710 Q_UNUSED( c )
711 s = mSettings;
712 return true;
713}
714
716{
717 return mDiagram->diagramSize( feature.attributes(), c, mSettings );
718}
719
721{
722 QList<QgsDiagramSettings> settingsList;
723 settingsList.push_back( mSettings );
724 return settingsList;
725}
726
727void QgsSingleCategoryDiagramRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
728{
729 const QDomElement categoryElem = elem.firstChildElement( QStringLiteral( "DiagramCategory" ) );
730 if ( categoryElem.isNull() )
731 {
732 return;
733 }
734
735 mSettings.readXml( categoryElem, context );
736 _readXml( elem, context );
737}
738
739void QgsSingleCategoryDiagramRenderer::writeXml( QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
740{
741 QDomElement rendererElem = doc.createElement( QStringLiteral( "SingleCategoryDiagramRenderer" ) );
742 mSettings.writeXml( rendererElem, doc, context );
743 _writeXml( rendererElem, doc, context );
744 layerElem.appendChild( rendererElem );
745}
746
747const QString QgsLinearlyInterpolatedDiagramRenderer::DIAGRAM_RENDERER_NAME_LINEARLY_INTERPOLATED = QLatin1String( "LinearlyInterpolated" );
748
750{
751 mInterpolationSettings.classificationAttributeIsExpression = false;
752}
753
755 : QgsDiagramRenderer( other )
756 , mSettings( other.mSettings )
757 , mInterpolationSettings( other.mInterpolationSettings )
758 , mDataDefinedSizeLegend( other.mDataDefinedSizeLegend ? new QgsDataDefinedSizeLegend( *other.mDataDefinedSizeLegend ) : nullptr )
759{
760}
761
766
768{
769 if ( &other == this )
770 {
771 return *this;
772 }
773 mSettings = other.mSettings;
774 mInterpolationSettings = other.mInterpolationSettings;
775 mDataDefinedSizeLegend = std::make_unique<QgsDataDefinedSizeLegend>( *other.mDataDefinedSizeLegend );
776
777 return *this;
778}
779
784
786{
787 QList<QgsDiagramSettings> settingsList;
788 settingsList.push_back( mSettings );
789 return settingsList;
790}
791
793{
794 s = mSettings;
795 s.size = diagramSize( feature, c );
796 return true;
797}
798
800{
801 return mSettings.categoryAttributes;
802}
803
805{
806 QSet< QString > referenced = QgsDiagramRenderer::referencedFields( context );
807 if ( mInterpolationSettings.classificationAttributeIsExpression )
808 {
809 QgsExpression *expression = mDiagram->getExpression( mInterpolationSettings.classificationAttributeExpression, context );
810 const auto constReferencedColumns = expression->referencedColumns();
811 for ( const QString &field : constReferencedColumns )
812 {
813 referenced << field;
814 }
815 }
816 else
817 {
818 referenced << mInterpolationSettings.classificationField;
819 }
820 return referenced;
821}
822
824{
825 return mDiagram->diagramSize( feature, c, mSettings, mInterpolationSettings );
826}
827
828void QgsLinearlyInterpolatedDiagramRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
829{
830 mInterpolationSettings.lowerValue = elem.attribute( QStringLiteral( "lowerValue" ) ).toDouble();
831 mInterpolationSettings.upperValue = elem.attribute( QStringLiteral( "upperValue" ) ).toDouble();
832 mInterpolationSettings.lowerSize.setWidth( elem.attribute( QStringLiteral( "lowerWidth" ) ).toDouble() );
833 mInterpolationSettings.lowerSize.setHeight( elem.attribute( QStringLiteral( "lowerHeight" ) ).toDouble() );
834 mInterpolationSettings.upperSize.setWidth( elem.attribute( QStringLiteral( "upperWidth" ) ).toDouble() );
835 mInterpolationSettings.upperSize.setHeight( elem.attribute( QStringLiteral( "upperHeight" ) ).toDouble() );
836 mInterpolationSettings.classificationAttributeIsExpression = elem.hasAttribute( QStringLiteral( "classificationAttributeExpression" ) );
837 if ( mInterpolationSettings.classificationAttributeIsExpression )
838 {
839 mInterpolationSettings.classificationAttributeExpression = elem.attribute( QStringLiteral( "classificationAttributeExpression" ) );
840 }
841 else
842 {
843 mInterpolationSettings.classificationField = elem.attribute( QStringLiteral( "classificationField" ) );
844 }
845 const QDomElement settingsElem = elem.firstChildElement( QStringLiteral( "DiagramCategory" ) );
846 if ( !settingsElem.isNull() )
847 {
848 mSettings.readXml( settingsElem );
849 }
850
851 mDataDefinedSizeLegend.reset( );
852
853 const QDomElement ddsLegendSizeElem = elem.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
854 if ( !ddsLegendSizeElem.isNull() )
855 {
856 mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
857 }
858 else
859 {
860 // pre-3.0 projects
861 if ( elem.attribute( QStringLiteral( "sizeLegend" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) )
862 {
863 mDataDefinedSizeLegend = std::make_unique<QgsDataDefinedSizeLegend>();
864 const QDomElement sizeLegendSymbolElem = elem.firstChildElement( QStringLiteral( "symbol" ) );
865 if ( !sizeLegendSymbolElem.isNull() && sizeLegendSymbolElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "sizeSymbol" ) )
866 {
867 mDataDefinedSizeLegend->setSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( sizeLegendSymbolElem, context ).release() );
868 }
869 }
870 else
871 {
872 mDataDefinedSizeLegend = nullptr;
873 }
874 }
875
876 _readXml( elem, context );
877}
878
879void QgsLinearlyInterpolatedDiagramRenderer::writeXml( QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
880{
881 QDomElement rendererElem = doc.createElement( QStringLiteral( "LinearlyInterpolatedDiagramRenderer" ) );
882 rendererElem.setAttribute( QStringLiteral( "lowerValue" ), QString::number( mInterpolationSettings.lowerValue ) );
883 rendererElem.setAttribute( QStringLiteral( "upperValue" ), QString::number( mInterpolationSettings.upperValue ) );
884 rendererElem.setAttribute( QStringLiteral( "lowerWidth" ), QString::number( mInterpolationSettings.lowerSize.width() ) );
885 rendererElem.setAttribute( QStringLiteral( "lowerHeight" ), QString::number( mInterpolationSettings.lowerSize.height() ) );
886 rendererElem.setAttribute( QStringLiteral( "upperWidth" ), QString::number( mInterpolationSettings.upperSize.width() ) );
887 rendererElem.setAttribute( QStringLiteral( "upperHeight" ), QString::number( mInterpolationSettings.upperSize.height() ) );
888 if ( mInterpolationSettings.classificationAttributeIsExpression )
889 {
890 rendererElem.setAttribute( QStringLiteral( "classificationAttributeExpression" ), mInterpolationSettings.classificationAttributeExpression );
891 }
892 else
893 {
894 rendererElem.setAttribute( QStringLiteral( "classificationField" ), mInterpolationSettings.classificationField );
895 }
896 mSettings.writeXml( rendererElem, doc );
897
898 if ( mDataDefinedSizeLegend )
899 {
900 QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
901 mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
902 rendererElem.appendChild( ddsLegendElem );
903 }
904
905 _writeXml( rendererElem, doc, context );
906 layerElem.appendChild( rendererElem );
907}
908
909const QString QgsStackedDiagramRenderer::DIAGRAM_RENDERER_NAME_STACKED = QStringLiteral( "Stacked" );
910
912 : QgsDiagramRenderer( other )
913 , mSettings( other.mSettings )
914 , mDiagramRenderers()
915{
916 for ( QgsDiagramRenderer *renderer : std::as_const( other.mDiagramRenderers ) )
917 {
918 if ( renderer )
919 mDiagramRenderers << renderer->clone();
920 }
921}
922
924{
925 if ( &other == this )
926 return *this;
927
928 mSettings = other.mSettings;
929 qDeleteAll( mDiagramRenderers );
930 mDiagramRenderers.clear();
931 for ( QgsDiagramRenderer *renderer : std::as_const( other.mDiagramRenderers ) )
932 {
933 if ( renderer )
934 mDiagramRenderers << renderer->clone();
935 }
936
937 return *this;
938}
939
941{
942 qDeleteAll( mDiagramRenderers );
943}
944
949
951{
952 QSizeF stackedSize( 0, 0 );
953 int enabledDiagramCount = 0; // We'll add spacing only for enabled subDiagrams
954
955 // Iterate renderers. For each renderer, get the diagram
956 // size for the feature and add it to the total size
957 // accounting for stacked diagram defined spacing
958 for ( const QgsDiagramRenderer *subRenderer : std::as_const( mDiagramRenderers ) )
959 {
960 QSizeF size = subRenderer->sizeMapUnits( feature, c );
961
962 if ( size.isValid() )
963 {
964 enabledDiagramCount++;
965 switch ( mSettings.stackedDiagramMode )
966 {
968 stackedSize.setWidth( stackedSize.width() + size.width() );
969 stackedSize.setHeight( std::max( stackedSize.height(), size.height() ) );
970 break;
971
973 stackedSize.setWidth( std::max( stackedSize.width(), size.width() ) );
974 stackedSize.setHeight( stackedSize.height() + size.height() );
975 break;
976 }
977 }
978 }
979
980 if ( stackedSize.isValid() )
981 {
982 const double spacing = c.convertToMapUnits( mSettings.stackedDiagramSpacing(), mSettings.stackedDiagramSpacingUnit(), mSettings.stackedDiagramSpacingMapUnitScale() );
983
984 switch ( mSettings.stackedDiagramMode )
985 {
987 stackedSize.scale( stackedSize.width() + spacing * ( enabledDiagramCount - 1 ), stackedSize.height(), Qt::IgnoreAspectRatio );
988 break;
989
991 stackedSize.scale( stackedSize.width(), stackedSize.height() + spacing * ( enabledDiagramCount - 1 ), Qt::IgnoreAspectRatio );
992 break;
993 }
994 }
995 return stackedSize;
996}
997
998void QgsStackedDiagramRenderer::renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties ) const
999{
1000 if ( !mDiagram )
1001 {
1002 return;
1003 }
1004
1005 QPointF newPos = pos; // Each subdiagram will have its own newPos
1006
1007 // Get subrenderers sorted by mode (vertical diagrams are returned backwards)
1008 const QList< QgsDiagramRenderer * > stackedRenderers = renderers( true );
1009
1010 for ( const QgsDiagramRenderer *stackedRenderer : stackedRenderers )
1011 {
1012 if ( stackedRenderer->rendererName() == QgsStackedDiagramRenderer::DIAGRAM_RENDERER_NAME_STACKED )
1013 {
1014 // Nested stacked diagrams will use this recursion
1015 stackedRenderer->renderDiagram( feature, c, newPos, properties );
1016 continue;
1017 }
1018
1020 if ( !stackedRenderer->diagramSettings( feature, c, s ) )
1021 {
1022 continue;
1023 }
1024
1025 if ( !s.enabled )
1026 {
1027 continue;
1028 }
1029
1030 if ( s.scaleBasedVisibility )
1031 {
1032 // Note: scale might be a non-round number, so compare with qgsDoubleNear
1033 const double rendererScale = c.rendererScale();
1034
1035 // maxScale is inclusive ( < --> no diagram )
1036 double maxScale = s.maximumScale;
1037 if ( maxScale > 0 && QgsScaleUtils::lessThanMaximumScale( rendererScale, maxScale ) )
1038 {
1039 continue;
1040 }
1041
1042 // minScale is exclusive ( >= --> no diagram)
1043 double minScale = s.minimumScale;
1044 if ( minScale > 0 && QgsScaleUtils::equalToOrGreaterThanMinimumScale( rendererScale, minScale ) )
1045 {
1046 continue;
1047 }
1048 }
1049
1050 if ( properties.hasActiveProperties() )
1051 {
1052 c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( s.backgroundColor ) );
1054 c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( s.penColor ) );
1055 s.penColor = properties.valueAsColor( QgsDiagramLayerSettings::Property::StrokeColor, c.expressionContext(), s.penColor );
1056 c.expressionContext().setOriginalValueVariable( s.penWidth );
1057 s.penWidth = properties.valueAsDouble( QgsDiagramLayerSettings::Property::StrokeWidth, c.expressionContext(), s.penWidth );
1058 c.expressionContext().setOriginalValueVariable( s.rotationOffset );
1060 }
1061
1062 QgsPaintEffect *effect = s.paintEffect();
1063 std::unique_ptr< QgsEffectPainter > effectPainter;
1064 if ( effect && effect->enabled() )
1065 {
1066 effectPainter = std::make_unique< QgsEffectPainter >( c, effect );
1067 }
1068
1069 stackedRenderer->diagram()->renderDiagram( feature, c, s, newPos );
1070 QgsStackedDiagram *stackedDiagram = dynamic_cast< QgsStackedDiagram *>( mDiagram.get() );
1071 stackedDiagram->subDiagramPosition( newPos, c, mSettings, s );
1072 }
1073}
1074
1076{
1077 Q_UNUSED( feature )
1078 Q_UNUSED( c )
1079 Q_UNUSED( s )
1080 return false;
1081}
1082
1084{
1085 Q_UNUSED( feature )
1086 Q_UNUSED( c )
1087 return QSizeF( 0, 0 );
1088}
1089
1090QList<QgsDiagramSettings> QgsStackedDiagramRenderer::diagramSettings() const
1091{
1092 QList<QgsDiagramSettings> settingsList;
1093 settingsList.push_back( mSettings );
1094 return settingsList;
1095}
1096
1098{
1099 return mSettings.categoryAttributes;
1100}
1101
1102QList< QgsLayerTreeModelLegendNode * > QgsStackedDiagramRenderer::legendItems( QgsLayerTreeLayer *nodeLayer ) const
1103{
1104 QList< QgsLayerTreeModelLegendNode * > nodes;
1105 for ( const QgsDiagramRenderer *renderer : std::as_const( mDiagramRenderers ) )
1106 {
1107 nodes << renderer->legendItems( nodeLayer );
1108 }
1109
1110 return nodes;
1111}
1112
1113QList< QgsDiagramRenderer * > QgsStackedDiagramRenderer::renderers( bool sortByDiagramMode ) const
1114{
1115 QList< QgsDiagramRenderer * > renderers = mDiagramRenderers;
1116
1117 if ( sortByDiagramMode && mSettings.stackedDiagramMode == QgsDiagramSettings::Vertical )
1118 {
1119 // We draw vertical diagrams backwards, so
1120 // we return the subrenderers in reverse order
1121 std::reverse( renderers.begin(), renderers.end() );
1122 }
1123 return renderers;
1124}
1125
1127{
1128 if ( renderer )
1129 {
1130 mDiagramRenderers.append( renderer );
1131 }
1132}
1133
1135{
1136 return mDiagramRenderers.value( index );
1137}
1138
1140{
1141 return mDiagramRenderers.size();
1142}
1143
1144void QgsStackedDiagramRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
1145{
1146 const QDomElement categoryElem = elem.firstChildElement( QStringLiteral( "DiagramCategory" ) );
1147 if ( categoryElem.isNull() )
1148 {
1149 return;
1150 }
1151
1152 mSettings.readXml( categoryElem, context );
1153 _readXml( elem, context );
1154 _readXmlSubRenderers( elem, context );
1155}
1156
1157void QgsStackedDiagramRenderer::_readXmlSubRenderers( const QDomElement &elem, const QgsReadWriteContext &context )
1158{
1159 qDeleteAll( mDiagramRenderers );
1160 mDiagramRenderers.clear();
1161
1162 const QDomElement subRenderersElem = elem.firstChildElement( QStringLiteral( "DiagramRenderers" ) );
1163
1164 if ( !subRenderersElem.isNull() )
1165 {
1166 const QDomNodeList childRendererList = subRenderersElem.childNodes();
1167
1168 for ( int i = 0; i < childRendererList.size(); i++ )
1169 {
1170 const QDomElement subRendererElem = childRendererList.at( i ).toElement();
1171
1172 if ( subRendererElem.nodeName() == QLatin1String( "SingleCategoryDiagramRenderer" ) )
1173 {
1174 auto singleCatDiagramRenderer = std::make_unique< QgsSingleCategoryDiagramRenderer >();
1175 singleCatDiagramRenderer->readXml( subRendererElem, context );
1176 addRenderer( singleCatDiagramRenderer.release() );
1177 }
1178 else if ( subRendererElem.nodeName() == QLatin1String( "LinearlyInterpolatedDiagramRenderer" ) )
1179 {
1180 auto linearDiagramRenderer = std::make_unique< QgsLinearlyInterpolatedDiagramRenderer >();
1181 linearDiagramRenderer->readXml( subRendererElem, context );
1182 addRenderer( linearDiagramRenderer.release() );
1183 }
1184 else if ( subRendererElem.nodeName() == QLatin1String( "StackedDiagramRenderer" ) )
1185 {
1186 auto stackedDiagramRenderer = std::make_unique< QgsStackedDiagramRenderer >();
1187 stackedDiagramRenderer->readXml( subRendererElem, context );
1188 addRenderer( stackedDiagramRenderer.release() );
1189 }
1190 }
1191 }
1192}
1193
1194void QgsStackedDiagramRenderer::writeXml( QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
1195{
1196 QDomElement rendererElem = doc.createElement( QStringLiteral( "StackedDiagramRenderer" ) );
1197 mSettings.writeXml( rendererElem, doc, context );
1198 _writeXml( rendererElem, doc, context );
1199 _writeXmlSubRenderers( rendererElem, doc, context );
1200 layerElem.appendChild( rendererElem );
1201}
1202
1203void QgsStackedDiagramRenderer::_writeXmlSubRenderers( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
1204{
1205 QDomElement renderersElem = doc.createElement( QStringLiteral( "DiagramRenderers" ) );
1206
1207 // Iterate sub renderers and write their settings to a DOM object
1208 for ( int i = 0; i < mDiagramRenderers.count(); i++ )
1209 {
1210 mDiagramRenderers.at( i )->writeXml( renderersElem, doc, context );
1211 }
1212 rendererElem.appendChild( renderersElem );
1213}
1214
1215QList< QgsLayerTreeModelLegendNode * > QgsDiagramSettings::legendItems( QgsLayerTreeLayer *nodeLayer ) const
1216{
1217 QList< QgsLayerTreeModelLegendNode * > list;
1218 list.reserve( categoryLabels.size() );
1219 for ( int i = 0; i < categoryLabels.size(); ++i )
1220 {
1221 QPixmap pix( 16, 16 );
1222 pix.fill( categoryColors[i] );
1223 list << new QgsSimpleLegendNode( nodeLayer, categoryLabels[i], QIcon( pix ), nullptr, QStringLiteral( "diagram_%1" ).arg( QString::number( i ) ) );
1224 }
1225 return list;
1226}
1227
1229{
1230 return mAxisLineSymbol.get();
1231}
1232
1234{
1235 if ( axisLineSymbol != mAxisLineSymbol.get() )
1236 mAxisLineSymbol.reset( axisLineSymbol );
1237}
1238
1240{
1241 return mShowAxis;
1242}
1243
1245{
1246 mShowAxis = showAxis;
1247}
1248
1250{
1251 return mPaintEffect.get();
1252}
1253
1255{
1256 if ( effect != mPaintEffect.get() )
1257 mPaintEffect.reset( effect );
1258}
1259
1261 : mAxisLineSymbol( std::make_unique< QgsLineSymbol >() )
1262{
1263}
1264
1266
1268 : enabled( other.enabled )
1269 , font( other.font )
1273 , size( other.size )
1274 , sizeType( other.sizeType )
1275 , sizeScale( other.sizeScale )
1276 , lineSizeUnit( other.lineSizeUnit )
1277 , lineSizeScale( other.lineSizeScale )
1279 , penColor( other.penColor )
1280 , penWidth( other.penWidth )
1284 , barWidth( other.barWidth )
1285 , opacity( other.opacity )
1286 , scaleByArea( other.scaleByArea )
1289 , maximumScale( other.maximumScale )
1290 , minimumScale( other.minimumScale )
1291 , minimumSize( other.minimumSize )
1292 , mSpacing( other.mSpacing )
1293 , mSpacingUnit( other.mSpacingUnit )
1294 , mSpacingMapUnitScale( other.mSpacingMapUnitScale )
1295 , mStackedDiagramSpacing( other.mStackedDiagramSpacing )
1296 , mStackedDiagramSpacingUnit( other.mStackedDiagramSpacingUnit )
1297 , mStackedDiagramSpacingMapUnitScale( other.mStackedDiagramSpacingMapUnitScale )
1298 , mDirection( other.mDirection )
1299 , mShowAxis( other.mShowAxis )
1300 , mAxisLineSymbol( other.mAxisLineSymbol ? other.mAxisLineSymbol->clone() : nullptr )
1301 , mPaintEffect( other.mPaintEffect ? other.mPaintEffect->clone() : nullptr )
1302{
1303
1304}
1305
1307{
1308 if ( &other == this )
1309 return *this;
1310
1311 enabled = other.enabled;
1312 font = other.font;
1316 size = other.size;
1317 sizeType = other.sizeType;
1318 sizeScale = other.sizeScale;
1319 lineSizeUnit = other.lineSizeUnit;
1322 penColor = other.penColor;
1323 penWidth = other.penWidth;
1327 barWidth = other.barWidth;
1328 opacity = other.opacity;
1329 scaleByArea = other.scaleByArea;
1332 maximumScale = other.maximumScale;
1333 minimumScale = other.minimumScale;
1334 minimumSize = other.minimumSize;
1335 mSpacing = other.mSpacing;
1336 mSpacingUnit = other.mSpacingUnit;
1337 mSpacingMapUnitScale = other.mSpacingMapUnitScale;
1338 mStackedDiagramSpacing = other.mStackedDiagramSpacing;
1339 mStackedDiagramSpacingUnit = other.mStackedDiagramSpacingUnit;
1340 mStackedDiagramSpacingMapUnitScale = other.mStackedDiagramSpacingMapUnitScale;
1341 mDirection = other.mDirection;
1342 mAxisLineSymbol.reset( other.mAxisLineSymbol ? other.mAxisLineSymbol->clone() : nullptr );
1343 mShowAxis = other.mShowAxis;
1344 mPaintEffect.reset( other.mPaintEffect ? other.mPaintEffect->clone() : nullptr );
1345 return *this;
1346}
1347
1349{
1350 return mDirection;
1351}
1352
1354{
1355 mDirection = direction;
1356}
1357
1358QList< QgsLayerTreeModelLegendNode * > QgsDiagramRenderer::legendItems( QgsLayerTreeLayer * ) const
1359{
1360 return QList< QgsLayerTreeModelLegendNode * >();
1361}
1362
1363QList< QgsLayerTreeModelLegendNode * > QgsSingleCategoryDiagramRenderer::legendItems( QgsLayerTreeLayer *nodeLayer ) const
1364{
1365 QList< QgsLayerTreeModelLegendNode * > nodes;
1366 if ( mShowAttributeLegend && mSettings.enabled )
1367 nodes = mSettings.legendItems( nodeLayer );
1368
1369 return nodes;
1370}
1371
1372QList< QgsLayerTreeModelLegendNode * > QgsLinearlyInterpolatedDiagramRenderer::legendItems( QgsLayerTreeLayer *nodeLayer ) const
1373{
1374 QList< QgsLayerTreeModelLegendNode * > nodes;
1375 if ( !mSettings.enabled )
1376 {
1377 return nodes;
1378 }
1379
1381 nodes = mSettings.legendItems( nodeLayer );
1382
1383 if ( mDataDefinedSizeLegend && mDiagram )
1384 {
1385 // add size legend
1386 QgsMarkerSymbol *legendSymbol = mDataDefinedSizeLegend->symbol() ? mDataDefinedSizeLegend->symbol()->clone() : QgsMarkerSymbol::createSimple( QVariantMap() ).release();
1387 legendSymbol->setSizeUnit( mSettings.sizeType );
1388 legendSymbol->setSizeMapUnitScale( mSettings.sizeScale );
1389
1390 QgsDataDefinedSizeLegend ddSizeLegend( *mDataDefinedSizeLegend );
1391 ddSizeLegend.setSymbol( legendSymbol ); // transfers ownership
1392
1393 QList<QgsDataDefinedSizeLegend::SizeClass> sizeClasses;
1394 if ( ddSizeLegend.classes().isEmpty() )
1395 {
1396 // automatic class creation if the classes are not defined manually
1397 const auto prettyBreaks { QgsSymbolLayerUtils::prettyBreaks( mInterpolationSettings.lowerValue, mInterpolationSettings.upperValue, 4 ) };
1398 for ( const double v : prettyBreaks )
1399 {
1400 const double size = mDiagram->legendSize( v, mSettings, mInterpolationSettings );
1401 sizeClasses << QgsDataDefinedSizeLegend::SizeClass( size, QString::number( v ) );
1402 }
1403 }
1404 else
1405 {
1406 // manual classes need to get size scaled because the QgsSizeScaleTransformer is not used in diagrams :-(
1407 const auto constClasses = ddSizeLegend.classes();
1408 for ( const QgsDataDefinedSizeLegend::SizeClass &sc : constClasses )
1409 {
1410 const double size = mDiagram->legendSize( sc.size, mSettings, mInterpolationSettings );
1411 sizeClasses << QgsDataDefinedSizeLegend::SizeClass( size, sc.label );
1412 }
1413 }
1414 ddSizeLegend.setClasses( sizeClasses );
1415
1416 const auto constLegendSymbolList = ddSizeLegend.legendSymbolList();
1417 for ( const QgsLegendSymbolItem &si : constLegendSymbolList )
1418 {
1419 if ( auto *lDataDefinedSizeLegendSettings = si.dataDefinedSizeLegendSettings() )
1420 nodes << new QgsDataDefinedSizeLegendNode( nodeLayer, *lDataDefinedSizeLegendSettings );
1421 else
1422 nodes << new QgsSymbolLegendNode( nodeLayer, si );
1423 }
1424 }
1425
1426 return nodes;
1427}
1428
1430{
1431 mDataDefinedSizeLegend.reset( settings );
1432
1433}
1434
1436{
1437 return mDataDefinedSizeLegend.get();
1438}
@ MapUnits
Map units.
Definition qgis.h:5185
QColor valueAsColor(int key, const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a color.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
static QgsPaintEffectRegistry * paintEffectRegistry()
Returns the application's paint effect registry, used for managing paint effects.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
Handles coordinate transforms between two coordinate systems.
A legend node with a marker symbol.
Object that keeps configuration of appearance of marker symbol's data-defined size in legend.
QList< QgsDataDefinedSizeLegend::SizeClass > classes() const
Returns list of classes: each class is a pair of symbol size (in units used by the symbol) and label.
void setSymbol(QgsMarkerSymbol *symbol SIP_TRANSFER)
Sets marker symbol that will be used to draw markers in legend.
void setClasses(const QList< QgsDataDefinedSizeLegend::SizeClass > &classes)
Sets list of classes: each class is a pair of symbol size (in units used by the symbol) and label.
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...
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
LinePlacementFlag
Line placement flags for controlling line based placements.
QgsDiagramLayerSettings & operator=(const QgsDiagramLayerSettings &rh)
void setRenderer(QgsDiagramRenderer *diagramRenderer)
Sets the diagram renderer associated with the layer.
@ PositionX
X-coordinate data defined diagram position.
@ Distance
Distance to diagram from feature.
@ PositionY
Y-coordinate data defined diagram position.
@ Show
Whether to show the diagram.
@ Priority
Diagram priority (between 0 and 10).
@ ZIndex
Z-index for diagram ordering.
@ BackgroundColor
Diagram background color.
@ StartAngle
Angle offset for pie diagram.
@ IsObstacle
Whether diagram features act as obstacles for other diagrams/labels.
@ AlwaysShow
Whether the diagram should always be shown, even if it overlaps other diagrams/labels.
void readXml(const QDomElement &elem)
Reads the diagram settings from a DOM element.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the diagram property definitions.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const
Returns the set of any fields referenced by the layer's diagrams.
void writeXml(QDomElement &layerElem, QDomDocument &doc) const
Writes the diagram settings to a DOM element.
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const
Prepares the diagrams for a specified expression context.
void setCoordinateTransform(const QgsCoordinateTransform &transform)
Sets the coordinate transform associated with the layer.
Evaluates and returns the diagram settings relating to a diagram for a specific feature.
virtual QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const
Returns list of legend nodes for the diagram.
virtual QSizeF diagramSize(const QgsFeature &feature, const QgsRenderContext &c) const =0
Returns size of the diagram (in painter units) or an invalid size in case of error.
void _writeXml(QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context) const
Writes internal QgsDiagramRenderer diagram state to a DOM element.
virtual QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const
Returns the set of any fields required for diagram rendering.
virtual void renderDiagram(const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties=QgsPropertyCollection()) const
Renders the diagram for a specified feature at a specific position in the passed render context.
void _readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads internal QgsDiagramRenderer state from a DOM element.
QgsDiagramRenderer & operator=(const QgsDiagramRenderer &other)
virtual QSizeF sizeMapUnits(const QgsFeature &feature, const QgsRenderContext &c) const
Returns size of the diagram for a feature in map units. Returns an invalid QSizeF in case of error.
virtual QList< QString > diagramAttributes() const =0
Returns attribute indices needed for diagram rendering.
std::unique_ptr< QgsDiagram > mDiagram
Reference to the object that does the real diagram rendering.
void convertSizeToMapUnits(QSizeF &size, const QgsRenderContext &context) const
Converts size from mm to map units.
virtual QList< QgsDiagramSettings > diagramSettings() const =0
Returns list with all diagram settings in the renderer.
bool mShowAttributeLegend
Whether to show an attribute legend for the diagrams.
QgsDiagramRenderer()=default
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads diagram state from a DOM element.
void setDiagram(QgsDiagram *d)
virtual QgsDiagramRenderer * clone() const =0
Returns new instance that is equivalent to this one.
static int dpiPaintDevice(const QPainter *)
Returns the paint device dpi (or -1 in case of error.
Stores the settings for rendering a single diagram.
Direction direction() const
Returns the chart's angular direction.
StackedDiagramMode stackedDiagramMode
void setDirection(Direction direction)
Sets the chart's angular direction.
bool showAxis() const
Returns true if the diagram axis should be shown.
LabelPlacementMethod labelPlacementMethod
void readXml(const QDomElement &elem, const QgsReadWriteContext &context=QgsReadWriteContext())
Reads diagram settings from XML.
double opacity
Opacity, from 0 (transparent) to 1.0 (opaque).
QgsDiagramSettings & operator=(const QgsDiagramSettings &other)
QgsLineSymbol * axisLineSymbol() const
Returns the line symbol to use for rendering axis in diagrams.
Qgis::RenderUnit sizeType
Diagram size unit.
QList< QString > categoryAttributes
QList< QString > categoryLabels
DiagramOrientation diagramOrientation
QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const
Returns list of legend nodes for the diagram.
QgsMapUnitScale lineSizeScale
Line unit scale.
void writeXml(QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context=QgsReadWriteContext()) const
Writes diagram settings to XML.
QList< QColor > categoryColors
double rotationOffset
Rotation offset, in degrees clockwise from horizontal.
QgsMapUnitScale sizeScale
Diagram size unit scale.
double minimumScale
The minimum map scale (i.e.
double maximumScale
The maximum map scale (i.e.
void setAxisLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol to use for rendering axis in diagrams.
Qgis::RenderUnit lineSizeUnit
Line unit index.
double minimumSize
Scale diagrams smaller than mMinimumSize to mMinimumSize.
Direction
Angular directions.
void setShowAxis(bool showAxis)
Sets whether the diagram axis should be shown.
void setPaintEffect(QgsPaintEffect *effect)
Sets the paint effect to use while rendering diagrams.
QgsPaintEffect * paintEffect() const
Returns the paint effect to use while rendering diagrams.
Base class for all diagram types.
Definition qgsdiagram.h:41
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Handles parsing and evaluation of expressions (formerly called "search strings").
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsAttributes attributes
Definition qgsfeature.h:67
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
static const QString DIAGRAM_NAME_HISTOGRAM
Layer tree node points to a map layer.
Stores information about one class/rule of a vector layer renderer in a unified way that can be used ...
A line symbol type, for rendering LineString and MultiLineString geometries.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend.
QSizeF diagramSize(const QgsFeature &, const QgsRenderContext &c) const override
Returns size of the diagram (in painter units) or an invalid size in case of error.
QList< QString > diagramAttributes() const override
Returns attribute indices needed for diagram rendering.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const override
Returns the set of any fields required for diagram rendering.
QList< QgsDiagramSettings > diagramSettings() const override
Returns list with all diagram settings in the renderer.
void writeXml(QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Writes diagram state to a DOM element.
QgsLinearlyInterpolatedDiagramRenderer * clone() const override
Returns new instance that is equivalent to this one.
QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const override
Returns list of legend nodes for the diagram.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads diagram state from a DOM element.
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend.
QgsLinearlyInterpolatedDiagramRenderer & operator=(const QgsLinearlyInterpolatedDiagramRenderer &other)
static const QString DIAGRAM_RENDERER_NAME_LINEARLY_INTERPOLATED
double mapUnitsPerPixel() const
Returns the current map units per pixel.
A marker symbol type, for rendering Point and MultiPoint geometries.
static std::unique_ptr< QgsMarkerSymbol > createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
void setSizeMapUnitScale(const QgsMapUnitScale &scale) const
Sets the size map unit scale for the whole symbol (including all symbol layers).
void setSizeUnit(Qgis::RenderUnit unit) const
Sets the size units for the whole symbol (including all symbol layers).
static QgsPaintEffect * defaultStack()
Returns a new effect stack consisting of a sensible selection of default effects.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
Base class for visual effects which can be applied to QPicture drawings.
bool enabled() const
Returns whether the effect is enabled.
static const QString DIAGRAM_NAME_PIE
A grouped map of multiple QgsProperty objects, each referenced by an integer key value.
bool hasActiveProperties() const final
Returns true if the collection has any active properties, or false if all properties within the colle...
@ Double
Double value (including negative values).
Definition qgsproperty.h:55
@ StrokeWidth
Line stroke width.
Definition qgsproperty.h:70
@ Boolean
Boolean value.
Definition qgsproperty.h:51
@ Rotation
Rotation (value between 0-360 degrees).
Definition qgsproperty.h:58
@ ColorWithAlpha
Color with alpha channel.
Definition qgsproperty.h:62
@ DoublePositive
Positive double value (including 0).
Definition qgsproperty.h:56
A container for the context for various read/write operations on objects.
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
static bool equalToOrGreaterThanMinimumScale(const double scale, const double minScale)
Returns whether the scale is equal to or greater than the minScale, taking non-round numbers into acc...
static bool lessThanMaximumScale(const double scale, const double maxScale)
Returns whether the scale is less than the maxScale, taking non-round numbers into account.
Implementation of legend node interface for displaying arbitrary labels with icons.
QSizeF diagramSize(const QgsFeature &, const QgsRenderContext &c) const override
Returns size of the diagram (in painter units) or an invalid size in case of error.
void writeXml(QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Writes diagram state to a DOM element.
QgsSingleCategoryDiagramRenderer * clone() const override
Returns new instance that is equivalent to this one.
QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const override
Returns list of legend nodes for the diagram.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads diagram state from a DOM element.
QList< QgsDiagramSettings > diagramSettings() const override
Returns list with all diagram settings in the renderer.
static const QString DIAGRAM_RENDERER_NAME_SINGLE_CATEGORY
static const QString DIAGRAM_NAME_STACKED_BAR
QgsStackedDiagramRenderer * clone() const override
Returns new instance that is equivalent to this one.
QList< QgsDiagramSettings > diagramSettings() const override
Returns list with all diagram settings in the renderer.
QSizeF diagramSize(const QgsFeature &, const QgsRenderContext &c) const override
Returns size of the diagram (in painter units) or an invalid size in case of error.
void renderDiagram(const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties=QgsPropertyCollection()) const override
Renders the diagram for a specified feature at a specific position in the passed render context,...
QList< QString > diagramAttributes() const override
Returns attribute indices needed for diagram rendering.
void writeXml(QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Writes diagram state to a DOM element.
static const QString DIAGRAM_RENDERER_NAME_STACKED
QgsStackedDiagramRenderer & operator=(const QgsStackedDiagramRenderer &other)
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads diagram state from a DOM element.
void addRenderer(QgsDiagramRenderer *renderer)
Adds a renderer to the stacked renderer object.
void _writeXmlSubRenderers(QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context) const
Writes stacked renderers state to a DOM element.
QList< QgsDiagramRenderer * > renderers(bool sortByDiagramMode=false) const
Returns an ordered list with the renderers of the stacked renderer object.
const QgsDiagramRenderer * renderer(const int index) const
Returns the renderer at the given index.
void _readXmlSubRenderers(const QDomElement &elem, const QgsReadWriteContext &context)
Reads stacked renderers state from a DOM element.
int rendererCount() const
Returns the number of sub renderers in the stacked diagram renderer.
QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const override
Returns list of legend nodes for the diagram.
QgsStackedDiagramRenderer()=default
QSizeF sizeMapUnits(const QgsFeature &feature, const QgsRenderContext &c) const override
Returns size of the diagram for a feature in map units. Returns an invalid QSizeF in case of error.
A diagram composed of several subdiagrams, located side by side.
static const QString DIAGRAM_NAME_STACKED
void subDiagramPosition(QPointF &newPos, const QgsRenderContext &c, const QgsDiagramSettings &s, const QgsDiagramSettings &subSettings)
Calculates the position for the next subdiagram, updating the newPos object.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QList< double > prettyBreaks(double minimum, double maximum, int classes)
Computes a sequence of about 'classes' equally spaced round values which cover the range of values fr...
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static std::unique_ptr< QgsSymbol > loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
static const QString DIAGRAM_NAME_TEXT
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
Definition of one class for the legend.