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

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

update buffering (gcs part)
seems to work!

File size: 12.3 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, uint16_t period, uint16_t nb_buffering)
25 : DataRemote(plot_name, "DataPlot2D", parent, enabled, period, nb_buffering) {
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,uint16_t nb_buffering,bool big_endian) {
254
255 if (IsEnabled() == false || RefreshRate_ms() != period || NbBuffering()!=nb_buffering) return;
256
257 for (int i = 0; i < datas->count(); i++) {
258 if (datas_type->at(i) == "float") {
259 uint32_t data1_raw;
260 float *data1 = (float *)&data1_raw;
261 uint32_t data2_raw;
262 float *data2 = (float *)&data2_raw;
263
264 memcpy((void *)&data1_raw, *buf, sizeof(uint32_t));
265 *buf += sizeof(uint32_t);
266 memcpy((void *)&data2_raw, *buf, sizeof(uint32_t));
267 *buf += sizeof(uint32_t);
268 if (big_endian == true)
269 data1_raw = qFromBigEndian(data1_raw);
270 if (big_endian == true)
271 data2_raw = qFromBigEndian(data2_raw);
272 plot_data(*data1, *data2, i);
273 } else if (datas_type->at(i) == "int8_t") {
274 int8_t data1, data2;
275 memcpy((void *)&data1, *buf, sizeof(data1));
276 *buf += sizeof(data1);
277 memcpy((void *)&data2, *buf, sizeof(data2));
278 *buf += sizeof(data2);
279 plot_data(data1, data2, i);
280 } else if (datas_type->at(i) == "int16_t") {
281 int16_t data1, data2;
282 memcpy((void *)&data1, *buf, sizeof(data1));
283 *buf += sizeof(data1);
284 memcpy((void *)&data2, *buf, sizeof(data2));
285 *buf += sizeof(data2);
286 plot_data(data1, data2, i);
287 } else {
288 fprintf(stderr,"DataPlot2D::DrawDatas type non connu\n");
289 }
290 }
291 plot->replot();
292}
293
294void DataPlot2D::plot_data(double data_x, double data_y, int index) {
295 if (index < d_y.count()) {
296 if (datas_first_update.at(index) == false) {
297 // Shift y array left and assign new value to y[view_size/refresh_rate-1].
298 for (int j = 0; j < view_size / refresh_rate - 1; j++)
299 d_y.at(index)[j] = d_y.at(index)[j + 1];
300 for (int j = 0; j < view_size / refresh_rate - 1; j++)
301 d_x.at(index)[j] = d_x.at(index)[j + 1];
302 d_y.at(index)[(int)(view_size / refresh_rate) - 1] = data_y;
303 d_x.at(index)[(int)(view_size / refresh_rate) - 1] = data_x;
304 } else {
305 for (int j = 0; j <= view_size / refresh_rate - 1; j++)
306 d_y.at(index)[j] = data_y;
307 for (int j = 0; j <= view_size / refresh_rate - 1; j++)
308 d_x.at(index)[j] = data_x;
309 datas_first_update[index] = false;
310 }
311 }
312}
313
314// context menu
315void DataPlot2D::mousePressEvent(QMouseEvent *event) {
316 if (event->button() == Qt::RightButton) {
317
318 QMenu *menu = new QMenu("nom", plot);
319 // ajout des actions
320 QAction *reset_zoom, *set_view_size, *action;
321
322 reset_zoom = menu->addAction("reset zoom");
323 menu->addSeparator();
324
325 set_view_size = menu->addAction(QString("set view size (%1s)").arg(view_size));
326
327 appendmenu(menu);
328 action = execmenu(plot, menu, event->globalPos());
329 delete menu;
330
331 if (action == reset_zoom) {
332 // zoom to original size
333 plot->setAxisScale(QwtPlot::yLeft, ymin_orig, ymax_orig);
334 plot->setAxisScale(QwtPlot::xBottom, xmin_orig, xmax_orig);
335 }
336
337 if (action == set_view_size) {
338 bool ok;
339 float new_view_size = QInputDialog::getInt(
340 plot, QString("Set view size (%1)").arg(plot->title().text()),
341 tr("Value (s):"), view_size, 1, 65535, 10, &ok);
342 if (ok == true) {
343 for (int i = 0; i < datas->count(); i++) {
344 if (new_view_size > view_size) {//get last samples and expand
345 double *buf =(double *)malloc(new_view_size / refresh_rate * sizeof(double));
346 memcpy(&buf[(int)(new_view_size / refresh_rate)-(int)(view_size / refresh_rate)], d_x[i], (view_size / refresh_rate) * sizeof(double));
347 free(d_x[i]);
348 d_x[i] = buf;
349
350 buf =(double *)malloc(new_view_size / refresh_rate * sizeof(double));
351 memcpy(&buf[(int)(new_view_size / refresh_rate)-(int)(view_size / refresh_rate)], d_y[i], (view_size / refresh_rate) * sizeof(double));
352 free(d_y[i]);
353 d_y[i] = buf;
354
355 for (int j=0;j<(int)(new_view_size/refresh_rate)-(int)(view_size/refresh_rate);j++) {
356 d_x.at(i)[j] = d_x.at(i)[(int)(new_view_size/refresh_rate)-(int)(view_size/refresh_rate)+1];
357 d_y.at(i)[j] = d_y.at(i)[(int)(new_view_size/refresh_rate)-(int)(view_size/refresh_rate)+1];
358 }
359 } else {//get last samples
360 double *buf =(double *)malloc(new_view_size / refresh_rate * sizeof(double));
361 memcpy(buf, &d_x[i][(int)(view_size / refresh_rate)-(int)(new_view_size / refresh_rate)],(new_view_size / refresh_rate) * sizeof(double));
362 free(d_x[i]);
363 d_x[i] = buf;
364
365 buf =(double *)malloc(new_view_size / refresh_rate * sizeof(double));
366 memcpy(buf, &d_y[i][(int)(view_size / refresh_rate) -(int)(new_view_size / refresh_rate)],(new_view_size / refresh_rate) * sizeof(double));
367 free(d_y[i]);
368 d_y[i] = buf;
369 }
370 datas->at(i)->setRawSamples(d_x.at(i), d_y.at(i), new_view_size / refresh_rate);
371 }
372 view_size = new_view_size;
373 }
374 }
375 }
376}
Note: See TracBrowser for help on using the repository browser.