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 }
ACG
Namespace providing different geometric functions concerning angles.
Definition: BaseObjectData.hh:68