datastreamplot.cpp
1 /********************************************************************************
2  * FARSA DataStreamPlot UI *
3  * Copyright (C) 2012-2013 *
4  * Gianluca Massera <emmegian@yahoo.it> *
5  * *
6  * This program is free software; you can redistribute it and/or modify *
7  * it under the terms of the GNU General Public License as published by *
8  * the Free Software Foundation; either version 2 of the License, or *
9  * (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License *
17  * along with this program; if not, write to the Free Software *
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
19  ********************************************************************************/
20 
21 #include "datastreamplot.h"
22 #include "qwt/qwt_plot_grid.h"
23 #include "qwt/qwt_plot_layout.h"
24 #include "qwt/qwt_plot_canvas.h"
25 #include "qwt/qwt_plot_curve.h"
26 #include "qwt/qwt_symbol.h"
27 #include "qwt/qwt_plot_directpainter.h"
28 #include "qwt/qwt_painter.h"
29 #include "qwt/qwt_legend.h"
30 #include "qwt/qwt_legend_label.h"
31 #include <QPaintEngine>
32 
33 namespace farsa {
34 
36 class DataStream: public QwtArraySeriesData<QPointF> {
37 public:
38  DataStream() : QwtArraySeriesData<QPointF>() { };
39  // return the bouding rect of the data
40  virtual QRectF boundingRect() const {
41  if ( d_boundingRect.width() < 0.0 ) {
42  d_boundingRect = qwtBoundingRect( *this );
43  }
44  return d_boundingRect;
45  }
46  virtual QPointF sample(size_t i) const {
47  QPointF f = QwtArraySeriesData<QPointF>::sample(i);
48  return f;
49  }
50  // append a new point to the data stream
51  inline void append( const QPointF &point ) {
52  d_samples += point;
53  }
54  // remove all points from the data stream
55  void clear() {
56  d_samples.clear();
57  d_samples.squeeze();
58  // it invalidate the bounding rect
59  d_boundingRect = QRectF( 0.0, 0.0, -1.0, -1.0 );
60  }
61 };
62 
63 DataStreamPlot::DataStreamPlot( QWidget* parent ) :
64  QwtPlot( parent ),
65  streams(),
66  directPainter(new QwtPlotDirectPainter( this )) {
67 
68  setFrameStyle( QFrame::NoFrame );
69  setLineWidth( 0 );
70 
71  plotLayout()->setAlignCanvasToScales( true );
72 
73  QwtPlotGrid *grid = new QwtPlotGrid;
74  grid->setMajorPen( Qt::gray, 0, Qt::DotLine );
75  grid->attach( this );
76 
77  QwtLegend *legend = new QwtLegend;
78  legend->setDefaultItemMode( QwtLegendData::Checkable );
79  insertLegend( legend, QwtPlot::RightLegend );
80  connect( legend, SIGNAL( checked( const QVariant &, bool, int ) ),
81  SLOT( legendChecked( const QVariant &, bool ) ) );
82 
83  setCanvasBackground( Qt::lightGray );
84 
85  minY = 0;
86  maxY = 1;
87  maxX = 0;
88  windowSize = 100;
89  updatePlot();
90  setAutoReplot( false );
91 }
92 
94  foreach( QwtPlotCurve* curve, streams ) {
95  delete curve;
96  }
97 }
98 
99 int DataStreamPlot::addDataStream( QString name ) {
100  QwtPlotCurve* curve = new QwtPlotCurve( name );
101  curve->setData( new DataStream() );
102  curve->attach( this );
103  curve->setYAxis( QwtPlot::yLeft );
104  showCurve( curve, true );
105  streams.append( curve );
106  return streams.size()-1;
107 }
108 
109 void DataStreamPlot::setDataStreamColor( int streamID, QColor color ) {
110  color.setAlpha( 150 );
111  streams[streamID]->setPen( color );
112  streams[streamID]->setBrush( color );
113 }
114 
115 void DataStreamPlot::appendData( int streamID, float value ) {
116  DataStream* data = static_cast<DataStream*>( streams[streamID]->data() );
117  QPointF point( data->size(), value );
118  data->append( point );
119 
120  // plot the new point just added
121  directPainter->drawSeries( streams[streamID], data->size()-1, data->size()-1 );
122  maxX = qMax( maxX, (float)data->size() );
123  if ( streams[streamID]->isVisible() ) {
124  minY = qMin( minY, value );
125  maxY = qMax( maxY, value );
126  }
127 }
128 
130  setAxisScale( QwtPlot::yLeft, minY, maxY );
131  float max = qMax( windowSize, maxX );
132  float min = qMax( 0.0f, max-windowSize );
133  setAxisScale( QwtPlot::xBottom, min, max );
134  replot();
135 }
136 
137 void DataStreamPlot::legendChecked( const QVariant &itemInfo, bool on ) {
138  QwtPlotItem *plotItem = infoToItem( itemInfo );
139  if ( plotItem ) {
140  showCurve( plotItem, on );
141  if ( !on ) {
142  // when something will be hide, we reset the minY and maxY values
143  minY = 0;
144  maxY = 0;
145  }
146  }
147 }
148 
149 void DataStreamPlot::showCurve( QwtPlotItem *item, bool on ) {
150  item->setVisible( on );
151 
152  QwtLegend *lgd = qobject_cast<QwtLegend *>( legend() );
153 
154  QList<QWidget *> legendWidgets = lgd->legendWidgets( itemToInfo( item ) );
155 
156  if ( legendWidgets.size() == 1 ) {
157  QwtLegendLabel* legendLabel = qobject_cast<QwtLegendLabel*>( legendWidgets[0] );
158  if ( legendLabel ) {
159  legendLabel->setChecked( on );
160  }
161  }
162  replot();
163 }
164 
165 } // end namespace farsa
void updatePlot()
recalculate the x and y scale axis and replot the data
A macro to deprecate functions.
extend QwtArraySeriesData in order to append data incrementally
FARSA_UTIL_TEMPLATE const T max(const T &t1, const U &t2)
Template for max calculation.
Definition: mathutils.h:154
void appendData(int streamID, float value)
append a point to the stream specified
int addDataStream(QString name)
add a new stream to the plot
virtual ~DataStreamPlot()
destructor
FARSA_UTIL_TEMPLATE const T min(const T &t1, const U &t2)
Template for min calculation.
Definition: mathutils.h:136
void setDataStreamColor(int streamID, QColor color)
set the color of the stream specified
DataStreamPlot(QWidget *parent=0)
constructor an empty LiveDataPlot without any data