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 
41 {
42  m_pen.setStyle(Qt::SolidLine);
43  m_brush.setStyle(Qt::SolidPattern);
44 }
45 
47 
49 {
50  assert(chart);
51  assert(dataset);
52 
53  QImage* result = nullptr;
54 
55  switch(chart->getType())
56  {
57  case te::map::Pie:
58  result = drawPies(chart, dataset, width);
59  break;
60 
61  case te::map::Bar:
62  result = drawBars(chart, dataset, width);
63  break;
64  }
65 
66  // Converts QImage to te::color::RGBAColor**
68 
69  delete result;
70 
71  return rgba;
72 }
73 
74 te::color::RGBAColor** te::qt::widgets::ChartRenderer::render(const te::map::Chart* chart, const std::map<std::string, double>& chartValue, std::size_t& width)
75 {
76  assert(chart);
77 
78  QImage* result = nullptr;
79 
80  switch(chart->getType())
81  {
82  case te::map::Pie:
83  result = drawPies(chart, chartValue, width);
84  break;
85 
86  case te::map::Bar:
87  result = drawBars(chart, chartValue, width);
88  break;
89  }
90 
91  // Converts QImage to te::color::RGBAColor**
93 
94  delete result;
95 
96  return rgba;
97 }
98 
100 {
101  m_painter.begin(img);
102  m_painter.setRenderHints(QPainter::Antialiasing);
103 }
104 
106 {
107  m_painter.end();
108 }
109 
111  const te::da::DataSet* dataset,
112  std::size_t& /*width*/)
113 {
114  // Creates the image that will represent the chart
115  QImage* img = new QImage(static_cast<int>(chart->getWidth()), static_cast<int>(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  {
128  end();
129 
130  return img;
131  }
132 
133  double sum = computeSum(values);
134 
135  int lastAngle = 0;
136 
137  // Draw each pie slice
138  for(std::size_t i = 0; i < values.size(); ++i)
139  {
140  int currentAngle = static_cast<int>((values[i] * 5760) / sum);
141 
142  // Test: Try shadow to help the chart svisualization
143  QColor shadowColor = Convert2Qt(chart->getColor(i));
144  shadowColor.setAlpha(128);
145  //QColor shadowColor = QColorQColor(128, 128, 128, 128);
146  QPen shadowPen(shadowColor);
147  shadowPen.setWidth(2);
148  m_painter.setPen(shadowPen);
149  m_painter.drawPie(img->rect(), lastAngle, currentAngle);
150 
151  // Configs a new color for this slice
152  m_painter.setPen(m_pen);
153  m_painter.setBrush(Convert2Qt(chart->getColor(i)));
154 
155  m_painter.drawPie(img->rect(), lastAngle, currentAngle);
156 
157  lastAngle += currentAngle;
158  }
159 
160  end();
161 
162  return img;
163 }
164 
166  const te::map::Chart* chart,
167  const std::map<std::string, double>& chartValue, std::size_t& /*width*/)
168 {
169  // Creates the image that will represent the chart
170  QImage* img = new QImage(static_cast<int>(chart->getWidth()), static_cast<int>(chart->getHeight()), QImage::Format_ARGB32_Premultiplied);
171  img->fill(Qt::transparent);
172 
173  setup(img);
174 
175  m_pen.setColor(Convert2Qt(chart->getContourColor()));
176  m_pen.setWidth(static_cast<int>(chart->getContourWidth()));
177 
178  std::vector<double> values;
179  getValues(chart, chartValue, values);
180 
181  if(values.empty())
182  {
183  end();
184 
185  return img;
186  }
187 
188  double sum = computeSum(values);
189 
190  int lastAngle = 0;
191 
192  // Draw each pie slice
193  for(std::size_t i = 0; i < values.size(); ++i)
194  {
195  int currentAngle = static_cast<int>((values[i] * 5760) / sum);
196 
197  // Test: Try shadow to help the chart svisualization
198  QColor shadowColor = Convert2Qt(chart->getColor(i));
199  shadowColor.setAlpha(128);
200  //QColor shadowColor = QColorQColor(128, 128, 128, 128);
201  QPen shadowPen(shadowColor);
202  shadowPen.setWidth(2);
203  m_painter.setPen(shadowPen);
204  m_painter.drawPie(img->rect(), lastAngle, currentAngle);
205 
206  // Configs a new color for this slice
207  m_painter.setPen(m_pen);
208  m_painter.setBrush(Convert2Qt(chart->getColor(i)));
209 
210  m_painter.drawPie(img->rect(), lastAngle, currentAngle);
211 
212  lastAngle += currentAngle;
213  }
214 
215  end();
216 
217  return img;
218 }
219 
221  const te::da::DataSet* dataset,
222  std::size_t& /*width*/)
223 {
224  // Creates the image that will represent the chart
225  QImage* img = new QImage(static_cast<int>(chart->getWidth()), static_cast<int>(chart->getHeight()), QImage::Format_ARGB32_Premultiplied);
226  img->fill(Qt::transparent);
227 
228  setup(img);
229 
230  m_pen.setColor(Convert2Qt(chart->getContourColor()));
231  m_pen.setWidth(static_cast<int>(chart->getContourWidth()));
232  m_painter.setPen(m_pen);
233 
234  std::vector<double> values;
235  getValues(chart, dataset, values);
236 
237  if(values.empty())
238  {
239  end();
240 
241  return img;
242  }
243 
244  // Gets the previous computed max value
245  double maxValue = chart->getMaxValue();
246  assert(maxValue > 0.0);
247 
248  int lastx = 0;
249 
250  int shadowOffset = 2;
251 
252  // Draw each bar
253  for(std::size_t i = 0; i < values.size(); ++i)
254  {
255  int barHeight = static_cast<int>((values[i] * chart->getHeight()) / maxValue);
256 
257  // Test: Try shadow to help the chart svisualization
258  QRect shadowBar(lastx - shadowOffset, -shadowOffset, static_cast<int>(chart->getBarWidth() + shadowOffset), barHeight + shadowOffset);
259  QColor shadowColor = Convert2Qt(chart->getColor(i));
260  shadowColor.setAlpha(128);
261  m_painter.setBrush(shadowColor);
262  //m_painter.setBrush(QColor(128, 128, 128, 128));
263  m_painter.setPen(Qt::NoPen);
264  m_painter.drawRect(shadowBar);
265 
266  // Current bar
267  QRect bar(lastx, 0, static_cast<int>(chart->getBarWidth()), barHeight);
268 
269  // Configs a new color for this bar
270  m_painter.setPen(m_pen);
271  m_painter.setBrush(Convert2Qt(chart->getColor(i)));
272 
273  m_painter.drawRect(bar);
274 
275  lastx += static_cast<int>(chart->getBarWidth());
276  }
277 
278  end();
279 
280  // TODO: Need review! Draw the bar on right place! ... For while, return the mirrored image.
281  QImage* mirroed = new QImage(img->mirrored());
282 
283  delete img;
284 
285  return mirroed;
286 }
287 
289  const te::map::Chart* chart,
290  const std::map<std::string, double>& chartValue, std::size_t& /*width*/)
291 {
292  // Creates the image that will represent the chart
293  QImage* img = new QImage(static_cast<int>(chart->getWidth()), static_cast<int>(chart->getHeight()), QImage::Format_ARGB32_Premultiplied);
294  img->fill(Qt::transparent);
295 
296  setup(img);
297 
298  m_pen.setColor(Convert2Qt(chart->getContourColor()));
299  m_pen.setWidth(static_cast<int>(chart->getContourWidth()));
300  m_painter.setPen(m_pen);
301 
302  std::vector<double> values;
303  getValues(chart, chartValue, values);
304 
305  if(values.empty())
306  {
307  end();
308 
309  return img;
310  }
311 
312  // Gets the previous computed max value
313  double maxValue = chart->getMaxValue();
314  assert(maxValue > 0.0);
315 
316  int lastx = 0;
317 
318  int shadowOffset = 2;
319 
320  // Draw each bar
321  for(std::size_t i = 0; i < values.size(); ++i)
322  {
323  int barHeight = static_cast<int>((values[i] * chart->getHeight()) / maxValue);
324 
325  // Test: Try shadow to help the chart svisualization
326  QRect shadowBar(lastx - shadowOffset, -shadowOffset, static_cast<int>(chart->getBarWidth() + shadowOffset), barHeight + shadowOffset);
327  QColor shadowColor = Convert2Qt(chart->getColor(i));
328  shadowColor.setAlpha(128);
329  m_painter.setBrush(shadowColor);
330  //m_painter.setBrush(QColor(128, 128, 128, 128));
331  m_painter.setPen(Qt::NoPen);
332  m_painter.drawRect(shadowBar);
333 
334  // Current bar
335  QRect bar(lastx, 0, static_cast<int>(chart->getBarWidth()), barHeight);
336 
337  // Configs a new color for this bar
338  m_painter.setPen(m_pen);
339  m_painter.setBrush(Convert2Qt(chart->getColor(i)));
340 
341  m_painter.drawRect(bar);
342 
343  lastx += static_cast<int>(chart->getBarWidth());
344  }
345 
346  end();
347 
348  // TODO: Need review! Draw the bar on right place! ... For while, return the mirrored image.
349  QImage* mirroed = new QImage(img->mirrored());
350 
351  delete img;
352 
353  return mirroed;
354 }
355 
356 void te::qt::widgets::ChartRenderer::getValues(const te::map::Chart* chart, const te::da::DataSet* dataset, std::vector<double>& values)
357 {
358  const std::vector<std::string>& properties = chart->getProperties();
359  size_t psize = properties.size();
360  size_t ppsize = chart->getPropertiesPos().size();
361  for(std::size_t i = 0; i < psize; ++i)
362  {
363  if(ppsize == psize)
364  values.push_back(te::da::GetValueAsDouble(dataset, chart->getPropertiesPos()[i]));
365  else
366  {
367  size_t pos = te::da::GetPropertyPos(dataset, properties[i]);
368  values.push_back(te::da::GetValueAsDouble(dataset, pos));
369  }
370  }
371 }
372 
373 void te::qt::widgets::ChartRenderer::getValues(const te::map::Chart* chart, const std::map<std::string, double>& chartValue, std::vector<double>& values)
374 {
375  std::map<std::string, double>::const_iterator it;
376  const std::vector<std::string>& properties = chart->getProperties();
377  for(std::size_t i = 0; i < properties.size(); ++i)
378  {
379  it = chartValue.find(properties[i]);
380  if(it != chartValue.end())
381  values.push_back(it->second);
382  else
383  {
384  values.clear();
385  break;
386  }
387  }
388 }
389 
390 double te::qt::widgets::ChartRenderer::computeSum(const std::vector<double>& values)
391 {
392  double sum = 0.0;
393 
394  for(std::size_t i = 0; i < values.size(); ++i)
395  sum += values[i];
396 
397  return sum;
398 }
399 
400 double te::qt::widgets::ChartRenderer::getMaxValue(const std::vector<double>& values)
401 {
402  double max = 0.0;
403 
404  for(std::size_t i = 0; i < values.size(); ++i)
405  if(std::abs(values[i]) > max)
406  max = values[i];
407 
408  return max;
409 }
ChartType getType() const
Definition: Chart.cpp:92
const std::vector< std::string > & getProperties() const
Definition: Chart.cpp:97
std::size_t getBarWidth() const
Definition: Chart.cpp:171
QPainter m_painter
The painter used to draw the chart.
Definition: ChartRenderer.h:99
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)
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.
double getMaxValue() const
Definition: Chart.cpp:186
A concrete chart renderer based on Qt4.
const te::color::RGBAColor & getColor(std::size_t i) const
Definition: Chart.cpp:112
double computeSum(const std::vector< double > &values)
This class represents the informations needed to build map charts.
Definition: Chart.h:51
std::size_t getHeight() const
Definition: Chart.cpp:146
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.
std::size_t getContourWidth() const
Definition: Chart.cpp:136
const te::color::RGBAColor & getContourColor() const
Definition: Chart.cpp:126
TEQTWIDGETSEXPORT QImage * GetImage(te::color::RGBAColor **img, int width, int height)
It creates a QImage from an RGBA color array.
const std::vector< size_t > & getPropertiesPos() const
Definition: Chart.cpp:102
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.
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:156
void end()
Finalizes the internal QPainter resources.