show accepted agents when hovering over an intersection

This commit is contained in:
Dustin Carlino 2018-12-14 11:16:46 -08:00
parent 2a8842aa00
commit 28d025103c
6 changed files with 138 additions and 98 deletions

View File

@ -33,7 +33,6 @@ pub fn default_colors() -> HashMap<String, Color> {
);
m.insert("car turn arrow".to_string(), Color::CYAN);
m.insert("car window".to_string(), Color::BLACK);
m.insert("car/building owner".to_string(), Color::PURPLE);
m.insert("chokepoint".to_string(), Color::RED);
m.insert("crosswalk".to_string(), Color::WHITE);
m.insert("crosswalk turn".to_string(), Color::WHITE);
@ -99,6 +98,10 @@ pub fn default_colors() -> HashMap<String, Color> {
m.insert("sidewalk corner".to_string(), Color::grey(0.7));
m.insert("sidewalk lines".to_string(), Color::grey(0.7));
m.insert("signal editor panel".to_string(), Color::BLACK.alpha(0.95));
m.insert(
"something associated with something else".to_string(),
Color::PURPLE,
);
m.insert("stop line for lane".to_string(), Color::RED);
m.insert("stop sign background".to_string(), Color::RED);
m.insert("stop sign priority turns".to_string(), Color::GREEN);

View File

@ -3,7 +3,7 @@ mod follow;
mod neighborhood_summary;
mod search;
mod show_activity;
mod show_owner;
mod show_associated;
mod show_route;
mod turn_cycler;
mod warp;
@ -37,7 +37,7 @@ impl ViewMode {
timer,
)),
Box::new(show_activity::ShowActivityState::new(Key::A)),
Box::new(show_owner::ShowOwnerState::new()),
Box::new(show_associated::ShowAssociatedState::new()),
Box::new(show_route::ShowRouteState::new(Key::R, Key::L)),
Box::new(turn_cycler::TurnCyclerState::new(Key::Tab)),
],

View File

@ -0,0 +1,113 @@
use crate::objects::{Ctx, ID};
use crate::plugins::{Plugin, PluginCtx};
use crate::render::ExtraShapeID;
use ezgui::Color;
use map_model::{BuildingID, IntersectionID, RoadID};
use sim::{AgentID, CarID};
use std::collections::HashSet;
pub enum ShowAssociatedState {
Inactive,
BuildingSelected(BuildingID, HashSet<CarID>),
CarSelected(CarID, Option<BuildingID>),
ShapeSelected(ExtraShapeID, Option<(RoadID, bool)>),
IntersectionSelected(IntersectionID, HashSet<AgentID>),
}
impl ShowAssociatedState {
pub fn new() -> ShowAssociatedState {
ShowAssociatedState::Inactive
}
}
impl Plugin for ShowAssociatedState {
fn ambient_event(&mut self, ctx: &mut PluginCtx) {
let (selected, sim) = (ctx.primary.current_selection, &ctx.primary.sim);
// Reset to Inactive when appropriate
let mut reset = false;
match self {
ShowAssociatedState::Inactive => {}
ShowAssociatedState::BuildingSelected(b, _) => {
reset = selected != Some(ID::Building(*b));
}
ShowAssociatedState::CarSelected(c, _) => {
reset = selected != Some(ID::Car(*c));
}
ShowAssociatedState::ShapeSelected(es, _) => {
reset = selected != Some(ID::ExtraShape(*es));
}
ShowAssociatedState::IntersectionSelected(_, _) => {
// Always recalculate.
// TODO Only if the tick has changed, actually.
reset = true;
}
}
if reset {
*self = ShowAssociatedState::Inactive;
}
if let ShowAssociatedState::Inactive = self {
match selected {
Some(ID::Building(id)) => {
*self = ShowAssociatedState::BuildingSelected(
id,
sim.get_parked_cars_by_owner(id)
.iter()
.map(|p| p.car)
.collect(),
);
}
Some(ID::Car(id)) => {
*self = ShowAssociatedState::CarSelected(id, sim.get_owner_of_car(id));
}
Some(ID::ExtraShape(id)) => {
*self = ShowAssociatedState::ShapeSelected(
id,
ctx.primary.draw_map.get_es(id).road,
);
}
Some(ID::Intersection(id)) => {
*self =
ShowAssociatedState::IntersectionSelected(id, sim.get_accepted_agents(id));
}
_ => {}
};
}
}
fn color_for(&self, obj: ID, ctx: &Ctx) -> Option<Color> {
let color = ctx
.cs
.get_def("something associated with something else", Color::PURPLE);
match (self, obj) {
(ShowAssociatedState::BuildingSelected(_, cars), ID::Car(id)) => {
if cars.contains(&id) {
return Some(color);
}
}
(ShowAssociatedState::CarSelected(_, Some(id1)), ID::Building(id2)) => {
if *id1 == id2 {
return Some(color);
}
}
(ShowAssociatedState::ShapeSelected(_, Some((r, fwds))), ID::Lane(l)) => {
let parent = ctx.map.get_parent(l);
if parent.id == *r
&& ((*fwds && parent.is_forwards(l)) || (!fwds && parent.is_backwards(l)))
{
return Some(color);
}
}
(ShowAssociatedState::IntersectionSelected(_, agents), _) => {
if let Some(agent) = obj.agent_id() {
if agents.contains(&agent) {
return Some(color);
}
}
}
_ => {}
}
None
}
}

View File

@ -1,92 +0,0 @@
use crate::objects::{Ctx, ID};
use crate::plugins::{Plugin, PluginCtx};
use crate::render::ExtraShapeID;
use ezgui::Color;
use map_model::{BuildingID, RoadID};
use sim::CarID;
use std::collections::HashSet;
// TODO rename ShowAssociated?
pub enum ShowOwnerState {
Inactive,
BuildingSelected(BuildingID, HashSet<CarID>),
CarSelected(CarID, Option<BuildingID>),
ShapeSelected(ExtraShapeID, Option<(RoadID, bool)>),
}
impl ShowOwnerState {
pub fn new() -> ShowOwnerState {
ShowOwnerState::Inactive
}
}
impl Plugin for ShowOwnerState {
fn ambient_event(&mut self, ctx: &mut PluginCtx) {
let (selected, sim) = (ctx.primary.current_selection, &ctx.primary.sim);
// Reset to Inactive when appropriate
let mut reset = false;
match self {
ShowOwnerState::Inactive => {}
ShowOwnerState::BuildingSelected(b, _) => {
reset = selected != Some(ID::Building(*b));
}
ShowOwnerState::CarSelected(c, _) => {
reset = selected != Some(ID::Car(*c));
}
ShowOwnerState::ShapeSelected(es, _) => {
reset = selected != Some(ID::ExtraShape(*es));
}
}
if reset {
*self = ShowOwnerState::Inactive;
}
if let ShowOwnerState::Inactive = self {
match selected {
Some(ID::Building(id)) => {
*self = ShowOwnerState::BuildingSelected(
id,
sim.get_parked_cars_by_owner(id)
.iter()
.map(|p| p.car)
.collect(),
);
}
Some(ID::Car(id)) => {
*self = ShowOwnerState::CarSelected(id, sim.get_owner_of_car(id));
}
Some(ID::ExtraShape(id)) => {
*self = ShowOwnerState::ShapeSelected(id, ctx.primary.draw_map.get_es(id).road);
}
_ => {}
};
}
}
fn color_for(&self, obj: ID, ctx: &Ctx) -> Option<Color> {
let color = ctx.cs.get_def("car/building owner", Color::PURPLE);
match (self, obj) {
(ShowOwnerState::BuildingSelected(_, cars), ID::Car(id)) => {
if cars.contains(&id) {
return Some(color);
}
}
(ShowOwnerState::CarSelected(_, Some(id1)), ID::Building(id2)) => {
if *id1 == id2 {
return Some(color);
}
}
(ShowOwnerState::ShapeSelected(_, Some((r, fwds))), ID::Lane(l)) => {
let parent = ctx.map.get_parent(l);
if parent.id == *r
&& ((*fwds && parent.is_forwards(l)) || (!fwds && parent.is_backwards(l)))
{
return Some(color);
}
}
_ => {}
}
None
}
}

View File

@ -9,7 +9,7 @@ use dimensioned::si;
use map_model::{ControlStopSign, IntersectionID, IntersectionType, Map, TurnID, TurnPriority};
use serde_derive::{Deserialize, Serialize};
use std;
use std::collections::{BTreeMap, BTreeSet};
use std::collections::{BTreeMap, BTreeSet, HashSet};
const WAIT_AT_STOP_SIGN: Time = si::Second {
value_unsafe: 1.5,
@ -155,6 +155,19 @@ impl IntersectionSimState {
IntersectionPolicy::Border => {}
};
}
pub fn get_accepted_agents(&self, id: IntersectionID) -> HashSet<AgentID> {
match self.intersections[id.0] {
IntersectionPolicy::StopSign(ref p) => {
p.accepted.iter().map(|req| req.agent).collect()
}
IntersectionPolicy::TrafficSignal(ref p) => {
p.accepted.iter().map(|req| req.agent).collect()
}
// Technically anybody on incoming lanes
IntersectionPolicy::Border => HashSet::new(),
}
}
}
// Use an enum instead of traits so that serialization works. I couldn't figure out erased_serde.

View File

@ -1,5 +1,3 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use crate::driving::DrivingSimState;
use crate::instrument::capture_backtrace;
use crate::intersections::IntersectionSimState;
@ -20,6 +18,7 @@ use map_model::{BuildingID, IntersectionID, LaneID, LaneType, Map, Path, Trace,
use rand::{FromEntropy, SeedableRng, XorShiftRng};
use serde_derive::{Deserialize, Serialize};
use std;
use std::collections::HashSet;
#[derive(Serialize, Deserialize, Derivative)]
#[derivative(PartialEq)]
@ -412,6 +411,10 @@ impl Sim {
.or_else(|| self.parking_state.get_owner_of_car(id))
}
pub fn get_accepted_agents(&self, id: IntersectionID) -> HashSet<AgentID> {
self.intersection_state.get_accepted_agents(id)
}
pub fn get_stats(&self) -> &SimStats {
&self.stats
}