broutes 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,152 @@
1
+ require 'spec_helper'
2
+
3
+ describe Formats::Tcx do
4
+ describe "#load" do
5
+ before(:all) do
6
+ @file = open_file('single_lap.tcx')
7
+ @target = Formats::Tcx.new
8
+ @route = GeoRoute.new
9
+
10
+ @target.load(@file, @route)
11
+ end
12
+
13
+ it "sets the start point lat" do
14
+ @route.start_point.lat.should eq(52.94124)
15
+ end
16
+ it "sets the start point lon" do
17
+ @route.start_point.lon.should eq(-1.26039)
18
+ end
19
+ it "sets the total distance" do
20
+ @route.total_distance.should eq(76037)
21
+ end
22
+ it "sets the total ascent" do
23
+ @route.total_ascent.round.should eq(1203)
24
+ end
25
+ it "sets the total descent" do
26
+ @route.total_descent.round.should eq(1204)
27
+ end
28
+ it "sets the total time" do
29
+ @route.total_time.round.should eq(10631)
30
+ end
31
+ it "sets the started_at" do
32
+ @route.started_at.to_i.should eq(Time.new(2012, 3, 15, 21, 20, 38).to_i)
33
+ end
34
+ it "sets the ended_at" do
35
+ @route.ended_at.to_i.should eq(Time.new(2012, 3, 16, 00, 17, 49).to_i)
36
+ end
37
+ it "can create hash" do
38
+ @route.to_hash
39
+ end
40
+ end
41
+
42
+ describe "#load Garmin Training Centre" do
43
+ before(:all) do
44
+ @file = open_file('garmin_training_center.tcx')
45
+ @target = Formats::Tcx.new
46
+ @route = GeoRoute.new
47
+
48
+ @target.load(@file, @route)
49
+ end
50
+
51
+ it "sets the start point lat" do
52
+ @route.start_point.lat.should eq(52.930873)
53
+ end
54
+ it "sets the start point lon" do
55
+ @route.start_point.lon.should eq(-1.2236503)
56
+ end
57
+ it "extracts the heart rate" do
58
+ @route.start_point.heart_rate.should eq(77)
59
+ end
60
+ it "extracts the cadence" do
61
+ @route.start_point.cadence.should eq(85)
62
+ end
63
+ it "extracts the speed" do
64
+ @route.start_point.speed.should eq(11.3190002)
65
+ end
66
+ it "extracts the power" do
67
+ @route.start_point.power.should eq(297)
68
+ end
69
+ it "sets the total distance" do
70
+ @route.total_distance.should eq(43892)
71
+ end
72
+ it "sets the total ascent" do
73
+ @route.total_ascent.round.should eq(416)
74
+ end
75
+ it "sets the total descent" do
76
+ @route.total_descent.round.should eq(404)
77
+ end
78
+ it "sets the total time" do
79
+ @route.total_time.round.should eq(6926)
80
+ end
81
+ it "can create hash" do
82
+ @route.to_hash
83
+ end
84
+ end
85
+
86
+ describe "file without GPS coordinates" do
87
+ before(:all) do
88
+ @file = open_file('no_gps_coordinates.tcx')
89
+ @target = Formats::Tcx.new
90
+ @route = GeoRoute.new
91
+
92
+ @target.load(@file, @route)
93
+ end
94
+
95
+ it "sets the total time" do
96
+ @route.total_time.should eq(653)
97
+ end
98
+ it "sets the start point lat" do
99
+ @route.start_point.lat.should be_nil
100
+ end
101
+ it "sets the start point lon" do
102
+ @route.start_point.lon.should be_nil
103
+ end
104
+ it "sets the total distance" do
105
+ @route.total_distance.should eq(0)
106
+ end
107
+ it "sets the total ascent" do
108
+ @route.total_ascent.should eq(2.403564500000016)
109
+ end
110
+ it "sets the total descent" do
111
+ @route.total_descent.should eq(2.8841553000000033)
112
+ end
113
+ it "can create hash" do
114
+ @route.to_hash
115
+ end
116
+ end
117
+
118
+ describe "file without points only summary" do
119
+ before(:all) do
120
+ @file = open_file('summary_no_points.tcx')
121
+ @target = Formats::Tcx.new
122
+ @route = GeoRoute.new
123
+
124
+ @target.load(@file, @route)
125
+ end
126
+
127
+ it "sets the total time" do
128
+ @route.total_time.should eq(2490)
129
+ end
130
+ it "start_point should be nil" do
131
+ @route.start_point.should be_nil
132
+ end
133
+ it "sets the total distance" do
134
+ @route.total_distance.should eq(21146)
135
+ end
136
+ it "sets the total ascent" do
137
+ @route.total_ascent.should eq(0)
138
+ end
139
+ it "sets the total descent" do
140
+ @route.total_descent.should eq(0)
141
+ end
142
+ it "can create hash" do
143
+ @route.to_hash
144
+ end
145
+ it "sets the started_at" do
146
+ @route.started_at.to_i.should eq(DateTime.parse("2012-09-05T18:55:11Z").to_time.to_i)
147
+ end
148
+ it "include the started at in the hash" do
149
+ @route.to_hash['started_at'].should_not be_nil
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe GeoPoint do
4
+ describe "#to_hash" do
5
+ before(:each) do
6
+ @point = GeoPoint.new(lat: random_lat, lon: random_lon)
7
+ end
8
+
9
+ subject { @point.to_hash }
10
+
11
+ it "contains lat" do
12
+ subject['lat'].should eq(@point.lat)
13
+ end
14
+ it "contains lon" do
15
+ subject['lon'].should eq(@point.lon)
16
+ end
17
+
18
+ context "when only lat lon set" do
19
+ it "should not contain distance" do
20
+ subject.keys.should_not include('distance')
21
+ end
22
+ it "should not contain elevation" do
23
+ subject.keys.should_not include('elevation')
24
+ end
25
+ end
26
+ context "when elevation set" do
27
+ before(:each) do
28
+ @point.elevation = random_elevation
29
+ end
30
+ it "should contain elevation" do
31
+ subject['elevation'].should eq(@point.elevation)
32
+ end
33
+ end
34
+ context "when distance set" do
35
+ before(:each) do
36
+ @point.distance = random_distance
37
+ end
38
+ it "should contain distance" do
39
+ subject['distance'].should eq(@point.distance)
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "#time=" do
45
+ let(:point) { GeoPoint.new }
46
+
47
+ subject { point.time = @value }
48
+
49
+ context "when parseable string" do
50
+ before(:each) do
51
+ @value = "2013-01-12T08:33:11Z"
52
+ end
53
+ it "should eq the time" do
54
+ subject
55
+ point.time.to_i.should eq(Time.utc(2013, 1, 12, 8, 33, 11).to_i)
56
+ end
57
+ end
58
+ context "when is a time" do
59
+ before(:each) do
60
+ @value = Time.new(2013, 4, 12, 12, 34, 45)
61
+ end
62
+ it "should eq the time" do
63
+ subject
64
+ point.time.to_i.should eq(@value.to_i)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,190 @@
1
+ require 'spec_helper'
2
+
3
+ describe GeoRoute do
4
+ describe "#add_point" do
5
+ before(:each) do
6
+ @route = GeoRoute.new
7
+ @lat = random_lat
8
+ @lon = random_lon
9
+ @elevation = 35.6000000
10
+ @new_point = GeoPoint.new(lat: @lat, lon: @lon, elevation: @elevation, distance: 0)
11
+ end
12
+
13
+ subject { @route.add_point(lat: @lat, lon: @lon, elevation: @elevation) }
14
+
15
+ context "when route is empty" do
16
+
17
+ it "sets the start point to the new_point" do
18
+ subject
19
+ @route.start_point.should eq(@new_point)
20
+ end
21
+ it "should set the total distance to zero" do
22
+ subject
23
+ @route.total_distance.should eq(0)
24
+ end
25
+ it "should add the start point to the points list" do
26
+ subject
27
+ @route.points.first.should eq(@route.start_point)
28
+ end
29
+ end
30
+ context "when route already has a start point" do
31
+ before(:each) do
32
+ @start_point = GeoPoint.new(lat: random_lat, lon: random_lon, elevation: random_elevation, distance: 0)
33
+ @route.add_point(lat: @start_point.lat, lon: @start_point.lon, elevation: @start_point.elevation)
34
+ end
35
+
36
+ it "should not change start_point" do
37
+ subject
38
+ @route.start_point.should eq(@start_point)
39
+ end
40
+ it "should set the total distance to be haversine distance between the start_point and the new point" do
41
+ subject
42
+ @route.total_distance.should eq(Maths.haversine_distance(@start_point, @new_point).round)
43
+ end
44
+ it "set the distance of the point to be the haverside_distance between the start_point" do
45
+ subject
46
+ last(@route.points).distance.should eq(Maths.haversine_distance(@start_point, @new_point))
47
+ end
48
+ end
49
+
50
+ context "when route already has at least two points" do
51
+ before(:each) do
52
+ @start_point = GeoPoint.new(lat: random_lat, lon: random_lon, elevation: random_elevation)
53
+ @next_point = GeoPoint.new(lat: random_lat, lon: random_lon, elevation: random_elevation)
54
+ @route.add_point(lat: @start_point.lat, lon: @start_point.lon, elevation: @start_point.elevation)
55
+ @route.add_point(lat: @next_point.lat, lon: @next_point.lon, elevation: @next_point.elevation)
56
+ end
57
+ it "should set the total distance to haversine distance along all points" do
58
+ subject
59
+ @route.total_distance.should be_within(1).of(
60
+ Maths.haversine_distance(@start_point, @next_point).round +
61
+ Maths.haversine_distance(@next_point, @new_point).round
62
+ )
63
+ end
64
+ it "set the distance of the point to haversine distance along all points" do
65
+ subject
66
+ last(@route.points).distance.should eq(
67
+ Maths.haversine_distance(@start_point, @next_point) +
68
+ Maths.haversine_distance(@next_point, @new_point)
69
+ )
70
+ end
71
+ end
72
+ end
73
+ describe "#process_elevation_delta" do
74
+ before(:each) do
75
+ @route = GeoRoute.new
76
+ @next_point = GeoPoint.new(lat: random_lat, lon: random_lon, elevation: random_elevation)
77
+ end
78
+
79
+ subject { @route.process_elevation_delta(@last_point, @next_point) }
80
+
81
+ context "when last_point is nil" do
82
+ it "has an total_ascent of nil" do
83
+ subject
84
+ @route.total_ascent.should eq(0)
85
+ end
86
+ it "has an total_descent of nil" do
87
+ subject
88
+ @route.total_descent.should eq(0)
89
+ end
90
+ end
91
+ context "when last_point is same elevation as next point" do
92
+ before(:each) do
93
+ @last_point = GeoPoint.new(lat: random_lat, lon: random_lon, elevation: @next_point.elevation)
94
+ end
95
+ it "has an total_ascent of zero" do
96
+ subject
97
+ @route.total_ascent.should eq(0)
98
+ end
99
+ it "has an total_descent of zero" do
100
+ subject
101
+ @route.total_descent.should eq(0)
102
+ end
103
+ end
104
+ context "when last_point is lower than the next point" do
105
+ before(:each) do
106
+ @delta = random_elevation
107
+ @last_point = GeoPoint.new(lat: random_lat, lon: random_lon, elevation: @next_point.elevation - @delta)
108
+ end
109
+ it "the delta is added to the total_ascent" do
110
+ subject
111
+ round_to(@route.total_ascent, 3).should eq(@delta)
112
+ end
113
+ it "has an total_descent of zero" do
114
+ subject
115
+ @route.total_descent.should eq(0)
116
+ end
117
+ end
118
+ context "when last_point is higher than the next point" do
119
+ before(:each) do
120
+ @delta = random_elevation
121
+ @last_point = GeoPoint.new(lat: random_lat, lon: random_lon, elevation: @next_point.elevation + @delta)
122
+ end
123
+ it "has an total_ascent of zero" do
124
+ subject
125
+ @route.total_ascent.should eq(0)
126
+ end
127
+ it "the delta is added to the total_descent" do
128
+ subject
129
+ round_to(@route.total_descent, 3).should eq(@delta)
130
+ end
131
+ end
132
+ end
133
+ describe "#hilliness" do
134
+ before(:each) do
135
+ @route = GeoRoute.new
136
+ end
137
+
138
+ subject { @route.hilliness }
139
+
140
+ context "when 1000 m ascent in 100km" do
141
+ before(:each) do
142
+ @route.stub(:total_distance) { 100000 }
143
+ @route.stub(:total_ascent) { 1000 }
144
+ end
145
+ it "is 10" do
146
+ subject.should eq(10)
147
+ end
148
+ end
149
+ context "when 0 ascent in 100km" do
150
+ before(:each) do
151
+ @route.stub(:total_distance) { 100000 }
152
+ @route.stub(:total_ascent) { 0 }
153
+ end
154
+ it "is 0" do
155
+ subject.should eq(0)
156
+ end
157
+ end
158
+ context "when 1000 ascent in 0km" do
159
+ before(:each) do
160
+ @route.stub(:total_distance) { 0 }
161
+ @route.stub(:total_ascent) { 1000 }
162
+ end
163
+ it "is 0" do
164
+ subject.should eq(0)
165
+ end
166
+ end
167
+ end
168
+
169
+ describe ".from_hash" do
170
+ let(:started_at) { Time.now }
171
+ let(:points) {[
172
+ GeoPoint.new(lat: random_lat, lon: random_lon, time: started_at),
173
+ GeoPoint.new(lat: random_lat, lon: random_lon, time: started_at + 1),
174
+ GeoPoint.new(lat: random_lat, lon: random_lon, time: started_at + 2)
175
+ ]}
176
+ let(:hash) {{
177
+ 'started_at' => started_at,
178
+ 'points' => points.collect { |p| p.to_hash }
179
+ }}
180
+
181
+ subject { GeoRoute.from_hash hash }
182
+
183
+ it "set the started_at" do
184
+ subject.started_at.to_i.should eq(started_at.to_i)
185
+ end
186
+ it "has the requisite number of points" do
187
+ subject.points.count.should eq(points.count)
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Maths do
4
+ describe ".haversine_distance" do
5
+ before(:each) do
6
+ @p1 = GeoPoint.new(lat: 39.06546, lon: -104.88544)
7
+ @p2 = GeoPoint.new(lat: 39.06546, lon: -104.80)
8
+ end
9
+
10
+ subject { Maths.haversine_distance( @p1, @p2 ) }
11
+
12
+ it "equals 7376.435 to 3dp" do
13
+ round_to(subject, 3).should eq(7376.435)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Broutes do
4
+ describe ".from_file" do
5
+ before(:all) do
6
+ @file = open_file('single_lap_gpx_track.gpx')
7
+ @route = Broutes.from_file(@file, 'single_lap_gpx_track.gpx')
8
+ end
9
+
10
+ it "sets the start point lat" do
11
+ @route.start_point.lat.should eq(52.9552055)
12
+ end
13
+ it "sets the start point lon" do
14
+ @route.start_point.lon.should eq(-1.1558583)
15
+ end
16
+ it "sets the total distance" do
17
+ @route.total_distance.should eq(7088)
18
+ end
19
+ it "sets the total ascent" do
20
+ @route.total_ascent.round.should eq(34)
21
+ end
22
+ it "sets the total descent" do
23
+ @route.total_descent.round.should eq(37)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,48 @@
1
+ require 'rake'
2
+ require 'rspec'
3
+ require "#{Rake.application.original_dir}/lib/broutes"
4
+
5
+ include Broutes
6
+ Broutes.logger.level = Logger::FATAL
7
+
8
+ def random_lat
9
+ rand + rand(180)
10
+ end
11
+
12
+ def random_lon
13
+ rand
14
+ end
15
+
16
+ def random_integer
17
+ rand(100000).to_i
18
+ end
19
+
20
+ def random_elevation
21
+ round_to(rand + rand(999), 3)
22
+ end
23
+
24
+ def random_distance
25
+ round_to(rand + rand(999), 3)
26
+ end
27
+
28
+ def random_string
29
+ (0...24).map{ ('a'..'z').to_a[rand(26)] }.join
30
+ end
31
+
32
+ def round_to(number, decimal_places)
33
+ if number
34
+ if decimal_places > 0
35
+ ((number * 10**decimal_places).round.to_f / 10**decimal_places)
36
+ else
37
+ number.round
38
+ end
39
+ end
40
+ end
41
+
42
+ def last(enum)
43
+ enum.collect{|item| item}.reverse.first
44
+ end
45
+
46
+ def open_file(name)
47
+ File.open("#{Rake.application.original_dir}/spec/support/#{name}")
48
+ end