starting a very basic plugin to show differences between trips in parallel worlds

This commit is contained in:
Dustin Carlino 2018-10-16 12:38:07 -07:00
parent 41817d3e91
commit 2c110a58f9
8 changed files with 155 additions and 7 deletions

View File

@ -135,13 +135,8 @@ though... Can we fork RNG for that too?
Problems: Problems:
- CarIDs are different, could make them be original parking spot - CarIDs are different, could make them be original parking spot
- Missing trip ID, different ped IDs
= gen_range on different inputs = gen_range on different inputs
Alright, now how do peds picking a car work?
## Parked cars and ownership ## Parked cars and ownership
Most cars are associated with a household. They usually park close to that Most cars are associated with a household. They usually park close to that
@ -155,3 +150,41 @@ Given:
Can then seed parked cars kinda greedily. Can then seed parked cars kinda greedily.
But back up, other section. But back up, other section.
Alright, now how do peds picking a car work?
- easy case: if the same car is present in both worlds, should use the same
- if cars are associated with buildings in a stable way, this should probably
help or at least push the problem to a slightly more explicit place
- if a parking lane is gone and an agent wouldve used something there, of
course they have to walk farther to get to their car. but we want to somehow
localize these effects. same number of parked cars in the neighborhood and same
assignment to buildings, but maybe some other lane gets more crowded?
Next thoughts:
- scrap the concept of SeedParkedCars. instead say "x% of buildings in this neighborhood have 1 or 2 cars." peds from these buildings will use those specific cars, others wont.
- probability of 0 cars = 40, 1 car = 40, 2 cars = 20 <--- thats much nicer
- go through each building, find a spot to seed that parked car.
- try to be close to building, random jitter to be a little far away
- if this process is somewhat stable, then should be fine. doesnt need to be perfectly stable -- removing lanes somewhere might put more pressure on another lane.
## Traces between worlds
Alright, now how do we even compare trip progress to show it visually? This is
kind of a UI-only problem; total score at the end can be compared way more
easily.
- easy case: if both worlds are using the same mode AND route, trace_route the
slower agent with the dist_ahead of the faster agent (difference between the
two)
- alright, have to track current distance traveled to do this. can keep
state per trip leg or something.
- if it's unclear who's closer to the goal, could just pathfind to exactly
where the other agent is, display in a neutral way
- mode changes are potentially weird... but just slide over between sidewalks and driving lanes? mmm...
- strawman: dont use the trace route thing, just have a straight arrow to the
other agent and green/red based on straight-line distance to goal bldg
- progress is non-monotonic -- might walk away from goal to get to car, then get there faster. or maybe get stuck in traffic. so straightline distance to goal is EXPECTED to fluctuate. thats kind of exciting to watch anyway.
Ah, upon seeing just the line between, I know what would make more sense --
show the divergence. The point in the route where one version goes one way, and
the second goes another. Two routes shown, symmetric.

View File

@ -5,7 +5,7 @@ use geom::Pt2D;
use kml::ExtraShapeID; use kml::ExtraShapeID;
use map_model::{AreaID, BuildingID, BusStopID, IntersectionID, LaneID, Map, ParcelID, TurnID}; use map_model::{AreaID, BuildingID, BusStopID, IntersectionID, LaneID, Map, ParcelID, TurnID};
use render::DrawMap; use render::DrawMap;
use sim::{CarID, PedestrianID, Sim, TripID}; use sim::{AgentID, CarID, PedestrianID, Sim, TripID};
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)] #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
pub enum ID { pub enum ID {
@ -23,6 +23,14 @@ pub enum ID {
} }
impl ID { impl ID {
pub fn agent_id(&self) -> Option<AgentID> {
match *self {
ID::Car(id) => Some(AgentID::Car(id)),
ID::Pedestrian(id) => Some(AgentID::Pedestrian(id)),
_ => None,
}
}
pub fn debug(&self, map: &Map, control_map: &ControlMap, sim: &mut Sim) { pub fn debug(&self, map: &Map, control_map: &ControlMap, sim: &mut Sim) {
match *self { match *self {
ID::Lane(id) => { ID::Lane(id) => {

View File

@ -1,5 +1,6 @@
use ezgui::{Canvas, GfxCtx, LogScroller, UserInput, Wizard, WrappedWizard}; use ezgui::{Canvas, GfxCtx, LogScroller, UserInput, Wizard, WrappedWizard};
use map_model::Map; use map_model::Map;
use objects::ID;
use objects::SIM_SETUP; use objects::SIM_SETUP;
use piston::input::Key; use piston::input::Key;
use plugins::{choose_edits, choose_scenario, load_ab_test, Colorizer}; use plugins::{choose_edits, choose_scenario, load_ab_test, Colorizer};
@ -21,6 +22,7 @@ impl ABTestManager {
pub fn event( pub fn event(
&mut self, &mut self,
input: &mut UserInput, input: &mut UserInput,
selected: Option<ID>,
map: &Map, map: &Map,
kml: &Option<String>, kml: &Option<String>,
current_flags: &SimFlags, current_flags: &SimFlags,
@ -29,7 +31,9 @@ impl ABTestManager {
let mut new_state: Option<ABTestManager> = None; let mut new_state: Option<ABTestManager> = None;
match self { match self {
ABTestManager::Inactive => { ABTestManager::Inactive => {
if input.unimportant_key_pressed(Key::B, SIM_SETUP, "manage A/B tests") { if selected.is_none()
&& input.unimportant_key_pressed(Key::B, SIM_SETUP, "manage A/B tests")
{
new_state = Some(ABTestManager::PickABTest(Wizard::new())); new_state = Some(ABTestManager::PickABTest(Wizard::new()));
} }
} }

View File

@ -0,0 +1,83 @@
use colors::ColorScheme;
use ezgui::{GfxCtx, UserInput};
use geom::Line;
use map_model::LANE_THICKNESS;
use piston::input::Key;
use plugins::Colorizer;
use sim::TripID;
use ui::PerMapUI;
pub enum DiffWorldsState {
Inactive,
// The Line just points from the agent in the primary sim to the agent in the secondary.
Active(TripID, Line),
}
impl DiffWorldsState {
pub fn new() -> DiffWorldsState {
DiffWorldsState::Inactive
}
pub fn event(
&mut self,
input: &mut UserInput,
primary: &PerMapUI,
secondary: &Option<PerMapUI>,
) -> bool {
let mut maybe_trip: Option<TripID> = None;
match self {
DiffWorldsState::Inactive => {
if secondary.is_some() {
if let Some(id) = primary.current_selection.and_then(|id| id.agent_id()) {
let trip = primary.sim.agent_to_trip(id);
if input.key_pressed(Key::B, &format!("Show {}'s parallel world", trip)) {
maybe_trip = Some(trip);
}
}
}
}
DiffWorldsState::Active(trip, _) => {
if input.key_pressed(
Key::Return,
&format!("Stop showing {}'s parallel world", trip),
) {
maybe_trip = None;
} else {
maybe_trip = Some(*trip);
}
}
}
if let Some(id) = maybe_trip {
let pt1 = primary.sim.get_canonical_point_for_trip(id, &primary.map);
let pt2 = secondary
.as_ref()
.and_then(|s| s.sim.get_canonical_point_for_trip(id, &s.map));
if pt1.is_some() && pt2.is_some() {
*self = DiffWorldsState::Active(id, Line::new(pt1.unwrap(), pt2.unwrap()));
} else {
warn!(
"{} isn't present in both sims, cancelling DiffWorldsState",
id
);
*self = DiffWorldsState::Inactive;
}
} else {
*self = DiffWorldsState::Inactive;
}
match self {
DiffWorldsState::Inactive => false,
_ => true,
}
}
pub fn draw(&self, g: &mut GfxCtx, _cs: &ColorScheme) {
if let DiffWorldsState::Active(_, ref line) = self {
// TODO move constants
g.draw_line([1.0, 1.0, 0.0, 1.0], LANE_THICKNESS, line);
}
}
}
impl Colorizer for DiffWorldsState {}

View File

@ -3,6 +3,7 @@ pub mod chokepoints;
pub mod classification; pub mod classification;
pub mod color_picker; pub mod color_picker;
pub mod debug_objects; pub mod debug_objects;
pub mod diff_worlds;
pub mod draw_neighborhoods; pub mod draw_neighborhoods;
pub mod floodfill; pub mod floodfill;
pub mod follow; pub mod follow;

View File

@ -16,6 +16,7 @@ use plugins::chokepoints::ChokepointsFinder;
use plugins::classification::OsmClassifier; use plugins::classification::OsmClassifier;
use plugins::color_picker::ColorPicker; use plugins::color_picker::ColorPicker;
use plugins::debug_objects::DebugObjectsState; use plugins::debug_objects::DebugObjectsState;
use plugins::diff_worlds::DiffWorldsState;
use plugins::draw_neighborhoods::DrawNeighborhoodState; use plugins::draw_neighborhoods::DrawNeighborhoodState;
use plugins::floodfill::Floodfiller; use plugins::floodfill::Floodfiller;
use plugins::follow::FollowState; use plugins::follow::FollowState;
@ -80,6 +81,7 @@ impl UIWrapper {
color_picker: ColorPicker::new(), color_picker: ColorPicker::new(),
ab_test_manager: ABTestManager::new(), ab_test_manager: ABTestManager::new(),
logs, logs,
diff_worlds: DiffWorldsState::new(),
active_plugin: None, active_plugin: None,
@ -252,6 +254,7 @@ impl UIWrapper {
Box::new(|ctx| { Box::new(|ctx| {
let (active, new_ui) = ctx.ui.ab_test_manager.event( let (active, new_ui) = ctx.ui.ab_test_manager.event(
ctx.input, ctx.input,
ctx.ui.primary.current_selection,
&ctx.ui.primary.map, &ctx.ui.primary.map,
&ctx.ui.kml, &ctx.ui.kml,
&ctx.ui.primary.current_flags, &ctx.ui.primary.current_flags,
@ -263,6 +266,11 @@ impl UIWrapper {
active active
}), }),
Box::new(|ctx| ctx.ui.logs.event(ctx.input)), Box::new(|ctx| ctx.ui.logs.event(ctx.input)),
Box::new(|ctx| {
ctx.ui
.diff_worlds
.event(ctx.input, &ctx.ui.primary, &ctx.ui.secondary)
}),
], ],
} }
} }
@ -361,6 +369,7 @@ struct UI {
color_picker: ColorPicker, color_picker: ColorPicker,
ab_test_manager: ABTestManager, ab_test_manager: ABTestManager,
logs: DisplayLogs, logs: DisplayLogs,
diff_worlds: DiffWorldsState,
// An index into UIWrapper.plugins. // An index into UIWrapper.plugins.
active_plugin: Option<usize>, active_plugin: Option<usize>,
@ -550,6 +559,7 @@ impl UI {
self.warp.draw(g, &self.canvas); self.warp.draw(g, &self.canvas);
self.sim_ctrl.draw(g, &self.canvas); self.sim_ctrl.draw(g, &self.canvas);
self.primary.show_route.draw(g, &self.cs); self.primary.show_route.draw(g, &self.cs);
self.diff_worlds.draw(g, &self.cs);
self.canvas.draw_text(g, osd, BOTTOM_LEFT); self.canvas.draw_text(g, osd, BOTTOM_LEFT);
} }
@ -604,6 +614,7 @@ impl UI {
19 => Some(Box::new(&self.primary.chokepoints)), 19 => Some(Box::new(&self.primary.chokepoints)),
20 => Some(Box::new(&self.ab_test_manager)), 20 => Some(Box::new(&self.ab_test_manager)),
21 => Some(Box::new(&self.logs)), 21 => Some(Box::new(&self.logs)),
22 => Some(Box::new(&self.diff_worlds)),
_ => panic!("Active plugin {} is too high", idx), _ => panic!("Active plugin {} is too high", idx),
} }
} }

View File

@ -378,6 +378,10 @@ impl Sim {
} }
} }
pub fn agent_to_trip(&self, id: AgentID) -> TripID {
self.trips_state.agent_to_trip(id)
}
pub fn get_canonical_point_for_trip(&self, id: TripID, map: &Map) -> Option<Pt2D> { pub fn get_canonical_point_for_trip(&self, id: TripID, map: &Map) -> Option<Pt2D> {
// Don't unwrap(); the trip might be registered before the agent has started. // Don't unwrap(); the trip might be registered before the agent has started.
match self.trips_state.current_mode(id) { match self.trips_state.current_mode(id) {

View File

@ -235,6 +235,10 @@ impl TripManager {
TripLeg::RideBus(_, _) => Some(AgentID::Pedestrian(trip.ped)), TripLeg::RideBus(_, _) => Some(AgentID::Pedestrian(trip.ped)),
} }
} }
pub fn agent_to_trip(&self, id: AgentID) -> TripID {
self.active_trip_mode[&id]
}
} }
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]