Skip to content

Instantly share code, notes, and snippets.

@mheadd
Created February 25, 2011 20:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mheadd/844421 to your computer and use it in GitHub Desktop.
Save mheadd/844421 to your computer and use it in GitHub Desktop.
A Tropo scripting application that finds library locations in Philadelphia.
<?php
/**
* Find My Library - an IM and SMS application that finds library locations in Philadelphia.
*
* @copyright 2011 Mark J. Headd (http://www.voiceingov.org)
* @author Mark Headd
*
* Deploy this application on http://www.tropo.com
*/
// Constants used to geocode an address.
define("MAPS_LOOKUP_BASE_URL", "http://maps.googleapis.com/maps/api/geocode/json");
define("MAPS_API_KEY", "your-api-key");
// CouchDB Details.
define("GEO_COUCH_URL", "http://libraries.phillyapi.com:5984/v1/locations?bbox=");
// 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_URL;
$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->BRANCH_NAM);
$library .= '. Library Address: '.$property->HOUSENUM.' '.strtoupper($property->ADDRESS);
$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();
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment