diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-27 11:21:17 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-08-27 11:21:17 +0200 |
| commit | 825cf388b55a6c8441e02149749bb6e2968477c0 (patch) | |
| tree | e3394cef97aa43df9775a1465d3c99f386ce3a9b /ride/difficulty_test.go | |
| parent | 366e7b0d671395c2ad32f85ee7706a592db69d15 (diff) | |
Extract climb detection into a dedicated climb package
Move climb detection, slope, and Cotacol scoring out of ride into a new
climb package that operates on a geometry-only Route (distances, elevations,
coords). Ride embeds climb.Route and keeps its timing and telemetry columns.
- climb.Detect returns []DetectedClimb (Climb + ride-absolute Start).
- Climb owns its sliced geometry; indices are local, with Start reported at
the detection boundary for absolute position.
- Detected bounds use core.Interval; freeRegions claim suppression fixed.
- ride no longer builds slices: ClimbFromDist/ClimbFromIndexes/climbFrom and
ride.Climb/Interval/Range are removed; rideanalysis, mountain_pass MatchClimb,
and web views are rewired to climb types.
- New internal/routetest builds climb.Route from the ride DSL; ridetest reuses
it and adds timestamps and telemetry.
- Tests moved to climb (synthetic detection and difficulty) and kept in ride
for GPX-example integration; ride.comparison detection coverage retained.
- mountain_pass.nearestCrossing now reuses geo.Nearest.
Diffstat (limited to 'ride/difficulty_test.go')
| -rw-r--r-- | ride/difficulty_test.go | 87 |
1 files changed, 0 insertions, 87 deletions
diff --git a/ride/difficulty_test.go b/ride/difficulty_test.go deleted file mode 100644 index bd316b4..0000000 --- a/ride/difficulty_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package ride_test - -import ( - "math" - "testing" - - "github.com/martinlehoux/biking_home/internal/ridetest" - "github.com/martinlehoux/biking_home/ride" - "github.com/stretchr/testify/assert" -) - -func TestCotacolConstantClimb(t *testing.T) { - r := ridetest.MustRide("2km at 7%") - assert.InDelta(t, 98.0, ride.Cotacol(r), 1e-9) -} - -func TestCotacolIgnoresDescent(t *testing.T) { - r := ridetest.MustRide("2km at 7% | 2km at -7%") - assert.InDelta(t, 98.0, ride.Cotacol(r), 1e-9) -} - -func TestCotacolFlatIsZero(t *testing.T) { - r := ridetest.MustRide("5km at 0%") - assert.Zero(t, ride.Cotacol(r)) -} - -func TestCotacolSteepShortCountsMore(t *testing.T) { - steep := ridetest.MustRide("0.5km at 14%") - long := ridetest.MustRide("1km at 7%") - assert.InDelta(t, 98.0, ride.Cotacol(steep), 1e-9) - assert.InDelta(t, 49.0, ride.Cotacol(long), 1e-9) -} - -func TestCotacolPrecisionInvariant(t *testing.T) { - coarse := ridetest.MustRide("3km at 5%") - fine := ridetest.MustRide("3km at 5%", ridetest.Sampling(50)) - assert.InDelta(t, ride.Cotacol(coarse), ride.Cotacol(fine), 1e-9) -} - -func TestCotacolExampleRide(t *testing.T) { - r, err := ride.ParseFile(parser, "../examples/2022-07-21.Pogacar.gpx") - assert.NoError(t, err) - assert.InDelta(t, 3049.0, ride.Cotacol(r), 1) -} - -func TestCotacolClimbNotAtStart(t *testing.T) { - r := ridetest.MustRide("1km at 0% | 2km at 7%") - climbs := r.DetectClimbs(nil, ride.ClimbSlopeMinimum) - assert.Len(t, climbs, 1) - assert.InDelta(t, 98.0, climbs[0].DifficultyScore(), 1e-9) -} - -func TestCategoryOfBoundaries(t *testing.T) { - cases := []struct { - score float64 - want ride.Category - }{ - {-5, ride.CategoryNo}, - {30, ride.CategoryNo}, - {35, ride.CategoryFour}, // 35 is the first floor, not below it - {79, ride.CategoryFour}, - {80, ride.CategoryThree}, - {179, ride.CategoryThree}, - {180, ride.CategoryTwo}, - {249, ride.CategoryTwo}, - {250, ride.CategoryOne}, - {599, ride.CategoryOne}, - {600, ride.CategoryHC}, - {700, ride.CategoryHC}, - {math.NaN(), ride.CategoryHC}, // reaches no floor, like the original switch default - } - for _, c := range cases { - assert.Equal(t, c.want, ride.CategoryOf(c.score), "score %v", c.score) - } - assert.Equal(t, "Cat 1", ride.CategoryOne.String()) - assert.Equal(t, "NO", ride.CategoryNo.String()) -} - -func TestCotacolHautacamClimbfinderReference(t *testing.T) { - r, err := ride.ParseFile(parser, "../examples/2022-07-21.Pogacar.gpx") - assert.NoError(t, err) - climbs := r.DetectClimbs(nil, ride.ClimbSlopeMinimum) - assert.Len(t, climbs, 6) - hautacam := climbs[5] - assert.InDelta(t, 128.6, hautacam.StartDistanceM()/1000, 0.1) - assert.InDelta(t, 930.0, hautacam.DifficultyScore(), 10) -} |
