27 April 2012

Distance between 2 addresses in CoffeeScript

A small script to find the distance of two addresses using the Google Maps API:
#! /usr/bin/env coffee
Http = require 'http'
Number::toRad = -> this * (Math.PI / 180)
# http://www.movable-type.co.uk/scripts/latlong.html
haversine = (p, q) ->
R = 6371
latDist = (q.lat - p.lat).toRad()
lngDist = (q.lng - p.lng).toRad()
qLat = q.lat.toRad()
pLat = p.lat.toRad()
a = Math.sin(latDist/2) * Math.sin(latDist/2) +
Math.sin(lngDist/2) * Math.sin(lngDist/2) * Math.cos(qLat) * Math.cos(pLat)
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
d = R * c
d / 1.6 # convert to miles
getLatLng = (address, onOK, onErr) ->
opts =
host: "maps.googleapis.com",
port: 80,
path: "/maps/api/geocode/json?address=#{address}&sensor=false"
Http.get opts, (res) ->
res.setEncoding 'utf8'
data = []
res.on 'data', (chunk) ->
data.push chunk
res.on 'end', () ->
j = JSON.parse(data.join "")
if j.status is "OK"
loc = j.results[0].geometry.location
onOK({lat: loc.lat, lng: loc.lng})
else
onErr("Error #{j.status}")
.on 'error', (e) -> onErr("Error #{e.message}")
distance = (address1, address2) ->
err = (msg) ->
console.log "Error: #{msg}"
console.exit 1
compute = (p, q) ->
dist = haversine(p, q).toFixed(3)
[a1, a2] = [unescape(address1), unescape(address2)]
console.log "Distance between #{a1} & #{a2}: #{dist} miles"
get2 = (p) -> getLatLng(address2, ((q) -> compute(p, q)), err)
getLatLng(address1, get2, err)
address1 = escape(process.argv[2])
address2 = escape(process.argv[3])
distance address1, address2