Skip to content

Instantly share code, notes, and snippets.

@rudyryk
Last active December 21, 2015 08:39
Show Gist options
  • Save rudyryk/6279782 to your computer and use it in GitHub Desktop.
Save rudyryk/6279782 to your computer and use it in GitHub Desktop.
Approximate longitude & latitude rectangle for specified location and distance.
import math
def georange(origin, distance):
"""
Returns approximate longitude & latitude rectangle range for
specified origin and distance in km. Works good when:
distance is far smaller 6400 km (approximate Earth radius)
origin isn't too close to North and South poles
Parameters:
origin -- tuple (lat, lng) in degrees
distance -- float > 0 in km
Result:
((lat1, lat2), (lng1, lng2), (lng3, lng4))
We should produce 2 ranges for longitude as it may have
gap at edges, e.g. [-190, -170] is invalid range and it's
splitted into [-180, -170] and [170, 180] ranges.
Examples:
>>> georange((55.45, 37.37), 2.0)[0]
(55.432013567881626, 55.46798643211838)
>>> georange((55.45, 37.37), 2.0)[1]
(37.33828490093818, 37.40171509906182)
>>> georange((55.45, 37.37), 2.0)[2]
(37.33828490093818, 37.40171509906182)
>>> georange((200.0, 0), 2.0)
Traceback (most recent call last):
...
Exception: Latitude must be in range [-90.0, 90.0]
>>> georange((0.0, 190), 2.0)
Traceback (most recent call last):
...
Exception: Longitude must be in range [-180.0, 180.0]
NO COPYRIGHT
------------
You can copy, modify, distribute and perform the work, even for
commercial purposes, all without asking permission.
See Other Information below.
CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
http://creativecommons.org/publicdomain/zero/1.0/
"""
radius = 6371.0 # in km
lat, lng = map(float, origin)
# Validate values range
if not (-90.0 <= lat <= 90.0):
raise ValueError("Latitude must be in range [%s, %s]" % (-90.0, 90.0))
if not (-180.0 <= lng <= 180.0):
raise ValueError("Longitude must be in range [%s, %s]" % (-180.0, 180.0))
# Range for latitude
dlat = math.degrees(distance / radius)
lat1, lat2 = max(-90.0, lat - dlat), min(90.0, lat + dlat)
# Ranges for longitude
r = radius * math.cos(math.radians(lat))
dlng = (r > 0) and min(180.0, math.degrees(distance / r)) or 180.0
lng1, lng2 = lng - dlng, lng + dlng
lng3, lng4 = lng1, lng2
# Split longitude range if required
if lng1 < -180.0:
lng3, lng4 = (360.0 + lng1, 180.0)
lng1, lng2 = (-180.0, lng2)
elif lng2 > 180.0:
lng3, lng4 = (-180.0, lng2 - 360)
lng1, lng2 = (lng1, 180.0)
return ((lat1, lat2), (lng1, lng2), (lng3, lng4))
if __name__ == "__main__":
import doctest
doctest.testmod()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment