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

Last change on this file since 15 was 15, checked in by Bayard Gildas, 6 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.