source: flair-src/trunk/tools/FlairGCS/src/DataPlot2D.cpp @ 269

Last change on this file since 269 was 269, checked in by Sanahuja Guillaume, 3 years ago

flairgcs:
speed up processing time when receiving datas from uav
triger watchdog while receiving datas from uav
(avoids connection lost in uav)

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