Travel times in SUSTech Transit are computed from real
geometry (OpenStreetMap footways) + real elevation (Open-Elevation
API), using three simple formulas. You can tune all the constants by
editing state.PARAMS in web/static/app.js.
Speeds (defaults)
| Constant | Default | What |
|---|---|---|
walkFlatKmh | 4.5 km/h | Pedestrian flat-ground speed |
bikeFlatKmh | 16.0 km/h | Casual cyclist flat-ground speed |
toblerMaxKmh | 6.0 km/h | Peak Tobler speed (at -5% downhill) |
toblerAscentCoef | 3.5 | Tobler's slope-sensitivity k |
bikeClimbCoef | 10.0 | Bike climb-fraction multiplier |
transferPenaltyMin | 5 min | Per-bus-transfer pad |
waitHeadwayMin | 10 min | Typical bus headway |
๐ถ Walk โ Tobler's hiking function (1993)
The classic model: speed is maximized at a gentle downhill slope
(-5%) and falls off rapidly uphill. Slope s is in m/m
(rise/run); positive = uphill.
v(s) = toblerMaxKmh ยท exp(-toblerAscentCoef ยท |s + 0.05|)duration_min = (distance_m / 1000) / v(s) ยท 60
At +5% uphill: v โ 2.4 km/h. At -15% downhill:
v โ 3.0 km/h. Symmetric around the optimum.
๐ด Bike โ climb-fraction model
Cycling is dominated by vertical gain per unit distance. Downhill is essentially free (gravity + freewheel). Uphill requires real work proportional to the climb fraction.
climbFraction = max(0, climb_m) / max(distance_m, 1)speed_kmh = bikeFlatKmh / (1 + bikeClimbCoef ยท climbFraction)duration_min = (distance_m / 1000) / speed_kmh ยท 60
At 6.25% climb (typical ่ๅญโๆฌฃๅญ over ่ถๅ ๅฑฑ): ~8 km/h. At 15% climb: ~5.3 km/h. Flat: 16 km/h.
๐ Bus โ 2.5 min/km + transfer penalty
duration_min = (distance_m / 1000) ยท 2.5 + 0.1 + transferPenaltyMin / 2
The 2.5 min/km rate matches the campus schedule's
minuteOnRoad = 25 for the ~10 km inner loop (โ10 km/h average).
Elevation doesn't matter for a diesel bus. The half-transfer penalty
approximates average wait time; full transfer cost is a future TODO.
How the graph is built
Three kinds of nodes:
- Facility (buildings, gates, bus stops) โ from
facilities.geojson+bus_stops.geojson - Footway vertex โ every coordinate from
footways.json(OSM Overpass)
Three kinds of edges:
- Walk (footway) โ consecutive vertices along an OSM footway/path. Used by walk, bike, and transit modes.
- Walk (access) โ each facility โ its nearest footway vertex within 80 m. Used by walk, bike, transit.
- Bus โ consecutive bus stops on each line/direction. Used by bus and transit modes.
If footways.json is missing or empty, the graph falls back
to direct facility-to-facility edges within 250 m (the old "straight
line" behavior).
Mode filtering
| UI mode | Allowed edge modes |
|---|---|
walk | walk only |
bike | walk only (cyclist on path) |
bus | bus only |
transit | walk + bus |
Tuning guide
All formulas are in web/static/app.js, function
segmentDuration(lat1, lng1, lat2, lng2, mode).
Edit state.PARAMS at the top of the file to taste.
For best results, calibrate against your own timing:
- Pick a route you walk regularly (e.g. dorm โ ้ฃๅ ).
- Time it with a stopwatch.
- Compare to the model's estimate โ adjust
walkFlatKmhif it's consistently off. - For a hilly route, adjust
toblerAscentCoefif the uphill portion is over/underestimated.
- Schedule-aware wait time โ use the bus timetable to compute actual wait at the next departure.
- Per-transfer cost โ charge the full transfer penalty only when the path actually changes bus lines.
- Live bus mode โ if a bus is currently within 200 m of your origin, treat it as a free ride.
- Snap-to-2-vertices โ currently each facility snaps to the single nearest footway node; for proper path geometry we should snap to the two nearest (one in each direction).
- UI sliders โ let users pick their own walk/bike speeds ("I'm fast", "I hate hills").