gpx_ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8d28ab6aad3c8f49b2a1623c39a58a54a550e2fc
4
+ data.tar.gz: 9e87c82457414596fdad17d515489e7cf4a01375
5
+ SHA512:
6
+ metadata.gz: f1e26c42d0a11f5e6598f0f486b189ebdb37bf0af645dea7320ff7a736150a877123bf02d2996d7ffa885978b2e203406e870efcc197f8b397c05135b303b328
7
+ data.tar.gz: 241a076a866fefeb6e476ef24aa26e40f44941a82cdc6ad6041e1a7fe613d37cae92648743194288fdcb017c9da6c0ce8f91a118bb45ab07b0276d84facc9281
@@ -0,0 +1,7 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |task|
4
+ task.libs = ['.', 'lib', 'test']
5
+ task.test_files = FileList['test/test_*.rb']
6
+ task.verbose = true
7
+ end
@@ -0,0 +1,24 @@
1
+ module GpxRuby
2
+
3
+ require 'nokogiri'
4
+ require 'time'
5
+ require 'tempfile'
6
+ require 'gpx_ruby/gpx/point'
7
+ require 'gpx_ruby/gpx/track'
8
+ require 'gpx_ruby/gpx/parsers/track_parser'
9
+ require 'gpx_ruby/gpx/document'
10
+ require 'gpx_ruby/gpx/parser'
11
+
12
+ class << self
13
+
14
+ def File(input)
15
+ Gpx::Parser.new(input).parse
16
+ end
17
+
18
+ def XML(xml_string)
19
+ Gpx::Parser.new(xml: xml_string).parse
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,19 @@
1
+ module GpxRuby
2
+
3
+ module Gpx
4
+
5
+ class Document
6
+
7
+ attr_accessor :version, :creator, :tracks
8
+
9
+ def initialize(a_hash)
10
+ @creator = a_hash[:creator]
11
+ @version = a_hash[:version]
12
+ @tracks = a_hash[:tracks]
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,54 @@
1
+ module GpxRuby
2
+
3
+ module Gpx
4
+
5
+ class Parser
6
+
7
+ def initialize(input)
8
+ @xml = case input
9
+ when File
10
+ input.read
11
+ when Tempfile
12
+ input.read
13
+ when String
14
+ ::File.open(input, 'r') { |f| f.read }
15
+ when Hash
16
+ if input[:file_path] && input[:file_path].is_a?(String)
17
+ ::File.open(input[:file_path], 'r') { |f| f.read }
18
+ end
19
+ if input[:xml] && input[:xml].is_a?(String)
20
+ input[:xml]
21
+ elsif input[:file] && (input[:file].is_a?(File) || input[:file].is_a?(Tempfile))
22
+ input[:file].read
23
+ else
24
+ raise 'Error: invalid input!'
25
+ end
26
+ else
27
+ raise 'Error: invalid input!'
28
+ end
29
+ end
30
+
31
+
32
+ def parse
33
+ doc = Nokogiri::XML(@xml)
34
+ @gpx_node = doc.at_xpath('//xmlns:gpx')
35
+
36
+ properties = {
37
+ creator: @gpx_node.at_xpath('@creator').value,
38
+ version: @gpx_node.at_xpath('@version').value.to_f,
39
+ tracks: []
40
+ }
41
+
42
+ # parse track elements
43
+ tracks = Parsers::TrackParser.new(@gpx_node).parse
44
+ properties = properties.merge(tracks: tracks)
45
+
46
+ Document.new properties
47
+ end
48
+
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,121 @@
1
+ module GpxRuby
2
+
3
+ module Gpx
4
+
5
+ module Parsers
6
+
7
+ class TrackParser
8
+
9
+ def initialize(gpx_node)
10
+ @gpx_node = gpx_node
11
+ end
12
+
13
+ def parse
14
+ tracks = []
15
+ if track_nodes = @gpx_node.xpath('./xmlns:trk')
16
+ # iterate over all tracks
17
+ track_nodes.each do |trk|
18
+ trk_segments = trk.xpath('./xmlns:trkseg')
19
+
20
+ # map track segments for this track
21
+ track_segments = trk_segments.map do |trkseg|
22
+
23
+ # map all track points for this track segment
24
+ track_points = trkseg.xpath('./xmlns:trkpt').map do |trkpt|
25
+
26
+ lat = trkpt.at_xpath('./@lat').value.to_f
27
+ lon = trkpt.at_xpath('./@lon').value.to_f
28
+
29
+ time = begin
30
+ DateTime.xmlschema(trkpt.at_xpath('./xmlns:time').text).to_time
31
+ rescue
32
+ nil
33
+ end
34
+
35
+ elevation = begin
36
+ trkpt.at_xpath('./xmlns:ele').text.to_f
37
+ rescue
38
+ nil
39
+ end
40
+
41
+ Track::Point.new lat: lat, lon: lon, time: time, elevation: elevation
42
+ end
43
+
44
+ Track::Segment.new track_points
45
+ end
46
+
47
+ trk_name = begin
48
+ trk.at_xpath('./xmlns:name').text
49
+ rescue
50
+ nil
51
+ end
52
+
53
+ trk_cmt = begin
54
+ trk.at_xpath('./xmlns:cmt').text
55
+ rescue
56
+ nil
57
+ end
58
+
59
+ trk_src = begin
60
+ trk.at_xpath('./xmlns:src').text
61
+ rescue
62
+ nil
63
+ end
64
+
65
+ trk_desc = begin
66
+ trk.at_xpath('./xmlns:desc').text
67
+ rescue
68
+ nil
69
+ end
70
+
71
+ trk_number = begin
72
+ trk.at_xpath('./xmlns:number').text
73
+ rescue
74
+ nil
75
+ end
76
+
77
+ trk_url = begin
78
+ trk.at_xpath('./xmlns:url').text
79
+ rescue
80
+ nil
81
+ end
82
+
83
+ trk_url_name = begin
84
+ trk.at_xpath('./xmlns:urlname').text
85
+ rescue
86
+ nil
87
+ end
88
+
89
+ trk_time = begin
90
+ DateTime.xmlschema(trk.at_xpath('./xmlns:time').text).to_time
91
+ rescue
92
+ nil
93
+ end
94
+
95
+ track_hash = {
96
+ segments: track_segments,
97
+ name: trk_name,
98
+ time: trk_time,
99
+ source: trk_src,
100
+ description: trk_desc,
101
+ number: trk_number,
102
+ comment: trk_cmt,
103
+ url: trk_url,
104
+ url_name: trk_url_name
105
+ }
106
+
107
+ tracks << Track.new(track_hash)
108
+ end
109
+
110
+ end
111
+
112
+ tracks
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+
121
+ end
@@ -0,0 +1,78 @@
1
+ module GpxRuby
2
+
3
+ module Gpx
4
+
5
+ class Point
6
+
7
+ attr_accessor :lat, :lon
8
+
9
+ RADIUS_KM = 6371
10
+
11
+ def initialize(a_hash)
12
+ @lat = a_hash[:lat]
13
+ @lon = a_hash[:lon]
14
+ end
15
+
16
+
17
+ def [](index)
18
+ case index
19
+ when 0
20
+ lat
21
+ when 1
22
+ lon
23
+ else
24
+ raise 'Invalid index!'
25
+ end
26
+ end
27
+
28
+ def +(a_point)
29
+ nlat = lat + a_point.lat
30
+ nlon = lon + a_point.lon
31
+ Point.new lat: nlat, lon: nlon
32
+ end
33
+
34
+ def /(a_scalar)
35
+ nlat = lat / a_scalar.to_f
36
+ nlon = lon / a_scalar.to_f
37
+ Point.new lat: nlat, lon: nlon
38
+ end
39
+
40
+ def to_s
41
+ "lat: #{lat}, lon: #{lon}"
42
+ end
43
+
44
+ def to_a
45
+ [lat, lon]
46
+ end
47
+
48
+ def to_hash
49
+ { lat: lat, lon: lon }
50
+ end
51
+
52
+ alias_method :to_h, :to_hash
53
+
54
+
55
+ def distance(a_point)
56
+ p_point = self
57
+ rad_per_deg, radius_meter = Math::PI/180, RADIUS_KM * 1000
58
+
59
+ dlon_rad = (a_point.lon-p_point.lon) * rad_per_deg
60
+ dlat_rad = (a_point.lat-p_point.lat) * rad_per_deg
61
+
62
+ lat1_rad = p_point.lat * rad_per_deg
63
+ lat2_rad = a_point.lat * rad_per_deg
64
+
65
+ p_point = Math.sin(dlat_rad/2)**2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.sin(dlon_rad/2)**2
66
+ c = 2 * Math::atan2(Math::sqrt(p_point), Math::sqrt(1-p_point))
67
+
68
+ radius_meter * c
69
+ end
70
+
71
+
72
+ end
73
+
74
+ end
75
+
76
+
77
+
78
+ end
@@ -0,0 +1,100 @@
1
+ module GpxRuby
2
+
3
+ module Gpx
4
+
5
+ class Track
6
+
7
+ attr_accessor :segments, :name, :time,
8
+ :description, :source, :comment,
9
+ :number, :url, :url_name
10
+
11
+ def initialize(a_hash)
12
+ @name = a_hash[:name]
13
+ @time = a_hash[:time]
14
+ @segments = a_hash[:segments] || []
15
+ @number = a_hash[:number]
16
+ @source = a_hash[:source]
17
+ @url = a_hash[:url]
18
+ @url_name = a_hash[:url_name]
19
+ @comment = a_hash[:comment]
20
+ @description = a_hash[:description]
21
+ end
22
+
23
+ def points
24
+ @points ||= @segments.map {|segment| segment.points }.reduce(:+)
25
+ end
26
+
27
+ def distance
28
+ @distance ||= @segments.map {|segment| segment.distance }.reduce(:+)
29
+ end
30
+
31
+ def total_time
32
+ start_time = @segments.first.points.first.time
33
+ end_time = @segments.last.points.last.time
34
+ end_time - start_time rescue 0
35
+ end
36
+
37
+ def center_of_gravity
38
+ track_points = points
39
+ len = track_points.size
40
+ center = track_points.reduce(:+)
41
+ center / len
42
+ end
43
+
44
+
45
+ class Point < Gpx::Point
46
+
47
+ attr_accessor :lat, :lon, :time, :elevation
48
+
49
+ def initialize(params)
50
+ @lat = params[:lat]
51
+ @lon = params[:lon]
52
+ @time = params[:time]
53
+ @elevation = params[:elevation]
54
+ end
55
+
56
+ def to_a
57
+ [@lat,@lon]
58
+ end
59
+
60
+ end
61
+
62
+
63
+ class Segment
64
+
65
+ attr_accessor :points
66
+
67
+ def initialize(points)
68
+ @points = points || []
69
+ end
70
+
71
+ def distance
72
+ if @distance
73
+ @distance
74
+ else
75
+ zipped_points = @points[0...-1].zip(@points[1..-1])
76
+ distances = zipped_points.map {|(p,q)| p.distance(q) }
77
+ @distance = distances.reduce(:+)
78
+ end
79
+ end
80
+
81
+ def total_time
82
+ start_time, end_time = @points.first.time, @points.last.time
83
+ end_time - start_time rescue 0
84
+ end
85
+
86
+ def center_of_gravity
87
+ track_points = points
88
+ len = track_points.size
89
+ center = track_points.reduce(:+)
90
+ center / len
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+
99
+
100
+ end
@@ -0,0 +1,3 @@
1
+ module GpxRuby
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,167 @@
1
+ require 'test/test_helper'
2
+
3
+ class TestGpxParser < MiniTest::Test
4
+
5
+ def setup
6
+ @gpx_parser = GpxRuby::Gpx::Parser.new './test/run_keeper.gpx'
7
+ @gpx_file = @gpx_parser.parse
8
+ end
9
+
10
+ def test_should_read_gpx_file
11
+ gpx_parser = GpxRuby::Gpx::Parser.new File.open('./test/run_keeper.gpx','r')
12
+ gpx_file = gpx_parser.parse
13
+ assert gpx_file.creator
14
+ assert gpx_file.version
15
+ end
16
+
17
+
18
+ def test_should_read_gpx_temp_file
19
+ xml = File.open('./test/run_keeper.gpx','r') { |f| f.read }
20
+ tmp_file = Tempfile.open('blah.gpx')
21
+ tmp_file.write xml
22
+ tmp_file.rewind
23
+ gpx_parser = GpxRuby::Gpx::Parser.new tmp_file
24
+ gpx_file = gpx_parser.parse
25
+ assert gpx_file.creator
26
+ assert gpx_file.version
27
+ end
28
+
29
+
30
+ def test_should_read_file_path
31
+ gpx_parser = GpxRuby::Gpx::Parser.new './test/run_keeper.gpx'
32
+ gpx_file = gpx_parser.parse
33
+ assert gpx_file.creator
34
+ assert gpx_file.version
35
+ end
36
+
37
+
38
+ def test_should_read_gpx_xml
39
+ xml = File.open('./test/run_keeper.gpx') do |f|
40
+ f.read
41
+ end
42
+ gpx_parser = GpxRuby::Gpx::Parser.new xml: xml
43
+ gpx_file = gpx_parser.parse
44
+ assert gpx_file.creator
45
+ assert gpx_file.version
46
+ end
47
+
48
+
49
+ def test_should_read_gpx_xml_using_a_shortcut
50
+ xml = File.open('./test/run_keeper.gpx') do |f|
51
+ f.read
52
+ end
53
+ gpx_file = GpxRuby::XML(xml)
54
+ assert gpx_file.creator
55
+ assert gpx_file.version
56
+ end
57
+
58
+
59
+ def test_should_read_gpx_file_using_a_shortcut
60
+ gpx_file = GpxRuby::File './test/run_keeper.gpx'
61
+ assert gpx_file.creator
62
+ assert gpx_file.version
63
+ end
64
+
65
+
66
+ def test_should_compute_center_of_gravity
67
+ gpx_parser = GpxRuby::Gpx::Parser.new './test/run_keeper.gpx'
68
+ gpx_file = gpx_parser.parse
69
+ track = gpx_file.tracks.first
70
+ pp 'center of gravity: %s' % track.center_of_gravity
71
+ end
72
+
73
+
74
+ def test_should_read_fell_loops
75
+ gpx_file = GpxRuby::File './test/gpx_samples/fells_loop.gpx'
76
+ assert gpx_file.creator
77
+ assert gpx_file.version
78
+ track = gpx_file.tracks.first
79
+ assert track.nil?
80
+ gpx_file.tracks.each do |track|
81
+ assert track.name || track.name.nil?
82
+ assert track.time || track.time.nil?
83
+ assert track.distance
84
+ end
85
+ end
86
+
87
+
88
+ def test_should_read_boise_front
89
+ gpx_file = GpxRuby.File './test/gpx_samples/BoiseFront.gpx'
90
+ assert gpx_file.creator
91
+ assert gpx_file.version
92
+ track = gpx_file.tracks.first
93
+ assert track.nil? == false
94
+ assert track.total_time == 0
95
+ gpx_file.tracks.each do |track|
96
+ assert track.name || track.name.nil?
97
+ assert track.time || track.time.nil?
98
+ assert track.distance
99
+ end
100
+ end
101
+
102
+
103
+ def test_should_read_track
104
+ track = @gpx_file.tracks.first
105
+ assert track
106
+ assert track.is_a? GpxRuby::Gpx::Track
107
+ end
108
+
109
+
110
+ def test_should_read_track_segments
111
+ track = @gpx_file.tracks.first
112
+ track_segments = track.segments
113
+ assert track_segments.size == 4
114
+ end
115
+
116
+
117
+ def test_should_read_track_segment_points
118
+ track = @gpx_file.tracks.first
119
+ track_segment = track.segments.last
120
+ assert track_segment.points.size > 0
121
+ track_points = track_segment.points
122
+ track_points.each do |track_point|
123
+ assert track_point.lat
124
+ assert track_point.lon
125
+ assert track_point.elevation
126
+ end
127
+
128
+ end
129
+
130
+
131
+ def test_should_read_track_points
132
+ track = @gpx_file.tracks.first
133
+ assert track
134
+ assert track.points.size > 0
135
+ track_points = track.points
136
+ track_points.each do |track_point|
137
+ assert track_point.lat
138
+ assert track_point.lon
139
+ assert track_point.elevation
140
+ end
141
+ end
142
+
143
+
144
+ def test_should_compute_total_track_segment_distance
145
+ track = @gpx_file.tracks.first
146
+ puts track.segments.map {|segment| segment.distance }
147
+ end
148
+
149
+
150
+ def test_should_compute_total_track_distance
151
+ track = @gpx_file.tracks.first
152
+ puts track.distance
153
+ end
154
+
155
+
156
+ def test_should_compute_total_track_time
157
+ track = @gpx_file.tracks.first
158
+ puts track.total_time
159
+ end
160
+
161
+
162
+ def test_should_compute_total_segment_time
163
+ track = @gpx_file.tracks.first
164
+ puts track.segments.map {|segment| segment.total_time }
165
+ end
166
+
167
+ end
@@ -0,0 +1,3 @@
1
+ require 'minitest/autorun'
2
+ require 'gpx_ruby'
3
+ require 'pp'
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gpx_ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Rüeedlinger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.6.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.6'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.6.1
33
+ description: A simple gpx file parser for reading gpx files.
34
+ email: a.rueedlinger@gmail.com
35
+ executables: []
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - Rakefile
40
+ - lib/gpx_ruby.rb
41
+ - lib/gpx_ruby/gpx/document.rb
42
+ - lib/gpx_ruby/gpx/parser.rb
43
+ - lib/gpx_ruby/gpx/parsers/track_parser.rb
44
+ - lib/gpx_ruby/gpx/point.rb
45
+ - lib/gpx_ruby/gpx/track.rb
46
+ - lib/version.rb
47
+ - test/test_gpx_parser.rb
48
+ - test/test_helper.rb
49
+ homepage: http://github.com/lexruee/gpx_ruby
50
+ licenses:
51
+ - MIT
52
+ metadata: {}
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.9.3
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 2.2.2
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: A gpx file parser for reading gpx files.
73
+ test_files: []