周濤
摘要:為了實(shí)現(xiàn)了飛機(jī)姿態(tài)指引儀(ADI)的仿真,在Visual C++開發(fā)環(huán)境下采用GDI+以及雙緩沖技術(shù),利用GDI+中的繪圖坐標(biāo)面變換和區(qū)域裁剪特性,實(shí)現(xiàn)了ADI的俯仰刻度帶和橫滾刻度帶的動態(tài)仿真。其中通過DGI+的API實(shí)現(xiàn)了圖形和文本的反走樣,使顯示效果更加逼真。同時利用雙緩沖技術(shù),解決了Win32 環(huán)境下圖形頻繁重繪時出現(xiàn)的閃爍現(xiàn)象。提出了一種不同于虛擬儀表開發(fā)工具的仿真實(shí)現(xiàn)方法,實(shí)踐證明此種方法具有低成本高效率的優(yōu)勢,為電子飛行儀表的仿真提供了可以借鑒的思路和方法。
關(guān)鍵詞:姿態(tài)指引儀; GDI+; 雙緩沖; 坐標(biāo)面變換
中圖分類號: TN911?34 文獻(xiàn)標(biāo)識碼: 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
姿態(tài)指引儀(Attitude Direction Indicator?ADI)是電子飛行儀表系統(tǒng)(EFIS)的重要組成部分,為飛行員提供飛機(jī)的俯仰、滾轉(zhuǎn)、側(cè)滑等飛行參數(shù)。對電子飛行儀表仿真通常采用VAPS或GL Studio等虛擬儀表工具,此種方法的優(yōu)點(diǎn)是開發(fā)效率高,有封裝好的儀表模塊可以直接復(fù)用,但其也存在采購和培訓(xùn)成本過高,靈活性較差等缺點(diǎn),本文提出在Visual C++ 環(huán)境下,采用基于DGI+與雙緩沖技術(shù)實(shí)現(xiàn)姿態(tài)指引儀的仿真,為電子飛行儀表的仿真提供了一種新思路。
1 GDI+與雙緩沖
GDI+是Windows XP中的一個子系統(tǒng),是一組通過C++類實(shí)現(xiàn)的應(yīng)用程序編程接口,對以前Windows版本中的GDI進(jìn)行了優(yōu)化,并添加了許多新的功能。利用GDI+函數(shù),不必使用句柄或者設(shè)備描述表,只需簡單地創(chuàng)建一個圖形對象(Graphics),以熟悉的面向?qū)ο蟮木幊谭绞秸{(diào)用它的方法即可。Graphics對象是GDI+的核心,正如設(shè)備描述表是GDI的核心一樣,但是兩者也存在著本質(zhì)的不同。前者使用基于句柄的編程方法而后者使用面向?qū)ο蟮木幊谭椒?。在GDI中,所有與繪圖有關(guān)的繪圖對象必須選入指定設(shè)備描述表中(使用SelectObject函數(shù)),才能被指定的設(shè)備描述表所使用。而在GDI+中,只需把這些繪圖對象作為一個參數(shù)傳遞給圖形對象Graphics方法調(diào)用即可,它可以通過參數(shù)使用多種Pen和Brush繪圖,而不是與特定的筆和畫刷聯(lián)系在一起,極大地提高了繪圖效率。
雙緩沖是圖形圖像處理編程過程中的一種基本技術(shù),即在內(nèi)存中創(chuàng)建一個與屏幕繪圖區(qū)域一致的對象,先將圖形繪制到內(nèi)存中的這個對象上,再一次性將這個對象上的圖形拷貝到屏幕上,所以不會占用顯示系統(tǒng)的開銷,大大加快繪圖的速度,可以避免窗體頻繁重繪時出現(xiàn)閃爍現(xiàn)象。
2 ADI組成
ADI主要由滾轉(zhuǎn)刻度帶、俯仰刻度帶、滾轉(zhuǎn)游標(biāo)、側(cè)滑指示符以及飛機(jī)符號等組成,具體定義如下:
橫滾刻度帶:位置固定不動,指示飛機(jī)的橫滾角度。
橫滾指針:在橫滾刻度帶上滑行,指示當(dāng)前橫滾角。
側(cè)滑指示符:位于橫滾指針下方,相對其做橫向移動,移動幅度正比于橫向加速度。
俯仰刻度帶:在指定可見范圍內(nèi)上下滾動顯示,指示當(dāng)前俯仰角。
飛機(jī)符號:位置固定不動,指示飛機(jī)相對于地平線的姿態(tài)。
ADI示意圖如圖1所示。
圖1 ADI示意圖
3 GDI+中雙緩沖的實(shí)現(xiàn)
雙緩沖實(shí)現(xiàn)過程如下:
(1) 建立內(nèi)存畫布;
(2) 在內(nèi)存中創(chuàng)建與畫布一致的緩沖區(qū);
(3) 在緩沖區(qū)繪圖;
(4) 將緩沖區(qū)位圖拷貝到前臺。
以下給出在Visual C++環(huán)境中的實(shí)現(xiàn)代碼:
void CADISimDlg::OnPaint()
{
Graphics graphics(m_hWnd); //聲明GDI+繪圖對象
CRect rect;
GetClientRect(&rect); //獲取窗口客戶區(qū)大小
Point center(rect.CenterPoint().x, rect.CenterPoint().y);
//窗口客戶區(qū)中心坐標(biāo)
Bitmap CatchImage(rect.Width(), rect.Height());
//聲明內(nèi)存畫布
Graphics buffer(&CatchImage);
//聲明與內(nèi)存畫布一致的緩沖區(qū)
OnDrawADI(center.X, center.Y , buffer);
//調(diào)用ADI繪制函數(shù),并將客戶區(qū)中心坐標(biāo)和圖形對象作為參數(shù)
buffer.SetSmoothingMode(SmoothingModeAntiAlias);
//設(shè)置圖形和文本反走樣模式
buffer.SetTextRenderingHint(TextRenderingHintAntiAlias);
graphics.DrawImage(&CatchImage, 0, 0);
//將緩沖區(qū)位圖拷貝到前臺
}
4 ADI仿真中應(yīng)用的GDI+關(guān)鍵技術(shù)
4.1 平移變換與旋轉(zhuǎn)變換
平移變換將圖形繪制所在的坐標(biāo)面平移一個增量(dx,dy):
Status TranslateTransform (REAL dx, REAL dy, MatrixOrder order = MatrixOrderPrepend);即:[x′=x+d,y′=y+d];相當(dāng)于進(jìn)行如下矩陣變換:
[x′y′=xydxdy]
旋轉(zhuǎn)變換將圖形繪制所在的坐標(biāo)面旋轉(zhuǎn)一個角度α,單位為度,有:
Status RotateTransform ( REAL angle, MatrixOrder order = MatrixOrderPrepend);
即:[x′=xcosα-ysinα,y′=xsinα+ycosα]相當(dāng)于進(jìn)行如下矩陣變換:
[x′y′=cosα-sinαsinαcosαxy]
圖形的旋轉(zhuǎn)以坐標(biāo)面原點(diǎn)為中心,所以需將坐標(biāo)面原點(diǎn)平移到圖形的中心。在ADI仿真中可以通過平移變換將窗口坐標(biāo)原點(diǎn)從左上角移至中心,作為俯仰刻度帶以及滾轉(zhuǎn)游標(biāo)的旋轉(zhuǎn)中心,通過旋轉(zhuǎn)變換不必進(jìn)行三角函數(shù)運(yùn)算就可實(shí)現(xiàn)圖形的旋轉(zhuǎn)。
4.2 區(qū)域裁剪
Status SetClip(const Region* region, CombineMode combineMode = CombineModeReplace);
GDI+區(qū)域裁剪可實(shí)現(xiàn)特定局部重繪,在提高繪圖效率的同時可將區(qū)域之外的圖形進(jìn)行裁剪,在ADI仿真中,可利用這一特性實(shí)現(xiàn)俯仰刻度帶在限制區(qū)域內(nèi)的滾動顯示效果。
5 ADI的仿真實(shí)現(xiàn)
以下以俯仰刻度帶和橫滾刻度為例來說明,GDI+在ADI仿真中的應(yīng)用。
5.1 俯仰刻度帶
利用GDI+的區(qū)域裁剪特性,將俯仰刻度帶的更新區(qū)域限制在±20的刻度范圍內(nèi),同時利用坐標(biāo)面的旋轉(zhuǎn)變換實(shí)現(xiàn)俯仰刻度帶的與橫滾游標(biāo)的同步旋轉(zhuǎn),主要實(shí)現(xiàn)算法及代碼如下:
void CADISimDlg:: OnDrawADI(int x, int y, Graphics& buffer)
{……
buffer.ResetTransform(); //重置坐標(biāo)面
buffer.TranslateTransform(x, y);
//平移變換,將坐標(biāo)原點(diǎn)平移至客戶區(qū)中心
buffer.RotateTransform(RollAngle); //旋轉(zhuǎn)變換,將橫滾角
作為參數(shù),實(shí)現(xiàn)俯仰刻度帶和橫滾游標(biāo)繞坐標(biāo)原點(diǎn)旋轉(zhuǎn)
Rect rect(?Wm, ?Hm, PitchScaleWidth, PitchScaleHeight);
Region rgn(rect);
buffer.ResetClip(); //重置裁剪區(qū)
buffer.SetClip(&rgn, CombineModeReplace); //設(shè)置裁剪區(qū)
//以下為計算俯仰刻度帶第一個刻度線位置和刻度值的算法
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))
//建立繪圖對象并設(shè)置其屬性
Pen pen(Color::WhiteSmoke, 2);
SolidBrush brush(Color::WhiteSmoke);
FontFamily fontFamily(L" futura medium ");
Font font(&fontFamily, 19, FontStyleBold, UnitPixel);
//根據(jù)計算的第一個刻度線位置和刻度值,在循環(huán)中從下至上完成刻度帶的繪制
for (int L = 0; L <= PitchTicksCount + 1; L++) //
{ ……
//此處根據(jù)顯示要求繪制刻度線和刻度值,代碼從略
tickValue += TicksDistance; //更新刻度值
tickPosition ?= TickPixels; //更新刻度顯示位置
} }
5.2 橫滾刻度帶
橫滾刻度帶的繪制主要利用GDI+的坐標(biāo)系旋轉(zhuǎn),選定起始點(diǎn),然后在循環(huán)中完成繪制,
這樣可以避免在傳統(tǒng)GDI作圖中的角度計算,繪制效率更高。主要實(shí)現(xiàn)代碼如下:
void CADISimDlg:: OnDrawADI(int x, int y, Graphics& buffer)
{……
//因?yàn)闄M滾刻度帶固定不動,所以需重置裁剪區(qū)和坐標(biāo)面
buffer.ResetClip();
buffer.ResetTransform();
buffer.TranslateTransform(x, y);
buffer.RotateTransform(340);
//以短刻度線為例,在循環(huán)中完成刻度帶的繪制
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為程序運(yùn)行后的效果。
圖2 ADI初始畫面
圖3 俯仰角和滾轉(zhuǎn)角輸入后的ADI畫面
6 結(jié) 語
本文在Visual C++開發(fā)環(huán)境下,利用GDI+以及雙緩沖技術(shù),實(shí)現(xiàn)了電子飛行儀表中姿態(tài)指示儀的仿真,GDI+中的新特性極大地提高了繪圖效率和顯示效果,為電子飛行儀表系統(tǒng)仿真提供了可借鑒的思路和方法。
參考文獻(xiàn)
[1] 馬銀才,張興媛.航空機(jī)載電子設(shè)備[M].北京:清華大學(xué)出版社,2007.
[2] 周鳴揚(yáng),趙景亮.精通GDI+編程[M].北京:清華大學(xué)出版社,2003.
[3] [美]李普曼,[美]拉茹瓦,[美]穆.C++ Primer中文版[M].李師賢,譯.4版.北京:人民郵電出版社,2006.
[4] [美]PROSISE Jeff. MFC Windows程序設(shè)計[M].北京博彥科技發(fā)展有限公司,譯.2版.北京:清華大學(xué)出版社,2007.
[5] 車森,劉海硯,劉輝,等.GDI+在電子地圖可視化中的應(yīng)用[J].測繪科學(xué),2008(1):226?227.
[6] 張仁忠,常明志,許德新.利用MFC實(shí)現(xiàn)雙緩存機(jī)制改善圖形的顯示效果[J].應(yīng)用科技,2005(1):47?48.
* TicksDistance);
double tickValue = floor((pitchAngle ? PitchRange/2)/TicksDistance)*TicksDistance ;
float tickPosition = (float)floor(Hm + PitchScaleHeight/PitchRange*(pitchAngle ? tickValue))
//建立繪圖對象并設(shè)置其屬性
Pen pen(Color::WhiteSmoke, 2);
SolidBrush brush(Color::WhiteSmoke);
FontFamily fontFamily(L" futura medium ");
Font font(&fontFamily, 19, FontStyleBold, UnitPixel);
//根據(jù)計算的第一個刻度線位置和刻度值,在循環(huán)中從下至上完成刻度帶的繪制
for (int L = 0; L <= PitchTicksCount + 1; L++) //
{ ……
//此處根據(jù)顯示要求繪制刻度線和刻度值,代碼從略
tickValue += TicksDistance; //更新刻度值
tickPosition ?= TickPixels; //更新刻度顯示位置
} }
5.2 橫滾刻度帶
橫滾刻度帶的繪制主要利用GDI+的坐標(biāo)系旋轉(zhuǎn),選定起始點(diǎn),然后在循環(huán)中完成繪制,
這樣可以避免在傳統(tǒng)GDI作圖中的角度計算,繪制效率更高。主要實(shí)現(xiàn)代碼如下:
void CADISimDlg:: OnDrawADI(int x, int y, Graphics& buffer)
{……
//因?yàn)闄M滾刻度帶固定不動,所以需重置裁剪區(qū)和坐標(biāo)面
buffer.ResetClip();
buffer.ResetTransform();
buffer.TranslateTransform(x, y);
buffer.RotateTransform(340);
//以短刻度線為例,在循環(huán)中完成刻度帶的繪制
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為程序運(yùn)行后的效果。
圖2 ADI初始畫面
圖3 俯仰角和滾轉(zhuǎn)角輸入后的ADI畫面
6 結(jié) 語
本文在Visual C++開發(fā)環(huán)境下,利用GDI+以及雙緩沖技術(shù),實(shí)現(xiàn)了電子飛行儀表中姿態(tài)指示儀的仿真,GDI+中的新特性極大地提高了繪圖效率和顯示效果,為電子飛行儀表系統(tǒng)仿真提供了可借鑒的思路和方法。
參考文獻(xiàn)
[1] 馬銀才,張興媛.航空機(jī)載電子設(shè)備[M].北京:清華大學(xué)出版社,2007.
[2] 周鳴揚(yáng),趙景亮.精通GDI+編程[M].北京:清華大學(xué)出版社,2003.
[3] [美]李普曼,[美]拉茹瓦,[美]穆.C++ Primer中文版[M].李師賢,譯.4版.北京:人民郵電出版社,2006.
[4] [美]PROSISE Jeff. MFC Windows程序設(shè)計[M].北京博彥科技發(fā)展有限公司,譯.2版.北京:清華大學(xué)出版社,2007.
[5] 車森,劉海硯,劉輝,等.GDI+在電子地圖可視化中的應(yīng)用[J].測繪科學(xué),2008(1):226?227.
[6] 張仁忠,常明志,許德新.利用MFC實(shí)現(xiàn)雙緩存機(jī)制改善圖形的顯示效果[J].應(yīng)用科技,2005(1):47?48.
* TicksDistance);
double tickValue = floor((pitchAngle ? PitchRange/2)/TicksDistance)*TicksDistance ;
float tickPosition = (float)floor(Hm + PitchScaleHeight/PitchRange*(pitchAngle ? tickValue))
//建立繪圖對象并設(shè)置其屬性
Pen pen(Color::WhiteSmoke, 2);
SolidBrush brush(Color::WhiteSmoke);
FontFamily fontFamily(L" futura medium ");
Font font(&fontFamily, 19, FontStyleBold, UnitPixel);
//根據(jù)計算的第一個刻度線位置和刻度值,在循環(huán)中從下至上完成刻度帶的繪制
for (int L = 0; L <= PitchTicksCount + 1; L++) //
{ ……
//此處根據(jù)顯示要求繪制刻度線和刻度值,代碼從略
tickValue += TicksDistance; //更新刻度值
tickPosition ?= TickPixels; //更新刻度顯示位置
} }
5.2 橫滾刻度帶
橫滾刻度帶的繪制主要利用GDI+的坐標(biāo)系旋轉(zhuǎn),選定起始點(diǎn),然后在循環(huán)中完成繪制,
這樣可以避免在傳統(tǒng)GDI作圖中的角度計算,繪制效率更高。主要實(shí)現(xiàn)代碼如下:
void CADISimDlg:: OnDrawADI(int x, int y, Graphics& buffer)
{……
//因?yàn)闄M滾刻度帶固定不動,所以需重置裁剪區(qū)和坐標(biāo)面
buffer.ResetClip();
buffer.ResetTransform();
buffer.TranslateTransform(x, y);
buffer.RotateTransform(340);
//以短刻度線為例,在循環(huán)中完成刻度帶的繪制
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為程序運(yùn)行后的效果。
圖2 ADI初始畫面
圖3 俯仰角和滾轉(zhuǎn)角輸入后的ADI畫面
6 結(jié) 語
本文在Visual C++開發(fā)環(huán)境下,利用GDI+以及雙緩沖技術(shù),實(shí)現(xiàn)了電子飛行儀表中姿態(tài)指示儀的仿真,GDI+中的新特性極大地提高了繪圖效率和顯示效果,為電子飛行儀表系統(tǒng)仿真提供了可借鑒的思路和方法。
參考文獻(xiàn)
[1] 馬銀才,張興媛.航空機(jī)載電子設(shè)備[M].北京:清華大學(xué)出版社,2007.
[2] 周鳴揚(yáng),趙景亮.精通GDI+編程[M].北京:清華大學(xué)出版社,2003.
[3] [美]李普曼,[美]拉茹瓦,[美]穆.C++ Primer中文版[M].李師賢,譯.4版.北京:人民郵電出版社,2006.
[4] [美]PROSISE Jeff. MFC Windows程序設(shè)計[M].北京博彥科技發(fā)展有限公司,譯.2版.北京:清華大學(xué)出版社,2007.
[5] 車森,劉海硯,劉輝,等.GDI+在電子地圖可視化中的應(yīng)用[J].測繪科學(xué),2008(1):226?227.
[6] 張仁忠,常明志,許德新.利用MFC實(shí)現(xiàn)雙緩存機(jī)制改善圖形的顯示效果[J].應(yīng)用科技,2005(1):47?48.