source: flair-src/trunk/tools/FlairGCS/src/Scope.cpp@ 16

Last change on this file since 16 was 15, checked in by Bayard Gildas, 9 years ago

sources reformatted with flair-format-dir script

File size: 8.8 KB
Line 
1// %flair:license{
2// This file is part of the Flair framework distributed under the
3// CECILL-C License, Version 1.0.
4// %flair:license}
5#include "Scope.h"
6#include "Scrollbar.h"
7#include <qwt_plot_curve.h>
8#include <qwt_plot_grid.h>
9#include <qwt_plot_magnifier.h>
10#include <qwt_plot_canvas.h>
11#include <qwt_scale_widget.h>
12#include <qwt_legend_label.h>
13#include <qwt_legend.h>
14#include <qwt_plot_panner.h>
15#include <QMouseEvent>
16#include <QMenu>
17#include <QTimer>
18#include <QTime>
19#include <QApplication>
20
21#define WHEEL_DIVIDOR 30
22
23Scope::Scope(QString title, float ymin, float ymax, float view_size_s,
24 unsigned int refresh_rate_ms, unsigned int history_size)
25 : QwtPlot() {
26 this->ymin = ymin;
27 this->ymax = ymax;
28 this->history_size = history_size;
29 this->view_size_s = view_size_s;
30 orig_view_size_s = view_size_s;
31
32 // scroll bar
33 scrollbar = new ScrollBar(Qt::Horizontal, canvas());
34 connect(scrollbar, SIGNAL(valueChanged(Qt::Orientation, float, float)), this,
35 SLOT(scrollBarMoved(Qt::Orientation, float, float)));
36 scrolling = true;
37
38 // minimum size; sinon widget trop grand
39 setMinimumHeight(10);
40 setMinimumWidth(1);
41
42 alignScales(); // is it necessary?
43
44 // Initialize data
45 elapsed_time_s = 0;
46
47 // Assign a title
48 setTitle(title);
49
50 // Axis
51 setAxisTitle(QwtPlot::xBottom, "Time (s)");
52 setAxisScale(QwtPlot::xBottom, 0, view_size_s);
53
54 setAxisTitle(QwtPlot::yLeft, "Values");
55 setAxisScale(QwtPlot::yLeft, ymin, ymax);
56
57 // grid
58 QwtPlotGrid *grid = new QwtPlotGrid;
59 grid->setPen(QPen(Qt::black, 0, Qt::DotLine));
60 grid->attach(this);
61
62 // zoomer
63 QwtPlotMagnifier *zoomer = new QwtPlotMagnifier(canvas());
64 zoomer->setWheelModifiers(Qt::ControlModifier);
65 zoomer->setMouseButton(Qt::NoButton);
66 zoomer->setAxisEnabled(xBottom, 0);
67
68 // scroller
69 QwtPlotPanner *scroller = new QwtPlotPanner(canvas());
70 scroller->setAxisEnabled(xBottom, 0);
71
72 // legend
73 QwtLegend *new_legend = new QwtLegend();
74 new_legend->setDefaultItemMode(QwtLegendData::Checkable);
75 insertLegend(new_legend, QwtPlot::BottomLegend);
76
77 connect(new_legend, SIGNAL(checked(const QVariant &, bool, int)),
78 SLOT(legendChecked(const QVariant &, bool)));
79
80 QTimer *timer = new QTimer(this);
81 connect(timer, SIGNAL(timeout()), this, SLOT(replot()));
82 timer->start(refresh_rate_ms);
83}
84
85Scope::~Scope() {
86 for (int i = 0; i < curves.count(); i++) {
87 free(curves.at(i)->data_x);
88 free(curves.at(i)->data_y);
89 delete curves.at(i)->plot;
90 free(curves.at(i));
91 }
92}
93
94void Scope::resetXView(void) {
95 // setAxisScale(QwtPlot::xBottom,0, orig_view_size_s);
96 changeViewSize(orig_view_size_s);
97}
98
99void Scope::resetYView(void) { setAxisScale(QwtPlot::yLeft, ymin, ymax); }
100
101bool Scope::eventFilter(QObject *o, QEvent *e) {
102 switch (e->type()) {
103 case QEvent::Resize: {
104 const int fw = ((QwtPlotCanvas *)canvas())->frameWidth();
105
106 QRect rect;
107 rect.setSize(((QResizeEvent *)e)->size());
108 rect.setRect(rect.x() + fw, rect.y() + fw, rect.width() - 2 * fw,
109 rect.height() - 2 * fw);
110
111 scrollbar->setGeometry(0, 0, rect.width(), 10);
112 return true;
113 }
114 case QEvent::Wheel: {
115 // ctrl+wheel is already handled for y zoom
116 if (!(QApplication::keyboardModifiers() & Qt::ControlModifier)) {
117 QWheelEvent *wheelevent = static_cast<QWheelEvent *>(e);
118 if (view_size_s + wheelevent->delta() / WHEEL_DIVIDOR > 0)
119 changeViewSize(view_size_s + wheelevent->delta() / WHEEL_DIVIDOR);
120 }
121 return true;
122 }
123 default:
124 break;
125 }
126 return QwtPlot::eventFilter(o, e);
127}
128
129void Scope::changeViewSize(float new_view_size_s) {
130 view_size_s = new_view_size_s;
131
132 if (scrolling == false) {
133 // 4 cas: on utilise le temps au milieu de la vue actuelle
134
135 // le temps total est plus petit que le view_size_s, on affiche tout:
136 if (elapsed_time_s < view_size_s) {
137 scrolling = true;
138 } else {
139 double min = (min_scroll + max_scroll) / 2 - view_size_s / 2;
140 double max = (min_scroll + max_scroll) / 2 + view_size_s / 2;
141 // on va du debut jusqu'a view size
142 if (min < 0) {
143 min = 0;
144 max = view_size_s;
145 }
146 // on va de fin-viewsize jusqu'a la fin
147 if (max > elapsed_time_s) {
148 min = elapsed_time_s - view_size_s;
149 max = elapsed_time_s;
150 }
151 scrollbar->moveSlider(
152 min, max); // move slider coupe le signal, on fait aussi le scrollbar
153 scrollBarMoved(Qt::Horizontal, min, max);
154 }
155 }
156}
157
158void Scope::legendChecked(const QVariant &itemInfo, bool on) {
159 QwtPlotItem *plotItem = infoToItem(itemInfo);
160 if (plotItem)
161 showCurve(plotItem, on);
162}
163
164void Scope::showCurve(QwtPlotItem *item, bool on) {
165 item->setVisible(on);
166
167 QwtLegend *lgd = qobject_cast<QwtLegend *>(legend());
168
169 QList<QWidget *> legendWidgets = lgd->legendWidgets(itemToInfo(item));
170
171 if (legendWidgets.size() == 1) {
172 QwtLegendLabel *legendLabel =
173 qobject_cast<QwtLegendLabel *>(legendWidgets[0]);
174
175 if (legendLabel)
176 legendLabel->setChecked(on);
177 }
178}
179
180int Scope::addCurve(QPen pen, QString legend) {
181 Curve *curve = (Curve *)malloc(sizeof(Curve));
182 curve->data_x = (double *)calloc(history_size, sizeof(double));
183 curve->data_y = (double *)calloc(history_size, sizeof(double));
184 curve->index = 0;
185 curve->min_index = 0;
186 curve->max_index = 0;
187
188 // Insert new curve
189 curve->plot = new QwtPlotCurve(legend);
190 curve->plot->attach(this);
191 curve->plot->setPen(pen);
192 curves.append(curve);
193
194 showCurve(curve->plot, true);
195
196 return curves.count() - 1;
197}
198
199void Scope::updateCurve(Curve *curve) {
200 if (scrolling == true) {
201 curve->plot->setRawSamples(&curve->data_x[curve->min_index],
202 &curve->data_y[curve->min_index],
203 curve->max_index - curve->min_index);
204 }
205
206 if (curve->index == history_size) {
207 // printf("a revoir qd on arrive a la fin, il faudrait faire un realloc pour
208 // rien perdre\n");
209 // attention le setrawdata s'attend a ce que l'adresse change pas, ce qui
210 // n'est pas le cas avec lerealloc
211 // il faudra refaire un setrawdata ici
212 curve->index = 0;
213 curve->min_index = 0;
214 scrolling = true;
215 }
216
217 // determine les index pour la visualisation
218 if (scrolling == true) {
219 curve->max_index = curve->index;
220 computeMinIndex(curve, elapsed_time_s - view_size_s);
221 }
222
223 scrollbar->setBase(0, elapsed_time_s);
224 if (scrolling == true) {
225 scrollbar->moveSlider(elapsed_time_s - view_size_s, elapsed_time_s);
226
227 if (elapsed_time_s < view_size_s) {
228 setAxisScale(QwtPlot::xBottom, 0, view_size_s);
229 } else {
230 setAxisScale(QwtPlot::xBottom, elapsed_time_s - view_size_s,
231 elapsed_time_s);
232 }
233 } else {
234 scrollbar->moveSlider(min_scroll, max_scroll);
235 }
236}
237
238void Scope::alignScales(void) {
239 // The code below shows how to align the scales to
240 // the canvas frame, but is also a good example demonstrating
241 // why the spreaded API needs polishing.
242 /*
243 plot->canvas()->setFrameStyle(QFrame::Box | QFrame::Plain );
244 plot->canvas()->setLineWidth(1);
245 */
246 for (int i = 0; i < QwtPlot::axisCnt; i++) {
247 QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(i);
248 if (scaleWidget)
249 scaleWidget->setMargin(0);
250
251 QwtScaleDraw *scaleDraw = (QwtScaleDraw *)axisScaleDraw(i);
252 if (scaleDraw)
253 scaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone, false);
254 }
255}
256
257void Scope::scrollBarMoved(Qt::Orientation o, float min, float max) {
258 min_scroll = min;
259 max_scroll = max;
260
261 if (max == scrollbar->maxBaseValue()) {
262 scrolling = true;
263 } else {
264 scrolling = false;
265 setAxisScale(QwtPlot::xBottom, min, max);
266
267 // determine les index pour la visualisation
268 for (int i = 0; i < curves.count(); i++) {
269 computeMinIndex(curves.at(i), min);
270 computeMaxIndex(curves.at(i), max);
271 curves.at(i)->plot->setRawSamples(
272 &curves.at(i)->data_x[curves.at(i)->min_index],
273 &curves.at(i)->data_y[curves.at(i)->min_index],
274 curves.at(i)->max_index - curves.at(i)->min_index);
275 }
276 }
277}
278
279// TODO: faire une dichotomie
280void Scope::computeMinIndex(Curve *curve, float displayed_min_time) {
281 if (curve->data_x[curve->index] > displayed_min_time) {
282 if (curve->data_x[curve->min_index] < displayed_min_time) {
283 while (curve->data_x[curve->min_index] < displayed_min_time &&
284 curve->min_index != curve->index)
285 curve->min_index++;
286 } else {
287 while (curve->data_x[curve->min_index] > displayed_min_time &&
288 curve->min_index != 0)
289 curve->min_index--;
290 }
291 }
292}
293
294void Scope::computeMaxIndex(Curve *curve, float displayed_max_time) {
295 if (curve->data_x[curve->max_index] < displayed_max_time) {
296 while (curve->data_x[curve->max_index] < displayed_max_time &&
297 curve->max_index != curve->index)
298 curve->max_index++;
299 } else {
300 while (curve->data_x[curve->max_index] > displayed_max_time)
301 curve->max_index--;
302 }
303}
Note: See TracBrowser for help on using the repository browser.