Introduction
Why am I creating a simulation of an aircraft's flight instruments? The reason is because I grew up surrounded by jet and turboprop aircrafts and I've always wanted to replicate the dynamics of aircrafts on software.
The North American Aviation F-86 Sabre
The F-86 Sabre is a fighter aircraft. Sabre is best known for its Korean War against the Soviet MiG-15. There have been more than 7,800 aircrafts between 1949 and 1956 and were by far the most-produced Western jet fighters, with a total production of all variants at 9,860 units. Variants were built in Canada and Australia. The Canadair Sabre added another 1,815 airframes, and the significantly redesigned CAC Sabre (sometimes known as the Avon Sabre or CAC CA-27), had a production run of 112.
Specifications (F-86A):
Armament: |
Six .50-cal. machine guns and eight 5-in. rockets or 2,000 lbs. of bombs |
Engine: |
One General Electric J47 turbojet of 5,200 lbs. thrust |
Maximum speed: |
685 mph |
Cruising speed: |
540 mph |
Range: |
1,200 miles |
Combat ceiling: |
49,000 ft. |
Span: |
37 ft. 1 in. |
Length: |
37 ft. 6 in. |
Height: |
14 ft. 8 in. |
Weight: |
13,791 lbs. loaded |
Crew: |
One |
Fast Forwarding a Bit
Designing apps in Microsoft Visual C++ 2005 Express Edition is pretty straight forward. Point this, click that, presto! Place it on the form. Components on the form align to rectangular grids, giving your apps a symmetric look.
Fast forwarding a bit, we've created a Windows Form, placed labels and pictureboxes on the form to have all these controls respond to mouse clicks, and key events, we have to put some code into it. So we double-click on any given control, place some code in that controls' event method.
KeyDown Event
The KeyDown
event is called upon when a key is pressed down. The flight instruments and gauges respond accordingly by displaying the changes on the instruments. So when the user presses down the left, right, up or down key - the instruments and gauges will display tilting or banking.
private: System::Void KeyDown(System::Object^ sender,
System::Windows::Forms::KeyEventArgs^ e)
{
switch(e->KeyCode)
{
case System::Windows::Forms::Keys::Enter :
break;
case System::Windows::Forms::Keys::PageUp :
rpm =rpm + delta_rpm; filter_rpm();
break;
case System::Windows::Forms::Keys::PageDown :
rpm =rpm - delta_rpm; filter_rpm();
break;
case System::Windows::Forms::Keys::Up :
alpha_tail =alpha_tail - delta_elevator;
if (alpha_tail < -max_alpha_tail) alpha_tail =
-max_alpha_tail;
break;
case System::Windows::Forms::Keys::Down :
alpha_tail =alpha_tail + delta_elevator;
if (alpha_tail > max_alpha_tail) alpha_tail =
max_alpha_tail;
break;
case System::Windows::Forms::Keys::Left :
alpha_aileron =alpha_aileron - (delta_aileron*rTrim);
if (alpha_aileron < -max_aileron) alpha_aileron =
-max_aileron;
break;
case System::Windows::Forms::Keys::Right :
alpha_aileron =alpha_aileron + (delta_aileron*rTrim);
if (alpha_aileron >max_aileron) alpha_aileron =
max_aileron;
break;
case System::Windows::Forms::Keys::End :
revertToInitialParameters(); ;
break; case System::Windows::Forms::Keys::Home : initialize_variables();
break;
case System::Windows::Forms::Keys::R
:; break; case System::Windows::Forms::Keys::P
:; break; case System::Windows::Forms::Keys::E
:; break; case System::Windows::Forms::Keys::A
:;break; case System::Windows::Forms::Keys::S
:;break; case System::Windows::Forms::Keys::W
:; break; case System::Windows::Forms::Keys::B
:;break; case 102:; break; case 104:;break; case System::Windows::Forms::Keys::L:set_level();
break; case System::Windows::Forms::Keys::T: set_trim();
break; case System::Windows::Forms::Keys::Tab:debugon=-debugon;break;
}
}
MouseMove Event
The MouseMove
event is called upon when the mouse is dragged or moved. The flight instruments and gauges respond accordingly by displaying the changes on the instruments. So when the mouse moves up, down, left, right, - the instruments and gauges will display the movements accordingly.
private: System::Void pictureBox1_MouseMove
(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e)
{
label26->Text=L"mx= "+System::Convert::ToString(e->X)+L"
my= "+System::Convert::ToString(e->Y);
oldMouseX = mouseX; oldMouseY = mouseY;
mouseX = e->X; mouseY = e->Y;
if (mouseNavigationEnabled)
{
if ((mouseX - oldMouseX) > 0)
{
alpha_aileron =alpha_aileron + (delta_aileron*10);
if (alpha_aileron >max_aileron)
alpha_aileron = max_aileron; }
else if ((mouseX - oldMouseX) < 0)
{
alpha_aileron =alpha_aileron - (delta_aileron*10);
if (alpha_aileron < -max_aileron)
alpha_aileron = -max_aileron; }
if ((mouseY - oldMouseY) > 0)
{
alpha_tail =alpha_tail + (delta_elevator*10);
if (alpha_tail > max_alpha_tail)
alpha_tail = max_alpha_tail; }
else if ((mouseY - oldMouseY) < 0)
{
alpha_tail =alpha_tail - (delta_elevator*10);
if (alpha_tail < -max_alpha_tail)
alpha_tail = -max_alpha_tail; }
}
}
The pictureBox1_Paint Event
The pictureBox1_Paint
event is called upon to draw the gauges and instruments.
private: System::Void pictureBox1_Paint(System::Object^ sender,
System::Windows::Forms::PaintEventArgs^ e)
{
horizon_bar(e);
horizon_bar(e);
alt_needle(e);
t_and_b_needle(e);
hsi_heading(e);
rofc_needle(e);
fuelflow_value(e);
rpm_needle( e);
draw_rpm( rpm_x,rpm_y, e);
rpm_needle( e);
rpmmeter(e);
draw_n(e);
draw_mach( );
draw_tas(e);
draw_ias(ias_x, ias_y, e);
ias_needle(e);
airspeed(e);
hdi(e);
draw_altitude(alt_x, alt_y,e);
alt_needle(e);
altimeter(e);
t_and_b_needle( e);
t_and_b( e);
draw_heading( e);
hsi_heading( e);
hsi(e);
draw_hdi(e);
draw_rofc(roc_x, roc_y , e);
rofc_needle(e);
rofc( e);
draw_fuelflow(e);
fuelflow_value(e);
ias_needle(e); d
raw_circles(e);
}
The draw_rpm( ) Method
The draw_rpm( )
method is called upon to display when the user increases the throttle to give it more gas, the needle in the RPM meter will respond accordingly.
void gaugeSimulator::draw_rpm(int x, int y , PaintEventArgs^ e)
{
label25->Text=L"rpmx="+System::Convert::ToString(rpm_x)+L",
rpmy= "+System::Convert::ToString(rpm_y)+L",
x="+System::Convert::ToString(x)+L", y="+ System::Convert::ToString(y);
rpm_last =rpm;
e->Graphics->DrawLine( lineColor, rpm_x, rpm_y, x, y);
rpm_lastx =x;
rpm_lasty =y;
}
The rpm_needle( PaintEventArgs^ e)
The rpm_needle( PaintEventArgs^ e)
method is called upon to draw the needle of an RPM meter.
void gaugeSimulator::rpm_needle( PaintEventArgs^ e)
{
double x, y ;
double z ;
z =rpm * (max_engine_rpm/100) * 16 * PI/10;
x =rpm_x + (double)( 0.9 * rpm_r * Math::Cos(13*PI/10 - z) );
y =rpm_y - (double)( 0.9 * rpm_r * Math::Sin(13*PI/10 - z) * gAR );
label24->Text=L"rpmx="+System::Convert::ToString(rpm_x)+L",
rpmy= "+System::Convert::ToString(rpm_y)+L",
x="+System::Convert::ToString(rpm_lastx)+L",
y="+ System::Convert::ToString(rpm_lasty);
if ( (Math::Abs(rpm_lastx - x) > 0) || (Math::Abs(rpm_lasty - y) > 0) )
{
e->Graphics->DrawLine( lineColor, rpm_x, rpm_y, rpm_lastx, rpm_lasty);
draw_rpm((int)x, (int)y+17,e);
label29->Text=System::Convert::ToString(Math::Round
(rpm_last * max_engine_rpm,2));
}
}
Please also have a look at C# Avionic Instrument Controls[^].