source: flair-src/branches/mavlink/tools/FlairGCS/src/DataPlot2D.cpp @ 77

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

sources reformatted with flair-format-dir script

File size: 12.1 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 "DataPlot2D.h"
6#include "Layout.h"
7#include <qwt_plot.h>
8#include <qwt_plot_curve.h>
9#include <qwt_plot_grid.h>
10#include <qwt_plot_magnifier.h>
11#include <qwt_plot_canvas.h>
12#include <qwt_scale_widget.h>
13#include <qwt_legend_label.h>
14#include <qwt_legend.h>
15#include <qwt_plot_panner.h>
16#include <qwt_plot_rescaler.h>
17#include <QMouseEvent>
18#include <QMenu>
19#include <QInputDialog>
20#include <qendian.h>
21
22DataPlot2D::DataPlot2D(Layout *parent, int row, int col, QString plot_name,
23                       QString x_name, QString y_name, float xmin, float xmax,
24                       float ymin, float ymax, bool enabled, int period)
25    : DataRemote(plot_name, "DataPlot2D", parent, enabled, period) {
26  plot = new QwtPlot(NULL);
27  plot->setEnabled(enabled);
28
29  parent->addWidget(plot, row, col);
30  visible_widget = plot;
31
32  view_size = 20; // default 20s
33                  /*
34                      // Disable polygon clipping
35                      QwtPainter::setDeviceClipping(false);
36                 
37                      // We don't need the cache here
38                      plot->canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
39                      plot->canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);
40                  */
41#if QT_VERSION >= 0x040000
42#ifdef Q_WS_X11
43  /*
44     Qt::WA_PaintOnScreen is only supported for X11, but leads
45     to substantial bugs with Qt 4.2.x/Windows
46   */
47  plot->canvas()->setAttribute(Qt::WA_PaintOnScreen, true);
48#endif
49#endif
50
51  alignScales();
52
53  // d_x=new QList<double*>;
54  // d_y=new QList<double*>;
55  datas = new QList<QwtPlotCurve *>;
56  datas_type = new QList<QString>;
57
58  // Assign a title
59  plot->setTitle(plot_name);
60
61  // Axis
62  plot->setAxisTitle(QwtPlot::xBottom, x_name);
63  setXAxisScale(xmin, xmax);
64
65  plot->setAxisTitle(QwtPlot::yLeft, y_name);
66  setYAxisScale(ymin, ymax);
67
68  QwtPlotRescaler *rescaler = new QwtPlotRescaler(plot->canvas());
69  rescaler->setRescalePolicy(QwtPlotRescaler::Fixed); /*
70 rescaler->setReferenceAxis(QwtPlot::xBottom);
71 rescaler->setAspectRatio(QwtPlot::yLeft, 1.0);*/
72
73  // grid
74  QwtPlotGrid *grid = new QwtPlotGrid;
75  // grid->enableXMin(false);
76  grid->setPen(QPen(Qt::black, 0, Qt::DotLine));
77  // grid->setMinPen(QPen(Qt::gray, 0 , Qt::DotLine));
78  grid->attach(plot);
79
80  // zoomer
81  QwtPlotMagnifier *zoomer = new QwtPlotMagnifier(plot->canvas());
82  zoomer->setMouseButton(Qt::RightButton, Qt::ControlModifier);
83
84  // scroller
85  QwtPlotPanner *scroller = new QwtPlotPanner(plot->canvas());
86
87  // legend
88  QwtLegend *new_legend = new QwtLegend();
89  new_legend->setDefaultItemMode(QwtLegendData::Checkable);
90  plot->insertLegend(new_legend, QwtPlot::BottomLegend);
91
92  connect(new_legend, SIGNAL(checked(const QVariant &, bool, int)),
93          SLOT(legendChecked(const QVariant &, bool)));
94
95  plot->canvas()->installEventFilter(this);
96}
97
98DataPlot2D::~DataPlot2D() {
99  for (int i = 0; i < d_x.count(); i++) {
100    free(d_x.at(i));
101    free(d_y.at(i));
102  }
103
104  delete datas;
105  delete datas_type;
106}
107
108void DataPlot2D::XmlEvent(QDomElement dom) {
109  if (dom.attribute("curve") != "") {
110    QString type = dom.attribute("type");
111    int r = dom.attribute("r").toInt();
112    int g = dom.attribute("g").toInt();
113    int b = dom.attribute("b").toInt();
114    QString name = dom.attribute("curve");
115    addCurve(QPen(QColor(r, g, b, 255)), name, type);
116  } else {
117    XmlSetup(dom);
118  }
119}
120
121bool DataPlot2D::eventFilter(QObject *o, QEvent *e) {
122  if (o == plot->canvas()) {
123    switch (e->type()) {
124    case QEvent::MouseButtonPress: {
125      mousePressEvent((QMouseEvent *)e);
126      break;
127    }
128
129    default:
130      break;
131    }
132  }
133  return plot->eventFilter(o, e);
134}
135
136void DataPlot2D::legendChecked(const QVariant &itemInfo, bool on) {
137  QwtPlotItem *plotItem = plot->infoToItem(itemInfo);
138  if (plotItem)
139    showCurve(plotItem, on);
140}
141
142void DataPlot2D::showCurve(QwtPlotItem *item, bool on) {
143  item->setVisible(on);
144
145  QwtLegend *lgd = qobject_cast<QwtLegend *>(plot->legend());
146
147  QList<QWidget *> legendWidgets = lgd->legendWidgets(plot->itemToInfo(item));
148
149  if (legendWidgets.size() == 1) {
150    QwtLegendLabel *legendLabel =
151        qobject_cast<QwtLegendLabel *>(legendWidgets[0]);
152
153    if (legendLabel)
154      legendLabel->setChecked(on);
155  }
156
157  plot->replot();
158}
159
160void DataPlot2D::addCurve(QPen pen, QString legend, QString type) {
161  double *new_dx;
162  new_dx = (double *)malloc(view_size / refresh_rate * sizeof(double));
163  d_x.append(new_dx);
164  double *new_dy;
165  new_dy = (double *)malloc(view_size / refresh_rate * sizeof(double));
166  d_y.append(new_dy);
167
168  //  Initialize data
169  for (int i = 0; i < view_size / refresh_rate; i++)
170    new_dx[i] = 0;
171  for (int i = 0; i < view_size / refresh_rate; i++)
172    new_dy[i] = 0;
173
174  // Insert new curve
175  QwtPlotCurve *new_data;
176
177  new_data = new QwtPlotCurve(legend);
178  new_data->attach(plot);
179  new_data->setPen(pen);
180  datas->append(new_data);
181
182  showCurve(new_data, true);
183
184  datas_type->append(type);
185  bool tmp = true;
186  datas_first_update.append(tmp);
187
188  // Attach (don't copy) data. Both curves use the same x array.
189  new_data->setRawSamples(new_dx, new_dy, view_size / refresh_rate);
190
191  if (type == "float") {
192    receivesize += sizeof(float);
193  } else if (type == "int8_t") {
194    receivesize += sizeof(int8_t);
195  } else if (type == "int16_t") {
196    receivesize += sizeof(int16_t);
197  } else {
198    printf("DataPlot2D::addCurve unknown type %s\n",
199           type.toLocal8Bit().constData());
200  }
201}
202
203void DataPlot2D::setXAxisScale(float xmin, float xmax) {
204  xmin_orig = xmin;
205  xmax_orig = xmax;
206  plot->setAxisScale(QwtPlot::xBottom, xmin_orig, xmax_orig);
207}
208
209void DataPlot2D::setYAxisScale(float ymin, float ymax) {
210  ymin_orig = ymin;
211  ymax_orig = ymax;
212  plot->setAxisScale(QwtPlot::yLeft, ymin_orig, ymax_orig);
213}
214
215//
216//  Set a plain canvas frame and align the scales to it
217//
218void DataPlot2D::alignScales(void) {
219  // The code below shows how to align the scales to
220  // the canvas frame, but is also a good example demonstrating
221  // why the spreaded API needs polishing.
222  /*
223      plot->canvas()->setFrameStyle(QFrame::Box | QFrame::Plain );
224      plot->canvas()->setLineWidth(1);
225  */
226  for (int i = 0; i < QwtPlot::axisCnt; i++) {
227    QwtScaleWidget *scaleWidget = (QwtScaleWidget *)plot->axisWidget(i);
228    if (scaleWidget)
229      scaleWidget->setMargin(0);
230
231    QwtScaleDraw *scaleDraw = (QwtScaleDraw *)plot->axisScaleDraw(i);
232    if (scaleDraw)
233      scaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone, false);
234  }
235}
236
237void DataPlot2D::BufEvent(char **buf, int *buf_size, uint16_t period,
238                          bool big_endian) {
239  plot->setEnabled(IsEnabled());
240  if (IsEnabled() == false || RefreshRate_ms() != period)
241    return;
242
243  for (int i = 0; i < datas->count(); i++) {
244    if (datas_type->at(i) == "float") {
245      uint32_t data1_raw;
246      float *data1 = (float *)&data1_raw;
247      uint32_t data2_raw;
248      float *data2 = (float *)&data2_raw;
249
250      memcpy((void *)&data1_raw, *buf, sizeof(uint32_t));
251      *buf += sizeof(uint32_t);
252      memcpy((void *)&data2_raw, *buf, sizeof(uint32_t));
253      *buf += sizeof(uint32_t);
254      if (big_endian == true)
255        data1_raw = qFromBigEndian(data1_raw);
256      if (big_endian == true)
257        data2_raw = qFromBigEndian(data2_raw);
258      plot_data(*data1, *data2, i);
259    } else if (datas_type->at(i) == "int8_t") {
260      int8_t data1, data2;
261      memcpy((void *)&data1, *buf, sizeof(data1));
262      *buf += sizeof(data1);
263      memcpy((void *)&data2, *buf, sizeof(data2));
264      *buf += sizeof(data2);
265      plot_data(data1, data2, i);
266    } else if (datas_type->at(i) == "int16_t") {
267      int16_t data1, data2;
268      memcpy((void *)&data1, *buf, sizeof(data1));
269      *buf += sizeof(data1);
270      memcpy((void *)&data2, *buf, sizeof(data2));
271      *buf += sizeof(data2);
272      plot_data(data1, data2, i);
273    } else {
274      printf("DataPlot1D::DrawDatas type non connu\n");
275    }
276  }
277
278  plot->replot();
279}
280
281void DataPlot2D::plot_data(double data_x, double data_y, int index) {
282  if (index < d_y.count()) {
283    if (datas_first_update.at(index) == false) {
284      // Shift y array left and assign new value to y[view_size/refresh_rate -
285      // 1].
286      for (int j = 0; j < view_size / refresh_rate - 1; j++)
287        d_y.at(index)[j] = d_y.at(index)[j + 1];
288      for (int j = 0; j < view_size / refresh_rate - 1; j++)
289        d_x.at(index)[j] = d_x.at(index)[j + 1];
290      d_y.at(index)[(int)(view_size / refresh_rate) - 1] = data_y;
291      d_x.at(index)[(int)(view_size / refresh_rate) - 1] = data_x;
292    } else {
293      for (int j = 0; j <= view_size / refresh_rate - 1; j++)
294        d_y.at(index)[j] = data_y;
295      for (int j = 0; j <= view_size / refresh_rate - 1; j++)
296        d_x.at(index)[j] = data_x;
297      datas_first_update[index] = false;
298    }
299  }
300}
301
302// context menu
303void DataPlot2D::mousePressEvent(QMouseEvent *event) {
304  if (event->button() == Qt::RightButton) {
305
306    QMenu *menu = new QMenu("nom", plot);
307    // ajout des actions
308    QAction *a, *z, *d;
309
310    a = menu->addAction("reset zoom");
311    menu->addSeparator();
312
313    d = menu->addAction(QString("set view size (%1s)").arg(view_size));
314
315    appendmenu(menu);
316    z = execmenu(plot, menu, event->globalPos());
317    delete menu;
318
319    if (z == a) {
320      // zoom to original size
321      plot->setAxisScale(QwtPlot::yLeft, ymin_orig, ymax_orig);
322      plot->setAxisScale(QwtPlot::xBottom, xmin_orig, xmax_orig);
323    }
324
325    if (z == d) {
326      bool ok;
327      float time = QInputDialog::getInt(
328          plot, QString("Set view size (%1)").arg(plot->title().text()),
329          tr("Value (s):"), view_size, 1, 65535, 10, &ok);
330      if (ok == true) {
331        for (int i = 0; i < datas->count(); i++) {
332          if (time > view_size) {
333            double *buf =
334                (double *)malloc(time / refresh_rate * sizeof(double));
335            d_x[i] = (double *)realloc(d_x.at(i),
336                                       time / refresh_rate * sizeof(double));
337            memcpy(buf, d_x[i], (view_size / refresh_rate) * sizeof(double));
338            memcpy(&d_x[i][(int)(time / refresh_rate) -
339                           (int)(view_size / refresh_rate)],
340                   buf, (view_size / refresh_rate) * sizeof(double));
341            d_y[i] = (double *)realloc(d_y.at(i),
342                                       time / refresh_rate * sizeof(double));
343            memcpy(buf, d_y[i], (view_size / refresh_rate) * sizeof(double));
344            memcpy(&d_y[i][(int)(time / refresh_rate) -
345                           (int)(view_size / refresh_rate)],
346                   buf, (view_size / refresh_rate) * sizeof(double));
347            free(buf);
348            for (int j = 0; j < (int)(time / refresh_rate) -
349                                    (int)(view_size / refresh_rate);
350                 j++) {
351              d_x.at(i)[j] = d_x.at(i)[(int)(time / refresh_rate) -
352                                       (int)(view_size / refresh_rate) + 1];
353              d_y.at(i)[j] = d_y.at(i)[(int)(time / refresh_rate) -
354                                       (int)(view_size / refresh_rate) + 1];
355            }
356          } else {
357            double *buf =
358                (double *)malloc(time / refresh_rate * sizeof(double));
359            memcpy(buf, &d_x[i][(int)(view_size / refresh_rate) -
360                                (int)(time / refresh_rate)],
361                   (time / refresh_rate) * sizeof(double));
362            d_x[i] = (double *)realloc(d_x.at(i),
363                                       time / refresh_rate * sizeof(double));
364            memcpy(d_x[i], buf, (time / refresh_rate) * sizeof(double));
365            memcpy(buf, &d_y[i][(int)(view_size / refresh_rate) -
366                                (int)(time / refresh_rate)],
367                   (time / refresh_rate) * sizeof(double));
368            d_y[i] = (double *)realloc(d_y.at(i),
369                                       time / refresh_rate * sizeof(double));
370            memcpy(d_y[i], buf, (time / refresh_rate) * sizeof(double));
371            free(buf);
372          }
373          datas->at(i)
374              ->setRawSamples(d_x.at(i), d_y.at(i), time / refresh_rate);
375        }
376        view_size = time;
377      }
378    }
379  }
380}
Note: See TracBrowser for help on using the repository browser.