Learning to fly, and Jeppesen’s map data on Garmin is wrong.

It’s been a while since I’ve posted, I know.

But I have a good excuse. I’ve been learning to fly.

Flying is the coolest thing I’ve done in a long time. And in the past six months I’ve gone from my check ride to being just a few weeks away from my check ride. My last flight was my long cross country to Bakersfield and to San Luis Obispo from Whiteman Airport. And the view! There is nothing cooler than seeing Avila Bay from the front windscreen of an airplane under your control.

Now to justify spending all this money learning to fly (it ain’t cheap!) I’ve been spending some time building aviation-related software products. My first product was an E6B calculator which also includes methods for calculating maneuvering speed (that changes as the weight of your plane changes, and knowing it is vital when you hit turbulence).

My second product will be an EFB, a program which helps show you where you are on a map displaying airspace data, and also allows you to create a flight plan and file a flight plan with the FAA.

And it is building the mapping engine for Android (my first targeted platform), where my current story starts.

Building a map and testing.

In order to make rendering on Android quick, I’ve built a slippy map engine that uses OpenGL. There are several advantages to this; the biggest being if you scroll the map around you don’t have to redraw the entire screen. Instead, a few OpenGL translate calls or rotate calls–and you’re done. Some additional code to detect if you need to rebuild your tiles, and you can render the tiles in the background in a separate thread, and replace the tiles in the OpenGL instance once they’re done–this allows you to scroll around in real time even though it may take a second or so to render all the complex geometry.

And in testing my slippy map code, I noticed something.

My source of data for the shape of the airspace around Burbank, Van Nuys and Whiteman is the FAA FADDS (Federal Aeronautical Data Distribution System) database, updated every 56 days. I have the latest data set for this current cycle, and I’ve rendered it using my OpenGL slippy map engine in the following screen snapshot:

You can ignore the numbers; that’s just for debugging purposes. The airspace being hilited is the airspace at my altitude (currently set to 0); dim lines show airspace at a different flight level.

And I noticed something–interesting–when comparing the map with my Garmin Aera 796 with the Jeppesen America Navigation Data set:

There are a few differences.

Okay, let’s see what the printed VFR map shows for the same area:

I’ve taken the liberty to rotate the map to around the same orientation as the other maps.

And–there are errors.

Now the difference between the FADDS data set and the printed map is trivial: there is this extra crescent area that on the printed map belongs to Van Nuys:

The errors with the Jeppesen data set, however, are worse:

On this image I’ve superimposed the image of the terminal air chart for Van Nuys, Burbank and Whiteman on top of the Garmin’s screen. It may be hard to see exactly what’s going on, but if you look carefully you see three errors.

The first error is the west side of Van Nuys’ airspace it has been straightened out into a north-south line. On the chart, Van Nuys’ airspace curves to match Burbank’s class C airspace on the west.

The second error is the northern edge of Burbank’s C airspace over Whiteman. Whiteman’s class D airspace is entirely underneath Burbank’s class C airspace–but the border has been turned into a straight line on the Garmin.

The third error is a tiny little edge of airspace that shows Van Nuys and Whiteman’s class D airspaces overlapping. On the printed map, this little wedge belongs to Whiteman.

They say a handheld GPS device should only be used for “situational awareness” and not for navigation.

Well, one reason is simple: the airspace maps you’re looking at on the hand-held may be wrong.

I’ve also noticed similar errors around Oakland’s Class C airspace. Large chunks of the airspace have been turned from nice curving lines (showing a radius from a fixed point) into roughly shaped polygons.

Now my guess is this: the raw FADDS data from the FAA is similar to most mapping data: rather than specifying round curves, the georeferenced data is specified as a polygon with a very large number of nodes; some of the airspace curves are specified with several hundred points.

And somewhere during the conversion process, the number of points are being reduced in order to fit a compact file size, and so it renders quickly: if the length of one edge of the rendered polygon is less than a couple of pixels long, there is no point keeping the nodes of that line; you can approximate the polygon with one with fewer edges with less than a single display pixel of error.

But somewhere along the path, too many polygon edges are being removed–turning what should be a curved line into a straight edge.

I don’t know if this is because there is a limit to the number of polygon lines permitted in the file format being used for export and import, or if this is because approximation code is going haywire.

But curved lines are being turned straight–which implies if you are skirting someone’s airspace, and relying on your hand-held Garmin–you could very well be intruding into someone’s airspace and not even know it.

Fixed a memory leak in Flow Cover.

Meh. This one was a nasty little bug. And now its fixed.

The problem is that in FlowCoverView, the dealloc routine was resetting the EAGLContext object early. This caused the rest of the dealloc call to fail, which then resulted in the overall view to fail to be released.

The fix is to rewrite the dealloc routine for FlowCoverView. Around line 230, replace the old -dealloc routine with:

- (void)dealloc 
{
    [EAGLContext setCurrentContext:context];

    [self destroyFrameBuffer];
    [cache release];

    [EAGLContext setCurrentContext:nil];
    
    [context release];
    context = nil;
    [super dealloc];
}

The first call to EAGLContext setCurrentContext makes sure the context is current, so all operations done on the various texture maps and OpenGL objects are done in the right context. Then everything is released–and at the end, the EAGLContext is then released, and so is the view.

I’ve also uploaded a new version of FlowCover which puts the FlowCover view on a second view; press the “test” button to have it pop up.

A new version of the code has been uploaded here. Download and incorporate into your code as you will.

Oh, and I also modified the code license; essentially you do not have to include mention of me in the binary redistribution; just the source code.

WebProxy posted.

A final fix (turns out ThinkGeek.com sends an HTTP/1.1 response with a “Content-Type” header but no length, so I had to change the reader code to take that into account), and the proxy server code now appears to work with every web site I visit.

So it’s now posted.

This is a Java server program which listens to incoming connection and proxies (forwards) the HTTP requests to another server. This basically implements the proxy protocol, though this is a bit of an “itch scratch” on my part–so I cannot guarantee the code will work for you, even though it seems to work for me. It uses the common tools library that is also posted here–“common tools” being a nice phrase for “jar file which catches all of the common crap that doesn’t have a good home elsewhere”, and helped me exercise the bugs on my HTTP client and server code.

Of course if you want something robust and industrial strength, may I recommend looking at the Apache foundation web site instead? This stuff is small potatoes, but as I said, it does appear to work for me, so have at it!

Here is the web site with some information.

D’oh!

So I uploaded the common tools package to the web site last night–and realized that I had no version information in the jar file or the documentation files. How do you know if you have the latest thing?

Quick tweak to the build.xml file for all uploaded projects to add a build number to the jar and the javadocs, uploaded everything to the server–and all is well in the world.

What I did, by the way, was to use <propertyfile> in ant to manage a build properties file, then use the resulting properties to generate the correct manifest and copyright information. So now the copyright information contains the version number corresponding to the build number use to build the docs–which generally is the same as the build number for the jar files. (But not always; some of my code checks to make sure the jar file of other projects are up to date, which triggers a build number increment on that other project.)

The latest additions I made to the common files include code for an HTTP server framework–so I could build my proxy, a simple and stupid ‘debug’ IO Stream class which allows you to hook an OutputStream to an InputStream or OutputStream chain so you can see what’s going through the pipe, as well as a watchdog timer class which has the nice property that you can tell an object in the timer to reset itself.

Nothing earth-shattering here, and all are things you probably can find better examples of elsewhere. But what the heck; it entertains me, which is really what all this is about. Right? If someone else accidently finds all this stuff useful, then so much the better.

Progress on the HTML Proxy

I managed to work out the bug in my previous post. Turns out that it’s a bug in my software and a bug in whatever is handling the e-mail redirect at LunarPages. My bug: I was sending the ‘Host:’ HTML header twice. LunarPages? They were grabbing the list of host values, and concatenating them in order to produce the redirect location. So what was happening was in my host header I was writing

Host:www.chaosinmotion.com
Host: www.chaosinmotion.com:80

and apparently they were grabbing the value–presumably as part of some sort of JSP processing system, which I guess was returning the value

"www.chaosinmotion.com:80, www.chaosinmotion.com"

and they were just slapping a resource identifier at the end (“/forwardaddress”) and an “http://” on the front and sending it out.

I assert it’s a bug in their software because the RFC says that the Host: field of an HTTP request can be a host name optionally followed by a colon and a port number. Their software is broken because when they attempt to redirect people to their on-line e-mail reader application (which is on port 2095), if you set the Host string to

Host: www.chaosinmotion.com:80

you get redirected to http://www.chaosinmotion.com:80:2095

There are some other issues I’m ironing out. But it appears my proxy redirector is working on about 95% of the web sites I’ve tried it with. Of course it’s failing on the one web site I want–the on-line e-mail application I want to connect to from work–but at least I’m making progress.

Mail Server Uploaded

Several years ago I needed an MTA to run on an old MacOS X box that was running the Chaos In Motion web site, as well as the PandaWave web site. So I rolled my own. Didn’t need anything complicated; just something that could be scripted via XML and was running maybe a half-dozen different incoming e-mail locations.

So I rolled my own. I first rolled a library which could handle the SMTP and POP3 protocols, then an implementation that extended the library to store incoming and outgoing messages in various directory locations on the server box.

Years later, and I don’t have the time to productize this. Further, most MTAs seem to be moving towards being free and open source–so I may as well upload it under the BSD license in case someone out there finds it useful.

Which I did.

The library that implements the POP3 and SMTP protocol and parses incoming requests was uploaded here (MailServer), and the server code which implements the MTA database back end is uploaded here (CIMMail). I’ve also included the necessary MacOS X scripts to start up a Java server in the background, though it should be fairly simple to create a Windows Service and a Linux script which does the same thing on those platforms.

Finally: uploaded and updated the ASN.1 library.

A while ago, I wrote an LDAP server. Well, nothing as complex as OpenLDAP; just a simple LDAP protocol parser which could translate LDAP requests into requests to modify an internal in-memory data representation of the LDAP database. I actually managed to make it work against a product we were working on at the time.

Part of the problem with that code is that I used the BER ASN.1 library that was part of the Netscape LDAP API library, which while rather interesting, was rather weak in that it was written to be just good enough to deal with the LDAP client spec–and no better. (In fact I had to kludge the hell out of my code to make the LDAP server spec work, as the LDAP server spec is heavy on using the [APPLICATION] tag for just about everything. Turns out there is an ambiguity that had to be dealt with using some odd special-case code.)

So I wrote a replacement library, rewrote my LDAP code to use the new library, and away I went. Someday I’ll post the full LDAP engine, but in the meantime, I finally got around to both documenting my ASN.1 BER parser engine on the Wiki, and uploading the source kit. You can visit the main ASN.1 web page here, or go to the wiki for more information.