mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 15:33:44 +03:00
plugin to find and show chokepoints
This commit is contained in:
parent
99559fa578
commit
f7f9b5ab70
@ -13,9 +13,7 @@ pub fn split_up_roads(input: &raw_data::Map, elevation: &srtm::Elevation) -> raw
|
||||
for r in &input.roads {
|
||||
for (idx, raw_pt) in r.points.iter().enumerate() {
|
||||
let pt = raw_pt.to_hashable();
|
||||
counts_per_pt.entry(pt).or_insert(0);
|
||||
let count = counts_per_pt[&pt] + 1;
|
||||
counts_per_pt.insert(pt, count);
|
||||
let count = (*counts_per_pt.entry(pt).or_insert(0) += 1);
|
||||
|
||||
if count == 2 {
|
||||
intersections.insert(pt);
|
||||
|
@ -9,3 +9,4 @@
|
||||
- lighting?
|
||||
- fog effects
|
||||
- in 3D, what if roads are sunken rivers and buildings giant skyscrapers?
|
||||
- eyes on the houses, that blink
|
||||
|
@ -7,6 +7,7 @@ authors = ["Dustin Carlino <dabreegster@gmail.com>"]
|
||||
aabb-quadtree = "0.1.0"
|
||||
abstutil = { path = "../abstutil" }
|
||||
control = { path = "../control" }
|
||||
counter = "0.4.3"
|
||||
dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] }
|
||||
ezgui = { path = "../ezgui" }
|
||||
flame = "0.2.2"
|
||||
|
@ -3,6 +3,7 @@
|
||||
extern crate aabb_quadtree;
|
||||
extern crate abstutil;
|
||||
extern crate control;
|
||||
extern crate counter;
|
||||
extern crate dimensioned;
|
||||
extern crate ezgui;
|
||||
extern crate flame;
|
||||
|
101
editor/src/plugins/chokepoints.rs
Normal file
101
editor/src/plugins/chokepoints.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use colors::Colors;
|
||||
use counter::Counter;
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, UserInput};
|
||||
use map_model::{IntersectionID, LaneID, Map, Traversable};
|
||||
use objects::{Ctx, DEBUG_EXTRA, ID};
|
||||
use piston::input::Key;
|
||||
use plugins::Colorizer;
|
||||
use sim::Sim;
|
||||
use std::collections::HashSet;
|
||||
use std::f64;
|
||||
|
||||
const TOP_N: usize = 10;
|
||||
|
||||
pub enum ChokepointsFinder {
|
||||
Inactive,
|
||||
Active(HashSet<LaneID>, HashSet<IntersectionID>),
|
||||
}
|
||||
|
||||
impl ChokepointsFinder {
|
||||
pub fn new() -> ChokepointsFinder {
|
||||
ChokepointsFinder::Inactive
|
||||
}
|
||||
|
||||
pub fn event(&mut self, input: &mut UserInput, sim: &Sim, map: &Map) -> bool {
|
||||
let mut new_state: Option<ChokepointsFinder> = None;
|
||||
match self {
|
||||
ChokepointsFinder::Inactive => {
|
||||
if input.unimportant_key_pressed(
|
||||
Key::C,
|
||||
DEBUG_EXTRA,
|
||||
"find chokepoints of current sim",
|
||||
) {
|
||||
new_state = Some(find_chokepoints(sim, map));
|
||||
}
|
||||
}
|
||||
ChokepointsFinder::Active(_, _) => {
|
||||
if input.key_pressed(Key::Return, "stop showing chokepoints") {
|
||||
new_state = Some(ChokepointsFinder::Inactive);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(s) = new_state {
|
||||
*self = s;
|
||||
}
|
||||
match self {
|
||||
ChokepointsFinder::Inactive => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Colorizer for ChokepointsFinder {
|
||||
fn color_for(&self, obj: ID, ctx: Ctx) -> Option<Color> {
|
||||
match self {
|
||||
ChokepointsFinder::Inactive => None,
|
||||
ChokepointsFinder::Active(lanes, intersections) => match obj {
|
||||
ID::Lane(l) if lanes.contains(&l) => Some(ctx.cs.get(Colors::MatchClassification)),
|
||||
ID::Intersection(i) if intersections.contains(&i) => {
|
||||
Some(ctx.cs.get(Colors::MatchClassification))
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_chokepoints(sim: &Sim, map: &Map) -> ChokepointsFinder {
|
||||
let mut count_per_lane: Counter<LaneID, usize> = Counter::new();
|
||||
let mut count_per_intersection: Counter<IntersectionID, usize> = Counter::new();
|
||||
|
||||
let active = sim.active_agents();
|
||||
info!("Finding chokepoints from {} active agents", active.len());
|
||||
for a in active.into_iter() {
|
||||
for segment in sim.trace_route(a, map, f64::MAX * si::M).unwrap().segments {
|
||||
match segment.on {
|
||||
Traversable::Lane(l) => {
|
||||
count_per_lane.update(vec![l]);
|
||||
}
|
||||
Traversable::Turn(t) => {
|
||||
count_per_intersection.update(vec![t.parent]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let lanes: HashSet<LaneID> = count_per_lane
|
||||
.most_common_ordered()
|
||||
.into_iter()
|
||||
.take(TOP_N)
|
||||
.map(|(l, _)| l)
|
||||
.collect();
|
||||
let intersections: HashSet<IntersectionID> = count_per_intersection
|
||||
.most_common_ordered()
|
||||
.into_iter()
|
||||
.take(TOP_N)
|
||||
.map(|(i, _)| i)
|
||||
.collect();
|
||||
ChokepointsFinder::Active(lanes, intersections)
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
pub mod a_b_tests;
|
||||
pub mod chokepoints;
|
||||
pub mod classification;
|
||||
pub mod color_picker;
|
||||
pub mod debug_objects;
|
||||
|
@ -12,6 +12,7 @@ use map_model::{IntersectionID, Map};
|
||||
use objects::{Ctx, ID, ROOT_MENU};
|
||||
use piston::input::Key;
|
||||
use plugins::a_b_tests::ABTestManager;
|
||||
use plugins::chokepoints::ChokepointsFinder;
|
||||
use plugins::classification::OsmClassifier;
|
||||
use plugins::color_picker::ColorPicker;
|
||||
use plugins::debug_objects::DebugObjectsState;
|
||||
@ -241,6 +242,13 @@ impl UIWrapper {
|
||||
}
|
||||
active
|
||||
}),
|
||||
Box::new(|ctx| {
|
||||
ctx.ui.primary.chokepoints.event(
|
||||
ctx.input,
|
||||
&ctx.ui.primary.sim,
|
||||
&ctx.ui.primary.map,
|
||||
)
|
||||
}),
|
||||
Box::new(|ctx| {
|
||||
let (active, new_ui) =
|
||||
ctx.ui
|
||||
@ -285,6 +293,7 @@ pub struct PerMapUI {
|
||||
draw_neighborhoods: DrawNeighborhoodState,
|
||||
scenarios: ScenarioManager,
|
||||
edits_manager: EditsManager,
|
||||
chokepoints: ChokepointsFinder,
|
||||
}
|
||||
|
||||
impl PerMapUI {
|
||||
@ -330,6 +339,7 @@ impl PerMapUI {
|
||||
draw_neighborhoods: DrawNeighborhoodState::new(),
|
||||
scenarios: ScenarioManager::new(),
|
||||
edits_manager: EditsManager::new(),
|
||||
chokepoints: ChokepointsFinder::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -581,8 +591,9 @@ impl UI {
|
||||
16 => Some(Box::new(&self.primary.draw_neighborhoods)),
|
||||
17 => Some(Box::new(&self.primary.scenarios)),
|
||||
18 => Some(Box::new(&self.primary.edits_manager)),
|
||||
19 => Some(Box::new(&self.ab_test_manager)),
|
||||
20 => Some(Box::new(&self.logs)),
|
||||
19 => Some(Box::new(&self.primary.chokepoints)),
|
||||
20 => Some(Box::new(&self.ab_test_manager)),
|
||||
21 => Some(Box::new(&self.logs)),
|
||||
_ => panic!("Active plugin {} is too high", idx),
|
||||
}
|
||||
}
|
||||
|
@ -344,6 +344,10 @@ impl Sim {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn active_agents(&self) -> Vec<AgentID> {
|
||||
self.trips_state.active_agents()
|
||||
}
|
||||
|
||||
pub fn trace_route(&self, id: AgentID, map: &Map, dist_ahead: Distance) -> Option<Trace> {
|
||||
match id {
|
||||
AgentID::Car(car) => self.driving_state.trace_route(car, map, dist_ahead),
|
||||
|
@ -221,6 +221,10 @@ impl TripManager {
|
||||
}
|
||||
summary
|
||||
}
|
||||
|
||||
pub fn active_agents(&self) -> Vec<AgentID> {
|
||||
self.active_trip_mode.keys().cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
|
||||
|
Loading…
Reference in New Issue
Block a user