summaryrefslogtreecommitdiff
path: root/ride/climb_test.go
blob: 36b9d098b8eec3844d84222d5721130245b7e5de (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package ride_test

import (
	"strconv"
	"strings"
	"testing"

	"github.com/martinlehoux/biking_home/ride"
	"github.com/martinlehoux/kagamigo/kcore"
	"github.com/stretchr/testify/assert"
	"github.com/tkrajina/gpxgo/gpx"
)

type RideBuilderSection struct {
	slope    float64
	distance float64
}

type RideBuilder struct {
	precision float64
	sections  []RideBuilderSection
}

// Example: 13.4km at 7.5%
func (b RideBuilder) WithSection(input string) RideBuilder {
	inputs := strings.Split(input, " ")
	kcore.Assert(strings.HasSuffix(inputs[0], "km"), "wrong unit")
	distanceKm, err := strconv.ParseFloat(strings.TrimSuffix(inputs[0], "km"), 64)
	kcore.Expect(err, "faile to parse kms")
	kcore.Assert(strings.HasSuffix(inputs[2], "%"), "wrong unit")
	slopePercent, err := strconv.ParseFloat(strings.TrimSuffix(inputs[2], "%"), 64)
	kcore.Expect(err, "failed to parse %")

	b.sections = append(b.sections, RideBuilderSection{
		slope:    slopePercent / 100,
		distance: distanceKm * 1000,
	})

	return b
}

func (b RideBuilder) Build() ride.Ride {
	points := []ride.Point{ride.NewPoint(0, 0)}
	distance := 0.0
	elevation := 0.0
	for _, section := range b.sections {
		curSecDist := 0.0
		for curSecDist < section.distance {
			curSecDist += b.precision
			elevation += b.precision * section.slope
			points = append(points, ride.NewPoint(
				distance+curSecDist,
				elevation,
			))
		}
		distance += curSecDist
	}
	return ride.FromPoints(points)
}

func TestClimbThenFalseFlat(t *testing.T) {
	r := RideBuilder{precision: 100}.WithSection("2km at 7%").WithSection("10km at 1%").Build()
	climbs := r.AllClimbs()

	assert.Len(t, climbs, 1)
	assert.Equal(t, "0.0km-2.0km: 2.0km at 7.0% (98 pts - Cat 3)", r.String(climbs[0]))
}

func TestSmallClimbWithDescentInsideFalseFlat(t *testing.T) {
	r := RideBuilder{precision: 100}.WithSection("10km at 1%").WithSection("2km at 7%").WithSection("1km at -7%").WithSection("10km at 1%").Build()
	climbs := r.AllClimbs()

	assert.Len(t, climbs, 1)
	assert.Equal(t, "10.0km-12.0km: 2.0km at 7.0% (98 pts - Cat 3)", r.String(climbs[0]))
}

func TestPogacar20220721(t *testing.T) {
	gpxContent, err := gpx.ParseFile("../examples/2022-07-21.Pogacar.gpx")
	assert.NoError(t, err)
	r := ride.FromGPX(gpxContent)
	climbs := r.AllClimbs()

	assert.Len(t, climbs, 6)
	assert.Equal(t, "0.6km-5.6km: 5.0km at 3.5% (62 pts - Cat 4)", r.String(climbs[0]))
	assert.Equal(t, "42.9km-45.2km: 2.3km at 5.0% (59 pts - Cat 4)", r.String(climbs[1]))
	assert.Equal(t, "60.0km-76.4km: 16.4km at 7.2% (854 pts - HC)", r.String(climbs[2]))
	assert.Equal(t, "83.8km-85.9km: 2.0km at 5.4% (59 pts - Cat 4)", r.String(climbs[3]))
	assert.Equal(t, "99.2km-109.3km: 10.2km at 8.4% (710 pts - HC)", r.String(climbs[4]))
	assert.Equal(t, "128.6km-142.2km: 13.6km at 7.8% (832 pts - HC)", r.String(climbs[5]))
}

func TestBouclesVerdon2024(t *testing.T) {
	gpxContent, err := gpx.ParseFile("../examples/2024-06-29.BouclesVerdon.gpx")
	assert.NoError(t, err)
	r := ride.FromGPX(gpxContent)
	climbs := r.AllClimbs()

	assert.Len(t, climbs, 6)
	assert.Equal(t, "3.6km-13.8km: 10.3km at 2.1% (44 pts - Cat 4)", r.String(climbs[0])) // TODO: Not steep enough
	assert.Equal(t, "34.7km-37.3km: 2.5km at 5.0% (62 pts - Cat 4)", r.String(climbs[1]))
	assert.Equal(t, "41.9km-51.0km: 9.0km at 2.5% (55 pts - Cat 4)", r.String(climbs[2])) // TODO: Not steep enough
	assert.Equal(t, "57.6km-60.8km: 3.1km at 6.3% (124 pts - Cat 3)", r.String(climbs[3]))
	assert.Equal(t, "71.7km-74.7km: 3.0km at 5.3% (84 pts - Cat 3)", r.String(climbs[4]))
	assert.Equal(t, "77.4km-78.7km: 1.3km at 5.3% (37 pts - Cat 4)", r.String(climbs[5]))
}

func TestMimetArbois20241229(t *testing.T) {
	gpxContent, err := gpx.ParseFile("../examples/2024-12-29.MimetArbois.gpx")
	assert.NoError(t, err)
	r := ride.FromGPX(gpxContent)
	climbs := r.AllClimbs()

	assert.Len(t, climbs, 2)
	assert.Equal(t, "3.9km-5.3km: 1.4km at 10.3% (153 pts - Cat 3)", r.String(climbs[0]))
	assert.Equal(t, "14.4km-19.8km: 5.4km at 4.3% (98 pts - Cat 3)", r.String(climbs[1]))
}