Skip to content

Instantly share code, notes, and snippets.

@7kry
Forked from dtan4/gpx_distance.rb
Last active August 29, 2015 14:02
Show Gist options
  • Save 7kry/be49088ec63424787861 to your computer and use it in GitHub Desktop.
Save 7kry/be49088ec63424787861 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'nokogiri'
require 'pp'
module GpxDistance
def calc_gpx_distance(gpx_file)
distance = calc_distance(get_latlons(gpx_file))
distance / 1000 # kilometers
end
private
def get_latlons(gpx_file)
gpx = Nokogiri::XML(open(gpx_file))
gpx.css("gpx trk trkpt").map{|pt|
[pt.attribute("lat").value.to_f, pt.attribute("lon").value.to_f]
}
end
def calc_distance(latlons)
distance =
latlons.map{|latlon|
deg_to_rad(latlon)
}.each_cons(2).inject(0){|dist, pt|
dist + hubeny(*pt)
}
distance # meters
end
def deg_to_rad(latlng)
latlng.map { |deg| deg * Math::PI / 180 }
end
# http://yamadarake.jp/trdi/report000001.html
# WGS84 (GPS)
A = 6378137.000
B = 6356752.314245
def hubeny(latlng_1, latlng_2)
pow_e = 1 - B ** 2 / A ** 2
ave = (latlng_1[0] + latlng_2[0]) / 2
dp = latlng_1[0] - latlng_2[0]
dr = latlng_1[1] - latlng_2[1]
sin_ave = Math.sin(ave)
cos_ave = Math.cos(ave)
w = Math.sqrt(1 - pow_e * sin_ave ** 2)
m = A * (1 - pow_e) / w ** 3
n = A / w
distance = Math.sqrt((m * dp) ** 2 + (n * cos_ave * dr) ** 2)
distance #meters
end
extend self
end
if __FILE__ == $0
exit 1 if ARGV.length < 1
gpx_file = ARGV[0]
distance = GpxDistance::calc_gpx_distance(gpx_file)
puts sprintf("%.3f km", distance)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment