Skip to content

Instantly share code, notes, and snippets.

@alexreisner
Created July 25, 2011 16:17
Show Gist options
  • Save alexreisner/1104495 to your computer and use it in GitHub Desktop.
Save alexreisner/1104495 to your computer and use it in GitHub Desktop.
Compare two trig-less distance approximation formulas.
#
# This script is a rough test of two trig-less distance approximation formulas.
#
# Each formula takes two sets of lat/lon coordinates and returns the approximate
# number of miles between them, without using trigonometry.
#
require 'geocoder' # geocoder ruby gem
def dx(c1, c2)
d = Geocoder::Calculations.longitude_degree_distance(30)
d * (c1[1] - c2[1]).abs
end
def dy(c1, c2)
d = Geocoder::Calculations.latitude_degree_distance
d * (c1[0] - c2[0]).abs
end
def actual(c1, c2)
Geocoder::Calculations.distance_between(c1, c2)
end
# Alex Reisner's formula
def reisner(c1, c2)
(dy(c1, c2) * Math.sin(Math::PI / 4)) + (dx(c1, c2) * Math.sin(Math::PI / 4))
end
# Rob Poor's formula
def rdpoor(c1, c2)
[dx(c1, c2), dy(c1, c2)].max + ([dx(c1, c2), dy(c1, c2)].min * 0.5)
end
# Rafael Baptista's formula (rdpoor with better coefficients)
def baptista(c1, c2)
k1 = 1007.0 / 1024.0
k2 = 441.0 / 1024.0
([dx(c1, c2), dy(c1, c2)].max * k1) + ([dx(c1, c2), dy(c1, c2)].min * k2)
end
systems = [:reisner, :rdpoor, :baptista]
errors = {}; systems.each{ |s| errors[s] = [] }
c1 = [40, -80]
(0...10).each do |i|
c2 = [c1[0] + i, c1[1] + 10 - i]
bearing = Geocoder::Calculations.bearing_between(c1, c2)
puts "%s --> %s (%d degrees)" % [c1.inspect, c2.inspect, bearing]
systems.each do |s|
errors[s] << 100.0 * (send(s, c1, c2) - actual(c1, c2)) / actual(c1, c2)
puts "#{s} error: %.1f%%" % errors[s].last
end
puts ""
end
systems.each do |s|
avg = errors[s].inject(0){ |t,i| t + i } / errors[s].size
puts "avg #{s} error: %.1f" % avg
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment