tcxread 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -1
  3. data/lib/tcxread.rb +67 -54
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed1afce3cee9d915fdabd00e0732caafa749719188118bbe428ddf7eadd3f52d
4
- data.tar.gz: a3867ff511e74ea4e2b11efbdcfcf36d453e5b1030a4d5c28bd1ef10ac70a76f
3
+ metadata.gz: a0f94a5a07acd01e1c6b0419324bbef97912e0d7e67b3f2b1dc18d50336dd7e2
4
+ data.tar.gz: 776953d7610ffa6c6903449332eb1bf36ff2a7fb54c5fa10dde8e591ecefd3df
5
5
  SHA512:
6
- metadata.gz: 0666fd2bd6601145ad998911252e4856f9e4e6d8eca9673dd2f4076c3fc0abff1cd2264a3521a5602771f4a4d16914a9ded05f678d08c8ca04efef138effbcc9
7
- data.tar.gz: aa6bc442fe648352928bf01710b98ba37faca036c5e0be103fbef453e7edafe0da1060bf955fd66f206da97e048e40031f35878b45fe881e517c681ea062ab0f
6
+ metadata.gz: dc1240984ccb04288e3790d69529eea52269f16888e1b6d8906017b42252ce98eeef44240b729ed1358444e2f0d3f7ce377f3a49123ea5c85c21493a2438cc77
7
+ data.tar.gz: 99863f90228c50f2590709105fab6d55395c26462bec7b2ba2b11c429f2e85453867583fdcb964d83599f669bbc1dc991fa6ca8a0c5eff6aba8a3681007d1b48
data/README.md CHANGED
@@ -49,7 +49,11 @@ puts "Distance meters: #{data.total_distance_meters}, " \
49
49
  "Average heart rate: #{data.average_heart_rate}, " \
50
50
  "Average watts: #{data.average_watts}, " \
51
51
  "Max watts: #{data.max_watts}, " \
52
- "Average cadence: #{data.average_cadence}"
52
+ "Average speed: #{data.average_speed_all}, " \
53
+ "Average speed (moving): #{data.average_speed_moving}, " \
54
+ "Average cadence (moving): #{data.average_cadence_biking}, " \
55
+ "Average cadence: #{data.average_cadence_all}"
56
+
53
57
  ```
54
58
 
55
59
  ## 💾 Datasets
data/lib/tcxread.rb CHANGED
@@ -1,11 +1,10 @@
1
1
  require "nokogiri"
2
2
 
3
- # TCXRead is a class that parses TCX (Training Center XML) files to extract
4
- # workout data such as activities, laps, tracks, trackpoints, and integral metrics.
5
3
  class TCXRead
6
4
  attr_reader :total_distance_meters, :total_time_seconds, :total_calories,
7
5
  :total_ascent, :total_descent, :max_altitude, :average_heart_rate,
8
- :max_watts, :average_watts, :average_cadence
6
+ :max_watts, :average_watts, :average_cadence_all, :average_cadence_biking,
7
+ :average_speed_all, :average_speed_moving
9
8
 
10
9
  def initialize(file_path)
11
10
  @file_path = file_path
@@ -19,17 +18,16 @@ class TCXRead
19
18
  @total_descent = 0
20
19
  @max_altitude = 0
21
20
  @average_heart_rate = 0
22
- # use NA if no watts exist in the TCX file
23
21
  @max_watts = 'NA'
24
22
  @average_watts = 'NA'
25
- @average_cadence = 0
23
+ @average_cadence_all = 0
24
+ @average_cadence_biking = 0
25
+ @average_speed_all = 0
26
+ @average_speed_moving = 0
26
27
 
27
28
  parse
28
29
  end
29
30
 
30
- # Parses the TCX file and extracts data.
31
- #
32
- # @return [Hash] a hash containing the parsed activities.
33
31
  def parse
34
32
  activities = parse_activities
35
33
  if activities.any?
@@ -39,7 +37,12 @@ class TCXRead
39
37
  @total_ascent, @total_descent, @max_altitude = calculate_ascent_descent_and_max_altitude_from_activities(activities)
40
38
  @average_heart_rate = calculate_average_heart_rate_from_activities(activities)
41
39
  @max_watts, @average_watts = calculate_watts_from_activities(activities)
42
- @average_cadence = calculate_average_cadence_from_activities(activities)
40
+ cadence_results = calculate_average_cadence_from_activities(activities)
41
+ @average_cadence_all = cadence_results[:average_cadence_all]
42
+ @average_cadence_biking = cadence_results[:average_cadence_biking]
43
+ speed_results = calculate_average_speed_from_activities(activities)
44
+ @average_speed_all = speed_results[:average_speed_all]
45
+ @average_speed_moving = speed_results[:average_speed_moving]
43
46
  end
44
47
 
45
48
  { activities: activities }
@@ -47,9 +50,6 @@ class TCXRead
47
50
 
48
51
  private
49
52
 
50
- # Parses the activities from the TCX file.
51
- #
52
- # @return [Array<Hash>] an array of hashes, each representing an activity.
53
53
  def parse_activities
54
54
  activities = []
55
55
  @doc.xpath('//xmlns:Activities/xmlns:Activity').each do |activity|
@@ -76,10 +76,6 @@ class TCXRead
76
76
  activities
77
77
  end
78
78
 
79
- # Parses the laps for a given activity.
80
- #
81
- # @param activity [Nokogiri::XML::Element] the activity element from the TCX file.
82
- # @return [Array<Hash>] an array of hashes, each representing a lap.
83
79
  def parse_laps(activity)
84
80
  laps = []
85
81
  activity.xpath('xmlns:Lap').each do |lap|
@@ -100,10 +96,6 @@ class TCXRead
100
96
  laps
101
97
  end
102
98
 
103
- # Parses the tracks for a given lap.
104
- #
105
- # @param lap [Nokogiri::XML::Element] the lap element from the TCX file.
106
- # @return [Array<Array<Hash>>] an array of arrays, each representing a track containing trackpoints.
107
99
  def parse_tracks(lap)
108
100
  tracks = []
109
101
  lap.xpath('xmlns:Track').each do |track|
@@ -117,7 +109,8 @@ class TCXRead
117
109
  heart_rate: trackpoint.xpath('xmlns:HeartRateBpm/xmlns:Value').text.to_i,
118
110
  cadence: trackpoint.xpath('xmlns:Cadence').text.to_i,
119
111
  sensor_state: trackpoint.xpath('xmlns:SensorState').text,
120
- watts: trackpoint.xpath('xmlns:Extensions/ns3:TPX/ns3:Watts').text.to_f
112
+ watts: trackpoint.xpath('xmlns:Extensions/ns3:TPX/ns3:Watts').text.to_f,
113
+ speed: trackpoint.xpath('xmlns:Extensions/ns3:TPX/ns3:Speed').text.to_f
121
114
  }
122
115
  end
123
116
  tracks << trackpoints
@@ -125,10 +118,6 @@ class TCXRead
125
118
  tracks
126
119
  end
127
120
 
128
- # Parses the position for a given trackpoint.
129
- #
130
- # @param trackpoint [Nokogiri::XML::Element] the trackpoint element from the TCX file.
131
- # @return [Hash, nil] a hash representing the position (latitude and longitude) or nil if no position is available.
132
121
  def parse_position(trackpoint)
133
122
  position = trackpoint.at_xpath('xmlns:Position')
134
123
  return nil unless position
@@ -139,10 +128,6 @@ class TCXRead
139
128
  }
140
129
  end
141
130
 
142
- # Calculates the total ascent, total descent, and maximum altitude from the laps.
143
- #
144
- # @param laps [Array<Hash>] an array of lap hashes.
145
- # @return [Array<Float>] an array containing total ascent, total descent, and maximum altitude.
146
131
  def calculate_ascent_descent_and_max_altitude(laps)
147
132
  total_ascent = 0.0
148
133
  total_descent = 0.0
@@ -170,10 +155,6 @@ class TCXRead
170
155
  [total_ascent, total_descent, max_altitude]
171
156
  end
172
157
 
173
- # Calculates the total ascent, total descent, and maximum altitude from the activities.
174
- #
175
- # @param activities [Array<Hash>] an array of activity hashes.
176
- # @return [Array<Float>] an array containing total ascent, total descent, and maximum altitude.
177
158
  def calculate_ascent_descent_and_max_altitude_from_activities(activities)
178
159
  total_ascent = 0.0
179
160
  total_descent = 0.0
@@ -188,10 +169,6 @@ class TCXRead
188
169
  [total_ascent, total_descent, max_altitude]
189
170
  end
190
171
 
191
- # Calculates the average heart rate from the laps.
192
- #
193
- # @param laps [Array<Hash>] an array of lap hashes.
194
- # @return [Float] the average heart rate.
195
172
  def calculate_average_heart_rate(laps)
196
173
  total_heart_rate = 0
197
174
  heart_rate_count = 0
@@ -209,10 +186,6 @@ class TCXRead
209
186
  heart_rate_count > 0 ? total_heart_rate.to_f / heart_rate_count : 0.0
210
187
  end
211
188
 
212
- # Calculates the average heart rate from the activities.
213
- #
214
- # @param activities [Array<Hash>] an array of activity hashes.
215
- # @return [Float] the average heart rate.
216
189
  def calculate_average_heart_rate_from_activities(activities)
217
190
  total_heart_rate = 0
218
191
  heart_rate_count = 0
@@ -232,10 +205,6 @@ class TCXRead
232
205
  heart_rate_count > 0 ? total_heart_rate.to_f / heart_rate_count : 0.0
233
206
  end
234
207
 
235
- # Calculates the maximum and average watts from the activities.
236
- #
237
- # @param activities [Array<Hash>] an array of activity hashes.
238
- # @return [Array<Float, Float>] an array containing maximum watts and average watts. Returns 'NA' for both if no watts data is available.
239
208
  def calculate_watts_from_activities(activities)
240
209
  max_watts = 0
241
210
  total_watts = 0
@@ -265,26 +234,70 @@ class TCXRead
265
234
  [max_watts, average_watts]
266
235
  end
267
236
 
268
- # Calculates the average cadence from the activities.
269
- #
270
- # @param activities [Array<Hash>] an array of activity hashes.
271
- # @return [Float] the average cadence.
272
237
  def calculate_average_cadence_from_activities(activities)
273
- total_cadence = 0
274
- cadence_count = 0
238
+ total_cadence_all = 0
239
+ total_cadence_biking = 0
240
+ cadence_count_all = 0
241
+ cadence_count_biking = 0
275
242
 
276
243
  activities.each do |activity|
277
244
  activity[:laps].each do |lap|
278
245
  lap[:tracks].flatten.each do |trackpoint|
279
246
  cadence = trackpoint[:cadence]
247
+ total_cadence_all += cadence
248
+ cadence_count_all += 1
249
+
280
250
  if cadence > 0
281
- total_cadence += cadence
282
- cadence_count += 1
251
+ total_cadence_biking += cadence
252
+ cadence_count_biking += 1
283
253
  end
284
254
  end
285
255
  end
286
256
  end
287
257
 
288
- cadence_count > 0 ? total_cadence.to_f / cadence_count : 0.0
258
+ average_cadence_all = cadence_count_all > 0 ? total_cadence_all.to_f / cadence_count_all : 0.0
259
+ average_cadence_biking = cadence_count_biking > 0 ? total_cadence_biking.to_f / cadence_count_biking : 0.0
260
+
261
+ {
262
+ average_cadence_all: average_cadence_all,
263
+ average_cadence_biking: average_cadence_biking
264
+ }
265
+ end
266
+
267
+ # Calculates the average speed from the activities.
268
+ #
269
+ # @param activities [Array<Hash>] an array of activity hashes.
270
+ # @return [Hash] a hash containing average speed including zeros and average speed while moving.
271
+ def calculate_average_speed_from_activities(activities)
272
+ total_speed_all = 0
273
+ total_speed_moving = 0
274
+ speed_count_all = 0
275
+ speed_count_moving = 0
276
+
277
+ activities.each do |activity|
278
+ activity[:laps].each do |lap|
279
+ lap[:tracks].flatten.each do |trackpoint|
280
+ speed = trackpoint[:speed]
281
+
282
+ if speed
283
+ total_speed_all += speed
284
+ speed_count_all += 1
285
+
286
+ if speed > 0
287
+ total_speed_moving += speed
288
+ speed_count_moving += 1
289
+ end
290
+ end
291
+ end
292
+ end
293
+ end
294
+
295
+ average_speed_all = speed_count_all > 0 ? total_speed_all.to_f / speed_count_all : 0.0
296
+ average_speed_moving = speed_count_moving > 0 ? total_speed_moving.to_f / speed_count_moving : 0.0
297
+
298
+ {
299
+ average_speed_all: average_speed_all,
300
+ average_speed_moving: average_speed_moving
301
+ }
289
302
  end
290
303
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tcxread
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - firefly-cpp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-11 00:00:00.000000000 Z
11
+ date: 2024-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri