Files
TREK/shared/src/tours/run-pace.ts
T
Maurice c83eb42730 feat(tours): plan a run at your own pace
RUN-01. Run joins the tour types in the planner, with Running as its first
profile, chosen on purpose like a bike tour's. A run is routed on foot for
runnable, mostly paved ways: tracks and ferries only where there is no other
way (use_tracks 0, use_ferry 0, measured against the public Valhalla), no
hiking limit and no via ferrata. The runner types a pace in min/km; the
running time is the distance at that pace and nothing else, shown under the
field as badges (8 km x 6:00 /km = 48 min). TREK suggests no pace: without
one the time stays unknown and Save waits, text that is no pace or a pace
outside 2:00 to 20:00 is marked. The info dot, the overview and the head say
climbs, descents and difficulty are not in the time, and the time reads as
planned everywhere, so it never passes for a recorded one; the heights are
shown as for any tour on land.

Type, profile, pace and route come back on opening, survive a draft reload,
an undo of the type, a copy and a take-over; switching to another type drops
profile and pace. Day assignment, the 3D terrain view (with topo and
satellite, no ferratas) and a routing failure keeping the last route work as
for every tour. A GPX file can be imported as a run with its profile and no
pace, and planned over as a run. Runs export to GPX as running and get their
own places along the way (water, toilets, parks, viewpoints).

The server keeps tours.run_profile (CHECK list, already holding trail for
RUN-02, since SQLite cannot widen a CHECK in place) and
tours.run_pace_seconds_per_km (120 to 1200), switches the run type on,
refuses a run without a profile and run fields on any other type, and
list_tours names both with what the planned time does not include.
2026-10-20 15:05:38 +02:00

24 lines
963 B
TypeScript

import { z } from 'zod';
/**
* RUN-01: a run is planned with the runner's own pace, in seconds per
* kilometre, and its time is the distance at that pace. Nothing else goes in:
* no climb, no descent, no surface and no difficulty, and TREK suggests no
* pace of its own. A run without a pace has no time; it stays unknown.
*
* The bounds keep a typo out, not a runner: 2:00 min/km is faster than any
* road record, 20:00 min/km slower than walking.
*/
export const MIN_RUN_PACE_SECONDS_PER_KM = 2 * 60;
export const MAX_RUN_PACE_SECONDS_PER_KM = 20 * 60;
export const runPaceSecondsPerKmSchema = z
.number()
.int()
.min(MIN_RUN_PACE_SECONDS_PER_KM)
.max(MAX_RUN_PACE_SECONDS_PER_KM);
/** The planned running time in whole minutes: the distance at the pace, 8 km at 6:00 min/km is 48 minutes. */
export function runMinutesAtPace(distanceKm: number, paceSecondsPerKm: number): number {
return Math.round((distanceKm * paceSecondsPerKm) / 60);
}