Katie on Rails

On Internets and other things

8th Grade Math and Navigating the Globe

For my team’s presentation to the Ruby meetup, we’ve been working on an app that will help people navigate NYC’s Citibike program, using a mashup of Google maps and Citibike’s publicly available JSON location data. By way of navigation, the JSON includes street address, latitude, and longitude of each location.

Our initial prototype let users pick start and end points from a dropdown menu of Citibike locations and mapped the distance between them on the map. This was hardly ideal – very few people orient themselves in a city on the basis of bike locations – so one of the first things we wanted to give users was the ability to input a street address and have the app automatically find the Citibike stations around them.

It was a sensible idea, albiet one I had no idea how to implement. It was then that my groupmate discovered this implementation of a Citibike/Google maps mashup that does exactly that. Thanks, Internet! We found this in the JavaScript source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  function getDistance(lat1,lng1,lat2,lng2) {
      var i = lat1 - lat2;
      var j = lng1 - lng2;
      return i*i + j*j;
    }

    function findNearestStation(lat,lng) {
      var min_distance = 99999;
      var closest_station_id;
      $.each(stations.stationBeanList, function(i, station) {
        var distance = getDistance(lat,lng, station.latitude, station.longitude);

        if (distance < min_distance) {
          min_distance = distance;
          closest_station_id = i;
        }
      });

      console.log('Closest station idx: ' + closest_station_id);

      return stations.stationBeanList[closest_station_id];
    }

I’d expected a massive operation, and this was breathtakingly simple. It simply loops through all the stations, gets each one’s latitude and longitude, compares the current station to the closest station it has found so far. It was this “closeness” calculation that I was most interested in. JavaScript was comparing it using a numercal value, but how did it get that number? Well, it’s all figured out the closeness of the station using the 5-line getDistance function. getDistance which compares the station’s longitude and latitude to the user’s using this code:

1
2
3
  var i = lat1 - lat2;
  var j = lng1 - lng2;
  return i*i + j*j;

Why subtract latitude from latitude and longitude from longitude? The difference between latitude a and latitude b is the distance between them. Granted, it’s a difference measured in…latitude units, but it’s a distance nonetheless, and we actually don’t need to more precision here. If the distance between my location and station x is .123 latitude units and the distance between my location and station y is .01 latitude units, then station y is closer. That’s all we need to know. “Latitude units” work perfectly well for this purpose.

The same logic works perfectly well for longitude, but I didn’t initially understand why we were returning latitude2 and longitude2, but then it hit me – latitude runs perfectly east-west, and longitude runs perfectly north-south. When they meet, they create a perfect right angle, and therefore, we can use….Pythagorean theorem. a2+b2=c2 . You can get the hypotenuse of a triangle by multiplying the lengths of its sides.

The advantage of considering the hypotenuse of our right triangles is it lets us perfectly average out our longitude/latitude differences. For example, my location may be very close latitude as a bike station but be very far away in longitude. Or it may be on a similar longitude but on a very different latitude. Or else it may be on a similar latitude and longitude. Whatever. By calculating c 2, we’re averaging out the differences.

And that alone is enough to let us calculate the distance.