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 /mountain_pass/detection.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 'mountain_pass/detection.go')
| -rw-r--r-- | mountain_pass/detection.go | 33 |
1 files changed, 15 insertions, 18 deletions
diff --git a/mountain_pass/detection.go b/mountain_pass/detection.go index 40281f3..79e55e4 100644 --- a/mountain_pass/detection.go +++ b/mountain_pass/detection.go @@ -5,7 +5,8 @@ import ( "math" "github.com/jftuga/geodist" - "github.com/martinlehoux/biking_home/ride" + "github.com/martinlehoux/biking_home/climb" + "github.com/martinlehoux/biking_home/geo" ) // MountainPass is a pass extracted from OpenStreetMap: a node tagged @@ -112,9 +113,9 @@ func DetectCrossings(coords []geodist.Coord, distances, elevations []float64, pa // MatchClimb returns the pass whose coordinates lie within radiusM of the // climb's highest point and whose elevation is within elevationToleranceM of // that point's elevation, nearest first. Found is false when no pass matches. -func MatchClimb(climb ride.Climb, passes []MountainPass, radiusM, elevationToleranceM float64) (MountainPass, bool) { - topCoord := climb.TopCoord() - topElevation := climb.TopElevationM() +func MatchClimb(segment climb.Climb, passes []MountainPass, radiusM, elevationToleranceM float64) (MountainPass, bool) { + topIndex, topElevation := segment.Top() + topCoord := segment.Coords[topIndex] var best MountainPass bestDistanceM := radiusM found := false @@ -139,21 +140,17 @@ func MatchClimb(climb ride.Climb, passes []MountainPass, radiusM, elevationToler } func nearestCrossing(coords []geodist.Coord, distances, elevations []float64, mountainPass MountainPass) (Crossing, bool) { - best := Crossing{Pass: mountainPass, DistanceToM: 1e18} - for i := range coords { - distanceKm, _ := geodist.HaversineDistance(coords[i], *mountainPass.Coord) - distanceM := distanceKm * 1000 - if distanceM < best.DistanceToM { - best.DistanceToM = distanceM - best.RideDistanceM = distances[i] - best.RideElevation = elevations[i] - best.ElevationDiff = absFloat64(elevations[i] - float64(mountainPass.Elevation)) - } - } - if best.DistanceToM > 1e17 { - return best, false + index, distanceM := geo.Nearest(coords, *mountainPass.Coord) + if math.IsInf(distanceM, 1) { + return Crossing{Pass: mountainPass}, false } - return best, true + return Crossing{ + Pass: mountainPass, + DistanceToM: distanceM, + RideDistanceM: distances[index], + RideElevation: elevations[index], + ElevationDiff: absFloat64(elevations[index] - float64(mountainPass.Elevation)), + }, true } func absFloat64(value float64) float64 { |
