Created
December 29, 2010 01:30
-
-
Save haikusw/758018 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Find My Library - an IM (and SMS, and Twitter, and Phone) application that finds | |
* library locations in NYC. | |
* | |
* @copyright 2010 Mark J. Headd (http://www.voiceingov.org) | |
* @author Mark Headd | |
*/ | |
// Constants used to geocode an address. | |
define("MAPS_LOOKUP_BASE_URL", "http://maps.googleapis.com/maps/api/geocode/json"); | |
define("MAPS_API_KEY", ""); | |
// CouchDB Details. | |
define("GEO_COUCH_BASE_URL", "http://your.couchdb.host:5984"); | |
define("GEO_COUCH_DB_NAME", "libraries"); | |
define("GEO_COUCH_DESIGN_DOC_PATH", "_design/geojson/_spatial/points"); | |
// Exception classes. | |
class GeoCodeException extends Exception {} | |
class GeoCouchException extends Exception {} | |
// Get the lat / lon for an address. | |
function geoCodeAddress($address) { | |
// Format address and URL. | |
$address = str_replace(" ", "+", $address); | |
$url = MAPS_LOOKUP_BASE_URL."?address=".$address."&sensor=false&key=".MAPS_API_KEY; | |
return makeCurlCall($url, GeoCodeException, "Could not Geocode that address."); | |
} | |
// Mak call to GeoCouch and get locations. | |
function getLocations($bb_array) { | |
// Format URL to GeoCouch instance. | |
$url = GEO_COUCH_BASE_URL."/".GEO_COUCH_DB_NAME."/".GEO_COUCH_DESIGN_DOC_PATH."?bbox="; | |
$url .= implode(",", $bb_array); | |
return makeCurlCall($url, GeoCouchException, "Could not connect to GeoCouch instance."); | |
} | |
// Heler method to make an HTTP request. | |
function makeCurlCall($url, $exceptionType, $exceptionMessage) { | |
// Set up cURL call. | |
$ch = curl_init($url); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
// Execute. | |
$output = curl_exec($ch); | |
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE); | |
// Return results. | |
if($code != '200') { | |
throw new $exceptionType($exceptionMessage); | |
} | |
else { | |
return $output; | |
} | |
} | |
// Make a bounding box from a lat / lon pair | |
function makeBoundingBox($lon, $lat, $factor=.015) { | |
$bb_array = Array($lon-$factor, $lat-$factor, $lon+$factor, $lat+$factor); | |
return $bb_array; | |
} | |
// Calculate the distance between 2 points. | |
function calculateDistance($lat1, $lon1, $lat2, $lon2) { | |
return 3958*3.1415926*sqrt(($lat2-$lat1)*($lat2-$lat1) + cos($lat2/57.29578)*cos($lat1/57.29578)*($lon2-$lon1)*($lon2-$lon1))/180; | |
} | |
try { | |
// Get the address submited by the user. | |
$result = ask("", array("choices" => "[ANY]")); | |
// Geocode address and get lat / lon. | |
$geocoded_address = json_decode(geoCodeAddress($result->value)); | |
$lat = $geocoded_address->results[0]->geometry->location->lat; | |
$lon = $geocoded_address->results[0]->geometry->location->lng; | |
// Create a bound box from the lat / lon pair. | |
$bb_array = makeBoundingBox($lon, $lat); | |
// Get the locations from geocouch. | |
$locations = json_decode(getLocations($bb_array)); | |
// If locations are found,iterate over JSON and render to user. | |
if($locations->rows) { | |
foreach($locations->rows as $location) { | |
$property = $location->value->properties; | |
$geometry = $location->value->geometry->coordinates; | |
$library = 'Library Name: '.strtoupper($property->NAME); | |
$library .= '. Library Address: '.$property->HOUSENUM.' '.strtoupper($property->STREETNAME); | |
$library .= ', '.strtoupper($property->CITY).' NY '.$property->ZIP.'.'; | |
$library .= isset($property->SYSTEM) ? ' System: '.$property->SYSTEM : ''; | |
$distance = round(calculateDistance($lat, $lon, $geometry[1], $geometry[0]), 2); | |
$library .= ' Distance: '.$distance.' miles.'; | |
say($library); | |
} | |
} | |
// Otherwise, tell user no locations found. | |
else { | |
say("No locations found."); | |
} | |
} | |
// If address can not be Geocoded. | |
catch (GeoCodeException $ex) { | |
say("An error occured. ". $ex->getMessage()); | |
hangup(); | |
} | |
// If call can not be made to GeoCoud | |
catch (GeoCouchException $ex) { | |
say("An error occured. ". $ex->getMessage()); | |
hangup(); | |
} | |
// Last ditch exception handler. | |
catch (Exception $ex) { | |
say("Sorry. Something really bad happened."); | |
_log("*** ". $ex->getMessage() . " ***"); | |
hangup(); | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"_id": "_design/geojson", | |
"spatial": { | |
"points": "function(doc) { emit(doc.geometry, {id: doc._id, geometry: doc.geometry, properties: doc.properties}) };" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment