From 5aafac2025802b898f537e61de75ad81852ea5e5 Mon Sep 17 00:00:00 2001 From: Amy Bowersox Date: Mon, 17 Aug 2020 12:06:24 -0600 Subject: [PATCH] modified GCoder to detect "not found" cases, added DCalc --- src/dcalc.py | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/gcoder.py | 7 ++++- 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100755 src/dcalc.py diff --git a/src/dcalc.py b/src/dcalc.py new file mode 100755 index 0000000..f73dc59 --- /dev/null +++ b/src/dcalc.py @@ -0,0 +1,77 @@ +# DCalc.py: basic test of distance calculation from the Boulder office + +import sys +import argparse +import json +import math +import configparser +import urllib.parse +import urllib.request + + +class GeocodingError(RuntimeError): + pass + + +def geocode_google(config, address): + apikey = config['google']['apikey'] + if not apikey: + raise GeocodingError("Google API key not specified") + query = { 'key': apikey, 'address': address, 'region': 'us'} + url = 'https://maps.googleapis.com/maps/api/geocode/json?' + \ + urllib.parse.urlencode(query, quote_via=urllib.parse.quote) + with urllib.request.urlopen(url) as response: + if response.status == 200: + apireturn = json.loads(response.read()) + stat = apireturn['status'] + if stat == 'OK': + results = apireturn['results'] + if len(results) > 1: + raise GeocodingError(f"Google API returned ambiguous results (total count {len(results)})") + coords = results[0]['geometry']['location'] + return coords['lat'], coords['lng'] + elif stat == 'ZERO_RESULTS': + return None + else: + raise GeocodingError(f"Google API returns status of {stat}") + else: + raise GeocodingError(f"Google API returns {response.status} HTTP status code") + + +OFFICE_LOCATION = (40.0187905, -105.2764775) # office location - 1433 Pearl Street, Boulder, CO +RADIUS = 6371.0 * 1000.0 # Earth radius in meters +METERS_PER_MILE = 1852.0 # number of meters per mile + + +def distance_miles(point1, point2): + Φ1 = math.radians(point1[0]) + Φ2 = math.radians(point2[0]) + ΔΦ = math.radians(point2[0] - point1[0]) + Δλ = math.radians(point2[1] - point1[1]) + a = math.sin(ΔΦ / 2.0) * math.sin(ΔΦ / 2.0) + math.cos(Φ1) * math.cos(Φ2) * math.sin(Δλ / 2.0) * math.sin(Δλ / 2.0) + c = 2 * math.atan2(math.sqrt(a), math.sqrt(1.0 - a)) + return RADIUS * c / METERS_PER_MILE + + +cmdline_parser = argparse.ArgumentParser() +cmdline_parser.add_argument('address', nargs='+', help='The address to be calculated') +cmdline_parser.add_argument('-C', '--config', default='geoapi.ini', help='The geocoding API configuration file') + + +def main(args): + opts = cmdline_parser.parse_args(args) + config = configparser.ConfigParser() + config.read(opts.config) + my_address = ' '.join(opts.address) + print(f"Address: '{my_address}'") + coords = geocode_google(config, my_address) + if coords: + print(f"Coordinates: Latitude {coords[0]}, longitude {coords[1]}") + dist = distance_miles(OFFICE_LOCATION, coords) + print(f"Distance from Boulder office: {dist} miles") + else: + print("Location was not found.") + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/src/gcoder.py b/src/gcoder.py index c60413c..b058081 100755 --- a/src/gcoder.py +++ b/src/gcoder.py @@ -29,6 +29,8 @@ def geocode_google(config, address): raise GeocodingError(f"Google API returned ambiguous results (total count {len(results)})") coords = results[0]['geometry']['location'] return coords['lat'], coords['lng'] + elif stat == 'ZERO_RESULTS': + return None else: raise GeocodingError(f"Google API returns status of {stat}") else: @@ -112,7 +114,10 @@ def main(args): my_address = ' '.join(opts.address) print(f"Address: '{my_address}'") coords = geocoding_procs[opts.geocoder](config, my_address) - print(f"Coordinates: Latitude {coords[0]}, longitude {coords[1]}") + if coords: + print(f"Coordinates: Latitude {coords[0]}, longitude {coords[1]}") + else: + print("Location was not found.") if __name__ == '__main__':