Click here to Skip to main content
15,867,488 members
Articles / Desktop Programming / Win32

Animated Controls using graphic layers

Rate me:
Please Sign up or sign in to vote.
4.92/5 (28 votes)
25 Feb 2015CPOL9 min read 57.6K   6.1K   49   25
This article discusses how to create animated controls using graphic layers.

Abstract Table of Contents

This article presents a detailed discussion of using multiple graphic layers to create complex dynamic Windows Forms controls.

Often programmers are faced with significant challenges when implementing a complex graphic object. When multiple graphics layers are incorporated, the complexity can be significantly reduced. An additional benefit, significant execution time reduction, may also be obtained.

Introduction Table of Contents

Attitude Indicator P-20 R-20 Attitude Indicator Attitude Indicator P20 R20

Recently, while developing a demonstration of an interthread messaging system, I needed to create a simulation of a number of aircraft cockpit instruments. I really didn't need to create the instrument graphics, but it was a challenge that I couldn't resist. One of these instruments is known as an attitude indicator.

This instrument displays both pitch (nose up and down) and roll (wing up and down). In modern aircraft, this instrument has been replaced to a large extent by the electronic Attitude and Heading Reference System (AHRS). However, the attitude indicator can be driven by only two inputs (pitch and roll). Therefore, by using the attitude indicator, I can simulate the aircraft's attitude without resorting to a simulation of the AHRS.

The attitude indicator is a composite control. A small symbolic aircraft is fixed within the instrument. The top half of the instrument dial is blue, representing the sky; and the bottom half is brown, representing the ground. A bank index at the top of the instrument shows the angle of bank marked on the banking scale with lines and triangles that represent 0°, 10°, 20°, 30°, 45°, and 60°. A pitch index at the center of the instrument shows the amount of pitch. The symbolic aircraft moves up and down over the pitch index while the roll is represented by a clockwise or counterclockwise rotation of the sky-ground bank index.

In the following discussions, properties that are specified by the developer are displayed in BoldMixedCase text. Variables, used internally by the software, are displayed in italicized_lowercase text with underscores separating words.

Table of Contents

The symbol Table of Contents returns the reader to the top of the Table of Contents.

Visual Properties Table of Contents

The AttitudeIndicator control has properties that affect the user's visual image. The developer specifies the control's top-left corner by dragging the control from the ToolBox to a position on the form. This position becomes ( 0, 0 ) in the control's graphic environment.

The height of the AttitudeIndicator control is the same as the width of the control. The width of the control is specified using the resizing handles of the Visual Studio Designer [^] or by setting a new value for the control's Size [^] property or by specifying a value for the ControlWidth property. The control's width is limited to multiples of 50 from 150 to 500. If the control is resized, the values of all of the control's components are recomputed based upon the control's new width.

The CurrentPitch and CurrentRoll properties are the means by which pitch and roll, respectively, are communicated to the control. A change in either value will cause the display to be updated. Both CurrentPitch and CurrentRoll properties accept decimal values.

Implementation Table of Contents

With the exception of the background and the symbolic aircraft, the control's graphic components are dynamic and reflect the aircraft's instantaneous pitch and roll. This makes the attitude indicator a relatively complex instrument to simulate. However, if the graphic is broken down into separate graphic layers, the complexity can be reduced and the responsiveness of the control can be significantly increased.

For the attitude indicator I chose seven graphic layers:

Background      The instrument body layer.
Stationary      The symbolic aircraft layer.
SkyGround      The blue/brown layer.
Pitch      The pitch scale layer.
TopBottom      The caps that appear at the top and bottom of the SkyGround layer.
Roll      The bank index (roll) scale layer.
Indicator      The layer onto which the SkyGround, Pitch, TopBottom, and Roll layers are combined.

With the exception of the Indicator layer, each layer is created once and is recreated only on a resize event. It is only during the drawing of the Indicator layer that existing SkyGround, Pitch, TopBottom, and Roll layers are combined (translated and rotated) to create the aircraft attitude image. In the OnPaint event handler, the Background, Indicator, and Stationary layers are combined.

Layering Table of Contents

Readers are reminded that, in the graphics environment, objects that are drawn later override objects that were drawn earlier. This is true when layers are created or combined. So the drawing order for layers is:

Background
Indicator
SkyGround
Pitch
TopBottom
Roll
Stationary

Initialization Table of Contents

The attitude indicator is implemented as a Windows Forms Control. The dimensions of all of the graphics are determined by the control's width that can vary from 150 pixels to 500 pixels in width, incremented by 50 pixels. The OnCreateControl and OnResize event handlers invoke revise_geometry_values. That method recomputes the variables used to draw the control's components. It also forces all layers to be redrawn.

Background Layer Table of Contents

Background Layer

The Background layer is the bottommost layer displayed in the control. The width and height of the Background layer equal the width and height of the control. Drawing the Background layer is composed of the following steps:

1.  Draw and fill a rounded rectangle
2.  Draw and fill an instrument circle
3.  Draw an inner circle, inside of which all other components are drawn

Once drawn, unless the AttitudeIndicator control is resized, the Background layer is never redrawn.

Probably the only step of interest is drawing a rounded rectangle.

C#
// ************************************ rounded_rectangle_path

/// <summary>
/// computes the GraphicsPath of a rounded rectangle
/// </summary>
/// <param name="x">
/// x coordinate of the upper left corner of the rectangle
/// </param>
/// <param name="y">
/// y coordinate of the upper left corner of the rectangle
/// </param>
/// <param name="width">
/// width of the rectangle
/// </param>
/// <param name="height">
/// height of the rectangle
/// </param>
/// <param name="radius">
/// radius of the circle that defines the rounded corner
/// </param>
/// <returns>
/// the GraphicsPath that defines the rounded rectangle
/// </returns>
GraphicsPath rounded_rectangle_path ( int x,
                                      int y,
                                      int width,
                                      int height,
                                      int radius )
    {
    int           diameter = 2 * radius;
    GraphicsPath  path = new GraphicsPath ( );

    path.StartFigure ( );
    path.AddArc ( ( x + width - diameter ),
                  ( y + height - diameter ),
                  diameter,
                  diameter,
                  0.0F,
                  90.0F );
    path.AddArc ( x,
                  ( y + height - diameter ),
                  diameter,
                  diameter,
                  90.0F,
                  90.0F );
    path.AddArc ( x,
                  y,
                  diameter,
                  diameter,
                  180.0F,
                  90.0F );
    path.AddArc ( ( x + width - diameter ),
                  y,
                  diameter,
                  diameter,
                  270.0F,
                  90.0F );
    path.CloseFigure ( );

    return ( path );
    }

// ************************************ rounded_rectangle_path

/// <summary>
/// computes the GraphicsPath of a rounded rectangle
/// </summary>
/// <param name="rectangle">
/// the rectangle for which rounding is desired
/// </param>
/// <param name="radius">
/// radius of the circle that defines the rounded corner
/// </param>
/// <returns>
/// the GraphicsPath that defines the rounded rectangle
/// </returns>
GraphicsPath rounded_rectangle_path ( Rectangle  rectangle,
                                      int        radius )
    {

    return ( rounded_rectangle_path ( rectangle.X,
                                      rectangle.Y,
                                      rectangle.Width,
                                      rectangle.Height,
                                      radius ) );
    }

Stationary Layer Table of Contents

Stationary Layer

The Stationary layer contains those components of the AttitudeIndicator that must appear on top of all other AttitudeIndicator components. These include the symbolic aircraft and the fixed roll pointer.

The image is created from thirteen points, drawn or filled in various ways. The order in which the Stationary layer components are drawn is important.

Once drawn, unless the AttitudeIndicator control is resized, the Stationary layer is never redrawn.

SkyGround Layer Table of Contents

SkyGround Layer

The SkyGround layer contains the visual depiction of the sky and ground.

The sky is drawn from the top to the bottom, using a Linear Gradient Brush. The ground is drawn as two rectangles, both of the same color.

The two rectangles are separated by a distance equal to the ground portion of the Pitch layer. This allows the Pitch layer to be moved up and down as the aircraft pitch varies.

Once drawn, unless the AttitudeIndicator control is resized, the SkyGround layer is never redrawn.

Pitch Layer Table of Contents

Pitch Layer

The Pitch layer depicts the pitch index at the center of the instrument. It shows the amount of aircraft pitch.

The Pitch layer contains a pitch scale and a portion of the ground. These two components fit into the gap between the ground rectangles of the SkyGround layer.

Once drawn, unless the AttitudeIndicator control is resized, the Pitch layer is never redrawn.

TopBottom Layer Table of Contents

TopBottom Layer

The TopBottom layer compliments the SkyGround layer by providing upper and lower caps to that layer. It is purely cosmetic in nature.

Once drawn, unless the AttitudeIndicator control is resized, the TopBottom layer is never redrawn.

Roll Layer Table of Contents

Roll Layer

The Roll layer depicts the bank index at the top of the instrument. It shows the angle of bank marked on the banking scale with lines and triangles that represent 0°, 10°, 20°, 30°, 45°, and 60° of aircraft roll.

Once drawn, unless the AttitudeIndicator control is resized, the Roll layer is never redrawn.

Indicator Layer Table of Contents

Indicator Layer

The Indicator layer provides the canvas for the dynamic effects of aircraft pitch and roll. Whenever pitch or roll change, the Indicator layer is redrawn.

In the Indicator layer, each of the SkyGround, Pitch, TopBottom, and Roll layers are combined (translated and rotated) to create the aircraft attitude image.

The steps taken to create this image in the Indicator layer are:

  1. A clipping region is defined. This prevents any subordinate layer from overflowing the control bounds (set in the OnCreateControl and OnResize event handlers).
  2. The SkyGround layer image (bitmap) is rotated to the aircraft's CurrentRoll and drawn into the Indicator layer.
  3. The x- and y-coordinates for the Pitch layer are computed from the aircraft's CurrentPitch; the Pitch layer image (bitmap) is rotated to the aircraft's CurrentRoll; the origin of the Indicator layer is translated to the x- and y-coordinates computed earlier; the rotated Pitch layer image is drawn into the Indicator layer.
  4. The TopBottom layer image (bitmap) is rotated to the aircraft's CurrentRoll and drawn into the Indicator layer.
  5. The Roll layer image (bitmap) is rotated to the aircraft's CurrentRoll and drawn into the Indicator layer.

The method used to rotate the bitmaps was:

C#
// ********************************************* rotate_bitmap

// http://stackoverflow.com/questions/5172906/
//     c-rotating-graphics

/// <summary>
/// rotate a bitmap by a specified angle, in degrees
/// </summary>
/// <param name="bitmap">
/// bitmap to rotate
/// </param>
/// <param name="angle">
/// angle, in degrees, by which to rotate bitmap
/// </param>
/// <returns>
/// the rotated bitmap
/// </returns>
Bitmap rotate_bitmap ( Bitmap  bitmap,
                       float   angle )
    {
    Bitmap return_bitmap;
                                // create empty bitmap to hold
                                // rotated image
    return_bitmap = new Bitmap ( bitmap.Width,
                                 bitmap.Height );
                                // make a graphic object from
                                // the empty bitmap
    using ( Graphics graphic = Graphics.FromImage (
                                            return_bitmap ) )
        {
                                // translate rotation point to
                                // center of image
        graphic.TranslateTransform (
                            ( float ) bitmap.Width / 2.0F,
                            ( float ) bitmap.Height / 2.0F );
                                // rotate image
        graphic.RotateTransform ( angle );
                                //move image back
        graphic.TranslateTransform (
                            -( float ) bitmap.Width / 2.0F,
                            -( float ) bitmap.Height / 2.0F );
                                // draw passed in image onto
                                // graphic object
        graphic.DrawImage ( bitmap, new Point ( 0, 0 ) );

        graphic.ResetTransform ( );
        }

    return ( return_bitmap );
    }

Demonstration Table of Contents

Test Attitude Indicator

The demonstration program depicts how the AttitudeIndicator control reacts to changing pitch and roll. It also allows choosing which layers will be displayed.

When the program is launched, the Background, Indicator, and Stationary layers are displayed. If it is desired that layers that make up the Indicator layer be displayed, the Indicator layer checkbox must be cleared. This is required because the Indicator layer is a composite layer, made up of the SkyGround, Pitch, TopBottom, and Roll layers.

Conclusion Table of Contents

This article has presented a detailed discussion of using multiple graphic layers to create complex dynamic Windows Forms controls.

References Table of Contents

Aircraft Cockpit Instruments Table of Contents

For interested readers, I have included the following two links. A complete set of FAA Aviation Handbooks and Manuals can be found at the FAA site [^].

Programming Table of Contents

Development Environment Table of Contents

The AttitudeIndicator control was developed in the following environment:

Microsoft Windows 7 Professional Service Pack 1
Microsoft Visual Studio 2008 Professional
Microsoft .Net Framework Version 3.5 SP1
Microsoft Visual C# 2008

Downloads Table of Contents

In addition to the AttitudeIndicator control (the main topic of this article), the downloads also include a number of additional aircraft cockpit controls:

  • AirspeedIndicator
  • AltitudeIndicator
  • HeadingIndicator
  • RPMIndicator
  • VerticalSpeedIndicator

All of these controls use multiple graphic layers to achieve their effects. However, the AttitudeIndicator control is, by far, the most complex and thus was chosen for this article.

History Table of Contents

02/23/2015       Original article
02/25/2015       Modified article formatting

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
In 1964, I was in the US Coast Guard when I wrote my first program. It was written in RPG (note no suffixing numbers). Programs and data were entered using punched cards. Turnaround was about 3 hours. So much for the "good old days!"

In 1970, when assigned to Washington DC, I started my MS in Mechanical Engineering. I specialized in Transportation. Untold hours in statistical theory and practice were required, forcing me to use the university computer and learn the FORTRAN language, still using punched cards!

In 1973, I was employed by the Norfolk VA Police Department as a crime analyst for the High Intensity Target program. There, I was still using punched cards!

In 1973, I joined Computer Sciences Corporation (CSC). There, for the first time, I was introduced to a terminal with the ability to edit, compile, link, and test my programs on-line. CSC also gave me the opportunity to discuss technical issues with some of the brightest minds I've encountered during my career.

In 1975, I moved to San Diego to head up an IR&D project, BIODAB. I returned to school (UCSD) and took up Software Engineering at the graduate level. After BIODAB, I headed up a team that fixed a stalled project. I then headed up one of the two most satisfying projects of my career, the Automated Flight Operations Center at Ft. Irwin, CA.

I left Anteon Corporation (the successor to CSC on a major contract) and moved to Pensacola, FL. For a small company I built their firewall, given free to the company's customers. An opportunity to build an air traffic controller trainer arose. This was the other most satisfying project of my career.

Today, I consider myself capable.

Comments and Discussions

 
Praisewonderful Pin
Southmountain11-May-22 10:38
Southmountain11-May-22 10:38 
GeneralRe: wonderful Pin
gggustafson11-May-22 13:28
mvagggustafson11-May-22 13:28 
QuestionThank you Pin
Member 109267517-Apr-20 8:53
Member 109267517-Apr-20 8:53 
QuestionHow to add all avionic control to winform Pin
Member 142173977-Apr-19 19:26
Member 142173977-Apr-19 19:26 
AnswerRe: How to add all avionic control to winform Pin
gggustafson15-Jul-19 8:52
mvagggustafson15-Jul-19 8:52 
QuestionA big thank you Pin
Old Bloke Coder12-Feb-18 4:20
Old Bloke Coder12-Feb-18 4:20 
QuestionVery well done Pin
MitchellBaldwin19-Jan-18 4:26
MitchellBaldwin19-Jan-18 4:26 
AnswerRe: Very well done Pin
gggustafson21-Jan-18 5:16
mvagggustafson21-Jan-18 5:16 
PraiseVery nice write Thank you Pin
moolcup03107-Aug-17 17:56
moolcup03107-Aug-17 17:56 
GeneralRe: Very nice write Thank you Pin
gggustafson10-Aug-17 5:42
mvagggustafson10-Aug-17 5:42 
Praisevery nice Pin
BillW3319-Apr-17 6:42
professionalBillW3319-Apr-17 6:42 
GeneralRe: very nice Pin
gggustafson29-Apr-17 4:58
mvagggustafson29-Apr-17 4:58 
QuestionThanks For Tutorial of Attitude Pin
Siddaram K.Patil29-Jun-15 20:35
Siddaram K.Patil29-Jun-15 20:35 
AnswerRe: Thanks For Tutorial of Attitude Pin
gggustafson30-Jun-15 4:30
mvagggustafson30-Jun-15 4:30 
Thank you for your kind comments.

Although I will provide you with my email address (in a separate email), I would like to suggest that you use the Quick Answers of the Code Project web site. You gain two advantages: other as or more competent members will see your question and provide an answer; other members may be able to answer a question that I cannot.

Glad I could help.
Gus Gustafson

GeneralRe: Thanks For Tutorial of Attitude Pin
Siddaram K.Patil2-Jul-15 19:44
Siddaram K.Patil2-Jul-15 19:44 
GeneralVery nice Pin
Steve Messer26-Feb-15 5:48
Steve Messer26-Feb-15 5:48 
GeneralRe: Very nice Pin
gggustafson26-Feb-15 8:31
mvagggustafson26-Feb-15 8:31 
GeneralMy vote of 5 Pin
fredatcodeproject26-Feb-15 4:46
professionalfredatcodeproject26-Feb-15 4:46 
GeneralRe: My vote of 5 Pin
gggustafson26-Feb-15 8:32
mvagggustafson26-Feb-15 8:32 
GeneralNice job! Pin
Ravi Bhavnani25-Feb-15 13:55
professionalRavi Bhavnani25-Feb-15 13:55 
GeneralRe: Nice job! Pin
gggustafson25-Feb-15 17:06
mvagggustafson25-Feb-15 17:06 
QuestionImpressive Pin
phil.o25-Feb-15 7:50
professionalphil.o25-Feb-15 7:50 
AnswerRe: Impressive Pin
gggustafson25-Feb-15 8:03
mvagggustafson25-Feb-15 8:03 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun23-Feb-15 17:55
Humayun Kabir Mamun23-Feb-15 17:55 
GeneralRe: My vote of 5 Pin
gggustafson24-Feb-15 4:25
mvagggustafson24-Feb-15 4:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.