Implement no-through-traffic zones instead by adding a huge cost to crossing into the zones. #555, #574

Regenerate all maps. Gridlock-wise, Rainier and Poundbury broke, but
Wallingford started working again. Acceptable cost for a change this
useful; I'll work on fixing those maps later.
This commit is contained in:
Dustin Carlino 2021-03-22 16:01:06 -07:00
parent e6cf2d54bc
commit 7d2e8409e8
7 changed files with 419 additions and 387 deletions

File diff suppressed because it is too large Load Diff

View File

@ -30,8 +30,8 @@ pub fn prebake_all() {
MapName::seattle("lakeslice"),
MapName::seattle("phinney"),
MapName::seattle("qa"),
MapName::seattle("rainier_valley"),
//MapName::seattle("wallingford"), TODO broken
//MapName::seattle("rainier_valley"), // TODO broken
MapName::seattle("wallingford"),
] {
let map = map_model::Map::load_synchronously(name.path(), &mut timer);
let scenario: Scenario =
@ -39,7 +39,11 @@ pub fn prebake_all() {
prebake(&map, scenario, None, &mut timer);
}
for scenario_name in vec!["base", "go_active", "base_with_bg", "go_active_with_bg"] {
// TODO These two also broke
for scenario_name in vec![
"base",
"go_active", /* "base_with_bg", "go_active_with_bg" */
] {
let map = map_model::Map::load_synchronously(
MapName::new("gb", "poundbury", "center").path(),
&mut timer,

View File

@ -7,7 +7,7 @@ use petgraph::graphmap::DiGraphMap;
use geom::{Distance, Duration, Speed};
pub use self::walking::{all_walking_costs_from, WalkingOptions};
use crate::pathfind::build_graph_for_vehicles;
use crate::pathfind::{build_graph_for_vehicles, zone_cost};
pub use crate::pathfind::{driving_cost, WalkingNode};
use crate::{BuildingID, LaneID, Map, PathConstraints, PathRequest, RoadID};
@ -117,26 +117,28 @@ pub fn debug_vehicle_costs(req: PathRequest, map: &Map) -> Option<(f64, HashMap<
&graph,
req.start.lane(),
|l| l == req.end.lane(),
|(_, _, turn)| {
|(_, _, t)| {
let turn = map.get_t(*t);
driving_cost(
map.get_l(turn.src),
map.get_t(*turn),
map.get_l(turn.id.src),
turn,
req.constraints,
map.routing_params(),
map,
)
) + zone_cost(turn, req.constraints, map)
},
|_| 0.0,
)?;
let lane_costs = petgraph::algo::dijkstra(&graph, req.start.lane(), None, |(_, _, turn)| {
let lane_costs = petgraph::algo::dijkstra(&graph, req.start.lane(), None, |(_, _, t)| {
let turn = map.get_t(*t);
driving_cost(
map.get_l(turn.src),
map.get_t(*turn),
map.get_l(turn.id.src),
turn,
req.constraints,
map.routing_params(),
map,
)
) + zone_cost(turn, req.constraints, map)
});
// Express the costs per road for an easier debug experince. Take the LOWEST cost per road,
// since we don't want noise from considering the opposite direction.

View File

@ -6,6 +6,7 @@ use petgraph::graphmap::DiGraphMap;
use crate::pathfind::driving::driving_cost;
use crate::pathfind::walking::{walking_cost, WalkingNode};
use crate::pathfind::zone_cost;
use crate::{LaneID, Map, Path, PathConstraints, PathRequest, PathStep, RoutingParams, TurnID};
// TODO These should maybe keep the DiGraphMaps as state. It's cheap to recalculate it for edits.
@ -58,17 +59,14 @@ fn calc_path(
&graph,
req.start.lane(),
|l| l == req.end.lane(),
|(_, _, turn)| {
driving_cost(
map.get_l(turn.src),
map.get_t(*turn),
req.constraints,
params,
map,
)
|(_, _, t)| {
let turn = map.get_t(*t);
driving_cost(map.get_l(turn.id.src), turn, req.constraints, params, map)
+ zone_cost(turn, req.constraints, map)
},
|_| 0.0,
)?;
let mut steps = Vec::new();
for pair in path.windows(2) {
steps.push(PathStep::Lane(pair[0]));
@ -101,7 +99,8 @@ pub fn build_graph_for_pedestrians(map: &Map) -> DiGraphMap<WalkingNode, usize>
turn.id.dst,
map.get_l(turn.id.dst).dst_i == turn.id.parent,
),
walking_cost(turn.geom.length()),
walking_cost(turn.geom.length())
+ zone_cost(turn, PathConstraints::Pedestrian, map) as usize,
);
}
}

View File

@ -10,6 +10,7 @@ use abstutil::MultiMap;
use crate::pathfind::node_map::{deserialize_nodemap, NodeMap};
use crate::pathfind::uber_turns::{IntersectionCluster, UberTurn};
use crate::pathfind::zone_cost;
use crate::{
DrivingSide, Lane, LaneID, Map, Path, PathConstraints, PathRequest, PathStep, RoutingParams,
Turn, TurnID, TurnType,
@ -175,13 +176,10 @@ fn make_input_graph(
input_graph.add_edge(
from,
nodes.get(Node::Lane(turn.id.dst)),
round(driving_cost(
l,
turn,
constraints,
map.routing_params(),
map,
)),
round(
driving_cost(l, turn, constraints, map.routing_params(), map)
+ zone_cost(turn, constraints, map),
),
);
}
} else {
@ -191,13 +189,14 @@ fn make_input_graph(
let mut sum_cost = 0.0;
for t in &ut.path {
let turn = map.get_t(*t);
sum_cost += driving_cost(
map.get_l(t.src),
map.get_t(*t),
turn,
constraints,
map.routing_params(),
map,
);
) + zone_cost(turn, constraints, map);
}
input_graph.add_edge(from, nodes.get(Node::UberTurn(*idx)), round(sum_cost));
input_graph.add_edge(

View File

@ -15,7 +15,7 @@ pub use self::driving::driving_cost;
pub use self::pathfinder::Pathfinder;
pub use self::walking::{walking_cost, WalkingNode};
use crate::{
osm, BuildingID, Lane, LaneID, LaneType, Map, Position, Traversable, TurnID, UberTurn,
osm, BuildingID, Lane, LaneID, LaneType, Map, Position, Traversable, Turn, TurnID, UberTurn,
};
mod ch;
@ -644,16 +644,42 @@ fn validate_zones(map: &Map, steps: &Vec<PathStep>, req: &PathRequest) {
.allow_through_traffic
.contains(req.constraints)
{
// Maybe it's fine
// Entering our destination zone is fine
let into_zone = map.get_parent(t.dst).get_zone(map);
if into_zone != z1 && into_zone != z2 {
error!("{} causes illegal entrance into a zone at {}", req, t);
// TODO There are lots of false positive here that occur when part of the graph
// is separated from the rest by access-restricted roads. Could maybe detect
// that here, or ideally even extend the zone at map construction time (or edit
// time) when that happens.
panic!("{} causes illegal entrance into a zone at {}", req, t);
}
}
}
}
}
/// Heavily penalize crossing into an access-restricted zone that doesn't allow this mode.
pub fn zone_cost(turn: &Turn, constraints: PathConstraints, map: &Map) -> f64 {
// Detect when we cross into a new zone that doesn't allow constraints.
if map
.get_parent(turn.id.src)
.access_restrictions
.allow_through_traffic
.contains(constraints)
&& !map
.get_parent(turn.id.dst)
.access_restrictions
.allow_through_traffic
.contains(constraints)
{
// TODO Tune this after making driving_cost and walking_cost both roughly represent
// seconds. In the meantime, this penalty seems high enough to achieve the desired effect.
100_000.0
} else {
0.0
}
}
/// Tuneable parameters for all types of routing.
// These will maybe become part of the PathRequest later, but that's an extremely invasive and
// space-expensive change right now.

View File

@ -12,6 +12,7 @@ use geom::{Distance, Speed};
use crate::pathfind::driving::VehiclePathfinder;
use crate::pathfind::node_map::{deserialize_nodemap, NodeMap};
use crate::pathfind::zone_cost;
use crate::{
BusRoute, BusRouteID, BusStopID, IntersectionID, LaneID, Map, Path, PathConstraints,
PathRequest, PathStep, Position,
@ -254,7 +255,8 @@ fn make_input_graph(
input_graph.add_edge(
nodes.get(from),
nodes.get(to),
walking_cost(t.geom.length()),
walking_cost(t.geom.length())
+ zone_cost(t, PathConstraints::Pedestrian, map) as usize,
);
}
}