I am writing a haversine distance and angle calculator in Python as part of a small autonomous RC car project. My two test locations are 38.63594444444444,-90.2315
and 38.63594444444444,-90.23211111111111
.
Most online calculators (and my own personal TI-89) are getting a distance of roughly 0.05308 km. However, my Python function is getting a distance of 0.06795 km. That's ~15m off and that is huge with a small RC car.
My bearing calculation function, points2angle
, was failing until I did some float casting in my toDegrees
function. Integer division was screwing me over.
Be warned, my points2angle
and points2distance
functions expect a tuple of (degrees, minutes, seconds). The two test locations are (38, 38, 9.4), (-90, 13, 53.4)
and (38, 38, 9.4), (-90, 13, 55.6)
in that format.
EDIT: Thank you to MSeifert. I just had my latitude and longitude mixed up. I fixed my points2angle
code below but left the error in my points2distance
code so the difference between my wrong code and the answer was still clear.
My distance calculation (wrong distance returned):
def points2distance(start, end):
start_long = math.radians(toDegrees(start[0]))
start_latt = math.radians(toDegrees(start[1]))
end_long = math.radians(toDegrees(end[0]))
end_latt = math.radians(toDegrees(end[1]))
d_latt = float(end_latt - start_latt)
d_long = float(end_long - start_long)
a = (math.sin(d_latt/2)**2) + math.cos(start_latt) * math.cos(end_latt)* (math.sin(d_long/2)**2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
return 6371 * c
My decimal degrees conversion function (working):
def toDegrees(coord):
degrees = float(math.fabs(coord[0])) + float(coord[1]/60) + float(coord[2]/3600)
if coord[0] < 0:
degrees = degrees*-1
return degrees
My bearing angle calculation (working):
def points2angle(start, end):
start_long = math.radians(toDegrees(start[1]))
start_latt = math.radians(toDegrees(start[0]))
end_long = math.radians(toDegrees(end[1]))
end_latt = math.radians(toDegrees(end[0]))
d_latt = end_latt - start_latt
d_long = end_long - start_long
y = math.sin(d_long)*math.sin(end_latt)
x = (math.cos(start_latt)*math.sin(end_latt)) - (math.sin(start_latt)*math.cos(end_latt)*math.cos(d_long))
brng = math.degrees(math.atan2(y,x))
compBear = (brng+360) % 360;
return compBear
Your longitude and latitude are mixed up, just swap them (or if they were swapped in the arguments then swap them there) and it works:
def points2distance(start, end):
start_long = math.radians(toDegrees(start[1]))
start_latt = math.radians(toDegrees(start[0]))
end_long = math.radians(toDegrees(end[1]))
end_latt = math.radians(toDegrees(end[0]))
d_latt = float(end_latt - start_latt)
d_long = float(end_long - start_long)
a = (math.sin(d_latt/2)**2) + math.cos(start_latt) * math.cos(end_latt)* (math.sin(d_long/2)**2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
return 6371 * c
points2distance([(38, 38, 9.4), (-90, 13, 53.4)], [(38, 38, 9.4), (-90, 13, 55.6)])
# returns: 0.053079628495340196