QGIS API Documentation  3.6.0-Noosa (5873452)
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 
18 #include "qgsvectorlayer.h"
19 #include "diagram/qgstextdiagram.h"
20 #include "diagram/qgspiediagram.h"
22 #include "qgsrendercontext.h"
24 #include "qgsfontutils.h"
25 #include "qgssymbollayerutils.h"
26 
27 #include <QDomElement>
28 #include <QPainter>
29 
30 QgsPropertiesDefinition QgsDiagramLayerSettings::sPropertyDefinitions;
31 
32 void QgsDiagramLayerSettings::initPropertyDefinitions()
33 {
34  if ( !sPropertyDefinitions.isEmpty() )
35  return;
36 
37  const QString origin = QStringLiteral( "diagram" );
38 
39  sPropertyDefinitions = QgsPropertiesDefinition
40  {
41  { QgsDiagramLayerSettings::BackgroundColor, QgsPropertyDefinition( "backgroundColor", QObject::tr( "Background color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
42  { QgsDiagramLayerSettings::StrokeColor, QgsPropertyDefinition( "strokeColor", QObject::tr( "Stroke color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
43  { QgsDiagramLayerSettings::StrokeWidth, QgsPropertyDefinition( "strokeWidth", QObject::tr( "Stroke width" ), QgsPropertyDefinition::StrokeWidth, origin ) },
44  { QgsDiagramLayerSettings::PositionX, QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double, origin ) },
45  { QgsDiagramLayerSettings::PositionY, QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double, origin ) },
46  { QgsDiagramLayerSettings::Distance, QgsPropertyDefinition( "distance", QObject::tr( "Placement distance" ), QgsPropertyDefinition::DoublePositive, origin ) },
47  { QgsDiagramLayerSettings::Priority, QgsPropertyDefinition( "priority", QObject::tr( "Placement priority" ), QgsPropertyDefinition::DoublePositive, origin ) },
48  { QgsDiagramLayerSettings::ZIndex, QgsPropertyDefinition( "zIndex", QObject::tr( "Placement z-index" ), QgsPropertyDefinition::Double, origin ) },
49  { QgsDiagramLayerSettings::IsObstacle, QgsPropertyDefinition( "isObstacle", QObject::tr( "Diagram is an obstacle" ), QgsPropertyDefinition::Boolean, origin ) },
50  { QgsDiagramLayerSettings::Show, QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean, origin ) },
51  { QgsDiagramLayerSettings::AlwaysShow, QgsPropertyDefinition( "alwaysShow", QObject::tr( "Always show diagram" ), QgsPropertyDefinition::Boolean, origin ) },
52  { QgsDiagramLayerSettings::StartAngle, QgsPropertyDefinition( "startAngle", QObject::tr( "Pie chart start angle" ), QgsPropertyDefinition::Rotation, origin ) },
53  };
54 }
55 
57 {
58  initPropertyDefinitions();
59  return sPropertyDefinitions;
60 }
61 
63 {
64  initPropertyDefinitions();
65 }
66 
68  : mCt( rh.mCt )
69  , mPlacement( rh.mPlacement )
70  , mPlacementFlags( rh.mPlacementFlags )
71  , mPriority( rh.mPriority )
72  , mZIndex( rh.mZIndex )
73  , mObstacle( rh.mObstacle )
74  , mDistance( rh.mDistance )
75  , mRenderer( rh.mRenderer ? rh.mRenderer->clone() : nullptr )
76  , mShowAll( rh.mShowAll )
77  , mDataDefinedProperties( rh.mDataDefinedProperties )
78 {
79  initPropertyDefinitions();
80 }
81 
83 {
84  mPlacement = rh.mPlacement;
85  mPlacementFlags = rh.mPlacementFlags;
86  mPriority = rh.mPriority;
87  mZIndex = rh.mZIndex;
88  mObstacle = rh.mObstacle;
89  mDistance = rh.mDistance;
90  mRenderer = rh.mRenderer ? rh.mRenderer->clone() : nullptr;
91  mCt = rh.mCt;
92  mShowAll = rh.mShowAll;
93  mDataDefinedProperties = rh.mDataDefinedProperties;
94  return *this;
95 }
96 
98 {
99  delete mRenderer;
100 }
101 
103 {
104  if ( diagramRenderer == mRenderer )
105  return;
106 
107  delete mRenderer;
108  mRenderer = diagramRenderer;
109 }
110 
112 {
113  mCt = transform;
114 }
115 
116 void QgsDiagramLayerSettings::readXml( const QDomElement &elem )
117 {
118  QDomNodeList propertyElems = elem.elementsByTagName( QStringLiteral( "properties" ) );
119  if ( !propertyElems.isEmpty() )
120  {
121  ( void )mDataDefinedProperties.readXml( propertyElems.at( 0 ).toElement(), sPropertyDefinitions );
122  }
123  else
124  {
125  mDataDefinedProperties.clear();
126  }
127 
128  mPlacement = static_cast< Placement >( elem.attribute( QStringLiteral( "placement" ) ).toInt() );
129  mPlacementFlags = static_cast< LinePlacementFlag >( elem.attribute( QStringLiteral( "linePlacementFlags" ) ).toInt() );
130  mPriority = elem.attribute( QStringLiteral( "priority" ) ).toInt();
131  mZIndex = elem.attribute( QStringLiteral( "zIndex" ) ).toDouble();
132  mObstacle = elem.attribute( QStringLiteral( "obstacle" ) ).toInt();
133  mDistance = elem.attribute( QStringLiteral( "dist" ) ).toDouble();
134  mShowAll = ( elem.attribute( QStringLiteral( "showAll" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
135 }
136 
137 void QgsDiagramLayerSettings::writeXml( QDomElement &layerElem, QDomDocument &doc ) const
138 {
139  QDomElement diagramLayerElem = doc.createElement( QStringLiteral( "DiagramLayerSettings" ) );
140  QDomElement propertiesElem = doc.createElement( QStringLiteral( "properties" ) );
141  ( void )mDataDefinedProperties.writeXml( propertiesElem, sPropertyDefinitions );
142  diagramLayerElem.appendChild( propertiesElem );
143  diagramLayerElem.setAttribute( QStringLiteral( "placement" ), mPlacement );
144  diagramLayerElem.setAttribute( QStringLiteral( "linePlacementFlags" ), mPlacementFlags );
145  diagramLayerElem.setAttribute( QStringLiteral( "priority" ), mPriority );
146  diagramLayerElem.setAttribute( QStringLiteral( "zIndex" ), mZIndex );
147  diagramLayerElem.setAttribute( QStringLiteral( "obstacle" ), mObstacle );
148  diagramLayerElem.setAttribute( QStringLiteral( "dist" ), QString::number( mDistance ) );
149  diagramLayerElem.setAttribute( QStringLiteral( "showAll" ), mShowAll );
150  layerElem.appendChild( diagramLayerElem );
151 }
152 
154 {
155  return mDataDefinedProperties.prepare( context );
156 }
157 
159 {
160  QSet< QString > referenced;
161  if ( mRenderer )
162  referenced = mRenderer->referencedFields( context );
163 
164  //add the ones needed for data defined settings
165  referenced.unite( mDataDefinedProperties.referencedFields( context ) );
166 
167  return referenced;
168 }
169 
170 void QgsDiagramSettings::readXml( const QDomElement &elem )
171 {
172  enabled = ( elem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
173  if ( !QgsFontUtils::setFromXmlChildNode( font, elem, QStringLiteral( "fontProperties" ) ) )
174  {
175  font.fromString( elem.attribute( QStringLiteral( "font" ) ) );
176  }
177  backgroundColor.setNamedColor( elem.attribute( QStringLiteral( "backgroundColor" ) ) );
178  backgroundColor.setAlpha( elem.attribute( QStringLiteral( "backgroundAlpha" ) ).toInt() );
179  size.setWidth( elem.attribute( QStringLiteral( "width" ) ).toDouble() );
180  size.setHeight( elem.attribute( QStringLiteral( "height" ) ).toDouble() );
181  if ( elem.hasAttribute( QStringLiteral( "transparency" ) ) )
182  {
183  opacity = 1 - elem.attribute( QStringLiteral( "transparency" ), QStringLiteral( "0" ) ).toInt() / 255.0;
184  }
185  else
186  {
187  opacity = elem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1.00" ) ).toDouble();
188  }
189 
190  penColor.setNamedColor( elem.attribute( QStringLiteral( "penColor" ) ) );
191  int penAlpha = elem.attribute( QStringLiteral( "penAlpha" ), QStringLiteral( "255" ) ).toInt();
192  penColor.setAlpha( penAlpha );
193  penWidth = elem.attribute( QStringLiteral( "penWidth" ) ).toDouble();
194 
195  maximumScale = elem.attribute( QStringLiteral( "minScaleDenominator" ), QStringLiteral( "-1" ) ).toDouble();
196  minimumScale = elem.attribute( QStringLiteral( "maxScaleDenominator" ), QStringLiteral( "-1" ) ).toDouble();
197  if ( elem.hasAttribute( QStringLiteral( "scaleBasedVisibility" ) ) )
198  {
199  scaleBasedVisibility = ( elem.attribute( QStringLiteral( "scaleBasedVisibility" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
200  }
201  else
202  {
203  scaleBasedVisibility = maximumScale >= 0 && minimumScale >= 0;
204  }
205 
206  //diagram size unit type and scale
207  if ( elem.attribute( QStringLiteral( "sizeType" ) ) == QLatin1String( "MapUnits" ) )
208  {
209  //compatibility with pre-2.16 project files
210  sizeType = QgsUnitTypes::RenderMapUnits;
211  }
212  else
213  {
214  sizeType = QgsUnitTypes::decodeRenderUnit( elem.attribute( QStringLiteral( "sizeType" ) ) );
215  }
216  sizeScale = QgsSymbolLayerUtils::decodeMapUnitScale( elem.attribute( QStringLiteral( "sizeScale" ) ) );
217 
218  //line width unit type and scale
219  lineSizeUnit = QgsUnitTypes::decodeRenderUnit( elem.attribute( QStringLiteral( "lineSizeType" ) ) );
220  lineSizeScale = QgsSymbolLayerUtils::decodeMapUnitScale( elem.attribute( QStringLiteral( "lineSizeScale" ) ) );
221 
222  //label placement method
223  if ( elem.attribute( QStringLiteral( "labelPlacementMethod" ) ) == QLatin1String( "Height" ) )
224  {
225  labelPlacementMethod = Height;
226  }
227  else
228  {
229  labelPlacementMethod = XHeight;
230  }
231 
232  // orientation
233  if ( elem.attribute( QStringLiteral( "diagramOrientation" ) ) == QLatin1String( "Left" ) )
234  {
235  diagramOrientation = Left;
236  }
237  else if ( elem.attribute( QStringLiteral( "diagramOrientation" ) ) == QLatin1String( "Right" ) )
238  {
239  diagramOrientation = Right;
240  }
241  else if ( elem.attribute( QStringLiteral( "diagramOrientation" ) ) == QLatin1String( "Down" ) )
242  {
243  diagramOrientation = Down;
244  }
245  else
246  {
247  diagramOrientation = Up;
248  }
249 
250  // scale dependency
251  if ( elem.attribute( QStringLiteral( "scaleDependency" ) ) == QLatin1String( "Diameter" ) )
252  {
253  scaleByArea = false;
254  }
255  else
256  {
257  scaleByArea = true;
258  }
259 
260  barWidth = elem.attribute( QStringLiteral( "barWidth" ) ).toDouble();
261 
262  if ( elem.hasAttribute( QStringLiteral( "angleOffset" ) ) )
263  rotationOffset = std::fmod( 360.0 - elem.attribute( QStringLiteral( "angleOffset" ) ).toInt() / 16.0, 360.0 );
264  else
265  rotationOffset = elem.attribute( QStringLiteral( "rotationOffset" ) ).toDouble();
266 
267  minimumSize = elem.attribute( QStringLiteral( "minimumSize" ) ).toDouble();
268 
269  //colors
270  categoryColors.clear();
271  QDomNodeList attributes = elem.elementsByTagName( QStringLiteral( "attribute" ) );
272 
273  if ( attributes.length() > 0 )
274  {
275  for ( int i = 0; i < attributes.size(); i++ )
276  {
277  QDomElement attrElem = attributes.at( i ).toElement();
278  QColor newColor( attrElem.attribute( QStringLiteral( "color" ) ) );
279  newColor.setAlphaF( opacity );
280  categoryColors.append( newColor );
281  categoryAttributes.append( attrElem.attribute( QStringLiteral( "field" ) ) );
282  categoryLabels.append( attrElem.attribute( QStringLiteral( "label" ) ) );
283  if ( categoryLabels.back().isEmpty() )
284  {
285  categoryLabels.back() = categoryAttributes.back();
286  }
287  }
288  }
289  else
290  {
291  // Restore old format attributes and colors
292 
293  QStringList colorList = elem.attribute( QStringLiteral( "colors" ) ).split( '/' );
294  QStringList::const_iterator colorIt = colorList.constBegin();
295  for ( ; colorIt != colorList.constEnd(); ++colorIt )
296  {
297  QColor newColor( *colorIt );
298  newColor.setAlphaF( opacity );
299  categoryColors.append( QColor( newColor ) );
300  }
301 
302  //attribute indices
303  categoryAttributes.clear();
304  QStringList catList = elem.attribute( QStringLiteral( "categories" ) ).split( '/' );
305  QStringList::const_iterator catIt = catList.constBegin();
306  for ( ; catIt != catList.constEnd(); ++catIt )
307  {
308  categoryAttributes.append( *catIt );
309  categoryLabels.append( *catIt );
310  }
311  }
312 }
313 
314 void QgsDiagramSettings::writeXml( QDomElement &rendererElem, QDomDocument &doc ) const
315 {
316  QDomElement categoryElem = doc.createElement( QStringLiteral( "DiagramCategory" ) );
317  categoryElem.setAttribute( QStringLiteral( "enabled" ), enabled );
318  categoryElem.appendChild( QgsFontUtils::toXmlElement( font, doc, QStringLiteral( "fontProperties" ) ) );
319  categoryElem.setAttribute( QStringLiteral( "backgroundColor" ), backgroundColor.name() );
320  categoryElem.setAttribute( QStringLiteral( "backgroundAlpha" ), backgroundColor.alpha() );
321  categoryElem.setAttribute( QStringLiteral( "width" ), QString::number( size.width() ) );
322  categoryElem.setAttribute( QStringLiteral( "height" ), QString::number( size.height() ) );
323  categoryElem.setAttribute( QStringLiteral( "penColor" ), penColor.name() );
324  categoryElem.setAttribute( QStringLiteral( "penAlpha" ), penColor.alpha() );
325  categoryElem.setAttribute( QStringLiteral( "penWidth" ), QString::number( penWidth ) );
326  categoryElem.setAttribute( QStringLiteral( "scaleBasedVisibility" ), scaleBasedVisibility );
327  categoryElem.setAttribute( QStringLiteral( "minScaleDenominator" ), QString::number( maximumScale ) );
328  categoryElem.setAttribute( QStringLiteral( "maxScaleDenominator" ), QString::number( minimumScale ) );
329  categoryElem.setAttribute( QStringLiteral( "opacity" ), QString::number( opacity ) );
330 
331  //diagram size unit type and scale
332  categoryElem.setAttribute( QStringLiteral( "sizeType" ), QgsUnitTypes::encodeUnit( sizeType ) );
333  categoryElem.setAttribute( QStringLiteral( "sizeScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( sizeScale ) );
334 
335  //line width unit type and scale
336  categoryElem.setAttribute( QStringLiteral( "lineSizeType" ), QgsUnitTypes::encodeUnit( lineSizeUnit ) );
337  categoryElem.setAttribute( QStringLiteral( "lineSizeScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( lineSizeScale ) );
338 
339  // label placement method (text diagram)
340  if ( labelPlacementMethod == Height )
341  {
342  categoryElem.setAttribute( QStringLiteral( "labelPlacementMethod" ), QStringLiteral( "Height" ) );
343  }
344  else
345  {
346  categoryElem.setAttribute( QStringLiteral( "labelPlacementMethod" ), QStringLiteral( "XHeight" ) );
347  }
348 
349  if ( scaleByArea )
350  {
351  categoryElem.setAttribute( QStringLiteral( "scaleDependency" ), QStringLiteral( "Area" ) );
352  }
353  else
354  {
355  categoryElem.setAttribute( QStringLiteral( "scaleDependency" ), QStringLiteral( "Diameter" ) );
356  }
357 
358  // orientation (histogram)
359  switch ( diagramOrientation )
360  {
361  case Left:
362  categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Left" ) );
363  break;
364 
365  case Right:
366  categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Right" ) );
367  break;
368 
369  case Down:
370  categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Down" ) );
371  break;
372 
373  case Up:
374  categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Up" ) );
375  break;
376 
377  default:
378  categoryElem.setAttribute( QStringLiteral( "diagramOrientation" ), QStringLiteral( "Up" ) );
379  break;
380  }
381 
382  categoryElem.setAttribute( QStringLiteral( "barWidth" ), QString::number( barWidth ) );
383  categoryElem.setAttribute( QStringLiteral( "minimumSize" ), QString::number( minimumSize ) );
384  categoryElem.setAttribute( QStringLiteral( "rotationOffset" ), QString::number( rotationOffset ) );
385 
386  int nCats = std::min( categoryColors.size(), categoryAttributes.size() );
387  for ( int i = 0; i < nCats; ++i )
388  {
389  QDomElement attributeElem = doc.createElement( QStringLiteral( "attribute" ) );
390 
391  attributeElem.setAttribute( QStringLiteral( "field" ), categoryAttributes.at( i ) );
392  attributeElem.setAttribute( QStringLiteral( "color" ), categoryColors.at( i ).name() );
393  attributeElem.setAttribute( QStringLiteral( "label" ), categoryLabels.at( i ) );
394  categoryElem.appendChild( attributeElem );
395  }
396 
397  rendererElem.appendChild( categoryElem );
398 }
399 
401 {
402  if ( mDiagram.get() == d )
403  return;
404 
405  mDiagram.reset( d );
406 }
407 
409  : mDiagram( other.mDiagram ? other.mDiagram->clone() : nullptr )
410  , mShowAttributeLegend( other.mShowAttributeLegend )
411 {
412 }
413 
415 {
416  mDiagram.reset( other.mDiagram ? other.mDiagram->clone() : nullptr );
418  return *this;
419 }
420 
421 void QgsDiagramRenderer::renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties ) const
422 {
423  if ( !mDiagram )
424  {
425  return;
426  }
427 
429  if ( !diagramSettings( feature, c, s ) )
430  {
431  return;
432  }
433 
434  if ( properties.hasActiveProperties() )
435  {
444  }
445 
446  mDiagram->renderDiagram( feature, c, s, pos );
447 }
448 
449 QSizeF QgsDiagramRenderer::sizeMapUnits( const QgsFeature &feature, const QgsRenderContext &c ) const
450 {
452  if ( !diagramSettings( feature, c, s ) )
453  {
454  return QSizeF();
455  }
456 
457  QSizeF size = diagramSize( feature, c );
458  if ( size.isValid() )
459  {
460  double width = c.convertToMapUnits( size.width(), s.sizeType, s.sizeScale );
461  size.rheight() *= width / size.width();
462  size.setWidth( width );
463  }
464  return size;
465 }
466 
467 QSet<QString> QgsDiagramRenderer::referencedFields( const QgsExpressionContext &context ) const
468 {
469  QSet< QString > referenced;
470 
471  if ( !mDiagram )
472  return referenced;
473 
474  Q_FOREACH ( const QString &att, diagramAttributes() )
475  {
476  QgsExpression *expression = mDiagram->getExpression( att, context );
477  Q_FOREACH ( const QString &field, expression->referencedColumns() )
478  {
479  referenced << field;
480  }
481  }
482  return referenced;
483 }
484 
485 void QgsDiagramRenderer::convertSizeToMapUnits( QSizeF &size, const QgsRenderContext &context ) const
486 {
487  if ( !size.isValid() )
488  {
489  return;
490  }
491 
492  double pixelToMap = context.scaleFactor() * context.mapToPixel().mapUnitsPerPixel();
493  size.rwidth() *= pixelToMap;
494  size.rheight() *= pixelToMap;
495 }
496 
497 int QgsDiagramRenderer::dpiPaintDevice( const QPainter *painter )
498 {
499  if ( painter )
500  {
501  QPaintDevice *device = painter->device();
502  if ( device )
503  {
504  return device->logicalDpiX();
505  }
506  }
507  return -1;
508 }
509 
510 void QgsDiagramRenderer::_readXml( const QDomElement &elem, const QgsReadWriteContext &context )
511 {
512  Q_UNUSED( context );
513  mDiagram.reset();
514  QString diagramType = elem.attribute( QStringLiteral( "diagramType" ) );
515  if ( diagramType == QLatin1String( "Pie" ) )
516  {
517  mDiagram.reset( new QgsPieDiagram() );
518  }
519  else if ( diagramType == QLatin1String( "Text" ) )
520  {
521  mDiagram.reset( new QgsTextDiagram() );
522  }
523  else if ( diagramType == QLatin1String( "Histogram" ) )
524  {
525  mDiagram.reset( new QgsHistogramDiagram() );
526  }
527  mShowAttributeLegend = ( elem.attribute( QStringLiteral( "attributeLegend" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
528 }
529 
530 void QgsDiagramRenderer::_writeXml( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
531 {
532  Q_UNUSED( doc );
533  Q_UNUSED( context );
534 
535  if ( mDiagram )
536  {
537  rendererElem.setAttribute( QStringLiteral( "diagramType" ), mDiagram->diagramName() );
538  }
539  rendererElem.setAttribute( QStringLiteral( "attributeLegend" ), mShowAttributeLegend );
540 }
541 
543 {
544  return new QgsSingleCategoryDiagramRenderer( *this );
545 }
546 
548 {
549  Q_UNUSED( c );
550  s = mSettings;
551  return true;
552 }
553 
555 {
556  return mDiagram->diagramSize( feature.attributes(), c, mSettings );
557 }
558 
559 QList<QgsDiagramSettings> QgsSingleCategoryDiagramRenderer::diagramSettings() const
560 {
561  QList<QgsDiagramSettings> settingsList;
562  settingsList.push_back( mSettings );
563  return settingsList;
564 }
565 
566 void QgsSingleCategoryDiagramRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
567 {
568  QDomElement categoryElem = elem.firstChildElement( QStringLiteral( "DiagramCategory" ) );
569  if ( categoryElem.isNull() )
570  {
571  return;
572  }
573 
574  mSettings.readXml( categoryElem );
575  _readXml( elem, context );
576 }
577 
578 void QgsSingleCategoryDiagramRenderer::writeXml( QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
579 {
580  QDomElement rendererElem = doc.createElement( QStringLiteral( "SingleCategoryDiagramRenderer" ) );
581  mSettings.writeXml( rendererElem, doc );
582  _writeXml( rendererElem, doc, context );
583  layerElem.appendChild( rendererElem );
584 }
585 
586 
588 {
589  mInterpolationSettings.classificationAttributeIsExpression = false;
590 }
591 
593  : QgsDiagramRenderer( other )
594  , mSettings( other.mSettings )
595  , mInterpolationSettings( other.mInterpolationSettings )
596  , mDataDefinedSizeLegend( other.mDataDefinedSizeLegend ? new QgsDataDefinedSizeLegend( *other.mDataDefinedSizeLegend ) : nullptr )
597 {
598 }
599 
601 {
602  delete mDataDefinedSizeLegend;
603 }
604 
606 {
607  return new QgsLinearlyInterpolatedDiagramRenderer( *this );
608 }
609 
611 {
612  QList<QgsDiagramSettings> settingsList;
613  settingsList.push_back( mSettings );
614  return settingsList;
615 }
616 
618 {
619  s = mSettings;
620  s.size = diagramSize( feature, c );
621  return true;
622 }
623 
625 {
626  return mSettings.categoryAttributes;
627 }
628 
630 {
631  QSet< QString > referenced = QgsDiagramRenderer::referencedFields( context );
632  if ( mInterpolationSettings.classificationAttributeIsExpression )
633  {
634  QgsExpression *expression = mDiagram->getExpression( mInterpolationSettings.classificationAttributeExpression, context );
635  Q_FOREACH ( const QString &field, expression->referencedColumns() )
636  {
637  referenced << field;
638  }
639  }
640  else
641  {
642  referenced << mInterpolationSettings.classificationField;
643  }
644  return referenced;
645 }
646 
648 {
649  return mDiagram->diagramSize( feature, c, mSettings, mInterpolationSettings );
650 }
651 
652 void QgsLinearlyInterpolatedDiagramRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
653 {
654  mInterpolationSettings.lowerValue = elem.attribute( QStringLiteral( "lowerValue" ) ).toDouble();
655  mInterpolationSettings.upperValue = elem.attribute( QStringLiteral( "upperValue" ) ).toDouble();
656  mInterpolationSettings.lowerSize.setWidth( elem.attribute( QStringLiteral( "lowerWidth" ) ).toDouble() );
657  mInterpolationSettings.lowerSize.setHeight( elem.attribute( QStringLiteral( "lowerHeight" ) ).toDouble() );
658  mInterpolationSettings.upperSize.setWidth( elem.attribute( QStringLiteral( "upperWidth" ) ).toDouble() );
659  mInterpolationSettings.upperSize.setHeight( elem.attribute( QStringLiteral( "upperHeight" ) ).toDouble() );
660  mInterpolationSettings.classificationAttributeIsExpression = elem.hasAttribute( QStringLiteral( "classificationAttributeExpression" ) );
661  if ( mInterpolationSettings.classificationAttributeIsExpression )
662  {
663  mInterpolationSettings.classificationAttributeExpression = elem.attribute( QStringLiteral( "classificationAttributeExpression" ) );
664  }
665  else
666  {
667  mInterpolationSettings.classificationField = elem.attribute( QStringLiteral( "classificationField" ) );
668  }
669  QDomElement settingsElem = elem.firstChildElement( QStringLiteral( "DiagramCategory" ) );
670  if ( !settingsElem.isNull() )
671  {
672  mSettings.readXml( settingsElem );
673  }
674 
675  delete mDataDefinedSizeLegend;
676 
677  QDomElement ddsLegendSizeElem = elem.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
678  if ( !ddsLegendSizeElem.isNull() )
679  {
680  mDataDefinedSizeLegend = QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context );
681  }
682  else
683  {
684  // pre-3.0 projects
685  if ( elem.attribute( QStringLiteral( "sizeLegend" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) )
686  {
687  mDataDefinedSizeLegend = new QgsDataDefinedSizeLegend();
688  QDomElement sizeLegendSymbolElem = elem.firstChildElement( QStringLiteral( "symbol" ) );
689  if ( !sizeLegendSymbolElem.isNull() && sizeLegendSymbolElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "sizeSymbol" ) )
690  {
691  mDataDefinedSizeLegend->setSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( sizeLegendSymbolElem, context ) );
692  }
693  }
694  else
695  {
696  mDataDefinedSizeLegend = nullptr;
697  }
698  }
699 
700  _readXml( elem, context );
701 }
702 
703 void QgsLinearlyInterpolatedDiagramRenderer::writeXml( QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
704 {
705  QDomElement rendererElem = doc.createElement( QStringLiteral( "LinearlyInterpolatedDiagramRenderer" ) );
706  rendererElem.setAttribute( QStringLiteral( "lowerValue" ), QString::number( mInterpolationSettings.lowerValue ) );
707  rendererElem.setAttribute( QStringLiteral( "upperValue" ), QString::number( mInterpolationSettings.upperValue ) );
708  rendererElem.setAttribute( QStringLiteral( "lowerWidth" ), QString::number( mInterpolationSettings.lowerSize.width() ) );
709  rendererElem.setAttribute( QStringLiteral( "lowerHeight" ), QString::number( mInterpolationSettings.lowerSize.height() ) );
710  rendererElem.setAttribute( QStringLiteral( "upperWidth" ), QString::number( mInterpolationSettings.upperSize.width() ) );
711  rendererElem.setAttribute( QStringLiteral( "upperHeight" ), QString::number( mInterpolationSettings.upperSize.height() ) );
712  if ( mInterpolationSettings.classificationAttributeIsExpression )
713  {
714  rendererElem.setAttribute( QStringLiteral( "classificationAttributeExpression" ), mInterpolationSettings.classificationAttributeExpression );
715  }
716  else
717  {
718  rendererElem.setAttribute( QStringLiteral( "classificationField" ), mInterpolationSettings.classificationField );
719  }
720  mSettings.writeXml( rendererElem, doc );
721 
722  if ( mDataDefinedSizeLegend )
723  {
724  QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
725  mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
726  rendererElem.appendChild( ddsLegendElem );
727  }
728 
729  _writeXml( rendererElem, doc, context );
730  layerElem.appendChild( rendererElem );
731 }
732 
733 QList< QgsLayerTreeModelLegendNode * > QgsDiagramSettings::legendItems( QgsLayerTreeLayer *nodeLayer ) const
734 {
735  QList< QgsLayerTreeModelLegendNode * > list;
736  list.reserve( categoryLabels.size() );
737  for ( int i = 0; i < categoryLabels.size(); ++i )
738  {
739  QPixmap pix( 16, 16 );
740  pix.fill( categoryColors[i] );
741  list << new QgsSimpleLegendNode( nodeLayer, categoryLabels[i], QIcon( pix ), nullptr, QStringLiteral( "diagram_%1" ).arg( QString::number( i ) ) );
742  }
743  return list;
744 }
745 
746 QList< QgsLayerTreeModelLegendNode * > QgsDiagramRenderer::legendItems( QgsLayerTreeLayer * ) const
747 {
748  return QList< QgsLayerTreeModelLegendNode * >();
749 }
750 
751 QList< QgsLayerTreeModelLegendNode * > QgsSingleCategoryDiagramRenderer::legendItems( QgsLayerTreeLayer *nodeLayer ) const
752 {
753  QList< QgsLayerTreeModelLegendNode * > nodes;
754  if ( mShowAttributeLegend )
755  nodes = mSettings.legendItems( nodeLayer );
756 
757  return nodes;
758 }
759 
760 QList< QgsLayerTreeModelLegendNode * > QgsLinearlyInterpolatedDiagramRenderer::legendItems( QgsLayerTreeLayer *nodeLayer ) const
761 {
762  QList< QgsLayerTreeModelLegendNode * > nodes;
763  if ( mShowAttributeLegend )
764  nodes = mSettings.legendItems( nodeLayer );
765 
766  if ( mDataDefinedSizeLegend && mDiagram )
767  {
768  // add size legend
769  QgsMarkerSymbol *legendSymbol = mDataDefinedSizeLegend->symbol() ? mDataDefinedSizeLegend->symbol()->clone() : QgsMarkerSymbol::createSimple( QgsStringMap() );
770  legendSymbol->setSizeUnit( mSettings.sizeType );
771  legendSymbol->setSizeMapUnitScale( mSettings.sizeScale );
772 
773  QgsDataDefinedSizeLegend ddSizeLegend( *mDataDefinedSizeLegend );
774  ddSizeLegend.setSymbol( legendSymbol ); // transfers ownership
775 
776  QList<QgsDataDefinedSizeLegend::SizeClass> sizeClasses;
777  if ( ddSizeLegend.classes().isEmpty() )
778  {
779  // automatic class creation if the classes are not defined manually
780  Q_FOREACH ( double v, QgsSymbolLayerUtils::prettyBreaks( mInterpolationSettings.lowerValue, mInterpolationSettings.upperValue, 4 ) )
781  {
782  double size = mDiagram->legendSize( v, mSettings, mInterpolationSettings );
783  sizeClasses << QgsDataDefinedSizeLegend::SizeClass( size, QString::number( v ) );
784  }
785  }
786  else
787  {
788  // manual classes need to get size scaled because the QgsSizeScaleTransformer is not used in diagrams :-(
789  Q_FOREACH ( const QgsDataDefinedSizeLegend::SizeClass &sc, ddSizeLegend.classes() )
790  {
791  double size = mDiagram->legendSize( sc.size, mSettings, mInterpolationSettings );
792  sizeClasses << QgsDataDefinedSizeLegend::SizeClass( size, sc.label );
793  }
794  }
795  ddSizeLegend.setClasses( sizeClasses );
796 
797  Q_FOREACH ( const QgsLegendSymbolItem &si, ddSizeLegend.legendSymbolList() )
798  {
800  nodes << new QgsDataDefinedSizeLegendNode( nodeLayer, *si.dataDefinedSizeLegendSettings() );
801  else
802  nodes << new QgsSymbolLegendNode( nodeLayer, si );
803  }
804  }
805 
806  return nodes;
807 }
808 
810 {
811  delete mDataDefinedSizeLegend;
812  mDataDefinedSizeLegend = settings;
813 }
814 
816 {
817  return mDataDefinedSizeLegend;
818 }
void _writeXml(QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context) const
Writes internal QgsDiagramRenderer diagram state to a DOM element.
Class for parsing and evaluation of expressions (formerly called "search strings").
static int dpiPaintDevice(const QPainter *)
Returns the paint device dpi (or -1 in case of error.
The class is used as a container of context for various read/write operations on other objects...
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...
void setCoordinateTransform(const QgsCoordinateTransform &transform)
Sets the coordinate transform associated with the layer.
double convertToMapUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
y-coordinate data defined diagram position
void writeXml(QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Writes diagram state to a DOM element.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const override
Returns the set of any fields required for diagram rendering.
QString label
Label to be shown with the particular symbol size.
QgsSingleCategoryDiagramRenderer * clone() const override
Returns new instance that is equivalent to this one.
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...
Definition of one class for the legend.
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
Renders the diagrams for all features with the same settings.
QList< QString > categoryAttributes
QgsDiagramRenderer()=default
Constructor for QgsDiagramRenderer.
virtual QList< QgsLayerTreeModelLegendNode *> legendItems(QgsLayerTreeLayer *nodeLayer) const
Returns list of legend nodes for the diagram.
Produces legend node with a marker symbol.
virtual QList< QString > diagramAttributes() const =0
Returns attribute indices needed for diagram rendering.
void writeXml(QDomElement &layerElem, QDomDocument &doc) const
Writes the diagram settings to a DOM element.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the size map unit scale for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1367
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
Whether the diagram should always be shown, even if it overlaps other diagrams/labels.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Color with alpha channel.
Definition: qgsproperty.h:64
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const
Returns the set of any fields referenced by the layer&#39;s diagrams.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
Positive double value (including 0)
Definition: qgsproperty.h:58
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...
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
Z-index for diagram ordering.
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.
bool mShowAttributeLegend
Whether to show an attribute legend for the diagrams.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:587
double rotationOffset
Rotation offset, in degrees clockwise from horizontal.
QgsMarkerSymbol * symbol() const
Returns marker symbol that will be used to draw markers in legend.
Rotation (value between 0-360 degrees)
Definition: qgsproperty.h:60
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:732
void setDiagram(QgsDiagram *d)
QList< QgsDiagramSettings > diagramSettings() const override
Returns list with all diagram settings in the renderer.
static QString encodeColor(const QColor &color)
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
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
Diagram priority (between 0 and 10)
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...
Evaluates and returns the diagram settings relating to a diagram for a specific feature.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const
Prepares the diagrams for a specified expression context.
void readXml(const QDomElement &elem)
Reads the diagram settings from a DOM element.
void convertSizeToMapUnits(QSizeF &size, const QgsRenderContext &context) const
Converts size from mm to map units.
double size
Marker size in units used by the symbol (usually millimeters). May be further scaled before rendering...
QgsDiagramLayerSettings()
Constructor for QgsDiagramLayerSettings.
QgsMapUnitScale sizeScale
Diagram size unit scale.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads diagram state from a DOM element.
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.
x-coordinate data defined diagram position
Implementation of legend node interface for displaying arbitrary label with icon. ...
void clear() override
Removes all properties from the collection.
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
double mapUnitsPerPixel() const
Returns current map units per pixel.
Whether diagram features act as obstacles for other diagrams/labels.
Double value (including negative values)
Definition: qgsproperty.h:57
QList< QgsLayerTreeModelLegendNode *> legendItems(QgsLayerTreeLayer *nodeLayer) const
Returns list of legend nodes for the diagram.
std::unique_ptr< QgsDiagram > mDiagram
Reference to the object that does the real diagram rendering.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the size units for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1331
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const
Writes configuration to the given XML element.
void writeXml(QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Writes diagram state to a DOM element.
Definition for a property.
Definition: qgsproperty.h:46
Base class for all diagram types.
Definition: qgsdiagram.h:38
QgsLinearlyInterpolatedDiagramRenderer * clone() const override
Returns new instance that is equivalent to this one.
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
QgsUnitTypes::RenderUnit sizeType
Diagram size unit.
void setRenderer(QgsDiagramRenderer *diagramRenderer)
Sets the diagram renderer associated with the layer.
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
QgsExpressionContext & expressionContext()
Gets the expression context.
void readXml(const QDomElement &elem)
Reads diagram settings from XML.
Stores the settings for rendering of all diagrams for a layer.
static QList< double > prettyBreaks(double minimum, double maximum, int classes)
Computes a sequence of about &#39;classes&#39; equally spaced round values which cover the range of values fr...
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const override
Returns the set of any fields referenced by the active properties from the collection.
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
Contains information about the context of a rendering operation.
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend.
virtual QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const
Returns the set of any fields required for diagram rendering.
const QgsMapToPixel & mapToPixel() const
QList< QgsLayerTreeModelLegendNode *> legendItems(QgsLayerTreeLayer *nodeLayer) const override
Returns list of legend nodes for the diagram.
virtual QSizeF diagramSize(const QgsFeature &features, const QgsRenderContext &c) const =0
Returns size of the diagram (in painter units) or an invalid size in case of error.
Distance to diagram from feature.
void setSymbol(QgsMarkerSymbol *symbol SIP_TRANSFER)
Sets marker symbol that will be used to draw markers in legend.
QgsDataDefinedSizeLegend * dataDefinedSizeLegendSettings() const
Returns extra information for data-defined size legend rendering.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the diagram property definitions.
QList< QString > diagramAttributes() const override
Returns attribute indices needed for diagram rendering.
QgsDiagramRenderer & operator=(const QgsDiagramRenderer &other)
virtual QList< QgsDiagramSettings > diagramSettings() const =0
Returns list with all diagram settings in the renderer.
QString classificationField
Name of the field for classification.
Class for doing transforms between two map coordinate systems.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Whether to show the diagram.
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...
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
void writeXml(QDomElement &rendererElem, QDomDocument &doc) const
Writes diagram settings to XML.
static QgsMarkerSymbol * createSimple(const QgsStringMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
Definition: qgssymbol.cpp:1126
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
LinePlacementFlag
Line placement flags for controlling line based placements.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context) override
Reads diagram state from a DOM element.
QList< QgsLayerTreeModelLegendNode *> legendItems(QgsLayerTreeLayer *nodeLayer) const override
Returns list of legend nodes for the diagram.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Object that keeps configuration of appearance of marker symbol&#39;s data-defined size in legend...
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
static QgsDataDefinedSizeLegend * readXml(const QDomElement &elem, const QgsReadWriteContext &context) SIP_FACTORY
Creates instance from given element and returns it (caller takes ownership). Returns null on error...
QList< QgsDiagramSettings > diagramSettings() const override
Returns list with all diagram settings in the renderer.
QgsDiagramLayerSettings & operator=(const QgsDiagramLayerSettings &rh)
void _readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Reads internal QgsDiagramRenderer state from a DOM element.
Stores the settings for rendering a single diagram.
QgsAttributes attributes
Definition: qgsfeature.h:65
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:1585
virtual QgsDiagramRenderer * clone() const =0
Returns new instance that is equivalent to this one.
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...
Layer tree node points to a map layer.
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.