Developer Documentation
QtHistogramWidget.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 // Based on QtHistogram by hc
43 
44 #include "QtHistogramWidget.hh"
45 
46 #include <QPainter>
47 
48 namespace ACG {
49 namespace QtWidgets {
50 
51 QtHistogramWidget::QtHistogramWidget(QWidget *parent)
52  : QWidget(parent),
53  color_(QColor::fromRgbF(0.518, 0.573, 0.643, 1.0))
54 {}
55 
56 QtHistogramWidget::~QtHistogramWidget() = default;
57 
58 void QtHistogramWidget::setHistogram(std::unique_ptr<Histogram> histogram) {
59  histogram_ = std::move(histogram);
60  this->update();
61 }
62 
63 void QtHistogramWidget::setColorCoder(std::unique_ptr<IColorCoder> color_coder) {
64  color_coder_ = std::move(color_coder);
65  this->update();
66 }
67 
68 void QtHistogramWidget::paintEvent(QPaintEvent *event) {
69  if (!histogram_) {
70  QWidget::paintEvent(event);
71  return;
72  }
73 
74  /*
75  * Analyze histogram/
76  */
77  const std::vector<size_t> &bins = histogram_->getBins();
78  const std::vector<double> &bin_widths = histogram_->getBinWidths();
79  const double total_width = histogram_->getTotalWidth();
80 
81 
82  size_t hist_max = bins.size() > 0 ? *std::max_element(bins.begin(), bins.end()) : 0;
83 
84  /*
85  * Establish regions
86  */
87  const qreal labelHeight = 16;
88  QRectF paint_rect = this->contentsRect();
89  QRectF bargraph_rect = paint_rect;
90  bargraph_rect.setBottom(bargraph_rect.bottom() - labelHeight);
91  QRectF label_rect = paint_rect;
92  label_rect.setTop(bargraph_rect.bottom());
93  QPainter painter(this);
94 
95  /*
96  * Painter attributes.
97  */
98  painter.setRenderHint(QPainter::Antialiasing);
99  painter.setFont(this->font());
100 
101  const qreal avg_width = bargraph_rect.width() / bins.size();
102  const qreal gap = (avg_width > 8) ? 1.0 : 0.0;
103  const qreal label_gap = 4;
104  const qreal y_scale = bargraph_rect.height() / hist_max;
105 
106  const qreal total_gap = (bins.size() - 1) * gap;
107  const qreal total_barwidth = bargraph_rect.width() - total_gap;
108 
109  QRectF barRect;
110  /*
111  * Draw.
112  */
113  double cumulative_width = 0.0;
114  qreal xpos = 0;
115  qreal lastLabelX = label_rect.left();
116  const size_t n_bins = bins.size();
117  for (size_t idx = 0; idx < n_bins; ++idx) {
118  const double bin_width = bin_widths[idx];
119  const qreal bar_width = total_barwidth * (bin_width / total_width);
120  // Bar
121  painter.setPen(Qt::NoPen);
122  // relative position t in [0..1] for the middle of the current bin
123  const double t = (cumulative_width + bin_width/2) / total_width;
124  cumulative_width += bin_width;
125 
126  painter.setBrush(getColor(t));
127 
128  barRect.setWidth(bar_width - gap);
129  barRect.setHeight(y_scale * bins[idx]);
130  barRect.moveBottomLeft(bargraph_rect.bottomLeft() + QPoint(xpos, 0));
131 
132  if (gap > 0.0)
133  painter.drawRoundedRect(barRect, 3, 3, Qt::AbsoluteSize);
134  else
135  painter.drawRect(barRect);
136 
137  // Label
138  painter.setPen(Qt::black);
139  qreal labelX = 0;
140  QString labelText;
141  switch (histogram_->getLabelType()) {
142  case Histogram::LabelType::PerBin:
143  labelX = barRect.center().x();
144  labelText = histogram_->getBinLabel(idx);
145  break;
146  case Histogram::LabelType::PerBoundary:
147  labelX = barRect.x();
148  labelText = histogram_->getBoundaryLabel(idx);
149  break;
150  }
151  QRectF labelBB = painter.boundingRect(
152  QRectF(labelX - (label_distance_/2), label_rect.y(),
153  label_distance_, label_rect.height()),
154  Qt::AlignHCenter | Qt::AlignBottom, labelText);
155 
156  if (labelBB.left() >= lastLabelX + label_gap) {
157  painter.drawText(labelBB, Qt::AlignHCenter | Qt::AlignBottom,
158  labelText);
159  lastLabelX = labelBB.right();
160  }
161  xpos += bar_width;
162  }
163  // TODO: draw last perBoundary label?
164 }
165 
166 
167 
168 QColor QtHistogramWidget::getColor(double val)
169 {
170  if (color_coder_) {
171  return color_coder_->color_qcolor(val);
172  } else {
173  return color_;
174  }
175 }
176 
177 }
178 }
Namespace providing different geometric functions concerning angles.