基于GDI+与双缓冲的飞机姿态指示仪(ADI)仿真实现

2014-08-20 18:00周涛
现代电子技术 2014年16期

周涛

摘要:为了实现了飞机姿态指引仪(ADI)的仿真,在Visual C++开发环境下采用GDI+以及双缓冲技术,利用GDI+中的绘图坐标面变换和区域裁剪特性,实现了ADI的俯仰刻度带和横滚刻度带的动态仿真。其中通过DGI+的API实现了图形和文本的反走样,使显示效果更加逼真。同时利用双缓冲技术,解决了Win32 环境下图形频繁重绘时出现的闪烁现象。提出了一种不同于虚拟仪表开发工具的仿真实现方法,实践证明此种方法具有低成本高效率的优势,为电子飞行仪表的仿真提供了可以借鉴的思路和方法。

关键词:姿态指引仪; GDI+; 双缓冲; 坐标面变换

中图分类号: TN911?34 文献标识码: A 文章编号: 1004?373X(2014)16?0071?03

Simulation of airplane attitude direction indicator based on GDI+ and double buffer

ZHOU Tao

(AVIC Xian Aircraft Industry (Group) Company Ltd., Xian 710089, China)

Abstract:In order to implement the simulation of the airplane attitude direction indicator (ADI), the dynamic simulation of the pitch scale and roll scale was achieved by utilizing the GDI+ and the double buffer technique in the Visual C++ development environment, as well as the drawing coordinate plane transformation and region clip property of GDI+, in which the graph and text anti?aliasing was implemented by API in GDI+, so that make the display more realistic. The flicker phenomenon appearing when the graphs were redrawn frequently in the Win32 platform was eliminated by means of the double buffer technology. A simulation method unlike the virtual instrument development tool is proposed in this paper. The practical application has proved that this method has the advantages of low cost and high efficiency. It provided an idea and method for simulation of the electronic flight instruments.

Keywords: attitude direction indicator; GDI+; double buffer; coordinate plane transformation

姿态指引仪(Attitude Direction Indicator?ADI)是电子飞行仪表系统(EFIS)的重要组成部分,为飞行员提供飞机的俯仰、滚转、侧滑等飞行参数。对电子飞行仪表仿真通常采用VAPS或GL Studio等虚拟仪表工具,此种方法的优点是开发效率高,有封装好的仪表模块可以直接复用,但其也存在采购和培训成本过高,灵活性较差等缺点,本文提出在Visual C++ 环境下,采用基于DGI+与双缓冲技术实现姿态指引仪的仿真,为电子飞行仪表的仿真提供了一种新思路。

1 GDI+与双缓冲

GDI+是Windows XP中的一个子系统,是一组通过C++类实现的应用程序编程接口,对以前Windows版本中的GDI进行了优化,并添加了许多新的功能。利用GDI+函数,不必使用句柄或者设备描述表,只需简单地创建一个图形对象(Graphics),以熟悉的面向对象的编程方式调用它的方法即可。Graphics对象是GDI+的核心,正如设备描述表是GDI的核心一样,但是两者也存在着本质的不同。前者使用基于句柄的编程方法而后者使用面向对象的编程方法。在GDI中,所有与绘图有关的绘图对象必须选入指定设备描述表中(使用SelectObject函数),才能被指定的设备描述表所使用。而在GDI+中,只需把这些绘图对象作为一个参数传递给图形对象Graphics方法调用即可,它可以通过参数使用多种Pen和Brush绘图,而不是与特定的笔和画刷联系在一起,极大地提高了绘图效率。

双缓冲是图形图像处理编程过程中的一种基本技术,即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,所以不会占用显示系统的开销,大大加快绘图的速度,可以避免窗体频繁重绘时出现闪烁现象。

2 ADI组成

ADI主要由滚转刻度带、俯仰刻度带、滚转游标、侧滑指示符以及飞机符号等组成,具体定义如下:

横滚刻度带:位置固定不动,指示飞机的横滚角度。

横滚指针:在横滚刻度带上滑行,指示当前横滚角。

侧滑指示符:位于横滚指针下方,相对其做横向移动,移动幅度正比于横向加速度。

俯仰刻度带:在指定可见范围内上下滚动显示,指示当前俯仰角。

飞机符号:位置固定不动,指示飞机相对于地平线的姿态。

ADI示意图如图1所示。

图1 ADI示意图

3 GDI+中双缓冲的实现

双缓冲实现过程如下:

(1) 建立内存画布;

(2) 在内存中创建与画布一致的缓冲区;

(3) 在缓冲区绘图;

(4) 将缓冲区位图拷贝到前台。

以下给出在Visual C++环境中的实现代码:

void CADISimDlg::OnPaint()

{

Graphics graphics(m_hWnd); //声明GDI+绘图对象

CRect rect;

GetClientRect(&rect); //获取窗口客户区大小

Point center(rect.CenterPoint().x, rect.CenterPoint().y);

//窗口客户区中心坐标

Bitmap CatchImage(rect.Width(), rect.Height());

//声明内存画布

Graphics buffer(&CatchImage);

//声明与内存画布一致的缓冲区

OnDrawADI(center.X, center.Y , buffer);

//调用ADI绘制函数,并将客户区中心坐标和图形对象作为参数

buffer.SetSmoothingMode(SmoothingModeAntiAlias);

//设置图形和文本反走样模式

buffer.SetTextRenderingHint(TextRenderingHintAntiAlias);

graphics.DrawImage(&CatchImage, 0, 0);

//将缓冲区位图拷贝到前台

}

4 ADI仿真中应用的GDI+关键技术

4.1 平移变换与旋转变换

平移变换将图形绘制所在的坐标面平移一个增量(dx,dy):

Status TranslateTransform (REAL dx, REAL dy, MatrixOrder order = MatrixOrderPrepend);即:[x′=x+d,y′=y+d];相当于进行如下矩阵变换:

[x′y′=xydxdy]

旋转变换将图形绘制所在的坐标面旋转一个角度α,单位为度,有:

Status RotateTransform ( REAL angle, MatrixOrder order = MatrixOrderPrepend);

即:[x′=xcosα-ysinα,y′=xsinα+ycosα]相当于进行如下矩阵变换:

[x′y′=cosα-sinαsinαcosαxy]

图形的旋转以坐标面原点为中心,所以需将坐标面原点平移到图形的中心。在ADI仿真中可以通过平移变换将窗口坐标原点从左上角移至中心,作为俯仰刻度带以及滚转游标的旋转中心,通过旋转变换不必进行三角函数运算就可实现图形的旋转。

4.2 区域裁剪

Status SetClip(const Region* region, CombineMode combineMode = CombineModeReplace);

GDI+区域裁剪可实现特定局部重绘,在提高绘图效率的同时可将区域之外的图形进行裁剪,在ADI仿真中,可利用这一特性实现俯仰刻度带在限制区域内的滚动显示效果。

5 ADI的仿真实现

以下以俯仰刻度带和横滚刻度为例来说明,GDI+在ADI仿真中的应用。

5.1 俯仰刻度带

利用GDI+的区域裁剪特性,将俯仰刻度带的更新区域限制在±20的刻度范围内,同时利用坐标面的旋转变换实现俯仰刻度带的与横滚游标的同步旋转,主要实现算法及代码如下:

void CADISimDlg:: OnDrawADI(int x, int y, Graphics& buffer)

{……

buffer.ResetTransform(); //重置坐标面

buffer.TranslateTransform(x, y);

//平移变换,将坐标原点平移至客户区中心

buffer.RotateTransform(RollAngle); //旋转变换,将横滚角

作为参数,实现俯仰刻度带和横滚游标绕坐标原点旋转

Rect rect(?Wm, ?Hm, PitchScaleWidth, PitchScaleHeight);

Region rgn(rect);

buffer.ResetClip(); //重置裁剪区

buffer.SetClip(&rgn, CombineModeReplace); //设置裁剪区

//以下为计算俯仰刻度带第一个刻度线位置和刻度值的算法

double TicksDistance = PitchRange/PitchTicksCount;

float TickPixels = float((PitchScaleHeight/PitchRange)

* TicksDistance);

double tickValue = floor((pitchAngle ? PitchRange/2)/TicksDistance)*TicksDistance ;

float tickPosition = (float)floor(Hm + PitchScaleHeight/PitchRange*(pitchAngle ? tickValue))

//建立绘图对象并设置其属性

Pen pen(Color::WhiteSmoke, 2);

SolidBrush brush(Color::WhiteSmoke);

FontFamily fontFamily(L" futura medium ");

Font font(&fontFamily, 19, FontStyleBold, UnitPixel);

//根据计算的第一个刻度线位置和刻度值,在循环中从下至上完成刻度带的绘制

for (int L = 0; L <= PitchTicksCount + 1; L++) //

{ ……

//此处根据显示要求绘制刻度线和刻度值,代码从略

tickValue += TicksDistance; //更新刻度值

tickPosition ?= TickPixels; //更新刻度显示位置

} }

5.2 横滚刻度带

横滚刻度带的绘制主要利用GDI+的坐标系旋转,选定起始点,然后在循环中完成绘制,

这样可以避免在传统GDI作图中的角度计算,绘制效率更高。主要实现代码如下:

void CADISimDlg:: OnDrawADI(int x, int y, Graphics& buffer)

{……

//因为横滚刻度带固定不动,所以需重置裁剪区和坐标面

buffer.ResetClip();

buffer.ResetTransform();

buffer.TranslateTransform(x, y);

buffer.RotateTransform(340);

//以短刻度线为例,在循环中完成刻度带的绘制

for (int r = 0; r < 4 ; r++)

{

buffer.FillRectangle(&SolidBrush(Color::White), Rect(0, ?RollArcRadius ? RollShortTickLengh, 2, RollShortTickLengh));

if (r == 1)

{ buffer.RotateTransform(10);

} buffer.RotateTransform(10);

} }

图2和图3为程序运行后的效果。

图2 ADI初始画面

图3 俯仰角和滚转角输入后的ADI画面

6 结 语

本文在Visual C++开发环境下,利用GDI+以及双缓冲技术,实现了电子飞行仪表中姿态指示仪的仿真,GDI+中的新特性极大地提高了绘图效率和显示效果,为电子飞行仪表系统仿真提供了可借鉴的思路和方法。

参考文献

[1] 马银才,张兴媛.航空机载电子设备[M].北京:清华大学出版社,2007.

[2] 周鸣扬,赵景亮.精通GDI+编程[M].北京:清华大学出版社,2003.

[3] [美]李普曼,[美]拉茹瓦,[美]穆.C++ Primer中文版[M].李师贤,译.4版.北京:人民邮电出版社,2006.

[4] [美]PROSISE Jeff. MFC Windows程序设计[M].北京博彦科技发展有限公司,译.2版.北京:清华大学出版社,2007.

[5] 车森,刘海砚,刘辉,等.GDI+在电子地图可视化中的应用[J].测绘科学,2008(1):226?227.

[6] 张仁忠,常明志,许德新.利用MFC实现双缓存机制改善图形的显示效果[J].应用科技,2005(1):47?48.

* TicksDistance);

double tickValue = floor((pitchAngle ? PitchRange/2)/TicksDistance)*TicksDistance ;

float tickPosition = (float)floor(Hm + PitchScaleHeight/PitchRange*(pitchAngle ? tickValue))

//建立绘图对象并设置其属性

Pen pen(Color::WhiteSmoke, 2);

SolidBrush brush(Color::WhiteSmoke);

FontFamily fontFamily(L" futura medium ");

Font font(&fontFamily, 19, FontStyleBold, UnitPixel);

//根据计算的第一个刻度线位置和刻度值,在循环中从下至上完成刻度带的绘制

for (int L = 0; L <= PitchTicksCount + 1; L++) //

{ ……

//此处根据显示要求绘制刻度线和刻度值,代码从略

tickValue += TicksDistance; //更新刻度值

tickPosition ?= TickPixels; //更新刻度显示位置

} }

5.2 横滚刻度带

横滚刻度带的绘制主要利用GDI+的坐标系旋转,选定起始点,然后在循环中完成绘制,

这样可以避免在传统GDI作图中的角度计算,绘制效率更高。主要实现代码如下:

void CADISimDlg:: OnDrawADI(int x, int y, Graphics& buffer)

{……

//因为横滚刻度带固定不动,所以需重置裁剪区和坐标面

buffer.ResetClip();

buffer.ResetTransform();

buffer.TranslateTransform(x, y);

buffer.RotateTransform(340);

//以短刻度线为例,在循环中完成刻度带的绘制

for (int r = 0; r < 4 ; r++)

{

buffer.FillRectangle(&SolidBrush(Color::White), Rect(0, ?RollArcRadius ? RollShortTickLengh, 2, RollShortTickLengh));

if (r == 1)

{ buffer.RotateTransform(10);

} buffer.RotateTransform(10);

} }

图2和图3为程序运行后的效果。

图2 ADI初始画面

图3 俯仰角和滚转角输入后的ADI画面

6 结 语

本文在Visual C++开发环境下,利用GDI+以及双缓冲技术,实现了电子飞行仪表中姿态指示仪的仿真,GDI+中的新特性极大地提高了绘图效率和显示效果,为电子飞行仪表系统仿真提供了可借鉴的思路和方法。

参考文献

[1] 马银才,张兴媛.航空机载电子设备[M].北京:清华大学出版社,2007.

[2] 周鸣扬,赵景亮.精通GDI+编程[M].北京:清华大学出版社,2003.

[3] [美]李普曼,[美]拉茹瓦,[美]穆.C++ Primer中文版[M].李师贤,译.4版.北京:人民邮电出版社,2006.

[4] [美]PROSISE Jeff. MFC Windows程序设计[M].北京博彦科技发展有限公司,译.2版.北京:清华大学出版社,2007.

[5] 车森,刘海砚,刘辉,等.GDI+在电子地图可视化中的应用[J].测绘科学,2008(1):226?227.

[6] 张仁忠,常明志,许德新.利用MFC实现双缓存机制改善图形的显示效果[J].应用科技,2005(1):47?48.

* TicksDistance);

double tickValue = floor((pitchAngle ? PitchRange/2)/TicksDistance)*TicksDistance ;

float tickPosition = (float)floor(Hm + PitchScaleHeight/PitchRange*(pitchAngle ? tickValue))

//建立绘图对象并设置其属性

Pen pen(Color::WhiteSmoke, 2);

SolidBrush brush(Color::WhiteSmoke);

FontFamily fontFamily(L" futura medium ");

Font font(&fontFamily, 19, FontStyleBold, UnitPixel);

//根据计算的第一个刻度线位置和刻度值,在循环中从下至上完成刻度带的绘制

for (int L = 0; L <= PitchTicksCount + 1; L++) //

{ ……

//此处根据显示要求绘制刻度线和刻度值,代码从略

tickValue += TicksDistance; //更新刻度值

tickPosition ?= TickPixels; //更新刻度显示位置

} }

5.2 横滚刻度带

横滚刻度带的绘制主要利用GDI+的坐标系旋转,选定起始点,然后在循环中完成绘制,

这样可以避免在传统GDI作图中的角度计算,绘制效率更高。主要实现代码如下:

void CADISimDlg:: OnDrawADI(int x, int y, Graphics& buffer)

{……

//因为横滚刻度带固定不动,所以需重置裁剪区和坐标面

buffer.ResetClip();

buffer.ResetTransform();

buffer.TranslateTransform(x, y);

buffer.RotateTransform(340);

//以短刻度线为例,在循环中完成刻度带的绘制

for (int r = 0; r < 4 ; r++)

{

buffer.FillRectangle(&SolidBrush(Color::White), Rect(0, ?RollArcRadius ? RollShortTickLengh, 2, RollShortTickLengh));

if (r == 1)

{ buffer.RotateTransform(10);

} buffer.RotateTransform(10);

} }

图2和图3为程序运行后的效果。

图2 ADI初始画面

图3 俯仰角和滚转角输入后的ADI画面

6 结 语

本文在Visual C++开发环境下,利用GDI+以及双缓冲技术,实现了电子飞行仪表中姿态指示仪的仿真,GDI+中的新特性极大地提高了绘图效率和显示效果,为电子飞行仪表系统仿真提供了可借鉴的思路和方法。

参考文献

[1] 马银才,张兴媛.航空机载电子设备[M].北京:清华大学出版社,2007.

[2] 周鸣扬,赵景亮.精通GDI+编程[M].北京:清华大学出版社,2003.

[3] [美]李普曼,[美]拉茹瓦,[美]穆.C++ Primer中文版[M].李师贤,译.4版.北京:人民邮电出版社,2006.

[4] [美]PROSISE Jeff. MFC Windows程序设计[M].北京博彦科技发展有限公司,译.2版.北京:清华大学出版社,2007.

[5] 车森,刘海砚,刘辉,等.GDI+在电子地图可视化中的应用[J].测绘科学,2008(1):226?227.

[6] 张仁忠,常明志,许德新.利用MFC实现双缓存机制改善图形的显示效果[J].应用科技,2005(1):47?48.