QGIS API Documentation  2.8.2-Wien
 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"
21 
22 #include <QDomElement>
23 #include <QPainter>
24 
26  : placement( AroundPoint )
27  , placementFlags( OnLine )
28  , priority( 5 )
29  , obstacle( false )
30  , dist( 0.0 )
31  , renderer( 0 )
32  , palLayer( 0 )
33  , ct( 0 )
34  , xform( 0 )
35  , xPosColumn( -1 )
36  , yPosColumn( -1 )
37 {
38 }
39 
41 {
42  delete renderer;
43 }
44 
45 void QgsDiagramLayerSettings::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
46 {
47  Q_UNUSED( layer )
48 
49  placement = ( Placement )elem.attribute( "placement" ).toInt();
50  placementFlags = ( LinePlacementFlags )elem.attribute( "linePlacementFlags" ).toInt();
51  priority = elem.attribute( "priority" ).toInt();
52  obstacle = elem.attribute( "obstacle" ).toInt();
53  dist = elem.attribute( "dist" ).toDouble();
54  xPosColumn = elem.attribute( "xPosColumn" ).toInt();
55  yPosColumn = elem.attribute( "yPosColumn" ).toInt();
56 }
57 
58 void QgsDiagramLayerSettings::writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
59 {
60  Q_UNUSED( layer )
61 
62  QDomElement diagramLayerElem = doc.createElement( "DiagramLayerSettings" );
63  diagramLayerElem.setAttribute( "placement", placement );
64  diagramLayerElem.setAttribute( "linePlacementFlags", placementFlags );
65  diagramLayerElem.setAttribute( "priority", priority );
66  diagramLayerElem.setAttribute( "obstacle", obstacle );
67  diagramLayerElem.setAttribute( "dist", QString::number( dist ) );
68  diagramLayerElem.setAttribute( "xPosColumn", xPosColumn );
69  diagramLayerElem.setAttribute( "yPosColumn", yPosColumn );
70  layerElem.appendChild( diagramLayerElem );
71 }
72 
73 void QgsDiagramSettings::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
74 {
75  Q_UNUSED( layer );
76 
77  font.fromString( elem.attribute( "font" ) );
78  backgroundColor.setNamedColor( elem.attribute( "backgroundColor" ) );
79  backgroundColor.setAlpha( elem.attribute( "backgroundAlpha" ).toInt() );
80  size.setWidth( elem.attribute( "width" ).toDouble() );
81  size.setHeight( elem.attribute( "height" ).toDouble() );
82  transparency = elem.attribute( "transparency", "0" ).toInt();
83  penColor.setNamedColor( elem.attribute( "penColor" ) );
84  int penAlpha = elem.attribute( "penAlpha", "255" ).toInt();
85  penColor.setAlpha( penAlpha );
86  penWidth = elem.attribute( "penWidth" ).toDouble();
87 
88  minScaleDenominator = elem.attribute( "minScaleDenominator", "-1" ).toDouble();
89  maxScaleDenominator = elem.attribute( "maxScaleDenominator", "-1" ).toDouble();
90 
91  //mm vs map units
92  if ( elem.attribute( "sizeType" ) == "MM" )
93  {
94  sizeType = MM;
95  }
96  else
97  {
99  }
100 
101  //label placement method
102  if ( elem.attribute( "labelPlacementMethod" ) == "Height" )
103  {
105  }
106  else
107  {
109  }
110 
111  // orientation
112  if ( elem.attribute( "diagramOrientation" ) == "Left" )
113  {
115  }
116  else if ( elem.attribute( "diagramOrientation" ) == "Right" )
117  {
119  }
120  else if ( elem.attribute( "diagramOrientation" ) == "Down" )
121  {
123  }
124  else
125  {
127  }
128 
129  // scale dependency
130  if ( elem.attribute( "scaleDependency" ) == "Diameter" )
131  {
132  scaleByArea = false;
133  }
134  else
135  {
136  scaleByArea = true;
137  }
138 
139  barWidth = elem.attribute( "barWidth" ).toDouble();
140 
141  angleOffset = elem.attribute( "angleOffset" ).toInt();
142 
143  minimumSize = elem.attribute( "minimumSize" ).toDouble();
144 
145  //colors
146  categoryColors.clear();
147  QDomNodeList attributes = elem.elementsByTagName( "attribute" );
148 
149  if ( attributes.length() > 0 )
150  {
151  for ( uint i = 0; i < attributes.length(); i++ )
152  {
153  QDomElement attrElem = attributes.at( i ).toElement();
154  QColor newColor( attrElem.attribute( "color" ) );
155  newColor.setAlpha( 255 - transparency );
156  categoryColors.append( newColor );
157  categoryAttributes.append( attrElem.attribute( "field" ) );
158  }
159  }
160  else
161  {
162  // Restore old format attributes and colors
163 
164  QStringList colorList = elem.attribute( "colors" ).split( "/" );
165  QStringList::const_iterator colorIt = colorList.constBegin();
166  for ( ; colorIt != colorList.constEnd(); ++colorIt )
167  {
168  QColor newColor( *colorIt );
169  newColor.setAlpha( 255 - transparency );
170  categoryColors.append( QColor( newColor ) );
171  }
172 
173  //attribute indices
174  categoryAttributes.clear();
175  QStringList catList = elem.attribute( "categories" ).split( "/" );
176  QStringList::const_iterator catIt = catList.constBegin();
177  for ( ; catIt != catList.constEnd(); ++catIt )
178  {
179  categoryAttributes.append( *catIt );
180  }
181  }
182 }
183 
184 void QgsDiagramSettings::writeXML( QDomElement& rendererElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
185 {
186  Q_UNUSED( layer );
187 
188  QDomElement categoryElem = doc.createElement( "DiagramCategory" );
189  categoryElem.setAttribute( "font", font.toString() );
190  categoryElem.setAttribute( "backgroundColor", backgroundColor.name() );
191  categoryElem.setAttribute( "backgroundAlpha", backgroundColor.alpha() );
192  categoryElem.setAttribute( "width", QString::number( size.width() ) );
193  categoryElem.setAttribute( "height", QString::number( size.height() ) );
194  categoryElem.setAttribute( "penColor", penColor.name() );
195  categoryElem.setAttribute( "penAlpha", penColor.alpha() );
196  categoryElem.setAttribute( "penWidth", QString::number( penWidth ) );
197  categoryElem.setAttribute( "minScaleDenominator", QString::number( minScaleDenominator ) );
198  categoryElem.setAttribute( "maxScaleDenominator", QString::number( maxScaleDenominator ) );
199  categoryElem.setAttribute( "transparency", QString::number( transparency ) );
200 
201  // site type (mm vs. map units)
202  if ( sizeType == MM )
203  {
204  categoryElem.setAttribute( "sizeType", "MM" );
205  }
206  else
207  {
208  categoryElem.setAttribute( "sizeType", "MapUnits" );
209  }
210 
211  // label placement method (text diagram)
212  if ( labelPlacementMethod == Height )
213  {
214  categoryElem.setAttribute( "labelPlacementMethod", "Height" );
215  }
216  else
217  {
218  categoryElem.setAttribute( "labelPlacementMethod", "XHeight" );
219  }
220 
221  if ( scaleByArea )
222  {
223  categoryElem.setAttribute( "scaleDependency", "Area" );
224  }
225  else
226  {
227  categoryElem.setAttribute( "scaleDependency", "Diameter" );
228  }
229 
230  // orientation (histogram)
231  switch ( diagramOrientation )
232  {
233  case Left:
234  categoryElem.setAttribute( "diagramOrientation", "Left" );
235  break;
236 
237  case Right:
238  categoryElem.setAttribute( "diagramOrientation", "Right" );
239  break;
240 
241  case Down:
242  categoryElem.setAttribute( "diagramOrientation", "Down" );
243  break;
244 
245  case Up:
246  categoryElem.setAttribute( "diagramOrientation", "Up" );
247  break;
248 
249  default:
250  categoryElem.setAttribute( "diagramOrientation", "Up" );
251  break;
252  }
253 
254  categoryElem.setAttribute( "barWidth", QString::number( barWidth ) );
255  categoryElem.setAttribute( "minimumSize", QString::number( minimumSize ) );
256  categoryElem.setAttribute( "angleOffset", QString::number( angleOffset ) );
257 
258  QString colors;
259  int nCats = qMin( categoryColors.size(), categoryAttributes.size() );
260  for ( int i = 0; i < nCats; ++i )
261  {
262  QDomElement attributeElem = doc.createElement( "attribute" );
263 
264  attributeElem.setAttribute( "field", categoryAttributes.at( i ) );
265  attributeElem.setAttribute( "color", categoryColors.at( i ).name() );
266  categoryElem.appendChild( attributeElem );
267  }
268 
269  rendererElem.appendChild( categoryElem );
270 }
271 
273  : mDiagram( 0 )
274 {
275 }
276 
278 {
279  delete mDiagram;
280 }
281 
283 {
284  delete mDiagram;
285  mDiagram = d;
286 }
287 
289  : mDiagram( other.mDiagram ? other.mDiagram->clone() : 0 )
290 {
291 }
292 
293 void QgsDiagramRendererV2::renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QPointF& pos )
294 {
295  if ( !mDiagram )
296  {
297  return;
298  }
299 
301  if ( !diagramSettings( feature, c, s ) )
302  {
303  return;
304  }
305 
306  mDiagram->renderDiagram( feature, c, s, pos );
307 }
308 
310 {
312  if ( !diagramSettings( feature, c, s ) )
313  {
314  return QSizeF();
315  }
316 
317  QSizeF size = diagramSize( feature, c );
318  if ( s.sizeType == QgsDiagramSettings::MM )
319  {
320  convertSizeToMapUnits( size, c );
321  }
322  return size;
323 }
324 
326 {
327  if ( !size.isValid() )
328  {
329  return;
330  }
331 
332  double pixelToMap = context.scaleFactor() * context.mapToPixel().mapUnitsPerPixel();
333  size.rwidth() *= pixelToMap;
334  size.rheight() *= pixelToMap;
335 }
336 
337 int QgsDiagramRendererV2::dpiPaintDevice( const QPainter* painter )
338 {
339  if ( painter )
340  {
341  QPaintDevice* device = painter->device();
342  if ( device )
343  {
344  return device->logicalDpiX();
345  }
346  }
347  return -1;
348 }
349 
350 void QgsDiagramRendererV2::_readXML( const QDomElement& elem, const QgsVectorLayer* layer )
351 {
352  Q_UNUSED( layer )
353 
354  delete mDiagram;
355  QString diagramType = elem.attribute( "diagramType" );
356  if ( diagramType == "Pie" )
357  {
358  mDiagram = new QgsPieDiagram();
359  }
360  else if ( diagramType == "Text" )
361  {
362  mDiagram = new QgsTextDiagram();
363  }
364  else if ( diagramType == "Histogram" )
365  {
367  }
368  else
369  {
370  mDiagram = 0;
371  }
372 }
373 
374 void QgsDiagramRendererV2::_writeXML( QDomElement& rendererElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
375 {
376  Q_UNUSED( doc );
377  Q_UNUSED( layer )
378 
379  if ( mDiagram )
380  {
381  rendererElem.setAttribute( "diagramType", mDiagram->diagramName() );
382  }
383 }
384 
386 {
387 }
388 
390 {
391 }
392 
394 {
395  return new QgsSingleCategoryDiagramRenderer( *this );
396 }
397 
399 {
400  Q_UNUSED( c );
401  s = mSettings;
402  return true;
403 }
404 
406 {
407  return mDiagram->diagramSize( feature.attributes(), c, mSettings );
408 }
409 
410 QList<QgsDiagramSettings> QgsSingleCategoryDiagramRenderer::diagramSettings() const
411 {
412  QList<QgsDiagramSettings> settingsList;
413  settingsList.push_back( mSettings );
414  return settingsList;
415 }
416 
417 void QgsSingleCategoryDiagramRenderer::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
418 {
419  QDomElement categoryElem = elem.firstChildElement( "DiagramCategory" );
420  if ( categoryElem.isNull() )
421  {
422  return;
423  }
424 
425  mSettings.readXML( categoryElem, layer );
426  _readXML( elem, layer );
427 }
428 
429 void QgsSingleCategoryDiagramRenderer::writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
430 {
431  QDomElement rendererElem = doc.createElement( "SingleCategoryDiagramRenderer" );
432  mSettings.writeXML( rendererElem, doc, layer );
433  _writeXML( rendererElem, doc, layer );
434  layerElem.appendChild( rendererElem );
435 }
436 
437 
439 {
440  mInterpolationSettings.classificationAttributeIsExpression = false;
441 }
442 
444 {
445 }
446 
448 {
449  return new QgsLinearlyInterpolatedDiagramRenderer( *this );
450 }
451 
453 {
454  QList<QgsDiagramSettings> settingsList;
455  settingsList.push_back( mSettings );
456  return settingsList;
457 }
458 
460 {
461  s = mSettings;
462  s.size = diagramSize( feature, c );
463  return true;
464 }
465 
467 {
468  return mSettings.categoryAttributes;
469 }
470 
472 {
473  return mDiagram->diagramSize( feature, c, mSettings, mInterpolationSettings );
474 }
475 
476 void QgsLinearlyInterpolatedDiagramRenderer::readXML( const QDomElement& elem, const QgsVectorLayer* layer )
477 {
478  mInterpolationSettings.lowerValue = elem.attribute( "lowerValue" ).toDouble();
479  mInterpolationSettings.upperValue = elem.attribute( "upperValue" ).toDouble();
480  mInterpolationSettings.lowerSize.setWidth( elem.attribute( "lowerWidth" ).toDouble() );
481  mInterpolationSettings.lowerSize.setHeight( elem.attribute( "lowerHeight" ).toDouble() );
482  mInterpolationSettings.upperSize.setWidth( elem.attribute( "upperWidth" ).toDouble() );
483  mInterpolationSettings.upperSize.setHeight( elem.attribute( "upperHeight" ).toDouble() );
484  mInterpolationSettings.classificationAttributeIsExpression = elem.hasAttribute( "classificationAttributeExpression" );
485  if ( mInterpolationSettings.classificationAttributeIsExpression )
486  {
487  mInterpolationSettings.classificationAttributeExpression = elem.attribute( "classificationAttributeExpression" );
488  }
489  else
490  {
491  mInterpolationSettings.classificationAttribute = elem.attribute( "classificationAttribute" ).toInt();
492  }
493  QDomElement settingsElem = elem.firstChildElement( "DiagramCategory" );
494  if ( !settingsElem.isNull() )
495  {
496  mSettings.readXML( settingsElem, layer );
497  }
498  _readXML( elem, layer );
499 }
500 
501 void QgsLinearlyInterpolatedDiagramRenderer::writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const
502 {
503  QDomElement rendererElem = doc.createElement( "LinearlyInterpolatedDiagramRenderer" );
504  rendererElem.setAttribute( "lowerValue", QString::number( mInterpolationSettings.lowerValue ) );
505  rendererElem.setAttribute( "upperValue", QString::number( mInterpolationSettings.upperValue ) );
506  rendererElem.setAttribute( "lowerWidth", QString::number( mInterpolationSettings.lowerSize.width() ) );
507  rendererElem.setAttribute( "lowerHeight", QString::number( mInterpolationSettings.lowerSize.height() ) );
508  rendererElem.setAttribute( "upperWidth", QString::number( mInterpolationSettings.upperSize.width() ) );
509  rendererElem.setAttribute( "upperHeight", QString::number( mInterpolationSettings.upperSize.height() ) );
510  if ( mInterpolationSettings.classificationAttributeIsExpression )
511  {
512  rendererElem.setAttribute( "classificationAttributeExpression", mInterpolationSettings.classificationAttributeExpression );
513  }
514  else
515  {
516  rendererElem.setAttribute( "classificationAttribute", mInterpolationSettings.classificationAttribute );
517  }
518  mSettings.writeXML( rendererElem, doc, layer );
519  _writeXML( rendererElem, doc, layer );
520  layerElem.appendChild( rendererElem );
521 }