96 lines
2.9 KiB
Swift
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
|
|
}
|
|
}
|