## Generating GPX and KML maps with Ruby on Rails

While working on my various projects, I’ve dealt with various types of maps.

My Flight Historian plots flight data using the Great Circle Mapper tool. These maps are simple to generate from my flight data (I just have to pass it a plain text collection of airport codes) and easy to embed in my website. However, because they are static images, they can’t be easily panned, zoomed, or otherwise manipulated in the way that modern map websites and apps can.

On the other hand, my driving maps require too much detail for a single image, so I create them in Google Earth, which lets me manipulate the view as much as I need to. The driving data is a bit more complicated than my flight log data; while my flight log represents the abstract shortest distance straight line between two airports (and thus only requires specifying the airport at each end), a single drive can involve tens of thousands of coordinates that can be joined together, connect-the-dots style, to show the actual driving route taken.

Fortunately, all those coordinates are automatically generated and saved by my car’s GPS navigation unit in a file format called GPX (GPS Exchange Format), which is an XML-based file format which contains (among other things) latitude/longitudes sampled, in the case of my particular GPS, once per second.

Google Earth doesn’t use GPX format (though it can import it); instead, it uses a format called KML (Keyhole Markup Language, from back when Google Earth was Keyhole EarthViewer). KML is also an XML-based format, so conceptually it’s similarly a collection of coordinates that can all be joined together, with its own slightly different style.

But while GPX and KML can be used to represent complicated route shapes, they don’t have to be. These formats are both just as capable of taking a pair of points on the globe and drawing the shortest line between them. With that in mind, I decided to try to have Flight Historian automatically generate KML and GPX versions of my flight map, which would let me show my flight routes in Google Earth and Google Maps.

## My “Worst” Layovers

Flying out of a smaller city like Dayton, I’m used to having flight layovers on the way to nearly everywhere I travel. While any layover is going to lengthen a trip, one of the most common complaints I hear from traveling companions is when a layover forces them to fly east to go west, or vice versa.

[All maps in this post are generated by Paul Bogard using the Great Circle Mapper – copyright © Karl L. Swartz]

I started thinking about a way to quantify how bad a layover was, and ultimately decided that it would be best to compare the sum of the (great circle) distances for each of the flights flown compared to the (great circle) distance of a direct flight from the origin to the destination:

${ratio}_{layover} = \dfrac{distance_1+distance_2+\ldots+distance_n}{distance_\text{direct}}$

This would give me a ratio of how much further I flew than I needed to, where a higher ratio would mean a worse layover. A ratio of 2 would mean I flew twice as far as I needed to, a ratio of 3 would mean three times as far, and so on. A ratio of 1 would mean a layover didn’t add any extra distance at all.

## State Abbreviations Graph

In a recent chat that I participated in, we were discussing US two-letter state abbreviations that were one letter off of each other (e.g., NY and NJ).

After that discussion, I was curious about whether it would be possible to step from any state abbreviation to any other by changing one letter at a time, using only valid states along the way. My first step was to determine if there were any state abbreviations which didn’t share a first or last letter with any other states, so I wrote a simple Ruby script to test that.

state_codes = %w(AL AK AZ AR CA CO CT DE FL GA HI ID IL IN IA KS KY LA ME MD MA MI MN MS MO MT NE NV NH NJ NM NY NC ND OH OK OR PA RI SC SD TN TX UT VT VA WA WV WI WY)
state_codes.sort!
one_letter_changes = Hash.new()
state_codes.each do |sc|
one_letter_changes[sc] = state_codes.select{|s| sc != s && (sc[0] == s[0] || sc[1] == s[1])}
puts "#{sc}: #{one_letter_changes[sc].join(", ")}"
end

So every state had at least one other state it could go to. Texas (TX) had the fewest, with only Tennessee (TN); Massachusetts (MA) had the most, as quite a few state codes start with M or end with A.

Now I needed to find out if all the states would connect to each other, or if there would be several distinct “neighborhoods” of states. I decided to do this visually by creating a graph, using the output of my script to draw the connections:

Based on this graph, it is possible for any state abbreviation to change to any other state abbreviation!

I was also curious about the number of steps needed to go between any pair of state abbreviations, so I wrote a path distance algorithm based on Dijkstra’s algorithm (but with each path having equal weight) to find the shortest number of hops between any pair:

state_codes = %w(AL AK AZ AR CA CO CT DE FL GA HI ID IL IN IA KS KY LA ME MD MA MI MN MS MO MT NE NV NH NJ NM NY NC ND OH OK OR PA RI SC SD TN TX UT VT VA WA WV WI WY)
state_codes.sort!
one_letter_changes = Hash.new()
state_codes.each do |sc|
one_letter_changes[sc] = state_codes.select{|s| sc != s && (sc[0] == s[0] || sc[1] == s[1])}
end

def path_distance(graph, source)
vertexes = graph.keys
return nil unless vertexes.include?(source)

distance = Hash.new()
previous_vertex = Hash.new()
arbitrarily_large_distance = vertexes.length
unvisited_vertices = Array.new

vertexes.each do |v|
distance[v] = arbitrarily_large_distance
previous_vertex[v] = nil
unvisited_vertices.push(v)
end
distance = 0;

while(unvisited_vertices.any?)
min_distance_vertex = unvisited_vertices.min_by{|v| distance[v]}

graph[min_distance_vertex].each do |neighbor|
alt = distance[min_distance_vertex] + 1
if alt < distance[neighbor]
distance[neighbor] = alt
previous_vertex[neighbor] = min_distance_vertex
end
end
unvisited_vertices -= [min_distance_vertex]
end

return distance

end

state_codes.each do |code|
values = path_distance(one_letter_changes, code).sort_by{|k,v| k}.reject{|k,v| k > code}.map{|d| d[1]}
puts "#{code}  #{values.join("  ")}"
end
puts "   #{state_codes.join(" ")}"

Based on the results, the highest number of hops is 6 – so every state abbreviation can be changed into any other state abbreviation in at most six steps!

## Flight Historian Version 2.2: Regions and Flight Lookups

Flight Historian has been updated to Version 2.2. Please see the change log for the details!

## Switching Flight Historian to ICAO Regions

Early on during the development of Flight Historian, I realized that I’d have to do some filtering of my maps by region. Most of my travel is within the United States, so a world map of all of my flights left the United States as an unreadable mess of lines. Thus, I gave Flight Historian the ability to toggle between world maps (all flights) and CONUS maps (flights within the CONtiguous United States – that is, the United States except for Alaska, Hawaii, and territories).

Because of peculiarities with how the Great Circle Mapper generates maps, showing region maps wasn’t as simple as setting a map center and zoom level. Instead, I had to know which airports were inside the CONUS and which ones were outside. The easiest solution was to add an is_conus attribute to my Airports table, which would be set to true for CONUS airports and false for OCONUS (Outside CONUS) airports. Once I had that, I could set the world map to use every airport, and the CONUS map to show only airports where is_conus was true.

This worked well enough when I was only showing two regions (world and CONUS). But as I traveled, I realized I was going to want to zoom in on other regions (for example, Europe) as well, which meant that I’d have to have some way match airports to other regions.

## Flight Log Version 2.1: Import Flights from Digital Boarding Passes

In general, my Flight Historian has been a big time saver for me as far as tracking my flights – instead of manually generating reports and maps from an Excel file, I can simply add flights to a database and let it do all the work. However, as I’ve started tracking more details about my flights over time, the task of entering the flights has become less simple.

Since I’d been working on parsing boarding pass barcode data, it seemed like a logical next step to write some sort of scanner that would read a boarding pass barcode and import the data as a new flight. Then one of my Twitter followers had a suggestion:

## Creating Multiple Flash Messages in Ruby on Rails

On my Flight Historian application, a number of my pages make use of the flash and flash.now session messages capability for errors, warnings, successes, and informational messages. However, some of those pages needed to have multiple messages of the same type (e.g., multiple warnings), which flash didn’t allow me to do. Additionally, I had some views that were generating status messages of their own (for example, if a collection was empty on a page that had multiple collections), and so I ended up with several ways to generate messages that didn’t output consistent HTML.