aboutsummaryrefslogtreecommitdiff
path: root/climb/detection.go
diff options
context:
space:
mode:
Diffstat (limited to 'climb/detection.go')
-rw-r--r--climb/detection.go44
1 files changed, 22 insertions, 22 deletions
diff --git a/climb/detection.go b/climb/detection.go
index 9269c2f..a7b92e9 100644
--- a/climb/detection.go
+++ b/climb/detection.go
@@ -5,7 +5,7 @@ import (
"math"
"slices"
- "github.com/martinlehoux/biking_home/core"
+ "github.com/martinlehoux/biking_home/geo"
"github.com/martinlehoux/kagamigo/kcore"
)
@@ -15,13 +15,13 @@ type DetectedClimb struct {
}
// returns the detected climbs but never a climb that overlaps a claimed range.
-func Detect(route Route, claimed []core.Interval, minSlope float64) []DetectedClimb {
+func Detect(route Route, claimed []geo.Interval, minSlope float64) []DetectedClimb {
distances, elevations, coords := route.Distances, route.Elevations, route.Coords
- bounds := make([]core.Interval, 0)
+ bounds := make([]geo.Interval, 0)
for _, region := range freeRegions(0, len(distances)-1, claimed) {
- bounds = append(bounds, climbsBetween(distances, elevations, core.NewInterval(region.Start, region.End), minSlope)...)
+ bounds = append(bounds, climbsBetween(distances, elevations, geo.NewInterval(region.Start, region.End), minSlope)...)
}
- slices.SortFunc(bounds, func(a, b core.Interval) int { return a.Start - b.Start })
+ slices.SortFunc(bounds, func(a, b geo.Interval) int { return a.Start - b.Start })
climbs := make([]DetectedClimb, 0, len(bounds))
for _, b := range bounds {
climbs = append(climbs, DetectedClimb{
@@ -38,8 +38,8 @@ func Detect(route Route, claimed []core.Interval, minSlope float64) []DetectedCl
// freeRegions returns the maximal sub-ranges of [rStart, rEnd] that are not
// covered by any claimed range, after discarding claims that fall outside.
-func freeRegions(rStart, rEnd int, claimed []core.Interval) []core.Interval {
- valid := make([]core.Interval, 0, len(claimed))
+func freeRegions(rStart, rEnd int, claimed []geo.Interval) []geo.Interval {
+ valid := make([]geo.Interval, 0, len(claimed))
for _, claim := range claimed {
// Discard claims outside the route or with a degenerate range.
if claim.Start < 0 || claim.End >= rEnd+1 || claim.Start >= claim.End {
@@ -47,31 +47,31 @@ func freeRegions(rStart, rEnd int, claimed []core.Interval) []core.Interval {
}
valid = append(valid, claim)
}
- slices.SortFunc(valid, func(a, b core.Interval) int { return a.Start - b.Start })
- regions := make([]core.Interval, 0, len(valid)+1)
+ slices.SortFunc(valid, func(a, b geo.Interval) int { return a.Start - b.Start })
+ regions := make([]geo.Interval, 0, len(valid)+1)
current := rStart
for _, claim := range valid {
if claim.End < current {
continue
}
if claim.Start > current {
- regions = append(regions, core.NewInterval(current, claim.Start-1))
+ regions = append(regions, geo.NewInterval(current, claim.Start-1))
}
if claim.End+1 > current {
current = claim.End + 1
}
}
if current <= rEnd {
- regions = append(regions, core.NewInterval(current, rEnd))
+ regions = append(regions, geo.NewInterval(current, rEnd))
}
return regions
}
// climbsBetween returns the detected climb bounds inside bounds from the
// distance and elevation components.
-func climbsBetween(distances, elevations []float64, bounds core.Interval, minSlope float64) []core.Interval {
+func climbsBetween(distances, elevations []float64, bounds geo.Interval, minSlope float64) []geo.Interval {
start, end := bounds.Start, bounds.End
- climbs := []core.Interval{}
+ climbs := []geo.Interval{}
if distances[end]-distances[start] < ClimbDistanceMinimum {
return climbs
}
@@ -84,12 +84,12 @@ func climbsBetween(distances, elevations []float64, bounds core.Interval, minSlo
}
// TODO: Use descent to reduce recursion
if distances[highest]-distances[start] < ClimbDistanceMinimum {
- return climbsBetween(distances, elevations, core.NewInterval(start+1, end), minSlope)
+ return climbsBetween(distances, elevations, geo.NewInterval(start+1, end), minSlope)
}
climb, found := bestClimbBetween(distances[start:highest+1], elevations[start:highest+1], minSlope)
if !found {
// No qualifying climb up to the top; only the part past it can hold climbs.
- return climbsBetween(distances, elevations, core.NewInterval(highest, end), minSlope)
+ return climbsBetween(distances, elevations, geo.NewInterval(highest, end), minSlope)
}
// bestClimbBetween returns an interval relative to its sliced input;
// re-anchor it into this slice's index space.
@@ -97,10 +97,10 @@ func climbsBetween(distances, elevations []float64, bounds core.Interval, minSlo
climbEnd := start + climb.End
if climbDetectionScore(distances[climbStart:climbEnd+1], elevations[climbStart:climbEnd+1]) >= detectionMinimumScore && distances[climbEnd]-distances[climbStart] >= ClimbDistanceMinimum {
slog.Debug("Found climb between", slog.Int("start", int(distances[climbStart])), slog.Int("end", int(distances[climbEnd])))
- climbs = append(climbs, core.NewInterval(climbStart, climbEnd))
+ climbs = append(climbs, geo.NewInterval(climbStart, climbEnd))
}
- climbs = append(climbs, climbsBetween(distances, elevations, core.NewInterval(start, climbStart), minSlope)...)
- climbs = append(climbs, climbsBetween(distances, elevations, core.NewInterval(climbEnd, end), minSlope)...)
+ climbs = append(climbs, climbsBetween(distances, elevations, geo.NewInterval(start, climbStart), minSlope)...)
+ climbs = append(climbs, climbsBetween(distances, elevations, geo.NewInterval(climbEnd, end), minSlope)...)
return climbs
}
@@ -121,12 +121,12 @@ func climbDetectionScore(distances, elevations []float64) float64 {
// returns the best qualifying sub-segment (found=false when none exists). The
// returned interval is relative to the start of the given (already sliced)
// slices; callers add back their offset to recover absolute indices.
-func bestClimbBetween(distances, elevations []float64, minSlope float64) (core.Interval, bool) {
+func bestClimbBetween(distances, elevations []float64, minSlope float64) (geo.Interval, bool) {
end := len(distances) - 1
kcore.Assert(end > 0, "empty points")
bestDetectionScore := climbDetectionScore(distances, elevations)
- best := core.NewInterval(0, end)
+ best := geo.NewInterval(0, end)
for i := range end {
detectionScore := climbDetectionScore(distances[i:end], elevations[i:end])
if detectionScore > bestDetectionScore {
@@ -154,7 +154,7 @@ func bestClimbBetween(distances, elevations []float64, minSlope float64) (core.I
}
// Classic best too gentle: re-segment into the best qualifying sub-segment.
bestDetectionScore = math.Inf(-1)
- best = core.NewInterval(-1, -1)
+ best = geo.NewInterval(-1, -1)
for i := range end {
for j := i + 1; j <= end; j++ {
if Slope(distances[i:j+1], elevations[i:j+1]) < minSlope {
@@ -169,7 +169,7 @@ func bestClimbBetween(distances, elevations []float64, minSlope float64) (core.I
}
}
if best.Start < 0 {
- return core.Interval{}, false
+ return geo.Interval{}, false
}
return best, true
}