Next, we have several utility functions that are used several times throughout the program. All of these, except the functions related to time, have been used in the previous chapters in some form. The ll2m()
function converts latitude and longitude to meters. The world2pixel()
function converts geospatial coordinates to pixel coordinates on our output map image. Then, we have two functions named get_utc_epoch()
and get_local_time()
that convert the UTC time stored in the GPX file to the local time along the route. Finally, we have a haversine distance function and our simple wms function to retrieve the map images:
def ll2m(lat, lon): """Lat/lon to meters""" x = lon * 20037508.34 / 180.0 y = math.log(math.tan((90.0 + lat) * math.pi / 360.0)) / (math.pi / 180.0) y = y * 20037508.34 / 180.0 return (x, y) def world2pixel(x, y, w, h, bbox): """Converts world coordinates to image pixel coordinates""" # Bounding box of the map minx, miny, maxx, maxy = bbox # world x distance xdist = maxx - minx # world y distance ydist = maxy - miny # scaling factors for x, y xratio = w/xdist yratio = h/ydist # Calculate x, y pixel coordinate px = w - ((maxx - x) * xratio) py = (maxy-y) * yratio return int(px), int(py) def get_utc_epoch(timestr): """Converts a GPX timestamp to Unix epoch seconds in Greenwich Mean Time to make time math easier""" # Get time object from ISO time string utctime = time.strptime(timestr, '%Y-%m-%dT%H:%M:%SZ') # Convert to seconds since epoch secs = int(time.mktime(utctime)) return secs def get_local_time(timestr, utcoffset=None): """Converts a GPX timestamp to Unix epoch seconds in the local time zone""" secs = get_utc_epoch(timestr) if not utcoffset: # Get local timezone offset if time.localtime(secs).tm_isdst: utcoffset = time.altzone pass else: utcoffset = time.timezone pass pass return time.localtime(secs - utcoffset) def haversine(x1, y1, x2, y2): """Haversine distance formula""" x_dist = math.radians(x1 - x2) y_dist = math.radians(y1 - y2) y1_rad = math.radians(y1) y2_rad = math.radians(y2) a = math.sin(y_dist/2)**2 + math.sin(x_dist/2)**2 * math.cos(y1_rad) * math.cos(y2_rad) c = 2 * math.asin(math.sqrt(a)) # Distance in miles. Just use c * 6371 # for kilometers distance = c * (6371/1.609344) # Miles return distance def wms(minx, miny, maxx, maxy, service, lyr, epsg, style, img, w, h): """Retrieve a wms map image from the specified service and saves it as a JPEG.""" wms = service wms += "?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&" wms += "LAYERS={}".format(lyr) wms += "&STYLES={}&".format(style) wms += "SRS=EPSG:{}&".format(epsg) wms += "BBOX={},{},{},{}&".format(minx, miny, maxx, maxy) wms += "WIDTH={}&".format(w) wms += "HEIGHT={}&".format(h) wms += "FORMAT=image/jpeg" wmsmap = urllib.request.urlopen(wms) with open(img + ".jpg", "wb") as f: f.write(wmsmap.read())
Next, we have our program variables. We will be accessing the OpenStreetMap WMS service provided by NOAA as well as the SRTM data provided by NASA.
We access the WMS services in this book using Python's urllib
library for simplicity, but if you plan to use the OGC web services frequently, you should use the Python OWSLib package available through PyPI at https://pypi.python.org/pypi/OWSLib.
We will output several intermediate products and images. These variables are used in those steps. The route.gpx
file is defined in this section as the gpx
variable, as follows:
# Needed for numpy conversions in hillshading deg2rad = 3.141592653589793 / 180.0 rad2deg = 180.0 / 3.141592653589793 # Program Variables # Name of the gpx file containing a route. # http://git.io/vl7qi gpx = "route.gpx" # NOAA OpenStreetMap Basemap # NOAA OSM WMS service osm_WMS = "http://osm.woc.noaa.gov/mapcache" # Name of the WMS street layer osm_lyr = "osm" # Name of the basemap image to save osm_img = "basemap" # OSM EPSG code (spatial reference system) osm_epsg = 3857 # Optional WMS parameter osm_style = "" # Shaded elevation parameters # # Sun direction azimuth = 315.0 # Sun angle altitude = 45.0 # Elevation exaggerationexagerationexaggeration z = 5.0 # Resolution scale = 1.0 # No data value for output no_data = 0 # Output elevation image name elv_img = "elevation" # RGBA color of the SRTM minimum elevation min_clr = (255, 255, 255, 0) # RGBA color of the SRTM maximum elevation max_clr = (0, 0, 0, 0) # No data color zero_clr = (255, 255, 255, 255) # Pixel width and height of the # output images w = 800 h = 800