Start some new RoutingParams for bikes to avoid steep hills and

stressful roads. Initially experiment in the route debugger UI. #743

This is a binary map format change, but temporarily working around
that...
This commit is contained in:
Dustin Carlino 2021-09-02 10:57:17 -07:00
parent 0ad76921fd
commit 8c2c0e2e65
3 changed files with 79 additions and 13 deletions

View File

@ -207,7 +207,7 @@ fn params_to_controls(ctx: &mut EventCtx, mode: TripMode, params: &RoutingParams
.margin_right(20),
Spinner::widget(
ctx,
"unprotected turn penalty",
"unprotected_turn_penalty",
(Duration::seconds(1.0), Duration::seconds(100.0)),
params.unprotected_turn_penalty,
Duration::seconds(1.0),
@ -219,7 +219,7 @@ fn params_to_controls(ctx: &mut EventCtx, mode: TripMode, params: &RoutingParams
"Bike lane penalty:".text_widget(ctx).margin_right(20),
Spinner::widget(
ctx,
"bike lane penalty",
"bike_lane_penalty",
(0.0, 2.0),
params.bike_lane_penalty,
0.1,
@ -229,7 +229,7 @@ fn params_to_controls(ctx: &mut EventCtx, mode: TripMode, params: &RoutingParams
"Bus lane penalty:".text_widget(ctx).margin_right(20),
Spinner::widget(
ctx,
"bus lane penalty",
"bus_lane_penalty",
(0.0, 2.0),
params.bus_lane_penalty,
0.1,
@ -239,12 +239,34 @@ fn params_to_controls(ctx: &mut EventCtx, mode: TripMode, params: &RoutingParams
"Driving lane penalty:".text_widget(ctx).margin_right(20),
Spinner::widget(
ctx,
"driving lane penalty",
"driving_lane_penalty",
(0.0, 2.0),
params.driving_lane_penalty,
0.1,
),
]));
rows.push(Widget::row(vec![
"Avoid steep inclines (>= 8%):"
.text_widget(ctx)
.margin_right(20),
Spinner::widget(
ctx,
"avoid_steep_incline_penalty",
(0.0, 2.0),
params.avoid_steep_incline_penalty,
0.1,
),
]));
rows.push(Widget::row(vec![
"Avoid high-stress roads:".text_widget(ctx).margin_right(20),
Spinner::widget(
ctx,
"avoid_high_stress",
(0.0, 2.0),
params.avoid_high_stress,
0.1,
),
]));
}
Widget::col(rows)
}
@ -252,16 +274,18 @@ fn params_to_controls(ctx: &mut EventCtx, mode: TripMode, params: &RoutingParams
fn controls_to_params(panel: &Panel) -> (TripMode, RoutingParams) {
let mut params = RoutingParams::default();
if !panel.is_button_enabled("cars") {
params.unprotected_turn_penalty = panel.spinner("unprotected turn penalty");
params.unprotected_turn_penalty = panel.spinner("unprotected_turn_penalty");
return (TripMode::Drive, params);
}
if !panel.is_button_enabled("pedestrians") {
return (TripMode::Walk, params);
}
params.unprotected_turn_penalty = panel.spinner("unprotected turn penalty");
params.bike_lane_penalty = panel.spinner("bike lane penalty");
params.bus_lane_penalty = panel.spinner("bus lane penalty");
params.driving_lane_penalty = panel.spinner("driving lane penalty");
params.unprotected_turn_penalty = panel.spinner("unprotected_turn_penalty");
params.bike_lane_penalty = panel.spinner("bike_lane_penalty");
params.bus_lane_penalty = panel.spinner("bus_lane_penalty");
params.driving_lane_penalty = panel.spinner("driving_lane_penalty");
params.avoid_steep_incline_penalty = panel.spinner("avoid_steep_incline_penalty");
params.avoid_high_stress = panel.spinner("avoid_high_stress");
(TripMode::Bike, params)
}
@ -400,7 +424,7 @@ impl State<App> for AllRoutesExplorer {
((*after as isize) - (*before as isize)).abs() as usize
})
.max()
.unwrap() as f64;
.unwrap_or(0) as f64;
for (r, before, after) in comparisons {
match after.cmp(&before) {
std::cmp::Ordering::Less => {

View File

@ -159,11 +159,28 @@ pub fn zone_cost(mvmnt: MovementID, constraints: PathConstraints, map: &Map) ->
pub struct RoutingParams {
// For all vehicles. This is added to the cost of a movement as an additional delay.
pub unprotected_turn_penalty: Duration,
// For bike routing. Multiplied by the base cost, since spending more time on the wrong lane
// type matters.
pub bike_lane_penalty: f64,
pub bus_lane_penalty: f64,
pub driving_lane_penalty: f64,
// For bike routing.
// "Steep" is a fixed threshold of 8% incline, uphill only. Multiply by the base cost. (Note
// that cost already includes a reduction of speed to account for the incline -- this is a
// further "delay" on top of that!)
// TODO But even steeper roads matter more!
// TODO Serialize as usual. Requires regenerating all maps, not ready to do that yet.
#[serde(skip_serializing, skip_deserializing, default = "one")]
pub avoid_steep_incline_penalty: f64,
// If the road is `high_stress_for_bikes`, multiply by the base cost.
#[serde(skip_serializing, skip_deserializing, default = "one")]
pub avoid_high_stress: f64,
}
fn one() -> f64 {
1.0
}
impl RoutingParams {
@ -172,9 +189,13 @@ impl RoutingParams {
// This is a total guess -- it really depends on the traffic patterns of the particular
// road at the time we're routing.
unprotected_turn_penalty: Duration::const_seconds(30.0),
bike_lane_penalty: 1.0,
bus_lane_penalty: 1.1,
driving_lane_penalty: 1.5,
avoid_steep_incline_penalty: 1.0,
avoid_high_stress: 1.0,
}
}
}

View File

@ -317,10 +317,31 @@ pub fn vehicle_cost(
PathConstraints::Pedestrian => unreachable!(),
};
let mut multiplier = 1.0;
if constraints == PathConstraints::Bike && params.avoid_steep_incline_penalty != 1.0 {
let road = map.get_r(dr.id);
let percent_incline = if dr.dir == Direction::Fwd {
road.percent_incline
} else {
-road.percent_incline
};
if percent_incline >= 0.08 {
multiplier *= params.avoid_steep_incline_penalty;
}
}
if constraints == PathConstraints::Bike && params.avoid_high_stress != 1.0 {
let road = map.get_r(dr.id);
if road.high_stress_for_bikes(map) {
multiplier *= params.avoid_high_stress;
}
}
let mut extra = Duration::ZERO;
// Penalize unprotected turns at a stop sign from smaller to larger roads.
if map.is_unprotected_turn(dr.id, mvmnt.to.id, mvmnt_turn_type) {
base + params.unprotected_turn_penalty
} else {
base
extra += params.unprotected_turn_penalty
}
multiplier * base + extra
}