QGIS API Documentation  2.10.1-Pisa
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsdiagramrendererv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdiagramrendererv2.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 "qgsdiagramrendererv2.h"
16 #include "qgsvectorlayer.h"
17 #include "diagram/qgstextdiagram.h"
18 #include "diagram/qgspiediagram.h"
20 #include "qgsrendercontext.h"
22 #include "qgsfontutils.h"
23 
24 #include <QDomElement>
25 #include <QPainter>
26 
28  : placement( AroundPoint )
29  , placementFlags( OnLine )
30  , priority( 5 )
31  , obstacle( false )
32  , dist( 0.0 )
33  , renderer( 0 )
34  , palLayer( 0 )
35  , ct( 0 )
36  , xform( 0 )
37  , xPosColumn( -1 )
38  , yPosColumn( -1 )
39  , showAll( true )
40 {
41 }
42 
44 {
45  delete renderer;
46 }
47 
49 {
50  Q_UNUSED( layer )
51 
52  placement = ( Placement )elem.attribute( "placement" ).toInt();
53  placementFlags = ( LinePlacementFlags )elem.attribute( "linePlacementFlags" ).toInt();
54  priority = elem.attribute( "priority" ).toInt();
55  obstacle = elem.attribute( "obstacle" ).toInt();
56  dist = elem.attribute( "dist" ).toDouble();
57  xPosColumn = elem.attribute( "xPosColumn" ).toInt();
58  yPosColumn = elem.attribute( "yPosColumn" ).toInt();
59  showAll = ( elem.attribute( "showAll", "0" ) != "0" );
60 }
61 
62 void QgsDiagramLayerSettings::writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
63 {
64  Q_UNUSED( layer )
65 
66  QDomElement diagramLayerElem = doc.createElement( "DiagramLayerSettings" );
67  diagramLayerElem.setAttribute( "placement", placement );
68  diagramLayerElem.setAttribute( "linePlacementFlags", placementFlags );
69  diagramLayerElem.setAttribute( "priority", priority );
70  diagramLayerElem.setAttribute( "obstacle", obstacle );
71  diagramLayerElem.setAttribute( "dist", QString::number( dist ) );
72  diagramLayerElem.setAttribute( "xPosColumn", xPosColumn );
73  diagramLayerElem.setAttribute( "yPosColumn", yPosColumn );
74  diagramLayerElem.setAttribute( "showAll", showAll );
75  layerElem.appendChild( diagramLayerElem );
76 }
77 
78 void QgsDiagramSettings::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
79 {
80  Q_UNUSED( layer );
81 
82  enabled = ( elem.attribute( "enabled", "1" ) != "0" );
83  if ( !QgsFontUtils::setFromXmlChildNode( font, elem, "fontProperties" ) )
84  {
85  font.fromString( elem.attribute( "font" ) );
86  }
87  backgroundColor.setNamedColor( elem.attribute( "backgroundColor" ) );
88  backgroundColor.setAlpha( elem.attribute( "backgroundAlpha" ).toInt() );
89  size.setWidth( elem.attribute( "width" ).toDouble() );
90  size.setHeight( elem.attribute( "height" ).toDouble() );
91  transparency = elem.attribute( "transparency", "0" ).toInt();
92  penColor.setNamedColor( elem.attribute( "penColor" ) );
93  int penAlpha = elem.attribute( "penAlpha", "255" ).toInt();
94  penColor.setAlpha( penAlpha );
95  penWidth = elem.attribute( "penWidth" ).toDouble();
96 
97  minScaleDenominator = elem.attribute( "minScaleDenominator", "-1" ).toDouble();
98  maxScaleDenominator = elem.attribute( "maxScaleDenominator", "-1" ).toDouble();
99  if ( elem.hasAttribute( "scaleBasedVisibility" ) )
100  {
101  scaleBasedVisibility = ( elem.attribute( "scaleBasedVisibility", "1" ) != "0" );
102  }
103  else
104  {
106  }
107 
108  //mm vs map units
109  if ( elem.attribute( "sizeType" ) == "MM" )
110  {
111  sizeType = MM;
112  }
113  else
114  {
115  sizeType = MapUnits;
116  }
117 
118  //label placement method
119  if ( elem.attribute( "labelPlacementMethod" ) == "Height" )
120  {
122  }
123  else
124  {
126  }
127 
128  // orientation
129  if ( elem.attribute( "diagramOrientation" ) == "Left" )
130  {
132  }
133  else if ( elem.attribute( "diagramOrientation" ) == "Right" )
134  {
136  }
137  else if ( elem.attribute( "diagramOrientation" ) == "Down" )
138  {
140  }
141  else
142  {
144  }
145 
146  // scale dependency
147  if ( elem.attribute( "scaleDependency" ) == "Diameter" )
148  {
149  scaleByArea = false;
150  }
151  else
152  {
153  scaleByArea = true;
154  }
155 
156  barWidth = elem.attribute( "barWidth" ).toDouble();
157 
158  angleOffset = elem.attribute( "angleOffset" ).toInt();
159 
160  minimumSize = elem.attribute( "minimumSize" ).toDouble();
161 
162  //colors
164  QDomNodeList attributes = elem.elementsByTagName( "attribute" );
165 
166  if ( attributes.length() > 0 )
167  {
168  for ( uint i = 0; i < attributes.length(); i++ )
169  {
170  QDomElement attrElem = attributes.at( i ).toElement();
171  QColor newColor( attrElem.attribute( "color" ) );
172  newColor.setAlpha( 255 - transparency );
173  categoryColors.append( newColor );
174  categoryAttributes.append( attrElem.attribute( "field" ) );
175  categoryLabels.append( attrElem.attribute( "label" ) );
176  if ( categoryLabels.back().isEmpty() )
177  {
179  }
180  }
181  }
182  else
183  {
184  // Restore old format attributes and colors
185 
186  QStringList colorList = elem.attribute( "colors" ).split( "/" );
187  QStringList::const_iterator colorIt = colorList.constBegin();
188  for ( ; colorIt != colorList.constEnd(); ++colorIt )
189  {
190  QColor newColor( *colorIt );
191  newColor.setAlpha( 255 - transparency );
192  categoryColors.append( QColor( newColor ) );
193  }
194 
195  //attribute indices
197  QStringList catList = elem.attribute( "categories" ).split( "/" );
198  QStringList::const_iterator catIt = catList.constBegin();
199  for ( ; catIt != catList.constEnd(); ++catIt )
200  {
201  categoryAttributes.append( *catIt );
202  categoryLabels.append( *catIt );
203  }
204  }
205 }
206 
207 void QgsDiagramSettings::writeXML( QDomElement& rendererElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
208 {
209  Q_UNUSED( layer );
210 
211  QDomElement categoryElem = doc.createElement( "DiagramCategory" );
212  categoryElem.setAttribute( "enabled", enabled );
213  categoryElem.appendChild( QgsFontUtils::toXmlElement( font, doc, "fontProperties" ) );
214  categoryElem.setAttribute( "backgroundColor", backgroundColor.name() );
215  categoryElem.setAttribute( "backgroundAlpha", backgroundColor.alpha() );
216  categoryElem.setAttribute( "width", QString::number( size.width() ) );
217  categoryElem.setAttribute( "height", QString::number( size.height() ) );
218  categoryElem.setAttribute( "penColor", penColor.name() );
219  categoryElem.setAttribute( "penAlpha", penColor.alpha() );
220  categoryElem.setAttribute( "penWidth", QString::number( penWidth ) );
221  categoryElem.setAttribute( "scaleBasedVisibility", scaleBasedVisibility );
222  categoryElem.setAttribute( "minScaleDenominator", QString::number( minScaleDenominator ) );
223  categoryElem.setAttribute( "maxScaleDenominator", QString::number( maxScaleDenominator ) );
224  categoryElem.setAttribute( "transparency", QString::number( transparency ) );
225 
226  // site type (mm vs. map units)
227  if ( sizeType == MM )
228  {
229  categoryElem.setAttribute( "sizeType", "MM" );
230  }
231  else
232  {
233  categoryElem.setAttribute( "sizeType", "MapUnits" );
234  }
235 
236  // label placement method (text diagram)
237  if ( labelPlacementMethod == Height )
238  {
239  categoryElem.setAttribute( "labelPlacementMethod", "Height" );
240  }
241  else
242  {
243  categoryElem.setAttribute( "labelPlacementMethod", "XHeight" );
244  }
245 
246  if ( scaleByArea )
247  {
248  categoryElem.setAttribute( "scaleDependency", "Area" );
249  }
250  else
251  {
252  categoryElem.setAttribute( "scaleDependency", "Diameter" );
253  }
254 
255  // orientation (histogram)
256  switch ( diagramOrientation )
257  {
258  case Left:
259  categoryElem.setAttribute( "diagramOrientation", "Left" );
260  break;
261 
262  case Right:
263  categoryElem.setAttribute( "diagramOrientation", "Right" );
264  break;
265 
266  case Down:
267  categoryElem.setAttribute( "diagramOrientation", "Down" );
268  break;
269 
270  case Up:
271  categoryElem.setAttribute( "diagramOrientation", "Up" );
272  break;
273 
274  default:
275  categoryElem.setAttribute( "diagramOrientation", "Up" );
276  break;
277  }
278 
279  categoryElem.setAttribute( "barWidth", QString::number( barWidth ) );
280  categoryElem.setAttribute( "minimumSize", QString::number( minimumSize ) );
281  categoryElem.setAttribute( "angleOffset", QString::number( angleOffset ) );
282 
283  QString colors;
284  int nCats = qMin( categoryColors.size(), categoryAttributes.size() );
285  for ( int i = 0; i < nCats; ++i )
286  {
287  QDomElement attributeElem = doc.createElement( "attribute" );
288 
289  attributeElem.setAttribute( "field", categoryAttributes.at( i ) );
290  attributeElem.setAttribute( "color", categoryColors.at( i ).name() );
291  attributeElem.setAttribute( "label", categoryLabels.at( i ) );
292  categoryElem.appendChild( attributeElem );
293  }
294 
295  rendererElem.appendChild( categoryElem );
296 }
297 
299  : mDiagram( 0 )
300 {
301 }
302 
304 {
305  delete mDiagram;
306 }
307 
309 {
310  delete mDiagram;
311  mDiagram = d;
312 }
313 
315  : mDiagram( other.mDiagram ? other.mDiagram->clone() : 0 )
316 {
317 }
318 
320 {
321  if ( !mDiagram )
322  {
323  return;
324  }
325 
327  if ( !diagramSettings( feature, c, s ) )
328  {
329  return;
330  }
331 
332  mDiagram->renderDiagram( feature, c, s, pos );
333 }
334 
336 {
338  if ( !diagramSettings( feature, c, s ) )
339  {
340  return QSizeF();
341  }
342 
343  QSizeF size = diagramSize( feature, c );
344  if ( s.sizeType == QgsDiagramSettings::MM )
345  {
346  convertSizeToMapUnits( size, c );
347  }
348  return size;
349 }
350 
352 {
353  if ( !size.isValid() )
354  {
355  return;
356  }
357 
358  double pixelToMap = context.scaleFactor() * context.mapToPixel().mapUnitsPerPixel();
359  size.rwidth() *= pixelToMap;
360  size.rheight() *= pixelToMap;
361 }
362 
364 {
365  if ( painter )
366  {
367  QPaintDevice* device = painter->device();
368  if ( device )
369  {
370  return device->logicalDpiX();
371  }
372  }
373  return -1;
374 }
375 
377 {
378  Q_UNUSED( layer )
379 
380  delete mDiagram;
381  QString diagramType = elem.attribute( "diagramType" );
382  if ( diagramType == "Pie" )
383  {
384  mDiagram = new QgsPieDiagram();
385  }
386  else if ( diagramType == "Text" )
387  {
388  mDiagram = new QgsTextDiagram();
389  }
390  else if ( diagramType == "Histogram" )
391  {
393  }
394  else
395  {
396  mDiagram = 0;
397  }
398 }
399 
400 void QgsDiagramRendererV2::_writeXML( QDomElement& rendererElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
401 {
402  Q_UNUSED( doc );
403  Q_UNUSED( layer )
404 
405  if ( mDiagram )
406  {
407  rendererElem.setAttribute( "diagramType", mDiagram->diagramName() );
408  }
409 }
410 
412 {
413 }
414 
416 {
417 }
418 
420 {
421  return new QgsSingleCategoryDiagramRenderer( *this );
422 }
423 
425 {
426  Q_UNUSED( c );
427  s = mSettings;
428  return true;
429 }
430 
432 {
433  return mDiagram->diagramSize( feature.attributes(), c, mSettings );
434 }
435 
437 {
438  QList<QgsDiagramSettings> settingsList;
439  settingsList.push_back( mSettings );
440  return settingsList;
441 }
442 
444 {
445  QDomElement categoryElem = elem.firstChildElement( "DiagramCategory" );
446  if ( categoryElem.isNull() )
447  {
448  return;
449  }
450 
451  mSettings.readXML( categoryElem, layer );
452  _readXML( elem, layer );
453 }
454 
456 {
457  QDomElement rendererElem = doc.createElement( "SingleCategoryDiagramRenderer" );
458  mSettings.writeXML( rendererElem, doc, layer );
459  _writeXML( rendererElem, doc, layer );
460  layerElem.appendChild( rendererElem );
461 }
462 
463 
465 {
466  mInterpolationSettings.classificationAttributeIsExpression = false;
467 }
468 
470 {
471 }
472 
474 {
475  return new QgsLinearlyInterpolatedDiagramRenderer( *this );
476 }
477 
479 {
480  QList<QgsDiagramSettings> settingsList;
481  settingsList.push_back( mSettings );
482  return settingsList;
483 }
484 
486 {
487  s = mSettings;
488  s.size = diagramSize( feature, c );
489  return true;
490 }
491 
493 {
494  return mSettings.categoryAttributes;
495 }
496 
498 {
499  return mDiagram->diagramSize( feature, c, mSettings, mInterpolationSettings );
500 }
501 
503 {
504  mInterpolationSettings.lowerValue = elem.attribute( "lowerValue" ).toDouble();
505  mInterpolationSettings.upperValue = elem.attribute( "upperValue" ).toDouble();
506  mInterpolationSettings.lowerSize.setWidth( elem.attribute( "lowerWidth" ).toDouble() );
507  mInterpolationSettings.lowerSize.setHeight( elem.attribute( "lowerHeight" ).toDouble() );
508  mInterpolationSettings.upperSize.setWidth( elem.attribute( "upperWidth" ).toDouble() );
509  mInterpolationSettings.upperSize.setHeight( elem.attribute( "upperHeight" ).toDouble() );
510  mInterpolationSettings.classificationAttributeIsExpression = elem.hasAttribute( "classificationAttributeExpression" );
511  if ( mInterpolationSettings.classificationAttributeIsExpression )
512  {
513  mInterpolationSettings.classificationAttributeExpression = elem.attribute( "classificationAttributeExpression" );
514  }
515  else
516  {
517  mInterpolationSettings.classificationAttribute = elem.attribute( "classificationAttribute" ).toInt();
518  }
519  QDomElement settingsElem = elem.firstChildElement( "DiagramCategory" );
520  if ( !settingsElem.isNull() )
521  {
522  mSettings.readXML( settingsElem, layer );
523  }
524  _readXML( elem, layer );
525 }
526 
528 {
529  QDomElement rendererElem = doc.createElement( "LinearlyInterpolatedDiagramRenderer" );
530  rendererElem.setAttribute( "lowerValue", QString::number( mInterpolationSettings.lowerValue ) );
531  rendererElem.setAttribute( "upperValue", QString::number( mInterpolationSettings.upperValue ) );
532  rendererElem.setAttribute( "lowerWidth", QString::number( mInterpolationSettings.lowerSize.width() ) );
533  rendererElem.setAttribute( "lowerHeight", QString::number( mInterpolationSettings.lowerSize.height() ) );
534  rendererElem.setAttribute( "upperWidth", QString::number( mInterpolationSettings.upperSize.width() ) );
535  rendererElem.setAttribute( "upperHeight", QString::number( mInterpolationSettings.upperSize.height() ) );
536  if ( mInterpolationSettings.classificationAttributeIsExpression )
537  {
538  rendererElem.setAttribute( "classificationAttributeExpression", mInterpolationSettings.classificationAttributeExpression );
539  }
540  else
541  {
542  rendererElem.setAttribute( "classificationAttribute", mInterpolationSettings.classificationAttribute );
543  }
544  mSettings.writeXML( rendererElem, doc, layer );
545  _writeXML( rendererElem, doc, layer );
546  layerElem.appendChild( rendererElem );
547 }
548 
550 {
552  for ( int i = 0 ; i < categoryLabels.size(); ++i )
553  {
554  QPixmap pix( 16, 16 );
555  pix.fill( categoryColors[i] );
556  list << new QgsSimpleLegendNode( nodeLayer, categoryLabels[i], QIcon( pix ), 0, QString( "diagram_%1" ).arg( QString::number( i ) ) );
557  }
558  return list;
559 }
560 
562 {
564 }
565 
567 {
568  return mSettings.legendItems( nodeLayer );
569 }
570 
572 {
573  return mSettings.legendItems( nodeLayer );
574 }
void clear()
QDomNodeList elementsByTagName(const QString &tagname) const
double minimumSize
Scale diagrams smaller than mMinimumSize to mMinimumSize.
void writeXML(QDomElement &layerElem, QDomDocument &doc, const QgsVectorLayer *layer) const override
QgsDiagramRendererV2 * clone() const override
Returns new instance that is equivalent to this one.
QDomNode appendChild(const QDomNode &newChild)
void fill(const QColor &color)
void push_back(const T &value)
QString name() const
void _readXML(const QDomElement &elem, const QgsVectorLayer *layer)
virtual QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const
Returns list of legend nodes for the diagram.
QString attribute(const QString &name, const QString &defValue) const
QList< QString > categoryAttributes
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
qreal & rwidth()
const T & at(int i) const
bool isValid() const
virtual QList< QgsDiagramSettings > diagramSettings() const =0
Returns list with all diagram settings in the renderer.
void setAlpha(int alpha)
static int dpiPaintDevice(const QPainter *)
Returns the paint device dpi (or -1 in case of error.
void renderDiagram(const QgsFeature &feature, QgsRenderContext &c, const QPointF &pos)
double scaleFactor() const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:162
virtual Q_DECL_DEPRECATED void renderDiagram(const QgsAttributes &att, QgsRenderContext &c, const QgsDiagramSettings &s, const QPointF &position)
Definition: qgsdiagram.cpp:110
void setNamedColor(const QString &name)
double toDouble(bool *ok) const
void readXML(const QDomElement &elem, const QgsVectorLayer *layer)
QList< QgsDiagramSettings > diagramSettings() const override
Returns list with all diagram settings in the renderer.
int size() const
Returns diagram settings for a feature.
virtual QSizeF diagramSize(const QgsFeature &features, const QgsRenderContext &c)=0
Returns size of the diagram (in painter units) or an invalid size in case of error.
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 convertSizeToMapUnits(QSizeF &size, const QgsRenderContext &context) const
Converts size from mm to map units.
QDomElement toElement() const
DiagramOrientation diagramOrientation
QString number(int n, int base)
void readXML(const QDomElement &elem, const QgsVectorLayer *layer) override
void append(const T &value)
bool fromString(const QString &descrip)
bool hasAttribute(const QString &name) const
virtual QSizeF sizeMapUnits(const QgsFeature &feature, const QgsRenderContext &c)
Returns size of the diagram for a feature in map units.
QgsAttributes attributes() const
Returns the feature's attributes.
Definition: qgsfeature.cpp:90
void readXML(const QDomElement &elem, const QgsVectorLayer *layer)
void setAttribute(const QString &name, const QString &value)
void setWidth(qreal width)
int toInt(bool *ok, int base) const
QPaintDevice * device() const
QList< QgsLayerTreeModelLegendNode * > legendItems(QgsLayerTreeLayer *nodeLayer) const
Returns list of legend nodes for the diagram.
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
Return current map units per pixel.
QgsDiagramRendererV2 * renderer
Implementation of legend node interface for displaying arbitrary label with icon. ...
int alpha() const
virtual QSizeF diagramSize(const QgsAttributes &attributes, const QgsRenderContext &c, const QgsDiagramSettings &s)=0
Returns the size in map units the diagram will use to render.
int logicalDpiX() const
Base class for all diagram types.
Definition: qgsdiagram.h:34
bool isNull() const
virtual QString diagramName() const =0
void writeXML(QDomElement &layerElem, QDomDocument &doc, const QgsVectorLayer *layer) const override
void readXML(const QDomElement &elem, const QgsVectorLayer *layer) override
Contains information about the context of a rendering operation.
QList< QString > diagramAttributes() const override
Returns attribute indices needed for diagram rendering.
QDomElement firstChildElement(const QString &tagName) const
void writeXML(QDomElement &layerElem, QDomDocument &doc, const QgsVectorLayer *layer) const
QgsDiagramRendererV2 * clone() const override
Returns new instance that is equivalent to this one.
const QgsMapToPixel & mapToPixel() const
QList< QString > categoryLabels
int classificationAttribute
Index of the classification attribute.
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
uint length() const
const_iterator constEnd() const
qreal & rheight()
QDomElement createElement(const QString &tagName)
const_iterator constBegin() const
qreal height() const
void setDiagram(QgsDiagram *d)
QSizeF diagramSize(const QgsFeature &, const QgsRenderContext &c) override
Returns size of the diagram (in painter units) or an invalid size in case of error.
Represents a vector layer which manages a vector based data sets.
void setHeight(qreal height)
QList< QColor > categoryColors
void writeXML(QDomElement &rendererElem, QDomDocument &doc, const QgsVectorLayer *layer) const
QgsDiagram * mDiagram
Reference to the object that does the real diagram rendering.
T & back()
QList< QgsDiagramSettings > diagramSettings() const override
Returns list with all diagram settings in the renderer.
qreal width() const
void _writeXML(QDomElement &rendererElem, QDomDocument &doc, const QgsVectorLayer *layer) const
LabelPlacementMethod labelPlacementMethod
QSizeF diagramSize(const QgsFeature &, const QgsRenderContext &c) override
Returns size of the diagram (in painter units) or an invalid size in case of error.
Layer tree node points to a map layer.
QDomNode at(int index) const