mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
overly conservative gridlock detection, triggered kind of manually
This commit is contained in:
parent
e6d51cf421
commit
dd198bb37f
@ -131,6 +131,7 @@ impl AmbientPluginWithPrimaryPlugins for SimControls {
|
||||
self.run_sim(&mut ctx.primary.sim);
|
||||
} else if ctx.input.action_chosen("run one step of sim") {
|
||||
ctx.primary.sim.step(&ctx.primary.map);
|
||||
ctx.primary.sim.detect_gridlock(&ctx.primary.map);
|
||||
|
||||
*ctx.recalculate_current_selection = true;
|
||||
if let Some((s, _)) = ctx.secondary {
|
||||
|
@ -13,6 +13,7 @@ histogram = "0.6.9"
|
||||
map_model = { path = "../map_model" }
|
||||
more-asserts = "0.2.1"
|
||||
num_cpus = "1.10.0"
|
||||
petgraph = "0.4.13"
|
||||
pretty_assertions = "0.6.1"
|
||||
rand = { version = "0.6.5", features = ["serde1"] }
|
||||
rand_xorshift = "0.1.1"
|
||||
|
@ -8,9 +8,12 @@ use crate::{
|
||||
use abstutil::{deserialize_btreemap, serialize_btreemap};
|
||||
use ezgui::{Color, GfxCtx};
|
||||
use geom::{Distance, Duration};
|
||||
use map_model::{BuildingID, Map, Path, Trace, Traversable, LANE_THICKNESS};
|
||||
use map_model::{
|
||||
BuildingID, IntersectionID, LaneID, Map, Path, Trace, Traversable, LANE_THICKNESS,
|
||||
};
|
||||
use petgraph::graph::{Graph, NodeIndex};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::collections::{BTreeMap, HashMap, VecDeque};
|
||||
|
||||
const FREEFLOW: Color = Color::CYAN;
|
||||
const WAITING: Color = Color::RED;
|
||||
@ -609,7 +612,7 @@ impl DrivingSimState {
|
||||
pub fn tooltip_lines(&self, id: CarID) -> Option<Vec<String>> {
|
||||
let car = self.cars.get(&id)?;
|
||||
Some(vec![
|
||||
format!("{}", id),
|
||||
format!("{} on {:?}", id, car.router.head()),
|
||||
format!("Owned by {:?}", car.vehicle.owner),
|
||||
format!("{} lanes left", car.router.get_path().num_lanes()),
|
||||
format!("{:?}", car.state),
|
||||
@ -642,4 +645,71 @@ impl DrivingSimState {
|
||||
let car = self.cars.get(&id)?;
|
||||
car.vehicle.owner
|
||||
}
|
||||
|
||||
// This ignores capacity, pedestrians, and traffic signal overtime. So it should yield false
|
||||
// positives (thinks there's gridlock, when there isn't) but never false negatives.
|
||||
pub fn detect_gridlock(&self, map: &Map) {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
enum Node {
|
||||
Lane(LaneID),
|
||||
Intersection(IntersectionID),
|
||||
}
|
||||
|
||||
// TODO petgraph wrapper to map nodes -> node index and handle duplicate nodes
|
||||
let mut deps: Graph<Node, ()> = Graph::new();
|
||||
let mut nodes: HashMap<Node, NodeIndex<u32>> = HashMap::new();
|
||||
|
||||
for queue in self.queues.values() {
|
||||
if queue.cars.is_empty() {
|
||||
continue;
|
||||
}
|
||||
match queue.id {
|
||||
Traversable::Lane(l) => {
|
||||
let lane_id = Node::Lane(l);
|
||||
// Assume lead car will proceed to the intersection
|
||||
nodes.insert(lane_id, deps.add_node(lane_id));
|
||||
|
||||
let int_id = Node::Intersection(map.get_l(l).dst_i);
|
||||
if !nodes.contains_key(&int_id) {
|
||||
nodes.insert(int_id, deps.add_node(int_id));
|
||||
}
|
||||
|
||||
deps.add_edge(nodes[&lane_id], nodes[&int_id], ());
|
||||
}
|
||||
Traversable::Turn(t) => {
|
||||
let int_id = Node::Intersection(t.parent);
|
||||
if !nodes.contains_key(&int_id) {
|
||||
nodes.insert(int_id, deps.add_node(int_id));
|
||||
}
|
||||
|
||||
let target_lane_id = Node::Lane(t.dst);
|
||||
if !nodes.contains_key(&target_lane_id) {
|
||||
nodes.insert(target_lane_id, deps.add_node(target_lane_id));
|
||||
}
|
||||
|
||||
deps.add_edge(nodes[&int_id], nodes[&target_lane_id], ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(cycle) = petgraph::algo::toposort(&deps, None) {
|
||||
// Super lame, we only get one node in the cycle, and A* won't attempt to look for
|
||||
// loops.
|
||||
for start in deps.neighbors(cycle.node_id()) {
|
||||
if let Some((_, raw_nodes)) =
|
||||
petgraph::algo::astar(&deps, start, |n| n == cycle.node_id(), |_| 0, |_| 0)
|
||||
{
|
||||
println!("Gridlock involving:");
|
||||
for n in raw_nodes {
|
||||
println!("- {:?}", deps[n]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
println!(
|
||||
"Gridlock involving {:?}, but couldn't find the cycle!",
|
||||
cycle.node_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ impl WalkingSimState {
|
||||
pub fn ped_tooltip(&self, id: PedestrianID) -> Vec<String> {
|
||||
let p = &self.peds[&id];
|
||||
vec![
|
||||
format!("{}", p.id),
|
||||
format!("{} on {:?}", p.id, p.path.current_step()),
|
||||
format!("{} lanes left in path", p.path.num_lanes()),
|
||||
format!("{:?}", p.state),
|
||||
]
|
||||
|
@ -725,4 +725,8 @@ impl Sim {
|
||||
pub fn is_in_overtime(&self, id: IntersectionID, map: &Map) -> bool {
|
||||
self.intersections.is_in_overtime(self.time, id, map)
|
||||
}
|
||||
|
||||
pub fn detect_gridlock(&self, map: &Map) {
|
||||
self.driving.detect_gridlock(map)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user