summaryrefslogtreecommitdiff
path: root/ride
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-08-03 08:25:07 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-08-03 08:25:07 +0200
commit9707f9ad09db935af7d06b5de08bc52de13ba6a7 (patch)
tree34bcd01e5eda302a8730bf0817d5dd7e82186359 /ride
parentf06a10982ab9d5aaa7d31cea31964431fa75f253 (diff)
feat: Detect mountain pass crossings, name climbs after passes, render ride charts
- osmpass: extract mountain_pass=yes nodes from an OSM PBF, enrich centcols passes with OSM coordinates, resumable -fetch-osm download - mountain_pass: DetectCrossings for a ride, MatchClimb to name a climb after the pass it tops - ride: expose Points(), add Climb.Top() and Climb.Name - chart: -chart renders elevation profile with climb bands and pass markers - commands: -fetch-osm, -extract-osm, -import-cached, -enrich
Diffstat (limited to 'ride')
-rw-r--r--ride/climb.go19
-rw-r--r--ride/ride.go4
2 files changed, 22 insertions, 1 deletions
diff --git a/ride/climb.go b/ride/climb.go
index 8ac60fa..d5a1718 100644
--- a/ride/climb.go
+++ b/ride/climb.go
@@ -16,6 +16,7 @@ type Climb struct {
rideStart int
rideEnd int
points []Point
+ Name string
}
func (climb Climb) Duration() time.Duration {
@@ -34,11 +35,27 @@ func (climb Climb) End() Point {
return climb.points[len(climb.points)-1]
}
+// Top returns the highest point inside the climb, used as the crest anchor
+// when naming the climb after a pass.
+func (climb Climb) Top() Point {
+ top := climb.points[0]
+ for _, point := range climb.points {
+ if point.ElevationM > top.ElevationM {
+ top = point
+ }
+ }
+ return top
+}
+
func (climb Climb) String() string {
start := climb.points[0]
end := climb.points[len(climb.points)-1]
score := Score(climb.points, 0, len(climb.points)-1)
- return fmt.Sprintf("%.1fkm-%.1fkm: %.1fkm at %.1f%% (%d pts - %s)", start.DistanceM/1000, end.DistanceM/1000, (end.DistanceM-start.DistanceM)/1000, Slope(start, end)*100, int(score), Category(score))
+ body := fmt.Sprintf("%.1fkm-%.1fkm: %.1fkm at %.1f%% (%d pts - %s)", start.DistanceM/1000, end.DistanceM/1000, (end.DistanceM-start.DistanceM)/1000, Slope(start, end)*100, int(score), Category(score))
+ if climb.Name == "" {
+ return body
+ }
+ return climb.Name + ": " + body
}
func (climb Climb) Score() float64 {
diff --git a/ride/ride.go b/ride/ride.go
index 73e7a26..df5560b 100644
--- a/ride/ride.go
+++ b/ride/ride.go
@@ -31,6 +31,10 @@ func (r *Ride) check() {
kcore.Assert(len(r.points) > 0, "no points in ride")
}
+func (r *Ride) Points() []Point {
+ return r.points
+}
+
type RideParser interface {
Parse(reader io.Reader) (Ride, error)
}