From 825cf388b55a6c8441e02149749bb6e2968477c0 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Thu, 27 Aug 2026 11:21:17 +0200 Subject: 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. --- official_climb/official_climb_test.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'official_climb') diff --git a/official_climb/official_climb_test.go b/official_climb/official_climb_test.go index ed121e5..6ddce5a 100644 --- a/official_climb/official_climb_test.go +++ b/official_climb/official_climb_test.go @@ -56,10 +56,10 @@ func TestMatchClimbMatchesWithoutDetectedClimb(t *testing.T) { parsed := ridetest.MustRide("2km at 5% | 1km at -10%", ridetest.StartCoord(43.10, 5.10), ridetest.StartElevation(100), ridetest.Sampling(1000)) official := official_climb.OfficialClimb{ Name: "On route", - StartCoord: parsed.Coords()[1], - EndCoord: parsed.Coords()[2], + StartCoord: parsed.Coords[1], + EndCoord: parsed.Coords[2], } - matched, found := official_climb.MatchClimb(parsed.Coords(), official, official_climb.DefaultMatchRadiusM) + matched, found := official_climb.MatchClimb(parsed.Coords, official, official_climb.DefaultMatchRadiusM) require.True(t, found) assert.Equal(t, 1, matched.StartIndex) assert.Equal(t, 2, matched.EndIndex) @@ -72,7 +72,7 @@ func TestMatchClimbMatchesEndpointInsideRadius(t *testing.T) { StartCoord: geodist.Coord{Lat: 43.1101, Lon: 5.1101}, EndCoord: geodist.Coord{Lat: 43.1201, Lon: 5.1201}, } - matched, found := official_climb.MatchClimb(parsed.Coords(), official, official_climb.DefaultMatchRadiusM) + matched, found := official_climb.MatchClimb(parsed.Coords, official, official_climb.DefaultMatchRadiusM) require.True(t, found) assert.Equal(t, 1, matched.StartIndex) assert.Equal(t, 2, matched.EndIndex) @@ -82,10 +82,10 @@ func TestMatchClimbRejectsReversedEndpoints(t *testing.T) { parsed := ridetest.MustRide("2km at 5% | 1km at -10%", ridetest.StartCoord(43.10, 5.10), ridetest.StartElevation(100), ridetest.Sampling(1000)) official := official_climb.OfficialClimb{ Name: "Reversed", - StartCoord: parsed.Coords()[2], - EndCoord: parsed.Coords()[1], + StartCoord: parsed.Coords[2], + EndCoord: parsed.Coords[1], } - _, found := official_climb.MatchClimb(parsed.Coords(), official, official_climb.DefaultMatchRadiusM) + _, found := official_climb.MatchClimb(parsed.Coords, official, official_climb.DefaultMatchRadiusM) assert.False(t, found) } @@ -94,9 +94,9 @@ func TestMatchClimbRejectsEndpointOutsideRadius(t *testing.T) { official := official_climb.OfficialClimb{ Name: "Too far", StartCoord: geodist.Coord{Lat: 43.09, Lon: 5.09}, - EndCoord: parsed.Coords()[2], + EndCoord: parsed.Coords[2], } - _, found := official_climb.MatchClimb(parsed.Coords(), official, 10) + _, found := official_climb.MatchClimb(parsed.Coords, official, 10) assert.False(t, found) } @@ -122,14 +122,14 @@ func TestMatchClimbsMatchesTwoLaps(t *testing.T) { StartCoord: geodist.Coord{Lat: 43.10, Lon: 5.10}, EndCoord: geodist.Coord{Lat: 43.12, Lon: 5.12}, } - matches := official_climb.MatchClimbs(parsed.Coords(), official, official_climb.DefaultMatchRadiusM) + matches := official_climb.MatchClimbs(parsed.Coords, official, official_climb.DefaultMatchRadiusM) require.Len(t, matches, 2) assert.Equal(t, 0, matches[0].StartIndex) assert.Equal(t, 2, matches[0].EndIndex) assert.Equal(t, 4, matches[1].StartIndex) assert.Equal(t, 6, matches[1].EndIndex) // Single-match helper still returns first occurrence for backward compatibility. - single, found := official_climb.MatchClimb(parsed.Coords(), official, official_climb.DefaultMatchRadiusM) + single, found := official_climb.MatchClimb(parsed.Coords, official, official_climb.DefaultMatchRadiusM) require.True(t, found) assert.Equal(t, 0, single.StartIndex) } @@ -154,7 +154,7 @@ func TestMatchClimbsMatchesOnlyCompleteLaps(t *testing.T) { StartCoord: geodist.Coord{Lat: 43.10, Lon: 5.10}, EndCoord: geodist.Coord{Lat: 43.12, Lon: 5.12}, } - matches := official_climb.MatchClimbs(parsed.Coords(), official, official_climb.DefaultMatchRadiusM) + matches := official_climb.MatchClimbs(parsed.Coords, official, official_climb.DefaultMatchRadiusM) require.Len(t, matches, 1) assert.Equal(t, 3, matches[0].StartIndex) assert.Equal(t, 5, matches[0].EndIndex) @@ -177,7 +177,7 @@ func TestMatchClimbsPreservesDirectionAcrossLaps(t *testing.T) { StartCoord: geodist.Coord{Lat: 43.10, Lon: 5.10}, EndCoord: geodist.Coord{Lat: 43.12, Lon: 5.12}, } - matches := official_climb.MatchClimbs(parsed.Coords(), official, official_climb.DefaultMatchRadiusM) + matches := official_climb.MatchClimbs(parsed.Coords, official, official_climb.DefaultMatchRadiusM) assert.Empty(t, matches) } @@ -203,7 +203,7 @@ func TestMatchClimbsClustersContiguousPoints(t *testing.T) { StartCoord: geodist.Coord{Lat: 43.10, Lon: 5.10}, EndCoord: geodist.Coord{Lat: 43.12, Lon: 5.12}, } - matches := official_climb.MatchClimbs(parsed.Coords(), official, official_climb.DefaultMatchRadiusM) + matches := official_climb.MatchClimbs(parsed.Coords, official, official_climb.DefaultMatchRadiusM) require.Len(t, matches, 2) assert.Equal(t, 0, matches[0].StartIndex) assert.Equal(t, 4, matches[0].EndIndex) -- cgit v1.3