-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathplot.cpp
306 lines (237 loc) · 9.49 KB
/
plot.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
#include "plot.h"
#include "curvedata.h"
#include "signaldata.h"
#include <qwt_plot_grid.h>
#include <qwt_plot_layout.h>
#include <qwt_plot_canvas.h>
#include <qwt_plot_marker.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_directpainter.h>
#include <qwt_curve_fitter.h>
#include <qwt_painter.h>
#include <qevent.h>
class Canvas: public QwtPlotCanvas //定义Canvas画布类
{
public:
Canvas( QwtPlot *plot = NULL ):
QwtPlotCanvas( plot )
{
// The backing store is important, when working with widget
// overlays ( f.e rubberbands for zooming ).
// Here we don't have them and the internal
// backing store of QWidget is good enough.
setPaintAttribute( QwtPlotCanvas::BackingStore, false );
setBorderRadius( 10 );
if ( QwtPainter::isX11GraphicsSystem() )
{
#if QT_VERSION < 0x050000
// Even if not liked by the Qt development, Qt::WA_PaintOutsidePaintEvent
// works on X11. This has a nice effect on the performance.
setAttribute( Qt::WA_PaintOutsidePaintEvent, true );
#endif
// Disabling the backing store of Qt improves the performance
// for the direct painter even more, but the canvas becomes
// a native window of the window system, receiving paint events
// for resize and expose operations. Those might be expensive
// when there are many points and the backing store of
// the canvas is disabled. So in this application
// we better don't disable both backing stores.
if ( testPaintAttribute( QwtPlotCanvas::BackingStore ) )
{
setAttribute( Qt::WA_PaintOnScreen, true );
setAttribute( Qt::WA_NoSystemBackground, true );
}
}
setupPalette();
}
private:
void setupPalette()
{
QPalette pal = palette();
#if QT_VERSION >= 0x040400
QLinearGradient gradient;
gradient.setCoordinateMode( QGradient::StretchToDeviceMode );
gradient.setColorAt( 0.0, QColor( 0, 49, 110 ) );
gradient.setColorAt( 1.0, QColor( 0, 87, 174 ) );
pal.setBrush( QPalette::Window, QBrush( gradient ) );
#else
pal.setBrush( QPalette::Window, QBrush( color ) );
#endif
// QPalette::WindowText is used for the curve color
// 设置曲线的颜色
pal.setColor( QPalette::WindowText, Qt::yellow );
setPalette( pal );
}
};
Plot::Plot( QWidget *parent ): //定义Plot类的构造函数
QwtPlot( parent ),
d_paintedPoints( 0 ), //初始化Plot类的部分数据成员
d_interval( 0.0, 10.0 ),
d_timerId( -1 )
{
d_directPainter = new QwtPlotDirectPainter();
setAutoReplot( false );
setCanvas( new Canvas() );
plotLayout()->setAlignCanvasToScales( true );
setAxisTitle( QwtPlot::xBottom, "Time [s]" );
setAxisScale( QwtPlot::xBottom, d_interval.minValue(), d_interval.maxValue() );
setAxisScale( QwtPlot::yLeft, -200.0, 200.0 );
/* 画网格 */
QwtPlotGrid *grid = new QwtPlotGrid();
grid->setPen( Qt::gray, 0.0, Qt::DotLine );
grid->enableX( true );
grid->enableXMin( true );
grid->enableY( true );
grid->enableYMin( false );
grid->attach( this );
/* 画X-Y轴直线*/
d_origin = new QwtPlotMarker();
d_origin->setLineStyle( QwtPlotMarker::Cross ); //Crosshair十字光标
d_origin->setValue( d_interval.minValue() + d_interval.width() / 2.0, 0.0 );
d_origin->setLinePen( Qt::gray, 0.0, Qt::DashLine );
d_origin->attach( this );
/* 新建绘制曲线PlotCurve类对象 */
d_curve = new QwtPlotCurve();
d_curve->setStyle( QwtPlotCurve::Lines );
d_curve->setPen( canvas()->palette().color( QPalette::WindowText ) );
d_curve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
d_curve->setPaintAttribute( QwtPlotCurve::ClipPolygons, false );
d_curve->setData( new CurveData() ); //实例化一个曲线数据CurveData类对象,并将其设置为绘制曲线对象的数据
d_curve->attach( this );
}
Plot::~Plot()
{
delete d_directPainter;
}
void Plot::start()
{
//为定时器提供更高精度的clock
d_clock.start();
//启动定时器,设置定时器事件产生的间隔为10mS
d_timerId = startTimer( 10 );
}
/* 重绘 */
void Plot::replot()
{
//用法:static_cast < type-id > ( expression )
//该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。
//将QwtSeriesData指针类型显示强制转换为CurveData指针类型
//CurveData类继承自QwtSeriesData类
CurveData *data = static_cast<CurveData *>( d_curve->data() );
data->values().lock();
QwtPlot::replot();
/* d_paintedPoints变量记录了,已经绘制的容器中点的个数 */
d_paintedPoints = data->size();
data->values().unlock();
}
/* 设置显示区间的长度,单位:秒,并重绘 */
void Plot::setIntervalLength( double interval )
{
if ( interval > 0.0 && interval != d_interval.width() )
{
//设置区间的最大值
d_interval.setMaxValue( d_interval.minValue() + interval );
//设置X轴的比例
setAxisScale( QwtPlot::xBottom, d_interval.minValue(), d_interval.maxValue() );
//重绘
replot();
}
}
/* 更新曲线,在定时器事件中周期性调用 */
void Plot::updateCurve()
{
CurveData *data = static_cast<CurveData *>( d_curve->data() );
data->values().lock();
const int numPoints = data->size();
if ( numPoints > d_paintedPoints )
{
/* WA_PaintOnScreen属性,指示窗口部件想要直接画在屏幕上 */
const bool doClip = !canvas()->testAttribute( Qt::WA_PaintOnScreen );
if ( doClip ) //如果窗口部件不是要直接画在屏幕上
{
/*
Depending on the platform setting a clip might be an important
performance issue. F.e. for Qt Embedded this reduces the
part of the backing store that has to be copied out - maybe
to an unaccelerated frame buffer device.
*/
const QwtScaleMap xMap = canvasMap( d_curve->xAxis() );
const QwtScaleMap yMap = canvasMap( d_curve->yAxis() );
QRectF br = qwtBoundingRect( *data,
d_paintedPoints - 1, numPoints - 1 );
const QRect clipRect = QwtScaleMap::transform( xMap, yMap, br ).toRect();
/* 设置增量式画家的剪切区域 */
d_directPainter->setClipRegion( clipRect );
}
/* 使用增量式画家,绘制一系列点 */
/*
* 由此可以看出,如果没有缩放绘图比例,紧紧增加了一系列点,则不会调用replot函数,而是
* 调用增量式绘图函数,这样可以更高效
*/
d_directPainter->drawSeries( d_curve, d_paintedPoints - 1, numPoints - 1 );
/*
* 变量d_paintedPoints记录了,上次容器中的元素数量,
* 再次绘制时,从上次的最后一个元素+1的地方开始增量式绘制
*/
d_paintedPoints = numPoints;
}
data->values().unlock();
}
/* 增加区间,并重绘:当一屏数据显示完成,需要重头显示的时候调用 */
void Plot::incrementInterval()
{
/* 设置区间 */
d_interval = QwtInterval( d_interval.maxValue(),
d_interval.maxValue() + d_interval.width() );
CurveData *data = static_cast<CurveData *>( d_curve->data() );
/* 清除x轴坐标小于区间最小值的点,这种做法,可能会清除一部分还没有绘制的点 */
data->values().clearStaleValues( d_interval.minValue() );
// To avoid, that the grid is jumping, we disable
// the autocalculation of the ticks and shift them
// manually instead.
/* 设置x轴刻度 */
QwtScaleDiv scaleDiv = axisScaleDiv( QwtPlot::xBottom );
scaleDiv.setInterval( d_interval );
for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
{
QList<double> ticks = scaleDiv.ticks( i );
for ( int j = 0; j < ticks.size(); j++ )
ticks[j] += d_interval.width();
scaleDiv.setTicks( i, ticks );
}
setAxisScaleDiv( QwtPlot::xBottom, scaleDiv );
/* 设置十字交叉线的位置 */
d_origin->setValue( d_interval.minValue() + d_interval.width() / 2.0, 0.0 );
d_paintedPoints = 0;
replot();
}
void Plot::timerEvent( QTimerEvent *event ) //定时器事件
{
if ( event->timerId() == d_timerId )
{
updateCurve(); //更新曲线
const double elapsed = d_clock.elapsed() / 1000.0; //Plot对象启动定时器以来,经过了多少秒
if ( elapsed > d_interval.maxValue() ) //如果已经过去的时间大于区间的最大值,则更新区间
incrementInterval(); //增加区间
return;
}
QwtPlot::timerEvent( event );
}
void Plot::resizeEvent( QResizeEvent *event ) //改变尺寸事件
{
d_directPainter->reset(); //窗口尺寸发生改变,复位直接画家对象
QwtPlot::resizeEvent( event );
}
void Plot::showEvent( QShowEvent * ) //显示事件
{
replot();
}
bool Plot::eventFilter( QObject *object, QEvent *event ) //事件滤波器
{
if ( object == canvas() &&
event->type() == QEvent::PaletteChange )
{
d_curve->setPen( canvas()->palette().color( QPalette::WindowText ) );
}
return QwtPlot::eventFilter( object, event );
}