From 36f0c229310a0527beaf24b4880b25f9afe437c2 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Sun, 27 Sep 2026 11:41:08 +0200 Subject: Parse FIT Course files as rides --- ride/fit.go | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) (limited to 'ride/fit.go') diff --git a/ride/fit.go b/ride/fit.go index db9c0b6..61d0a7b 100644 --- a/ride/fit.go +++ b/ride/fit.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "errors" + "fmt" "io" "math" "time" @@ -13,8 +14,9 @@ import ( "github.com/tormoder/fit" ) -// FITRideParser parses FIT files into Ride values. It is the FIT counterpart -// to GPXRideParser and keeps the same invariants. +// FITRideParser parses FIT Activity and Course files into Ride values. Both +// types store their track as Record messages. It is the FIT counterpart to +// GPXRideParser and keeps the same invariants. type FITRideParser struct{} func (p FITRideParser) Parse(reader io.Reader) (Ride, error) { @@ -26,17 +28,16 @@ func (p FITRideParser) Parse(reader io.Reader) (Ride, error) { if err != nil { return Ride{}, err } - activity, err := file.Activity() + records, err := fitRecords(file) if err != nil { return Ride{}, err } - if len(activity.Records) == 0 { + if len(records) == 0 { return Ride{}, ErrNoTrackPoints } // Collect points discarding invalid positions — FIT encodes missing lat/lon // as 0x7FFFFFFF (Invalid). We also require altitude. - records := activity.Records distances := make([]float64, 0, len(records)) elevations := make([]float64, 0, len(records)) coords := make([]geodist.Coord, 0, len(records)) @@ -123,6 +124,27 @@ func (p FITRideParser) Parse(reader io.Reader) (Ride, error) { return fromColumns(distances, elevations, coords, timestamps, heartRatesColumn, cadencesColumn, powersColumn), nil } +// fitRecords returns the track points of an Activity or Course FIT file; both +// store them as Record messages. +func fitRecords(file *fit.File) ([]*fit.RecordMsg, error) { + switch file.Type() { + case fit.FileTypeActivity: + activity, err := file.Activity() + if err != nil { + return nil, err + } + return activity.Records, nil + case fit.FileTypeCourse: + course, err := file.Course() + if err != nil { + return nil, err + } + return course.Records, nil + default: + return nil, fmt.Errorf("fit file type is %v, not Activity or Course", file.Type()) + } +} + // EncodeFIT writes the ride as a minimal FIT Activity file. It stores only the // fields consumed by Ride (lat/lon, altitude, time, heart rate, cadence, power) // as Record messages. -- cgit v1.3