dougfales/gpx

View on GitHub
bin/gpx_smooth

Summary

Maintainability
Test Coverage
#!/usr/bin/env ruby

# frozen_string_literal: true

require File.expand_path('../lib/gpx', __dir__)
require 'optparse'

def str_to_int_or_time(str)
  case str
  when /\A\d{10}\Z/
    Time.at(str.to_i)
  when /\A\d+\Z/
    str.to_i
  else
    DateTime.strptime(str, '%Y%m%d-%H:%M:%S').to_time
  end
end

options = {}
OptionParser.new do |opts|
  opts.banner = 'Usage: smooth [options]'

  opts.on('-i', '--input-file FILE', 'Input file to read gpx data from (if omitted, data will be read from stdin)') do |v|
    options[:infile] = v
  end
  opts.on('-o', '--output-file FILE', 'Output file to write smoothed gpx data to (if omitted, data will be written to stdout)') do |v|
    options[:outfile] = v
  end
  opts.on('-s', '--start-time [YYYYMMDD-HH:MM:SS|EPOCH|OFFSET]', 'Start smoothing from time or offset specified (if omitted start from the start of the file)') do |v|
    options[:start] = v
  end
  opts.on('-e', '--end-time [YYYYMMDD-HH:MM:SS|EPOCH|OFFSET]', 'Finish smoothing from time or offset specified (if omitted finish at the end of the file)') do |v|
    options[:end] = v
  end
end.parse!

input = if options[:infile]
          File.open(options[:infile])
        else
          $stdin
        end

options[:start] = str_to_int_or_time(options[:start]) if options[:start]
options[:end] = str_to_int_or_time(options[:end]) if options[:end]

gpx = GPX::GPXFile.new(gpx_data: input)
warn "read track with distance #{gpx.distance}"

# 1419062980
gpx.tracks.each do |track|
  track.segments.each do |segment|
    segment.smooth_location_by_average(end: options[:end], start: options[:start])
  end
end
gpx.recalculate_distance
warn "smoothed distance #{gpx.distance}"

if options[:outfile]
  gpx.write(options[:outfile], false)
else
  puts gpx.to_s(false)
end