# # geomath.py # # some geo coordinate math that I found on the internet # # kevinabrandon@gmail.com # import math def HeadingStr(heading): """ Gives a heading string given the heading float """ headstr = "?" if heading != None: if heading < 22.5 or heading >= 337.5: headstr = "N" elif heading >=22.5 and heading < 67.5: headstr = "NE" elif heading >= 67.5 and heading < 112.5: headstr = "E" elif heading >= 112.5 and heading < 157.5: headstr = "SE" elif heading >= 157.5 and heading < 202.5: headstr = "S" elif heading >= 202.5 and heading < 247.5: headstr = "SW" elif heading >= 247.5 and heading < 292.5: headstr = "W" elif heading >= 292.5 and heading < 337.5: headstr = "NW" return headstr def knot2mph(k): """ Converts knots to miles per hour. """ if k == None: return None return k * 1.15078 def mi2km(mi): """ Converts to miles to kilometers. """ if mi == None: return None return mi * 1.60934 def mi2nm(mi): """ Converts miles to nautical miles """ if mi == None: return None return mi * 0.868976 def ft2m(ft): """ Converts feet to meters. """ if ft == None: return None return ft * 0.3048 def distance(pointA, pointB): """ Calculate the great circle distance between two points on the earth (specified in decimal degrees) http://stackoverflow.com/questions/15736995/how-can-i-quickly-estimate-the-distance-between-two-latitude-longitude-points """ # convert decimal degrees to radians lon1, lat1, lon2, lat2 = map(math.radians, [pointA[1], pointA[0], pointB[1], pointB[0]]) # haversine formula dlon = lon2 - lon1 dlat = lat2 - lat1 a = math.sin(dlat/2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon/2)**2 c = 2 * math.asin(math.sqrt(a)) r = 3956 # Radius of earth in miles. Use 6371 for kilometers return c * r def bearing(pointA, pointB): """ Calculates the bearing between two points. Found here: https://gist.github.com/jeromer/2005586 The formulae used is the following: θ = atan2(sin(Δlong).cos(lat2), cos(lat1).sin(lat2) − sin(lat1).cos(lat2).cos(Δlong)) :Parameters: - `pointA: The tuple representing the latitude/longitude for the first point. Latitude and longitude must be in decimal degrees - `pointB: The tuple representing the latitude/longitude for the second point. Latitude and longitude must be in decimal degrees :Returns: The bearing in degrees :Returns Type: float """ if (type(pointA) != tuple) or (type(pointB) != tuple): raise TypeError("Only tuples are supported as arguments") lat1 = math.radians(pointA[0]) lat2 = math.radians(pointB[0]) diffLong = math.radians(pointB[1] - pointA[1]) x = math.sin(diffLong) * math.cos(lat2) y = math.cos(lat1) * math.sin(lat2) - (math.sin(lat1) * math.cos(lat2) * math.cos(diffLong)) initial_bearing = math.atan2(x, y) # Now we have the initial bearing but math.atan2 return values # from -180° to + 180° which is not what we want for a compass bearing # The solution is to normalize the initial bearing as shown below initial_bearing = math.degrees(initial_bearing) compass_bearing = (initial_bearing + 360) % 360 return compass_bearing