mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-22 22:01:41 +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 search;
|
||||||
pub mod show_activity;
|
pub mod show_activity;
|
||||||
pub mod show_associated;
|
pub mod show_associated;
|
||||||
pub mod show_route;
|
|
||||||
pub mod turn_cycler;
|
pub mod turn_cycler;
|
||||||
pub mod warp;
|
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;
|
mod spawner;
|
||||||
|
|
||||||
use crate::game::{GameState, Mode};
|
use crate::game::{GameState, Mode};
|
||||||
@ -13,6 +14,7 @@ const ADJUST_SPEED: f64 = 0.1;
|
|||||||
pub struct SandboxMode {
|
pub struct SandboxMode {
|
||||||
desired_speed: f64, // sim seconds per real second
|
desired_speed: f64, // sim seconds per real second
|
||||||
following: Option<TripID>,
|
following: Option<TripID>,
|
||||||
|
route_viewer: route_viewer::RouteViewer,
|
||||||
state: State,
|
state: State,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +34,7 @@ impl SandboxMode {
|
|||||||
desired_speed: 1.0,
|
desired_speed: 1.0,
|
||||||
state: State::Paused,
|
state: State::Paused,
|
||||||
following: None,
|
following: None,
|
||||||
|
route_viewer: route_viewer::RouteViewer::Inactive,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +68,15 @@ impl SandboxMode {
|
|||||||
if let Some(trip) = mode.following {
|
if let Some(trip) = mode.following {
|
||||||
txt.add_line(format!("Following {}", trip));
|
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
|
ctx.input
|
||||||
.set_mode_with_new_prompt("Sandbox Mode", txt, ctx.canvas);
|
.set_mode_with_new_prompt("Sandbox Mode", txt, ctx.canvas);
|
||||||
|
|
||||||
@ -109,6 +121,7 @@ impl SandboxMode {
|
|||||||
mode.following = None;
|
mode.following = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mode.route_viewer.event(ctx, &mut state.ui);
|
||||||
|
|
||||||
if ctx.input.modal_action("quit") {
|
if ctx.input.modal_action("quit") {
|
||||||
// TODO This shouldn't be necessary when we plumb state around instead of
|
// TODO This shouldn't be necessary when we plumb state around instead of
|
||||||
@ -252,7 +265,10 @@ impl SandboxMode {
|
|||||||
State::Spawning(ref spawner) => {
|
State::Spawning(ref spawner) => {
|
||||||
spawner.draw(g, &state.ui);
|
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!(),
|
_ => 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.
|
// inactive state.
|
||||||
Box::new(view::show_activity::ShowActivityState::new()),
|
Box::new(view::show_activity::ShowActivityState::new()),
|
||||||
Box::new(view::show_associated::ShowAssociatedState::new()),
|
Box::new(view::show_associated::ShowAssociatedState::new()),
|
||||||
Box::new(view::show_route::ShowRouteState::new()),
|
|
||||||
Box::new(view::turn_cycler::TurnCyclerState::new()),
|
Box::new(view::turn_cycler::TurnCyclerState::new()),
|
||||||
],
|
],
|
||||||
time_travel: plugins::sim::time_travel::TimeTravel::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("A/B All Trips Explorer", vec![(Key::Enter, "quit")]),
|
||||||
ModalMenu::new("Search", vec![(Key::Enter, "quit")]),
|
ModalMenu::new("Search", vec![(Key::Enter, "quit")]),
|
||||||
ModalMenu::new("Neighborhood Summaries", 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("Active Traffic Visualizer", vec![(Key::A, "quit")]),
|
||||||
ModalMenu::new("Object Hider", vec![(Key::K, "unhide everything")]),
|
ModalMenu::new("Object Hider", vec![(Key::K, "unhide everything")]),
|
||||||
// TODO F1?
|
// TODO F1?
|
||||||
@ -195,10 +191,13 @@ impl GUI for UI {
|
|||||||
(Key::U, "load next sim state"),
|
(Key::U, "load next sim state"),
|
||||||
(Key::Space, "run/pause sim"),
|
(Key::Space, "run/pause sim"),
|
||||||
(Key::M, "run one step of sim"),
|
(Key::M, "run one step of sim"),
|
||||||
(Key::R, "reset sim"),
|
(Key::X, "reset sim"),
|
||||||
(Key::S, "seed the sim with agents"),
|
(Key::S, "seed the sim with agents"),
|
||||||
// TODO Strange to always have this. Really it's a case of stacked modal?
|
// TODO Strange to always have this. Really it's a case of stacked modal?
|
||||||
(Key::F, "stop following agent"),
|
(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")]),
|
ModalMenu::new("Agent Spawner", vec![(Key::Escape, "quit")]),
|
||||||
|
Loading…
Reference in New Issue
Block a user