import math import urllib # Useful code for 22c80 HW11. # Jim Cremer, 5/1/09, extending/modifying/adapting code found # on the web at http://wiki.forum.nokia.com/index.php/PyS60_Google_Maps_API # To use this code, look at the showMap function at the bottom of the file. # Then execute something like # showMap("Varanasi, India", 12, 0, 0) # To understand the code, study the key functions # geocodeAdress(...) and # retrieveStaticMap(...) ################################################################################ # apikey for running on localhost:8080 # if you use this Google Maps API key, you don't need to get your own right now. # However, if you create Google Maps applications after this homework assignment # you will need to get your own key and make sure you follow Google's legal Terms # and Conditions for usage of the mapping APIs. api_key = 'ABQIAAAA1XbMiDxx_BTCY2_FkPh06RR20YmIEbERyaW5EQEiVNF0mpNGfBSRb_rzgcy5bqzSaTV8cyi2Bgsx3g' tmp_file = '/Users/cremer/Desktop/pic.jpg' # Given a string representing a location, return 2-element # [latitude, longitude] list for that location (or print # an error message when Google doesn't find the location) # def geocodeAddress(addressString): url = getGeocodeUrl(addressString) resultFromGoogle = urllib.urlopen(url).read() data = resultFromGoogle.split(',') # The URL asked Google to return information in "csv" form. # data[0] contains: HTTP status code. 200 is good, others are errors. # data[1] contains: some "accuracy" information - ignore this for now. # data[2] contains: latitude # data[3] contains: longitude if data[0] != "200": errorCode = int(data[0]) printNow("Google Maps Exception: %s" % getGeocodeError(errorCode)) else: # if no error return a [latitude, longitude] list return [float(data[2]),float(data[3])] # Construct a URL that represents a query to google for the # location of the given addressString. # def getGeocodeUrl(addressString): urlbase = "http://maps.google.com/maps/geo" return "%(urlbase)s?%(params)s" % {'params': urllib.urlencode({'q':addressString, 'output':'csv', 'key':api_key }), 'urlbase': urlbase} def getGeocodeError(errorCode): errorDict = {400: "Bad request", 500: "Server error", 601: "Missing query", 602: "Unknown address", 603: "Unavailable address", 604: "Unknown directions", 610: "Bad API key", 620: "Too many queries"} if errorCode in errorDict: return errorDict[errorCode] else: return "Unknown error" # First construct a URL suitable for the Google Static Maps API # Then use the URL to request a map from Google, storing the # resulting image in tmp_file # def retrieveStaticMap(width, height, lat, long, zoom): url = getMapUrl(width, height, lat, long, zoom) urllib.urlretrieve(url, tmp_file) return tmp_file # Contruct a Google Static Maps API URL for a map that: # has size width x height in pixels # is centered at latitude lat and longitude long # is "zoomed" to the give Google Maps zoom level (0 <= zoom <= 21) # def getMapUrl(width, height, lat, lng, zoom): urlbase = "http://maps.google.com/staticmap" params = ["center=%(lat)s,%(lng)s" % {"lat":lat,"lng":lng}] params.append("format=%(format)s" % {"format":"jpeg"}) params.append("zoom=%(zoom)s" % {"zoom":zoom}) params.append("size=%(width)sx%(height)s" % {"width":width,"height":height}) params.append("key=%(api_key)s" % {"api_key":api_key}) return "%(urlbase)s?%(params)s" % {"urlbase":urlbase,"params":"&".join(params)} # some code useful for lat/long <--> x/y conversion # magic_number = 128<<21 # this is half the earth's circumference *in pixels* # at Google zoom level 21 radius = magic_number / math.pi # Return a new [latitude, longitude] pair that is # deltaX pixels to the right/left and # deltaY pixels above/below the input [lat, long] pair # Since the shift/adjustment is in pixels you need # to specify a Google zoom level since one-pixel shifts # represent different lat/long shifts at different zoom # levels. # Example: adjust(0, 0, 100, 0, 0) yields # (0, 140.625) meaning that # at zoom 0 (max farthest away view) # a 100 pixel shift moves from longitude # 0 to 140.625 (with latitude at the equator) # # But adjust(0, 0, 100, 0, 18), a zoomed-way-in # view, yields just a tiny latitude change # 0.00429 for the 100-pixel change. # def adjust(lat, lng, deltaX, deltaY, z): return (googleYToLat(latToGoogleY(lat) + (deltaY<<(21-z))), googleXToLong( longToGoogleX(lng) + (deltaX<<(21-z)))) # Return a list [winX, winY] of window coordinates corresponding to the # given lat/long location for a google map of winWidth-by-winHeight pixels # centered at lat/long [winCenterLat, winCenterLng] and with the given zoom level # # This function should make it easy to place additional text on your maps - # in particular, it will make it pretty easy to annotate the graph edges with # their lengths/distances # def latLongToWindowXY(lat, lng, winCenterLat, winCenterLng, winWidth, winHeight, zoom): winCenterX = winWidth/2 winCenterY = winHeight/2 winX = winCenterX + ((longToGoogleX(lng) - longToGoogleX(winCenterLng))>>(21-zoom)) winY = winCenterY + ((latToGoogleY(lat) - latToGoogleY(winCenterLat))>>(21-zoom)) return [winX, winY] def longToGoogleX(lng): return int(round(magic_number + (lng / 180.0) * magic_number)) def latToGoogleY(lat): return int(round(magic_number - radius * math.log( (1 + math.sin(lat * math.pi / 180)) / (1 - math.sin(lat * math.pi / 180)) ) / 2)) def googleXToLong(x): return 180.0 * ((round(x) - magic_number) / magic_number) def googleYToLat(y): return ( (math.pi / 2) - (2 * math.atan(math.exp( (round(y)-magic_number)/radius ))) ) * 180 / math.pi # Show a map, built via Google Static Maps API, based on the location # specified by "addressString" and zoomed according to the # given zoom level (Google's zoom levels range from 0 to 21). # The location will be in the center of the map is xShift and # yShift are zero. Otherwise the location will be offset # xShift pixels left/right of the center and yShift pixels up/down. # def showMap(addressString, zoom, xShift, yShift): latLong = geocodeAddress(addressString) adjustedLatLong= adjust(latLong[0], latLong[1], xShift, yShift, zoom) retrieveStaticMap(400,300, adjustedLatLong[0], adjustedLatLong[1], zoom) pic = makePicture(tmp_file) addText(pic, 10, 10, "hello") show(pic)