Click here to Skip to main content
6,630,901 members and growing! (19,113 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » Mobile Development » Applications     Intermediate

Flight Tracker - An Application For Mapping Flight Routes

By Jacob Senecal

An entertaining exploration of .NET Compact Framework Graphics and XML features
VB, Windows, .NET CF, .NET, MobileVS.NET2003, Dev
Posted:30 May 2004
Views:66,182
Bookmarked:24 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
16 votes for this article.
Popularity: 3.90 Rating: 3.24 out of 5
4 votes, 25.0%
1
2 votes, 12.5%
2
4 votes, 25.0%
3
3 votes, 18.8%
4
3 votes, 18.8%
5

Introduction

This program is more an exploration of the Compact Framework than an actual useful application. My first goal was to have some fun while getting away from the everyday "Hello World" type apps that are ordinarily used to illustrate features and techniques. When I was a teenager, I had a friend who was obsessed with airline flight schedules. He would spend countless hours drawing maps of airline routes by hand. They were not terribly useful (unless you were an airline industry analyst), but they were pretty cool to look at.

I decided to create a PocketPC solution for drawing airline maps. The "Flight Tracker", as I dubbed it, would included the ability to enter and maintain data for individual airports, airlines and flights. I limited my map area to North America, and only entered the data for a subset of the Southwest Airlines flight schedule. A comprehensive database would have taken months for data entry or required the purchase of commercial flight databases. This project would require the use of basic .NET form controls, as well as the Graphics interface and .NET XML classes for data storage.

Managing Flight Data

The first task was to compile and manage the data needed to draw flight maps. I created a class, FlightData.vb, to contain all data-related structures, arrays and methods. I prefer to use structures and arrays of structures to hold program data because it makes it so easy to see what you're doing in the code. This arrangement is also very efficient in terms of memory and processor usage. I wanted to store the data in an open, cross-platform format, so I decided to try out the XML class in .NET.

The System.XML.XmlDocument class makes it easy to load and save the contents of XML files. You simply instantiate the XmlDocument object and then call its Load or Save method with the desired filename. The data is stored in XmlNode and XmlAttribute objects within the XmlDocument. Each XmlNode contains a collection of child XmlNodes and a collection of XmlAttributes. I included in each of my structure definitions a method to load a new structure's member values from an XmlNode object and a method to return a new XmlNode containing the member values. Here I've included the simplest of my structures to illustrate this configuration:

Public Structure AirlineStruct
        Dim Airline As String

        Public Sub New(ByRef XmlNode As Xml.XmlNode)
            Dim xAttribute As Xml.XmlAttribute
            For Each xAttribute In XmlNode.Attributes
                Select Case xAttribute.Name
                    Case "Airline"
                        Airline = xAttribute.Value
                End Select
            Next
        End Sub

        Public Function GetXmlNode(ByRef Doc As Xml.XmlDocument) _
              As Xml.XmlNode
            Dim Node As Xml.XmlNode = Doc.CreateNode( _
               Xml.XmlNodeType.Element, "AIRLINE", "")
            Node.Attributes.Append(GetXmlAttribute(Doc, "Airline", Airline))
            Return Node
        End Function
    End Structure

One interesting limitation to the XmlNode and XmlAttribute classes is that they can only be instantiated by an XmlDocument object. This was a little annoying in my case since I had to pass a pointer to the XmlDocument to my structure's GetXmlNode method just for this purpose.

With these methods in place, saving the class's data consists of creating an XmlDocument and adding an XmlNode for each structure stored in the class's arrays. When XmlNodes have all been added, simply call the XmlDocument's Save method.

    Public Sub Save()
        Dim xDoc As New Xml.XmlDocument
        Try
            xDoc.AppendChild(xDoc.CreateElement("FlightData"))
            Dim Flight As FlightStruct
            For Each Flight In Flights
                xDoc.FirstChild.AppendChild(Flight.GetXmlNode(xDoc))
            Next
            Dim Airline As AirlineStruct
            For Each Airline In Airlines
                xDoc.FirstChild.AppendChild(Airline.GetXmlNode(xDoc))
            Next
            Dim Airport As AirportStruct
            For Each Airport In Airports
                xDoc.FirstChild.AppendChild(Airport.GetXmlNode(xDoc))
            Next
            xDoc.Save("\Program Files\Flight Tracker\FlightData.xml")
            HasUnsavedChanges = False
        Catch ex As Exception
            MsgBox("Error saving XML data file.", _
               MsgBoxStyle.Exclamation, "File Error")
        End Try
    End Sub

Note that the all the XmlDocument's other nodes are typically located within the document's first child node, which you must create and add yourself if when assembling the new file's contents.

Loading is easily accomplished by loading the XmlDocument from file and then sequencing through the collection of child nodes, loading each one into the appropriate structure type and adding the structure its corresponding array.

    Public Sub Load()
        Dim xDoc As New Xml.XmlDocument
        Try
            Dim Flight As FlightStruct
            Dim Airline As AirlineStruct
            Dim Airport As AirportStruct
            ReDim Flights(-1)
            ReDim Airlines(-1)
            ReDim Airports(-1)
            xDoc.Load("\Program Files\Flight Tracker\FlightData.xml")
            Dim Root As Xml.XmlNode = xDoc.FirstChild
            Dim Child As Xml.XmlNode
            For Each Child In Root.ChildNodes
                Select Case Child.Name
                    Case "FLIGHT"
                        Flight = New FlightStruct(Child)
                        ReDim Preserve Flights(UBound(Flights) + 1)
                        Flights(UBound(Flights)) = Flight
                    Case "AIRLINE"
                        Airline = New AirlineStruct(Child)
                        ReDim Preserve Airlines(UBound(Airlines) + 1)
                        Airlines(UBound(Airlines)) = Airline
                    Case "AIRPORT"
                        Airport = New AirportStruct(Child)
                        ReDim Preserve Airports(UBound(Airports) + 1)
                        Airports(UBound(Airports)) = Airport
                End Select
            Next
            HasUnsavedChanges = False
        Catch ex As Exception
            MsgBox("Error loading XML data file.", _
                MsgBoxStyle.Exclamation, "File Error")
        End Try
    End Sub

The rest of the data management portion of the program consisted of a tabbed dialog with ListView controls for Flights, Airlines and Airports, as well as buttons and menus for creating, editing, deleting and sorting the list elements.

Drawing The Flight Map

The first thing I needed was a background image for my map. I found a simple outline of the North American continent on a CorelDraw 8 clip art CD (I assume that it is royalty-free, but I couldn't find any documentation to verify this). I changed the color scheme of the map and converted it to a 240 x 274 JPG. Everything was going fine until I tried to run the program on my iPAQ 3765 (what I use for development purposes at work). The program started to load...and then exited with an ArgumentException! I tried to load the image dynamically at runtime but still ended up with the same error message. After a couple of hours scouring the internet for an answer, I finally found the following post on the OpenNetCF.org forums: 16bpp Bitmap allways an error - Terry Mohre. The posting stated that, "16bpp ALWAYS raises an 'ArgumentException' and fails to instantiate the Bitmap class". I checked my JPG and ,sure enough, it was in 16 bits. I converted it to 24 bit and it loaded without a hitch.

Next, as I began to fill in the Paint event handler for my map, I realized that all the familiar .NET desktop Graphics features had been pared down to a tiny subset in the Compact Framework. I set out in my web browser once again to see what solutions were available in place of the GDI+ double-buffering and anti-aliasing features. I quickly found a solid example for a double-buffering technique on MSDN: How to Create a Microsoft .NET Compact Framework-based Image Button - Alex Yakhnin. The first part of this technique was to override the OnPaintBackground event handler in the .NET Control class. Because this event handler is a protected class member, you must create a derived class to perform the override. This new class is used wherever a double buffered drawing surface is needed throughout the program.

Public Class MapCanvas
    Inherits System.Windows.Forms.Control

    Protected Overrides Sub OnPaintBackground(ByVal e As _
         System.Windows.Forms.PaintEventArgs)
        'do nothing

    End Sub
End Class

Although this class worked fine in the compiled program, I must say that it wreaked havoc in the development environment. Maybe this is somehow related to the fact that the Compact Framework does not support the UserControl class that is normally used for this sort of thing? As a result, I was constantly having to delete and re-create the canvas objects in my forms. Sometimes I had to restart Visual Studio to get it to recognize that the MapCanvases were valid objects.

The second part of the double-buffering technique was to draw everything in an off-screen bitmap first, and then copy the bitmap onto the MapCanvas object. This is illustrated by the Paint handler from the airport location picking dialog:

    Private Sub Canvas_Paint(ByVal sender As Object, ByVal e _
         As System.Windows.Forms.PaintEventArgs) Handles Canvas.Paint
        Dim bg As Graphics = Graphics.FromImage(bmBuffer)
        bg.DrawImage(pbMap.Image, 0, 0)
        bg.DrawLine(Pen, 0, YPos, 240, YPos)
        bg.DrawLine(Pen, XPos, 0, XPos, 272)
        bg.Dispose()
        e.Graphics.DrawImage(bmBuffer, 0, 0)
    End Sub

You can make the Paint handler run faster by maintaining graphics objects at the form-level...

    Private Brush As New SolidBrush(Color.Blue)
    Private Pen As New Pen(Color.Blue)
    Private bmBuffer As Bitmap

As for anti-aliasing, there doesn't appear to be any support for it in the PocketPC's GDI. I'm sure there are probably third-party libraries that could provided features equivalent to the desktop's GDI+, but I didn't spend any time looking for them.

Once my double-buffering code was in place, I processed the contents of the flight data class to fill an array of RectangleF objects, each of which represented a single flight path. A corresponding array of integers was used to store heading information which determined which corners of the rectangle were the origination point and destination point. In order to animate the flight paths on the map, a Timer was used to increment the rectangle sizes from 0 to 100% in a succession of screen refreshes. The timer and rectangles were a quick and dirty approach, but they worked rather well.

Using the Program

The program is easy to use. Just copy the .NET CF executable to your PocketPC (You must put it in "\Program Files\Flight Tracker". Create if necessary), along with the FlightData.xml file. The program will initially show a map of airport locations. Click Show/Flights to see the animated map of airline routes. Clicking Tools/Edit Flight Data will open the tabbed dialog where you can add the flight info for your favorite airline!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Jacob Senecal


Member
Jacob works as an application engineer designing and programming process control and data acquisition systems for Green Mountain Technologies, a manufacturer of commercial composting equipment.
Occupation: Web Developer
Location: United States United States

Other popular Mobile Development articles:

  • Writing Your Own GPS Applications: Part 2
    In part two of the series, the author of "GPS.NET" teaches developers how to write GPS applications suitable for the real world by mastering GPS precision concepts. Source code includes a working NMEA interpreter and sample high-precision application in C# and VB.NET.
  • Writing Your Own GPS Applications: Part I
    What is it that GPS applications need to be good enough to use for in-car navigation? Also, how does the process of interpreting GPS data actually work? In this three-part series, I will cover both topics and give you the skills you need to write a commercial-grade GPS application.
  • Learn How to Find GPS Location on Any SmartPhone, and Then Make it Relevant
    A step by step tutorial for getting GPS from any SmartPhone, even without GPS built in, and then making location useful.
  • iPhone UI in Windows Mobile
    It's an interface that works with transparency effects. As a sample I used an interface just like the iPhone one. In this tutorial I am explaining how simple is working with transparency on Windows Mobile.
  • Pocket 1945 - A C# .NET CF Shooter
    An article on Pocket PC game development
Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 7 of 7 (Total in Forum: 7) (Refresh)FirstPrevNext
GeneralFernando Pinmemberfvaldesc14:47 13 Feb '06  
GeneralRe: Fernando Pinmembercarlmalden13:01 29 Oct '08  
Generalfernando Pinmemberfvaldesc14:18 8 Feb '06  
GeneralFlight tracker Pinmembertonbob6:39 13 Nov '05  
GeneralRe: Flight tracker Pinmembercarlmalden12:30 29 Oct '08  
GeneralDesktop Version? Pinmembernewtodotnet11:09 2 Jun '04  
GeneralRe: Desktop Version? PinsupporterJacob Senecal6:40 3 Jun '04  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 30 May 2004
Editor: Nishant Sivakumar
Copyright 2004 by Jacob Senecal
Everything else Copyright © CodeProject, 1999-2009
Web19 | Advertise on the Code Project