mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 07:52:05 +03:00
mvp of visualizing interactive sources/sinks
This commit is contained in:
parent
8fa813f5c2
commit
965037ce77
@ -139,9 +139,10 @@ fn info_for(id: ID, ui: &UI, ctx: &EventCtx) -> Text {
|
||||
txt.add(Line(format!("{} turning", accepted.len())));
|
||||
}
|
||||
|
||||
if let Some(lines) = sim.count_trips_involving_border(id) {
|
||||
let cnt = sim.count_trips_involving_border(id);
|
||||
if cnt.nonzero() {
|
||||
txt.add(Line(""));
|
||||
for line in lines {
|
||||
for line in cnt.describe() {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
}
|
||||
@ -170,9 +171,10 @@ fn info_for(id: ID, ui: &UI, ctx: &EventCtx) -> Text {
|
||||
txt.add(Line(""));
|
||||
}
|
||||
|
||||
if let Some(lines) = sim.count_trips_involving_bldg(id) {
|
||||
let cnt = sim.count_trips_involving_bldg(id);
|
||||
if cnt.nonzero() {
|
||||
txt.add(Line(""));
|
||||
for line in lines {
|
||||
for line in cnt.describe() {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,18 @@
|
||||
use crate::game::{msg, Transition, WizardState};
|
||||
use crate::sandbox::gameplay::{change_scenario, load_map, GameplayState};
|
||||
use crate::helpers::ID;
|
||||
use crate::sandbox::gameplay::{change_scenario, load_map, spawner, GameplayState};
|
||||
use crate::sandbox::overlays::Overlays;
|
||||
use crate::sandbox::spawner;
|
||||
use crate::ui::UI;
|
||||
use ezgui::{hotkey, lctrl, EventCtx, Key, ModalMenu};
|
||||
use ezgui::{hotkey, lctrl, Color, EventCtx, GfxCtx, Key, Line, ModalMenu, Text};
|
||||
use map_model::IntersectionID;
|
||||
use sim::Analytics;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
// TODO Maybe remember what things were spawned, offer to replay this later
|
||||
pub struct Freeform;
|
||||
pub struct Freeform {
|
||||
// TODO Clean these up later when done?
|
||||
pub spawn_pts: BTreeSet<IntersectionID>,
|
||||
}
|
||||
|
||||
impl Freeform {
|
||||
pub fn new(ctx: &EventCtx) -> (ModalMenu, Box<dyn GameplayState>) {
|
||||
@ -21,7 +26,9 @@ impl Freeform {
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
Box::new(Freeform),
|
||||
Box::new(Freeform {
|
||||
spawn_pts: BTreeSet::new(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -55,4 +62,22 @@ impl GameplayState for Freeform {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||
// TODO Overriding draw options would be ideal, but...
|
||||
for i in &self.spawn_pts {
|
||||
g.draw_polygon(Color::GREEN.alpha(0.8), &ui.primary.map.get_i(*i).polygon);
|
||||
}
|
||||
|
||||
if let Some(ID::Intersection(i)) = ui.primary.current_selection {
|
||||
if self.spawn_pts.contains(&i) {
|
||||
let cnt = ui.primary.sim.count_trips_involving_border(i);
|
||||
let mut txt = Text::new();
|
||||
for line in cnt.describe() {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
g.draw_mouse_tooltip(&txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ mod faster_trips;
|
||||
mod freeform;
|
||||
mod optimize_bus;
|
||||
mod play_scenario;
|
||||
mod spawner;
|
||||
|
||||
use crate::game::Transition;
|
||||
use crate::render::AgentColorScheme;
|
||||
@ -42,6 +43,7 @@ pub trait GameplayState: downcast_rs::Downcast {
|
||||
menu: &mut ModalMenu,
|
||||
analytics: &Analytics,
|
||||
) -> Option<Transition>;
|
||||
fn draw(&self, _: &mut GfxCtx, _: &UI) {}
|
||||
}
|
||||
downcast_rs::impl_downcast!(GameplayState);
|
||||
|
||||
@ -133,8 +135,9 @@ impl GameplayRunner {
|
||||
.event(ctx, ui, overlays, &mut self.menu, &self.prebaked)
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||
self.menu.draw(g);
|
||||
self.state.draw(g, ui);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@ use crate::common::CommonState;
|
||||
use crate::game::{msg, State, Transition, WizardState};
|
||||
use crate::helpers::ID;
|
||||
use crate::render::DrawOptions;
|
||||
use crate::sandbox::gameplay::freeform::Freeform;
|
||||
use crate::sandbox::SandboxMode;
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use abstutil::Timer;
|
||||
use ezgui::{hotkey, EventCtx, GfxCtx, Key, ModalMenu};
|
||||
@ -463,14 +465,16 @@ impl State for SpawnManyAgents {
|
||||
// PopWithData is a weird pattern; we should have a resume() handler that handles the
|
||||
// context
|
||||
if let Some((count, duration)) = self.schedule {
|
||||
create_swarm(
|
||||
ui,
|
||||
self.from,
|
||||
self.maybe_goal.take().unwrap().0,
|
||||
count,
|
||||
duration,
|
||||
);
|
||||
return Transition::Pop;
|
||||
let dst_l = self.maybe_goal.take().unwrap().0;
|
||||
create_swarm(ui, self.from, dst_l, count, duration);
|
||||
let src = ui.primary.map.get_l(self.from).src_i;
|
||||
let dst = ui.primary.map.get_l(dst_l).dst_i;
|
||||
return Transition::PopWithData(Box::new(move |state, _, _| {
|
||||
let sandbox = state.downcast_mut::<SandboxMode>().unwrap();
|
||||
let freeform = sandbox.gameplay.state.downcast_mut::<Freeform>().unwrap();
|
||||
freeform.spawn_pts.insert(src);
|
||||
freeform.spawn_pts.insert(dst);
|
||||
}));
|
||||
}
|
||||
|
||||
self.menu.event(ctx);
|
@ -2,7 +2,6 @@ mod bus_explorer;
|
||||
mod gameplay;
|
||||
mod overlays;
|
||||
mod score;
|
||||
mod spawner;
|
||||
|
||||
use crate::common::{time_controls, AgentTools, CommonState, SpeedControls};
|
||||
use crate::debug::DebugMode;
|
||||
@ -322,7 +321,7 @@ impl State for SandboxMode {
|
||||
self.info_tools.draw(g);
|
||||
self.general_tools.draw(g);
|
||||
self.save_tools.draw(g);
|
||||
self.gameplay.draw(g);
|
||||
self.gameplay.draw(g, ui);
|
||||
}
|
||||
|
||||
fn on_suspend(&mut self, _: &mut EventCtx, _: &mut UI) {
|
||||
|
@ -22,8 +22,8 @@ pub(crate) use self::router::{ActionAtEnd, Router};
|
||||
pub(crate) use self::scheduler::{Command, Scheduler};
|
||||
pub use self::sim::{Sim, SimOptions};
|
||||
pub(crate) use self::transit::TransitSimState;
|
||||
pub use self::trips::TripResult;
|
||||
pub use self::trips::{FinishedTrips, TripEnd, TripMode, TripStart, TripStatus};
|
||||
pub use self::trips::{TripCount, TripResult};
|
||||
pub(crate) use self::trips::{TripLeg, TripManager};
|
||||
pub use crate::render::{
|
||||
AgentMetadata, CarStatus, DontDrawAgents, DrawCarInput, DrawPedCrowdInput, DrawPedestrianInput,
|
||||
|
@ -2,9 +2,9 @@ use crate::{
|
||||
AgentID, AgentMetadata, Analytics, CarID, Command, CreateCar, DrawCarInput, DrawPedCrowdInput,
|
||||
DrawPedestrianInput, DrivingGoal, DrivingSimState, Event, FinishedTrips, GetDrawAgents,
|
||||
IntersectionSimState, ParkedCar, ParkingSimState, ParkingSpot, PedestrianID, Router, Scheduler,
|
||||
SidewalkPOI, SidewalkSpot, TransitSimState, TripID, TripLeg, TripManager, TripPositions,
|
||||
TripResult, TripSpawner, TripSpec, TripStart, TripStatus, UnzoomedAgent, VehicleSpec,
|
||||
VehicleType, WalkingSimState, BUS_LENGTH,
|
||||
SidewalkPOI, SidewalkSpot, TransitSimState, TripCount, TripID, TripLeg, TripManager,
|
||||
TripPositions, TripResult, TripSpawner, TripSpec, TripStart, TripStatus, UnzoomedAgent,
|
||||
VehicleSpec, VehicleType, WalkingSimState, BUS_LENGTH,
|
||||
};
|
||||
use abstutil::{elapsed_seconds, Timer};
|
||||
use derivative::Derivative;
|
||||
@ -759,10 +759,10 @@ impl Sim {
|
||||
self.trips.get_finished_trips()
|
||||
}
|
||||
|
||||
pub fn count_trips_involving_bldg(&self, b: BuildingID) -> Option<Vec<String>> {
|
||||
pub fn count_trips_involving_bldg(&self, b: BuildingID) -> TripCount {
|
||||
self.trips.count_trips_involving_bldg(b, self.time)
|
||||
}
|
||||
pub fn count_trips_involving_border(&self, i: IntersectionID) -> Option<Vec<String>> {
|
||||
pub fn count_trips_involving_border(&self, i: IntersectionID) -> TripCount {
|
||||
self.trips.count_trips_involving_border(i, self.time)
|
||||
}
|
||||
|
||||
|
121
sim/src/trips.rs
121
sim/src/trips.rs
@ -530,74 +530,49 @@ impl TripManager {
|
||||
}
|
||||
|
||||
// TODO Refactor after wrangling the TripStart/TripEnd mess
|
||||
pub fn count_trips_involving_bldg(&self, b: BuildingID, now: Duration) -> Option<Vec<String>> {
|
||||
pub fn count_trips_involving_bldg(&self, b: BuildingID, now: Duration) -> TripCount {
|
||||
self.count_trips(TripStart::Bldg(b), TripEnd::Bldg(b), now)
|
||||
}
|
||||
pub fn count_trips_involving_border(
|
||||
&self,
|
||||
i: IntersectionID,
|
||||
now: Duration,
|
||||
) -> Option<Vec<String>> {
|
||||
pub fn count_trips_involving_border(&self, i: IntersectionID, now: Duration) -> TripCount {
|
||||
self.count_trips(TripStart::Border(i), TripEnd::Border(i), now)
|
||||
}
|
||||
fn count_trips(&self, start: TripStart, end: TripEnd, now: Duration) -> Option<Vec<String>> {
|
||||
let mut from_aborted = 0;
|
||||
let mut from_in_progress = 0;
|
||||
let mut from_completed = 0;
|
||||
let mut from_unstarted = 0;
|
||||
let mut to_aborted = 0;
|
||||
let mut to_in_progress = 0;
|
||||
let mut to_completed = 0;
|
||||
let mut to_unstarted = 0;
|
||||
|
||||
let mut any = false;
|
||||
fn count_trips(&self, start: TripStart, end: TripEnd, now: Duration) -> TripCount {
|
||||
let mut cnt = TripCount {
|
||||
from_aborted: 0,
|
||||
from_in_progress: 0,
|
||||
from_completed: 0,
|
||||
from_unstarted: 0,
|
||||
to_aborted: 0,
|
||||
to_in_progress: 0,
|
||||
to_completed: 0,
|
||||
to_unstarted: 0,
|
||||
};
|
||||
for trip in &self.trips {
|
||||
if trip.start == start {
|
||||
any = true;
|
||||
if trip.aborted {
|
||||
from_aborted += 1;
|
||||
cnt.from_aborted += 1;
|
||||
} else if trip.finished_at.is_some() {
|
||||
from_completed += 1;
|
||||
cnt.from_completed += 1;
|
||||
} else if now >= trip.spawned_at {
|
||||
from_in_progress += 1;
|
||||
cnt.from_in_progress += 1;
|
||||
} else {
|
||||
from_unstarted += 1;
|
||||
cnt.from_unstarted += 1;
|
||||
}
|
||||
} else if trip.end == end {
|
||||
any = true;
|
||||
}
|
||||
// One trip might could towards both!
|
||||
if trip.end == end {
|
||||
if trip.aborted {
|
||||
to_aborted += 1;
|
||||
cnt.to_aborted += 1;
|
||||
} else if trip.finished_at.is_some() {
|
||||
to_completed += 1;
|
||||
cnt.to_completed += 1;
|
||||
} else if now >= trip.spawned_at {
|
||||
to_in_progress += 1;
|
||||
cnt.to_in_progress += 1;
|
||||
} else {
|
||||
to_unstarted += 1;
|
||||
cnt.to_unstarted += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !any {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(vec![
|
||||
format!(
|
||||
"Aborted trips: {} from here, {} to here",
|
||||
from_aborted, to_aborted
|
||||
),
|
||||
format!(
|
||||
"Finished trips: {} from here, {} to here",
|
||||
from_completed, to_completed
|
||||
),
|
||||
format!(
|
||||
"In-progress trips: {} from here, {} to here",
|
||||
from_in_progress, to_in_progress
|
||||
),
|
||||
format!(
|
||||
"Future trips: {} from here, {} to here",
|
||||
from_unstarted, to_unstarted
|
||||
),
|
||||
])
|
||||
cnt
|
||||
}
|
||||
}
|
||||
|
||||
@ -781,3 +756,49 @@ impl<T> TripResult<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TripCount {
|
||||
pub from_aborted: usize,
|
||||
pub from_in_progress: usize,
|
||||
pub from_completed: usize,
|
||||
pub from_unstarted: usize,
|
||||
pub to_aborted: usize,
|
||||
pub to_in_progress: usize,
|
||||
pub to_completed: usize,
|
||||
pub to_unstarted: usize,
|
||||
}
|
||||
|
||||
impl TripCount {
|
||||
pub fn nonzero(&self) -> bool {
|
||||
self.from_aborted
|
||||
+ self.from_in_progress
|
||||
+ self.from_completed
|
||||
+ self.from_unstarted
|
||||
+ self.to_aborted
|
||||
+ self.to_in_progress
|
||||
+ self.to_completed
|
||||
+ self.to_unstarted
|
||||
> 0
|
||||
}
|
||||
|
||||
pub fn describe(&self) -> Vec<String> {
|
||||
vec![
|
||||
format!(
|
||||
"Aborted trips: {} from here, {} to here",
|
||||
self.from_aborted, self.to_aborted
|
||||
),
|
||||
format!(
|
||||
"Finished trips: {} from here, {} to here",
|
||||
self.from_completed, self.to_completed
|
||||
),
|
||||
format!(
|
||||
"In-progress trips: {} from here, {} to here",
|
||||
self.from_in_progress, self.to_in_progress
|
||||
),
|
||||
format!(
|
||||
"Future trips: {} from here, {} to here",
|
||||
self.from_unstarted, self.to_unstarted
|
||||
),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user