Files
ChWebsiteApp/CHDataManagement/Workouts/File/RouteSample.swift
2025-08-31 16:27:32 +02:00

96 lines
2.9 KiB
Swift

struct RouteSample {
/// The x-coordinate in the map image (left to right) in the range [0,1]
var x: Double
/// The y-coordinate in the map image (top to bottom) in the range [0,1]
var y: Double
/// The timestamp of the sample in the range [0,1]
var time: Double
/// The distance of the sample in the range [0,1]
var distance: Double
/// The elevation of the sample in the range [0,1]
var elevation: Double
/// The speed of the sample in the range [0,1]
var speed: Double
/// The pace of the sample in the range [0,1]
var pace: Double
/// The heart rate of the sample in the range [0,1]
var hr: Double
/// The active energy rate of the sample in the range [0,1]
var energy: Double?
}
extension RouteSample: Codable {
func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(x.rounded(decimals: 4), forKey: .x)
try container.encode(y.rounded(decimals: 4), forKey: .y)
try container.encode(time.rounded(decimals: 4), forKey: .time)
try container.encode(distance.rounded(decimals: 4), forKey: .distance)
try container.encode(elevation.rounded(decimals: 4), forKey: .elevation)
try container.encode(speed.rounded(decimals: 4), forKey: .speed)
try container.encode(pace.rounded(decimals: 4), forKey: .pace)
try container.encode(hr.rounded(decimals: 4), forKey: .hr)
try container.encodeIfPresent(energy?.rounded(decimals: 4), forKey: .energy)
}
}
extension RouteSample: Identifiable {
var id: Double { x }
}
extension RouteSample {
static var zero: RouteSample {
.init(x: 0, y: 0, time: 0, distance: 0, elevation: 0, speed: 0, pace: 0, hr: 0, energy: nil)
}
}
extension Collection where Element == RouteSample {
var averageSample: RouteSample {
guard var average = first else {
return .zero
}
var energySamples = average.energy == nil ? 0 : 1
for sample in dropFirst() {
average.x += sample.x
average.y += sample.y
average.time += sample.time
average.distance += sample.distance
average.elevation += sample.elevation
average.speed += sample.speed
average.pace += sample.pace
average.hr += sample.hr
if let energy = sample.energy {
average.energy = (average.energy ?? 0) + energy
energySamples += 1
}
}
let scale = 1 / Double(count)
average.x *= scale
average.y *= scale
average.time *= scale
average.distance *= scale
average.elevation *= scale
average.speed *= scale
average.pace *= scale
average.hr *= scale
if let energy = average.energy, energySamples > 0 {
average.energy = energy / Double(energySamples)
}
return average
}
}