mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-22 13:51:33 +03:00
moving route viewer to sandbox
This commit is contained in:
parent
79b87d6040
commit
e763171bc9
@ -3,6 +3,5 @@ pub mod neighborhood_summary;
|
||||
pub mod search;
|
||||
pub mod show_activity;
|
||||
pub mod show_associated;
|
||||
pub mod show_route;
|
||||
pub mod turn_cycler;
|
||||
pub mod warp;
|
||||
|
@ -1,155 +0,0 @@
|
||||
use crate::objects::{DrawCtx, ID};
|
||||
use crate::plugins::{AmbientPlugin, PluginCtx};
|
||||
use ezgui::{Color, GfxCtx, Key};
|
||||
use geom::{Duration, PolyLine};
|
||||
use map_model::LANE_THICKNESS;
|
||||
use sim::{AgentID, TripID};
|
||||
|
||||
pub enum ShowRouteState {
|
||||
Inactive,
|
||||
Hovering(Duration, AgentID, PolyLine),
|
||||
Active(Duration, TripID, Option<PolyLine>),
|
||||
DebugAllRoutes(Duration, Vec<PolyLine>),
|
||||
}
|
||||
|
||||
impl ShowRouteState {
|
||||
pub fn new() -> ShowRouteState {
|
||||
ShowRouteState::Inactive
|
||||
}
|
||||
}
|
||||
|
||||
impl AmbientPlugin for ShowRouteState {
|
||||
fn ambient_event(&mut self, ctx: &mut PluginCtx) {
|
||||
match self {
|
||||
ShowRouteState::Inactive => {
|
||||
if let Some(agent) = ctx.primary.current_selection.and_then(|id| id.agent_id()) {
|
||||
if let Some(trace) = ctx.primary.sim.trace_route(agent, &ctx.primary.map, None)
|
||||
{
|
||||
*self = ShowRouteState::Hovering(ctx.primary.sim.time(), agent, trace);
|
||||
}
|
||||
};
|
||||
}
|
||||
ShowRouteState::Hovering(time, agent, _) => {
|
||||
// Argh, borrow checker.
|
||||
let agent = *agent;
|
||||
|
||||
if *time != ctx.primary.sim.time()
|
||||
|| ctx.primary.current_selection != Some(ID::from_agent(agent))
|
||||
{
|
||||
*self = ShowRouteState::Inactive;
|
||||
if let Some(new_agent) =
|
||||
ctx.primary.current_selection.and_then(|id| id.agent_id())
|
||||
{
|
||||
if let Some(trace) =
|
||||
ctx.primary
|
||||
.sim
|
||||
.trace_route(new_agent, &ctx.primary.map, None)
|
||||
{
|
||||
*self =
|
||||
ShowRouteState::Hovering(ctx.primary.sim.time(), new_agent, trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there's a current route, then there must be a trip.
|
||||
let trip = ctx.primary.sim.agent_to_trip(agent).unwrap();
|
||||
// TODO agent might be stale here! Really need a second match after this or
|
||||
// something. Expressing a state machine like this isn't really great.
|
||||
if ctx
|
||||
.input
|
||||
.contextual_action(Key::R, &format!("show {}'s route", agent))
|
||||
{
|
||||
*self = show_route(trip, ctx);
|
||||
}
|
||||
}
|
||||
ShowRouteState::Active(time, trip, _) => {
|
||||
ctx.input.set_mode_with_prompt(
|
||||
"Agent Route Debugger",
|
||||
format!("Agent Route Debugger for {}", trip),
|
||||
&ctx.canvas,
|
||||
);
|
||||
if ctx.input.modal_action("quit") {
|
||||
*self = ShowRouteState::Inactive;
|
||||
} else if ctx.input.modal_action("show route for all agents") {
|
||||
*self = debug_all_routes(ctx);
|
||||
} else if *time != ctx.primary.sim.time() {
|
||||
*self = show_route(*trip, ctx);
|
||||
}
|
||||
}
|
||||
ShowRouteState::DebugAllRoutes(time, _) => {
|
||||
ctx.input.set_mode_with_prompt(
|
||||
"Agent Route Debugger",
|
||||
"Agent Route Debugger for all routes".to_string(),
|
||||
&ctx.canvas,
|
||||
);
|
||||
if ctx.input.modal_action("quit") {
|
||||
*self = ShowRouteState::Inactive;
|
||||
} else if *time != ctx.primary.sim.time() {
|
||||
*self = debug_all_routes(ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, ctx: &DrawCtx) {
|
||||
match self {
|
||||
ShowRouteState::Hovering(_, _, ref trace) => {
|
||||
g.draw_polygon(
|
||||
ctx.cs.get("route").alpha(0.5),
|
||||
&trace.make_polygons(LANE_THICKNESS),
|
||||
);
|
||||
}
|
||||
ShowRouteState::Active(_, _, Some(ref trace)) => {
|
||||
g.draw_polygon(
|
||||
ctx.cs.get_def("route", Color::RED.alpha(0.8)),
|
||||
&trace.make_polygons(LANE_THICKNESS),
|
||||
);
|
||||
}
|
||||
ShowRouteState::DebugAllRoutes(_, ref traces) => {
|
||||
for t in traces {
|
||||
g.draw_polygon(ctx.cs.get("route"), &t.make_polygons(LANE_THICKNESS));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show_route(trip: TripID, ctx: &mut PluginCtx) -> ShowRouteState {
|
||||
let time = ctx.primary.sim.time();
|
||||
if let Some(agent) = ctx.primary.sim.trip_to_agent(trip) {
|
||||
// Trace along the entire route by passing in max distance
|
||||
if let Some(trace) = ctx.primary.sim.trace_route(agent, &ctx.primary.map, None) {
|
||||
ShowRouteState::Active(time, trip, Some(trace))
|
||||
} else {
|
||||
println!("{} has no trace right now", agent);
|
||||
ShowRouteState::Active(time, trip, None)
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"{} has no agent associated right now; is the trip done?",
|
||||
trip
|
||||
);
|
||||
ShowRouteState::Active(time, trip, None)
|
||||
}
|
||||
}
|
||||
|
||||
fn debug_all_routes(ctx: &mut PluginCtx) -> ShowRouteState {
|
||||
let mut traces: Vec<PolyLine> = Vec::new();
|
||||
let trips: Vec<TripID> = ctx
|
||||
.primary
|
||||
.sim
|
||||
.get_stats(&ctx.primary.map)
|
||||
.canonical_pt_per_trip
|
||||
.keys()
|
||||
.cloned()
|
||||
.collect();
|
||||
for trip in trips {
|
||||
if let Some(agent) = ctx.primary.sim.trip_to_agent(trip) {
|
||||
if let Some(trace) = ctx.primary.sim.trace_route(agent, &ctx.primary.map, None) {
|
||||
traces.push(trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
ShowRouteState::DebugAllRoutes(ctx.primary.sim.time(), traces)
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
mod route_viewer;
|
||||
mod spawner;
|
||||
|
||||
use crate::game::{GameState, Mode};
|
||||
@ -13,6 +14,7 @@ const ADJUST_SPEED: f64 = 0.1;
|
||||
pub struct SandboxMode {
|
||||
desired_speed: f64, // sim seconds per real second
|
||||
following: Option<TripID>,
|
||||
route_viewer: route_viewer::RouteViewer,
|
||||
state: State,
|
||||
}
|
||||
|
||||
@ -32,6 +34,7 @@ impl SandboxMode {
|
||||
desired_speed: 1.0,
|
||||
state: State::Paused,
|
||||
following: None,
|
||||
route_viewer: route_viewer::RouteViewer::Inactive,
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,6 +68,15 @@ impl SandboxMode {
|
||||
if let Some(trip) = mode.following {
|
||||
txt.add_line(format!("Following {}", trip));
|
||||
}
|
||||
match mode.route_viewer {
|
||||
route_viewer::RouteViewer::Active(_, trip, _) => {
|
||||
txt.add_line(format!("Showing {}'s route", trip));
|
||||
}
|
||||
route_viewer::RouteViewer::DebugAllRoutes(_, _) => {
|
||||
txt.add_line("Showing all routes".to_string());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ctx.input
|
||||
.set_mode_with_new_prompt("Sandbox Mode", txt, ctx.canvas);
|
||||
|
||||
@ -109,6 +121,7 @@ impl SandboxMode {
|
||||
mode.following = None;
|
||||
}
|
||||
}
|
||||
mode.route_viewer.event(ctx, &mut state.ui);
|
||||
|
||||
if ctx.input.modal_action("quit") {
|
||||
// TODO This shouldn't be necessary when we plumb state around instead of
|
||||
@ -252,7 +265,10 @@ impl SandboxMode {
|
||||
State::Spawning(ref spawner) => {
|
||||
spawner.draw(g, &state.ui);
|
||||
}
|
||||
_ => state.ui.new_draw(g, None, HashMap::new()),
|
||||
_ => {
|
||||
state.ui.new_draw(g, None, HashMap::new());
|
||||
mode.route_viewer.draw(g, &state.ui);
|
||||
}
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
167
editor/src/sandbox/route_viewer.rs
Normal file
167
editor/src/sandbox/route_viewer.rs
Normal file
@ -0,0 +1,167 @@
|
||||
use crate::objects::ID;
|
||||
use crate::ui::UI;
|
||||
use ezgui::{Color, EventCtx, GfxCtx, Key};
|
||||
use geom::{Duration, PolyLine};
|
||||
use map_model::LANE_THICKNESS;
|
||||
use sim::{AgentID, TripID};
|
||||
|
||||
pub enum RouteViewer {
|
||||
Inactive,
|
||||
Hovering(Duration, AgentID, PolyLine),
|
||||
Active(Duration, TripID, Option<PolyLine>),
|
||||
DebugAllRoutes(Duration, Vec<PolyLine>),
|
||||
}
|
||||
|
||||
impl RouteViewer {
|
||||
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) {
|
||||
match self {
|
||||
RouteViewer::Inactive => {
|
||||
if let Some(agent) = ui
|
||||
.state
|
||||
.primary
|
||||
.current_selection
|
||||
.and_then(|id| id.agent_id())
|
||||
{
|
||||
if let Some(trace) =
|
||||
ui.state
|
||||
.primary
|
||||
.sim
|
||||
.trace_route(agent, &ui.state.primary.map, None)
|
||||
{
|
||||
*self = RouteViewer::Hovering(ui.state.primary.sim.time(), agent, trace);
|
||||
}
|
||||
} else if ctx.input.modal_action("show/hide route for all agents") {
|
||||
*self = debug_all_routes(ui);
|
||||
}
|
||||
}
|
||||
RouteViewer::Hovering(time, agent, _) => {
|
||||
// Argh, borrow checker.
|
||||
let agent = *agent;
|
||||
|
||||
if *time != ui.state.primary.sim.time()
|
||||
|| ui.state.primary.current_selection != Some(ID::from_agent(agent))
|
||||
{
|
||||
*self = RouteViewer::Inactive;
|
||||
if let Some(new_agent) = ui
|
||||
.state
|
||||
.primary
|
||||
.current_selection
|
||||
.and_then(|id| id.agent_id())
|
||||
{
|
||||
if let Some(trace) =
|
||||
ui.state
|
||||
.primary
|
||||
.sim
|
||||
.trace_route(new_agent, &ui.state.primary.map, None)
|
||||
{
|
||||
*self = RouteViewer::Hovering(
|
||||
ui.state.primary.sim.time(),
|
||||
new_agent,
|
||||
trace,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there's a current route, then there must be a trip.
|
||||
let trip = ui.state.primary.sim.agent_to_trip(agent).unwrap();
|
||||
// TODO agent might be stale here! Really need a second match after this or
|
||||
// something. Expressing a state machine like this isn't really great.
|
||||
if ctx
|
||||
.input
|
||||
.contextual_action(Key::R, &format!("show {}'s route", agent))
|
||||
{
|
||||
*self = show_route(trip, ui);
|
||||
}
|
||||
}
|
||||
RouteViewer::Active(time, trip, _) => {
|
||||
// TODO Using the modal menu from parent is weird...
|
||||
if ctx.input.modal_action("stop showing agent's route") {
|
||||
*self = RouteViewer::Inactive;
|
||||
} else if *time != ui.state.primary.sim.time() {
|
||||
*self = show_route(*trip, ui);
|
||||
}
|
||||
}
|
||||
RouteViewer::DebugAllRoutes(time, _) => {
|
||||
if ctx.input.modal_action("show/hide route for all agents") {
|
||||
*self = RouteViewer::Inactive;
|
||||
} else if *time != ui.state.primary.sim.time() {
|
||||
*self = debug_all_routes(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||
match self {
|
||||
RouteViewer::Hovering(_, _, ref trace) => {
|
||||
g.draw_polygon(
|
||||
ui.state.cs.get("route").alpha(0.5),
|
||||
&trace.make_polygons(LANE_THICKNESS),
|
||||
);
|
||||
}
|
||||
RouteViewer::Active(_, _, Some(ref trace)) => {
|
||||
g.draw_polygon(
|
||||
ui.state.cs.get_def("route", Color::RED.alpha(0.8)),
|
||||
&trace.make_polygons(LANE_THICKNESS),
|
||||
);
|
||||
}
|
||||
RouteViewer::DebugAllRoutes(_, ref traces) => {
|
||||
for t in traces {
|
||||
g.draw_polygon(ui.state.cs.get("route"), &t.make_polygons(LANE_THICKNESS));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show_route(trip: TripID, ui: &UI) -> RouteViewer {
|
||||
let time = ui.state.primary.sim.time();
|
||||
if let Some(agent) = ui.state.primary.sim.trip_to_agent(trip) {
|
||||
// Trace along the entire route by passing in max distance
|
||||
if let Some(trace) = ui
|
||||
.state
|
||||
.primary
|
||||
.sim
|
||||
.trace_route(agent, &ui.state.primary.map, None)
|
||||
{
|
||||
RouteViewer::Active(time, trip, Some(trace))
|
||||
} else {
|
||||
println!("{} has no trace right now", agent);
|
||||
RouteViewer::Active(time, trip, None)
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"{} has no agent associated right now; is the trip done?",
|
||||
trip
|
||||
);
|
||||
RouteViewer::Active(time, trip, None)
|
||||
}
|
||||
}
|
||||
|
||||
fn debug_all_routes(ui: &mut UI) -> RouteViewer {
|
||||
let mut traces: Vec<PolyLine> = Vec::new();
|
||||
let trips: Vec<TripID> = ui
|
||||
.state
|
||||
.primary
|
||||
.sim
|
||||
.get_stats(&ui.state.primary.map)
|
||||
.canonical_pt_per_trip
|
||||
.keys()
|
||||
.cloned()
|
||||
.collect();
|
||||
for trip in trips {
|
||||
if let Some(agent) = ui.state.primary.sim.trip_to_agent(trip) {
|
||||
if let Some(trace) =
|
||||
ui.state
|
||||
.primary
|
||||
.sim
|
||||
.trace_route(agent, &ui.state.primary.map, None)
|
||||
{
|
||||
traces.push(trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
RouteViewer::DebugAllRoutes(ui.state.primary.sim.time(), traces)
|
||||
}
|
@ -433,7 +433,6 @@ impl PluginsPerMap {
|
||||
// inactive state.
|
||||
Box::new(view::show_activity::ShowActivityState::new()),
|
||||
Box::new(view::show_associated::ShowAssociatedState::new()),
|
||||
Box::new(view::show_route::ShowRouteState::new()),
|
||||
Box::new(view::turn_cycler::TurnCyclerState::new()),
|
||||
],
|
||||
time_travel: plugins::sim::time_travel::TimeTravel::new(),
|
||||
|
@ -138,10 +138,6 @@ impl GUI for UI {
|
||||
ModalMenu::new("A/B All Trips Explorer", vec![(Key::Enter, "quit")]),
|
||||
ModalMenu::new("Search", vec![(Key::Enter, "quit")]),
|
||||
ModalMenu::new("Neighborhood Summaries", vec![(Key::Enter, "quit")]),
|
||||
ModalMenu::new(
|
||||
"Agent Route Debugger",
|
||||
vec![(Key::R, "quit"), (Key::L, "show route for all agents")],
|
||||
),
|
||||
ModalMenu::new("Active Traffic Visualizer", vec![(Key::A, "quit")]),
|
||||
ModalMenu::new("Object Hider", vec![(Key::K, "unhide everything")]),
|
||||
// TODO F1?
|
||||
@ -195,10 +191,13 @@ impl GUI for UI {
|
||||
(Key::U, "load next sim state"),
|
||||
(Key::Space, "run/pause sim"),
|
||||
(Key::M, "run one step of sim"),
|
||||
(Key::R, "reset sim"),
|
||||
(Key::X, "reset sim"),
|
||||
(Key::S, "seed the sim with agents"),
|
||||
// TODO Strange to always have this. Really it's a case of stacked modal?
|
||||
(Key::F, "stop following agent"),
|
||||
(Key::R, "stop showing agent's route"),
|
||||
// TODO This should probably be a debug thing instead
|
||||
(Key::L, "show/hide route for all agents"),
|
||||
],
|
||||
),
|
||||
ModalMenu::new("Agent Spawner", vec![(Key::Escape, "quit")]),
|
||||
|
Loading…
Reference in New Issue
Block a user