tcxread 0.1.3 → 0.1.5

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.
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