QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 }
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...
void setCoordinateTransform(const QgsCoordinateTransform &transform)
Sets the coordinate transform associated with the layer.
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.
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
QgsSingleCategoryDiagramRenderer * clone() const override
Returns new instance that is equivalent to this one.
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.
void convertSizeToMapUnits(QSizeF &size, const QgsRenderContext &context) const
Converts size from mm to map units.
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...
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
Produces legend node with a marker symbol.
double convertToMapUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
virtual QList< QString > diagramAttributes() const =0
Returns attribute indices needed for diagram rendering.
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the size map unit scale for the whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1369
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
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const
Prepares the diagrams for a specified expression context.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
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
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:577
double rotationOffset
Rotation offset, in degrees clockwise from horizontal.
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.
QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const override
Returns list of legend nodes for the diagram.
QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const override
Returns list of legend nodes for the diagram.
void _writeXml(QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context) const
Writes internal QgsDiagramRenderer diagram state to a DOM element.
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)
virtual QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const
Returns list of legend nodes for 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...
Evaluates and returns the diagram settings relating to a diagram for a specific feature.
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void readXml(const QDomElement &elem)
Reads the diagram settings from a DOM element.
double size
Marker size in units used by the symbol (usually millimeters). May be further scaled before rendering...
QgsDiagramLayerSettings()
Constructor for QgsDiagramLayerSettings.
QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const
Returns list of legend nodes for the diagram.
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.
double mapUnitsPerPixel() const
Returns current map units per pixel.
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const
Writes configuration to the given XML element.
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.
Whether diagram features act as obstacles for other diagrams/labels.
Double value (including negative values)
Definition: qgsproperty.h:57
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:1333
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
Returns the set of any fields referenced by the layer&#39;s diagrams.
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...
Definition for a property.
Definition: qgsproperty.h:46
Base class for all diagram types.
Definition: qgsdiagram.h:38
void writeXml(QDomElement &layerElem, QDomDocument &doc) const
Writes the diagram settings to a DOM element.
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...
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 writeXml(QDomElement &rendererElem, QDomDocument &doc) const
Writes diagram settings to XML.
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.
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend.
QgsMarkerSymbol * symbol() const
Returns marker symbol that will be used to draw markers in legend.
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...
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.
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.
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.
const QgsMapToPixel & mapToPixel() const
Returns the context&#39;s map to pixel transform, which transforms between map coordinates and device coo...
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
virtual QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const
Returns the set of any fields required for diagram rendering.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Whether to show the diagram.
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
static QgsMarkerSymbol * createSimple(const QgsStringMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
Definition: qgssymbol.cpp:1128
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.
Object that keeps configuration of appearance of marker symbol&#39;s data-defined size in legend...
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)
QgsDataDefinedSizeLegend * dataDefinedSizeLegendSettings() const
Returns extra information for data-defined size legend rendering.
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:1590
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.