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

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