All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ChartRenderer.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/qt/widgets/charts/ChartRenderer.cpp
22 
23  \brief A concrete chart renderer based on Qt4.
24 */
25 
26 // TerraLib
27 #include "../../../dataaccess/dataset/DataSet.h"
28 #include "../../../dataaccess/utils/Utils.h"
29 #include "../../../maptools/Chart.h"
30 #include "../Utils.h"
31 #include "ChartRenderer.h"
32 
33 // Boost
34 #include <boost/lexical_cast.hpp>
35 
36 // STL
37 #include <cassert>
38 
40  : te::map::AbstractChartRenderer()
41 {
42  m_pen.setStyle(Qt::SolidLine);
43  m_brush.setStyle(Qt::SolidPattern);
44 }
45 
47 {
48 }
49 
51 {
52  assert(chart);
53  assert(dataset);
54 
55  QImage* result = 0;
56 
57  switch(chart->getType())
58  {
59  case te::map::Pie:
60  result = drawPies(chart, dataset, width);
61  break;
62 
63  case te::map::Bar:
64  result = drawBars(chart, dataset, width);
65  break;
66  }
67 
68  // Converts QImage to te::color::RGBAColor**
70 
71  delete result;
72 
73  return rgba;
74 }
75 
76 te::color::RGBAColor** te::qt::widgets::ChartRenderer::render(const te::map::Chart* chart, const std::map<std::string, double>& chartValue, std::size_t& width)
77 {
78  assert(chart);
79 
80  QImage* result = 0;
81 
82  switch(chart->getType())
83  {
84  case te::map::Pie:
85  result = drawPies(chart, chartValue, width);
86  break;
87 
88  case te::map::Bar:
89  result = drawBars(chart, chartValue, width);
90  break;
91  }
92 
93  // Converts QImage to te::color::RGBAColor**
95 
96  delete result;
97 
98  return rgba;
99 }
100 
102 {
103  m_painter.begin(img);
104  m_painter.setRenderHints(QPainter::Antialiasing);
105 }
106 
108 {
109  m_painter.end();
110 }
111 
112 QImage* te::qt::widgets::ChartRenderer::drawPies(const te::map::Chart* chart, const te::da::DataSet* dataset, std::size_t& width)
113 {
114  // Creates the image that will represent the chart
115  QImage* img = new QImage(chart->getWidth(), chart->getHeight(), QImage::Format_ARGB32_Premultiplied);
116  img->fill(Qt::transparent);
117 
118  setup(img);
119 
120  m_pen.setColor(Convert2Qt(chart->getContourColor()));
121  m_pen.setWidth(static_cast<int>(chart->getContourWidth()));
122 
123  std::vector<double> values;
124  getValues(chart, dataset, values);
125 
126  if(values.empty())
127  return img;
128 
129  double sum = computeSum(values);
130 
131  int lastAngle = 0;
132 
133  // Draw each pie slice
134  for(std::size_t i = 0; i < values.size(); ++i)
135  {
136  int currentAngle = static_cast<int>((values[i] * 5760) / sum);
137 
138  // Test: Try shadow to help the chart svisualization
139  QColor shadowColor = Convert2Qt(chart->getColor(i));
140  shadowColor.setAlpha(128);
141  //QColor shadowColor = QColorQColor(128, 128, 128, 128);
142  QPen shadowPen(shadowColor);
143  shadowPen.setWidth(2);
144  m_painter.setPen(shadowPen);
145  m_painter.drawPie(img->rect(), lastAngle, currentAngle);
146 
147  // Configs a new color for this slice
148  m_painter.setPen(m_pen);
149  m_painter.setBrush(Convert2Qt(chart->getColor(i)));
150 
151  m_painter.drawPie(img->rect(), lastAngle, currentAngle);
152 
153  lastAngle += currentAngle;
154  }
155 
156  end();
157 
158  return img;
159 }
160 
161 QImage* te::qt::widgets::ChartRenderer::drawPies(const te::map::Chart* chart, const std::map<std::string, double>& chartValue, std::size_t& width)
162 {
163  // Creates the image that will represent the chart
164  QImage* img = new QImage(chart->getWidth(), chart->getHeight(), QImage::Format_ARGB32_Premultiplied);
165  img->fill(Qt::transparent);
166 
167  setup(img);
168 
169  m_pen.setColor(Convert2Qt(chart->getContourColor()));
170  m_pen.setWidth(static_cast<int>(chart->getContourWidth()));
171 
172  std::vector<double> values;
173  getValues(chart, chartValue, values);
174 
175  if(values.empty())
176  return img;
177 
178  double sum = computeSum(values);
179 
180  int lastAngle = 0;
181 
182  // Draw each pie slice
183  for(std::size_t i = 0; i < values.size(); ++i)
184  {
185  int currentAngle = static_cast<int>((values[i] * 5760) / sum);
186 
187  // Test: Try shadow to help the chart svisualization
188  QColor shadowColor = Convert2Qt(chart->getColor(i));
189  shadowColor.setAlpha(128);
190  //QColor shadowColor = QColorQColor(128, 128, 128, 128);
191  QPen shadowPen(shadowColor);
192  shadowPen.setWidth(2);
193  m_painter.setPen(shadowPen);
194  m_painter.drawPie(img->rect(), lastAngle, currentAngle);
195 
196  // Configs a new color for this slice
197  m_painter.setPen(m_pen);
198  m_painter.setBrush(Convert2Qt(chart->getColor(i)));
199 
200  m_painter.drawPie(img->rect(), lastAngle, currentAngle);
201 
202  lastAngle += currentAngle;
203  }
204 
205  end();
206 
207  return img;
208 }
209 
210 QImage* te::qt::widgets::ChartRenderer::drawBars(const te::map::Chart* chart, const te::da::DataSet* dataset, std::size_t& width)
211 {
212  // Creates the image that will represent the chart
213  QImage* img = new QImage(chart->getWidth(), chart->getHeight(), QImage::Format_ARGB32_Premultiplied);
214  img->fill(Qt::transparent);
215 
216  setup(img);
217 
218  m_pen.setColor(Convert2Qt(chart->getContourColor()));
219  m_pen.setWidth(static_cast<int>(chart->getContourWidth()));
220  m_painter.setPen(m_pen);
221 
222  std::vector<double> values;
223  getValues(chart, dataset, values);
224 
225  if(values.empty())
226  return img;
227 
228  // Gets the previous computed max value
229  double maxValue = chart->getMaxValue();
230  assert(maxValue > 0.0);
231 
232  int lastx = 0;
233 
234  int shadowOffset = 2;
235 
236  // Draw each bar
237  for(std::size_t i = 0; i < values.size(); ++i)
238  {
239  int barHeight = static_cast<int>((values[i] * chart->getHeight()) / maxValue);
240 
241  // Test: Try shadow to help the chart svisualization
242  QRect shadowBar(lastx - shadowOffset, -shadowOffset, chart->getBarWidth() + shadowOffset, barHeight + shadowOffset);
243  QColor shadowColor = Convert2Qt(chart->getColor(i));
244  shadowColor.setAlpha(128);
245  m_painter.setBrush(shadowColor);
246  //m_painter.setBrush(QColor(128, 128, 128, 128));
247  m_painter.setPen(Qt::NoPen);
248  m_painter.drawRect(shadowBar);
249 
250  // Current bar
251  QRect bar(lastx, 0, chart->getBarWidth(), barHeight);
252 
253  // Configs a new color for this bar
254  m_painter.setPen(m_pen);
255  m_painter.setBrush(Convert2Qt(chart->getColor(i)));
256 
257  m_painter.drawRect(bar);
258 
259  lastx += chart->getBarWidth();
260  }
261 
262  end();
263 
264  // TODO: Need review! Draw the bar on right place! ... For while, return the mirrored image.
265  QImage* mirroed = new QImage(img->mirrored());
266 
267  delete img;
268 
269  return mirroed;
270 }
271 
272 QImage* te::qt::widgets::ChartRenderer::drawBars(const te::map::Chart* chart, const std::map<std::string, double>& chartValue, std::size_t& width)
273 {
274  // Creates the image that will represent the chart
275  QImage* img = new QImage(chart->getWidth(), chart->getHeight(), QImage::Format_ARGB32_Premultiplied);
276  img->fill(Qt::transparent);
277 
278  setup(img);
279 
280  m_pen.setColor(Convert2Qt(chart->getContourColor()));
281  m_pen.setWidth(static_cast<int>(chart->getContourWidth()));
282  m_painter.setPen(m_pen);
283 
284  std::vector<double> values;
285  getValues(chart, chartValue, values);
286 
287  if(values.empty())
288  return img;
289 
290  // Gets the previous computed max value
291  double maxValue = chart->getMaxValue();
292  assert(maxValue > 0.0);
293 
294  int lastx = 0;
295 
296  int shadowOffset = 2;
297 
298  // Draw each bar
299  for(std::size_t i = 0; i < values.size(); ++i)
300  {
301  int barHeight = static_cast<int>((values[i] * chart->getHeight()) / maxValue);
302 
303  // Test: Try shadow to help the chart svisualization
304  QRect shadowBar(lastx - shadowOffset, -shadowOffset, chart->getBarWidth() + shadowOffset, barHeight + shadowOffset);
305  QColor shadowColor = Convert2Qt(chart->getColor(i));
306  shadowColor.setAlpha(128);
307  m_painter.setBrush(shadowColor);
308  //m_painter.setBrush(QColor(128, 128, 128, 128));
309  m_painter.setPen(Qt::NoPen);
310  m_painter.drawRect(shadowBar);
311 
312  // Current bar
313  QRect bar(lastx, 0, chart->getBarWidth(), barHeight);
314 
315  // Configs a new color for this bar
316  m_painter.setPen(m_pen);
317  m_painter.setBrush(Convert2Qt(chart->getColor(i)));
318 
319  m_painter.drawRect(bar);
320 
321  lastx += chart->getBarWidth();
322  }
323 
324  end();
325 
326  // TODO: Need review! Draw the bar on right place! ... For while, return the mirrored image.
327  QImage* mirroed = new QImage(img->mirrored());
328 
329  delete img;
330 
331  return mirroed;
332 }
333 
334 void te::qt::widgets::ChartRenderer::getValues(const te::map::Chart* chart, const te::da::DataSet* dataset, std::vector<double>& values)
335 {
336  const std::vector<std::string>& properties = chart->getProperties();
337  size_t psize = properties.size();
338  size_t ppsize = chart->getPropertiesPos().size();
339  for(std::size_t i = 0; i < psize; ++i)
340  {
341  if(dataset->isNull(properties[i]))
342  {
343  values.clear();
344  break;
345  }
346 
347  if(ppsize == psize)
348  values.push_back(te::da::GetValueAsDouble(dataset, chart->getPropertiesPos()[i]));
349  else
350  {
351  size_t pos = te::da::GetPropertyPos(dataset, properties[i]);
352  values.push_back(te::da::GetValueAsDouble(dataset, pos));
353  }
354  }
355 }
356 
357 void te::qt::widgets::ChartRenderer::getValues(const te::map::Chart* chart, const std::map<std::string, double>& chartValue, std::vector<double>& values)
358 {
359  std::map<std::string, double>::const_iterator it;
360  const std::vector<std::string>& properties = chart->getProperties();
361  for(std::size_t i = 0; i < properties.size(); ++i)
362  {
363  it = chartValue.find(properties[i]);
364  if(it != chartValue.end())
365  values.push_back(it->second);
366  else
367  {
368  values.clear();
369  break;
370  }
371  }
372 }
373 
374 double te::qt::widgets::ChartRenderer::computeSum(const std::vector<double>& values)
375 {
376  double sum = 0.0;
377 
378  for(std::size_t i = 0; i < values.size(); ++i)
379  sum += values[i];
380 
381  return sum;
382 }
383 
384 double te::qt::widgets::ChartRenderer::getMaxValue(const std::vector<double>& values)
385 {
386  double max = 0.0;
387 
388  for(std::size_t i = 0; i < values.size(); ++i)
389  if(std::abs(values[i]) > max)
390  max = values[i];
391 
392  return max;
393 }
ChartType getType() const
Definition: Chart.cpp:78
const std::vector< std::string > & getProperties() const
Definition: Chart.cpp:83
std::size_t getBarWidth() const
Definition: Chart.cpp:157
QBrush m_brush
The pen used to draw the chart.
void getValues(const te::map::Chart *chart, const te::da::DataSet *dataset, std::vector< double > &values)
TEDATAACCESSEXPORT std::size_t GetPropertyPos(const DataSet *dataset, const std::string &name)
Definition: Utils.cpp:500
void setup(QImage *img)
Setups the internal QPainter and associates it with the given paint device (QImage).
TEDATAACCESSEXPORT double GetValueAsDouble(const te::da::DataSet *ds, const size_t pos)
It gets the value as double.
Definition: Utils.cpp:1337
double getMaxValue() const
Definition: Chart.cpp:172
A concrete chart renderer based on Qt4.
const te::color::RGBAColor & getColor(std::size_t i) const
Definition: Chart.cpp:98
double computeSum(const std::vector< double > &values)
This class represents the informations needed to build map charts.
Definition: Chart.h:51
virtual bool isNull(std::size_t i) const =0
It checks if the attribute value is NULL.
std::size_t getHeight() const
Definition: Chart.cpp:132
te::color::RGBAColor ** render(const te::map::Chart *chart, const te::da::DataSet *dataset, std::size_t &width)
It generates the image pattern from the given chart and the current element of dataset.
QPen m_pen
The pen used to draw the chart.
double getMaxValue(const std::vector< double > &values)
A dataset is the unit of information manipulated by the data access module of TerraLib.
Definition: DataSet.h:112
std::size_t getContourWidth() const
Definition: Chart.cpp:122
const te::color::RGBAColor & getContourColor() const
Definition: Chart.cpp:112
TEQTWIDGETSEXPORT QImage * GetImage(te::color::RGBAColor **img, int width, int height)
It creates a QImage from an RGBA color array.
Definition: Utils.cpp:69
const std::vector< size_t > & getPropertiesPos() const
Definition: Chart.cpp:88
QImage * drawPies(const te::map::Chart *chart, const te::da::DataSet *dataset, std::size_t &width)
A helper class for 32-bit RGBA (Red-Green-Blue-Alpha channel) color.
Definition: RGBAColor.h:57
TEQTWIDGETSEXPORT QColor Convert2Qt(const te::color::RGBAColor &color)
It converts a TerraLib Color to Qt Color.
Definition: Utils.cpp:232
QImage * drawBars(const te::map::Chart *chart, const te::da::DataSet *dataset, std::size_t &width)
ChartRenderer()
Default constructor.
std::size_t getWidth() const
Definition: Chart.cpp:142
void end()
Finalizes the internal QPainter resources.