↓ Archives ↓

Posts Tagged → haversine

Finding Nearby Locations

Let’s say you have a list of 60 or so locations and you need a fast way to sort them by distance from a user’s current location.  You might have a form where a user can enter their current address or zip code, etc. and you want it to output the different locations sorted by distance.  Here’s one way to do that:

First, you will need a Google Maps API Key.  That is very easy to obtain here: http://code.google.com/apis/maps/signup.html

Now that you have that, you have a couple of options.  If you want to work on the client side (and assuming this is a web application), you can use Google’s Javascript API’s Geocoding Object.  I am going to talk about doing it on the server side though…

Google also has a HTTP Geocoding Service which can be called as follows:

http://maps.google.com/maps/geo?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA&output=json&sensor=true_or_false&key=your_api_key

In PHP, you can take the query and the result from this web service and get the result:

<?php
$query = $_POST['q']
$result = file_get_contents('http://maps.google.com/maps/geo?q='.urlencode($query).'&output=json&sensor=false&key=your_api_key')
?>

Now, parse the result for the geocode object.  Note, the result can be request in json or other formats such as XML.  Choose whichever fits your purpose.

At this point, you will also need to know the geocode of all of your locations. Assuming that you have them in a database, you can add a field called “geocode” or “lat” and “lon”. If you you do not have a particular geocode set for a certain location you can set it this one time using the web service and store it so it never has to be checked again. Obviously it would be a large operation to have to check each location for every search.

Assuming that you have all of the locations, run the Haversine formula on each location’s geocode and the entered location’s geocode from the web service.  (Note: for much more accuracy you can use Vincenty’s formula, but that is not necessary in this application).  Here is an implementation that I found on stackoverflow.com and have tested:

// pass the latitudes and longitudes in as degrees
function getDistance($lat1,$long1,$lat2,$long2)
{
    $r = 3963.1; //3963.1 statute miles; 3443.9 nautical miles; 6378 km
    $pi = pi();

    // convert the degrees to radians
    $lat1 = $lat1*($pi/180);
    $lat2 = $lat2*($pi/180);
    $long1 = $long1*($pi/180);
    $long2 = $long2*($pi/180);

    $ret = (acos(cos($lat1)*cos($long1)*cos($lat2)*cos($long2) + cos($lat1)*sin($long1)*cos($lat2)*sin($long2) + sin($lat1)*sin($lat2)) * $r) ;
    return $ret;
}

Put each of those distances in an array, putting them either at the beginning or end of the array depending on whether they are greater than or less than the first or last item.

Then display to the user the corresponding stores.