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

Last change on this file since 236 was 235, checked in by Sanahuja Guillaume, 7 years ago

resolved https://devel.hds.utc.fr/projects/flair/ticket/37

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 printf("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 printf("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.