aboutsummaryrefslogtreecommitdiff
path: root/climb/cotacol.go
blob: 85b096b3d10a02f2249ccf6b45ba5104b7bc6437 (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

package climb

import "math"

const (
	CotacolAlgorithmVersion = "v1"
	cotacolSegmentLengthM   = 100
)

func Cotacol(distances, elevations []float64) float64 {
	startIndex, endIndex := 0, len(distances)-1
	if endIndex-startIndex < 1 {
		return 0
	}
	startDistance := distances[startIndex]
	lastDistance := distances[endIndex]
	if lastDistance <= startDistance {
		return 0
	}
	cotacol := 0.0
	i := startIndex
	for start := startDistance; start < lastDistance; start += cotacolSegmentLengthM {
		end := math.Min(start+cotacolSegmentLengthM, lastDistance)
		for i < endIndex && distances[i+1] <= start {
			i++
		}
		startElevation := interpolateElevation(distances, elevations, i, start)
		for i < endIndex && distances[i+1] < end {
			i++
		}
		endElevation := interpolateElevation(distances, elevations, i, end)
		slope := (endElevation - startElevation) / (end - start)
		if slope > 0 {
			cotacol += (end - start) / 1000 * (slope * 100) * (slope * 100)
		}
	}
	return cotacol
}

func interpolateElevation(distances, elevations []float64, i int, distance float64) float64 {
	if i+1 >= len(distances) {
		return elevations[i]
	}
	startDistance := distances[i]
	endDistance := distances[i+1]
	t := (distance - startDistance) / (endDistance - startDistance)
	return elevations[i] + t*(elevations[i+1]-elevations[i])
}