Skip to content

Instantly share code, notes, and snippets.

@dtan4
Last active December 29, 2018 18:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dtan4/5743825 to your computer and use it in GitHub Desktop.
Save dtan4/5743825 to your computer and use it in GitHub Desktop.
Calculate distance between all Lat-Lons saved in GPX file.
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
module GpxDistance
def calc_gpx_distance(gpx_file)
gpx = File.open(gpx_file) { |f| f.read }
latlons = []
gpx.each_line { |line| latlons << [$1.to_f, $2.to_f] if line =~ /<trkpt lat="([0-9.]+)" lon="([0-9.]+)">/ }
distance = calc_distance(latlons)
distance / 1000 # kilometers
end
private
def calc_distance(latlons)
latlons.map! { |latlon| deg_to_rad(latlon) }
distance = (0...latlons.length - 1).inject(0) { |dist, i| dist + hubeny(latlons[i], latlons[i + 1]) }
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
end
include GpxDistance
exit 1 if ARGV.length < 1
gpx_file = ARGV[0]
distance = calc_gpx_distance(gpx_file)
puts sprintf("%.3f km", distance)
@hogsmill
Copy link

hogsmill commented Dec 29, 2018

Nor sure this is still supported (it rocks, BTW...) but the matches in line 8 should be

([0-9.\-]+)

...to cater for minus lat/longs - my files (in the UK) have minuses in them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment