We at Pivotal Action were recently given a task for a client – develop a tool for a mobile API where admin can upload a list of retailers so that their mobile app users could find locations near them. It’s basically a “Find near me” utility.
This type of project is broken down into 3 parts: Upload & store geolocation data, find addresses near a given point, and display those locations either textually or on a map display. This quick tutorial will cover the first two parts.
Part 1, Getting Located
The goal of this part is to obtain and store latitude/longitude pairs for given addresses. I’m going to assume you can already get a list of addresses, whether for a spreadsheet/csv file, or other source. With a parsed address, you can obtain the lat/lng pairs from the Google Maps API. Just be forewarned that Google limits you to 2,500 requests per 24h period. That could be a problem for some applications, so you may need another provider like SimpleGeo.com
<?php // Google maps API. rate limit to 2,500 reqs/24h $url = 'http://maps.googleapis.com/maps/api/geocode/json'; $address = urlencode($row['address']); $city = urlencode($row['city']); $state = urlencode($row['state']); $zip = $row['zip']; $requestUrl = $url."?address=".($address.",".$city.",".$state.",".$zip). "&sensor=false"; // echo $requestUrl; $crl = curl_init(); curl_setopt($crl, CURLOPT_HEADER, 0); curl_setopt($crl, CURLOPT_RETURNTRANSFER, 1); // Set up the CURL request curl_setopt($crl, CURLOPT_URL, $requestUrl); // Here we get the google result in JSON $googJson = curl_exec($crl); curl_close($crl); $googArr = json_decode($googJson); $status = $googArr->status; $loc = $googArr->results[0]->geometry->location; if( strtolower($status) == "ok" ){ $tableData[count($tableData) - 1]['lat'] = $loc->lat; $tableData[count($tableData) - 1]['lng'] = $loc->lng; } else { $tableData[count($tableData) - 1]['lat'] = 0.0; $tableData[count($tableData) - 1]['lng'] = 0.0; } //go on to save $tableData to your DB ?>
There are a couple key parts in there. First, you need to URL encode the address details. Second, the curl stuff is pretty standard – you can find similar versions all over the net. Third, the response data comes back as a JSON string, so you need to decode it into a PHP array to make it useful. My default value for lat/lng pairs is 0.0/0.0. There may be cases where Google doesn’t understand the address information or perhaps you’ve gone over your rate limit, so you have to accept more or less a throw-away response. The important thing is that you have your address coordinates saved (dare I say, cached) in your DB. You need this.
Part 2, Finding Yourself
Now how are you supposed to find these stores that are near you, at this moment, without having to use a lame web form or other manual means? You’re going to use the Haversine, aka Great Circle Formula. Don’t click that link unless you really want to be confused. Here’s the gist – the globe is a big sphere, and we know from high school and/or college trigonometry classes that you can figure out lengths and distances on geometric objects. Some guy long ago (whose name was not Haversine) sat down and figured this out for us. What we get as a result of running these maths is the distance between to points on earth, using lat/long pairs. The caveat is these are as the crow flies, not driving directions. What I’m going to show you below is some SQL you can use to find the N closest points within a given distance. This will work on MySQL, and I’m assuming other SQL-compliant DBs. YMMV.
// scale: MILES - use 3959 ; KM - use 6371 (mean radius of the earth) $scale = 3959; $sql = "SELECT name, address, city, state, zip, ( " . (int) $scale ." * acos( cos( radians(".(float) $loc['lat'] . ") ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(" . (float) $loc['lng'].") ) + sin( radians(". (float) $loc['lat'] . ") ) * sin( radians( lat ) ) ) ) AS distance FROM " . $tablename ." HAVING distance < ". (int) $distance . " ORDER BY distance LIMIT 0 , ". (int) $limit . ";";
(Thank Pavel Chuchuva on Stack Overflow for the SQL [answer here]). You only need a couple parameters to get this chugging along and giving you a list of distances, closest to farthest from the point you are feeding it. Along with your address information, you’re also provided a distance in miles (using 3959 for measurement in Km).
Now you can use these results to display distances to your users. Let Google be your guide for implementing Part 3.
Hey Cameron. Thanks for the point in the right direction. Now I just need to figure out how to make this work in LotusScript (boo). I noticed you’re in San Diego. We’re in Kearney Mesa, how about you?
Sorry to hear you need to do this in LotusScript. We’re based in the College area.
I appreciate your sympathy.