Developer Documentation
QwtHistogramm.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 
44 
45 // Include the plot header to get the qwt version
46 #include <qwt_plot.h>
47 
48 // This file is for QWT >= 6.0 only
49 #if QWT_VERSION >= 0x060000
50 
51 #include <qwt_plot_histogram.h>
52 #include <qwt_painter.h>
53 #include <qwt_scale_map.h>
54 
55 #include <QString>
56 #include <QPainter>
57 
58 #include <iostream>
59 
60 
61 #include "QwtHistogramm.hh"
62 
63 class Histogram::PrivateData {
64 
65 public:
66 
67  PrivateData() :
68  attributes(Histogram::Auto),
69  data(0),
70  reference(0.0)
71  {}
72 
73  int attributes;
74  QwtIntervalSeriesData* data;
75  std::vector<QColor> colors_;
76  double reference;
77 
78 };
79 
80 Histogram::Histogram(const QwtText &title) :
81  QwtPlotItem(title)
82 {
83  init();
84 }
85 
86 Histogram::Histogram(const QString &title) :
87  QwtPlotItem(QwtText(title))
88 {
89  init();
90 }
91 
93 {
94  delete d_data;
95 }
96 
97 void Histogram::init()
98 {
99  d_data = new PrivateData();
100 
101  setItemAttribute(QwtPlotItem::AutoScale, true);
102  setItemAttribute(QwtPlotItem::Legend, true);
103 
104  setZ(20.0);
105 }
106 
107 void Histogram::setBaseline(double reference)
108 {
109  if (d_data->reference != reference) {
110  d_data->reference = reference;
111  itemChanged();
112  }
113 }
114 
115 double Histogram::baseline() const
116 {
117  return d_data->reference;
118 }
119 
120 void Histogram::setData(QwtIntervalSeriesData* data)
121 {
122  d_data->data = data;
123  itemChanged();
124 }
125 
126 const QwtIntervalSeriesData* Histogram::data() const
127 {
128  return d_data->data;
129 }
130 
131 void Histogram::setColors(std::vector<QColor>& _colors)
132 {
133  d_data->colors_ = _colors;
134  itemChanged();
135 }
136 
137 QColor Histogram::color(uint i) const
138 {
139  if (i < d_data->colors_.size())
140  return d_data->colors_[i];
141  else
142  return Qt::darkBlue;
143 }
144 
145 QRectF Histogram::boundingRect() const
146 {
147  QRectF rect = d_data->data->boundingRect();
148  if (!rect.isValid())
149  return rect;
150 
151  if (d_data->attributes & Xfy) {
152  rect = QRectF(rect.y(), rect.x(), rect.height(), rect.width());
153 
154  if (rect.left() > d_data->reference)
155  rect.setLeft(d_data->reference);
156  else if (rect.right() < d_data->reference)
157  rect.setRight(d_data->reference);
158  } else {
159  if (rect.bottom() < d_data->reference)
160  rect.setBottom(d_data->reference);
161  else if (rect.top() > d_data->reference)
162  rect.setTop(d_data->reference);
163  }
164 
165  return rect;
166 }
167 
168 
169 int Histogram::rtti() const
170 {
171  return QwtPlotItem::Rtti_PlotHistogram;
172 }
173 
174 void Histogram::setHistogramAttribute(HistogramAttribute attribute, bool on)
175 {
176  if (bool(d_data->attributes & attribute) == on)
177  return;
178 
179  if (on)
180  d_data->attributes |= attribute;
181  else
182  d_data->attributes &= ~attribute;
183 
184  itemChanged();
185 }
186 
187 bool Histogram::testHistogramAttribute(HistogramAttribute attribute) const
188 {
189  return d_data->attributes & attribute;
190 }
191 
192 void Histogram::draw(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &) const
193 {
194  const QwtIntervalSeriesData &iData = *(d_data->data);
195 
196  const int x0 = xMap.transform(baseline());
197  const int y0 = yMap.transform(baseline());
198 
199  for (int i = 0; i < (int) iData.size(); i++) {
200  if (d_data->attributes & Histogram::Xfy) {
201  const int x2 = xMap.transform(iData.sample(i).value);
202  if (x2 == x0)
203  continue;
204 
205  int y1 = yMap.transform(iData.sample(i).interval.minValue());
206  int y2 = yMap.transform(iData.sample(i).interval.maxValue());
207  if (y1 > y2)
208  qSwap(y1, y2);
209 
210  if (i < (int) iData.size() - 2) {
211  const int yy1 = yMap.transform(iData.sample(i + 1).interval.minValue());
212  const int yy2 = yMap.transform(iData.sample(i + 1).interval.maxValue());
213 
214  if (y2 == qMin(yy1, yy2)) {
215  const int xx2 = xMap.transform(iData.sample(i + 1).interval.minValue());
216  if (xx2 != x0 && ((xx2 < x0 && x2 < x0) || (xx2 > x0 && x2 > x0))) {
217  // One pixel distance between neighbored bars
218  y2++;
219  }
220  }
221  }
222 
223  painter->setPen(QPen(color(i)));
224 
225  drawBar(painter, Qt::Horizontal, QRect(x0, y1, x2 - x0, y2 - y1));
226  } else {
227  const int y2 = yMap.transform(iData.sample(i).value);
228  if (y2 == y0)
229  continue;
230 
231  int x1 = xMap.transform(iData.sample(i).interval.minValue());
232  int x2 = xMap.transform(iData.sample(i).interval.maxValue());
233  if (x1 > x2)
234  qSwap(x1, x2);
235 
236  if (i < (int) iData.size() - 2) {
237  const int xx1 = xMap.transform(iData.sample(i + 1).interval.minValue());
238  const int xx2 = xMap.transform(iData.sample(i + 1).interval.maxValue());
239 
240  if (x2 == qMin(xx1, xx2)) {
241  const int yy2 = yMap.transform(iData.sample(i + 1).value);
242  if (yy2 != y0 && ((yy2 < y0 && y2 < y0) || (yy2 > y0 && y2 > y0))) {
243  // One pixel distance between neighbored bars
244  x2--;
245  }
246  }
247  }
248 
249  painter->setPen(QPen(color(i)));
250 
251  drawBar(painter, Qt::Vertical, QRect(x1, y0, x2 - x1, y2 - y0));
252  }
253  }
254 }
255 
256 void Histogram::drawBar(QPainter *painter, Qt::Orientation, const QRect& rect) const
257 {
258  painter->save();
259 
260  const QColor color(painter->pen().color());
261  const QRect r = rect.normalized();
262 
263  const int factor = 125;
264  const QColor light(color.light(factor));
265  const QColor dark(color.dark(factor));
266 
267  painter->setBrush(color);
268  painter->setPen(Qt::NoPen);
269  QwtPainter::drawRect(painter, r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2);
270  painter->setBrush(Qt::NoBrush);
271 
272  painter->setPen(QPen(light, 2));
273 
274  QwtPainter::drawLine(painter, r.left() + 1, r.top() + 2, r.right() + 1, r.top() + 2);
275 
276  painter->setPen(QPen(dark, 2));
277 
278  painter->setPen(QPen(light, 1));
279 
280  QwtPainter::drawLine(painter, r.left(), r.top() + 1, r.left(), r.bottom());
281  QwtPainter::drawLine(painter, r.left() + 1, r.top() + 2, r.left() + 1, r.bottom() - 1);
282 
283  painter->setPen(QPen(dark, 1));
284 
285  QwtPainter::drawLine(painter, r.right() + 1, r.top() + 1, r.right() + 1, r.bottom());
286  QwtPainter::drawLine(painter, r.right(), r.top() + 2, r.right(), r.bottom() - 1);
287 
288  painter->restore();
289 }
290 
291 #endif
virtual void drawBar(QPainter *, Qt::Orientation o, const QRect &) const
Draws a single bar.
virtual QRectF boundingRect() const
Function hat will return the datas bounding rectangle (for rendering)
void setData(QwtIntervalSeriesData *data)
set data to render
Histogram(const QString &title=QString())
Constructor.
Histogram plot.
void setColors(std::vector< QColor > &_colors)
Set colors.
virtual ~Histogram()
Destructor.
virtual void draw(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &) const
The actual draw function, drawing the bars inside the plot widget.