mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 09:24:26 +03:00
cutover sim time (via the API) to time
This commit is contained in:
parent
e109c6b5a4
commit
819e27aa5d
@ -4,7 +4,7 @@ use crate::{
|
||||
hotkey, Canvas, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, InputResult, Key, Line,
|
||||
ModalMenu, MultiKey, ScreenDims, ScreenPt, ScreenRectangle, Text, Warper,
|
||||
};
|
||||
use geom::{Distance, Duration, Polygon, Pt2D};
|
||||
use geom::{Distance, Polygon, Pt2D, Time};
|
||||
|
||||
pub struct Slider {
|
||||
current_percent: f64,
|
||||
@ -409,16 +409,16 @@ impl<T: PartialEq> WarpingItemSlider<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Hardcoded to Durations right now...
|
||||
// TODO Hardcoded to Times right now...
|
||||
pub struct SliderWithTextBox {
|
||||
slider: Slider,
|
||||
tb: TextBox,
|
||||
low: Duration,
|
||||
high: Duration,
|
||||
low: Time,
|
||||
high: Time,
|
||||
}
|
||||
|
||||
impl SliderWithTextBox {
|
||||
pub fn new(prompt: &str, low: Duration, high: Duration, canvas: &Canvas) -> SliderWithTextBox {
|
||||
pub fn new(prompt: &str, low: Time, high: Time, canvas: &Canvas) -> SliderWithTextBox {
|
||||
SliderWithTextBox {
|
||||
slider: Slider::new(canvas.text_dims(&Text::from(Line(prompt))).width),
|
||||
tb: TextBox::new(prompt, None, canvas),
|
||||
@ -427,7 +427,7 @@ impl SliderWithTextBox {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event(&mut self, ctx: &mut EventCtx) -> InputResult<Duration> {
|
||||
pub fn event(&mut self, ctx: &mut EventCtx) -> InputResult<Time> {
|
||||
ctx.canvas.handle_event(ctx.input);
|
||||
stack_vertically(
|
||||
ContainerOrientation::Centered,
|
||||
@ -443,7 +443,7 @@ impl SliderWithTextBox {
|
||||
let line_before = self.tb.get_line().to_string();
|
||||
match self.tb.event(ctx.input) {
|
||||
InputResult::Done(line, _) => {
|
||||
if let Ok(t) = Duration::parse(&line) {
|
||||
if let Ok(t) = Time::parse(&line) {
|
||||
if t >= self.low && t <= self.high {
|
||||
return InputResult::Done(line, t);
|
||||
}
|
||||
@ -453,7 +453,7 @@ impl SliderWithTextBox {
|
||||
}
|
||||
InputResult::StillActive => {
|
||||
if line_before != self.tb.get_line() {
|
||||
if let Ok(t) = Duration::parse(self.tb.get_line()) {
|
||||
if let Ok(t) = Time::parse(self.tb.get_line()) {
|
||||
if t >= self.low && t <= self.high {
|
||||
self.slider
|
||||
.set_percent(ctx, (t - self.low) / (self.high - self.low));
|
||||
|
@ -3,7 +3,7 @@ use crate::widgets::text_box::TextBox;
|
||||
use crate::widgets::PopupMenu;
|
||||
use crate::{layout, EventCtx, GfxCtx, InputResult, Key, MultiKey, SliderWithTextBox, Text};
|
||||
use abstutil::Cloneable;
|
||||
use geom::Duration;
|
||||
use geom::Time;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
pub struct Wizard {
|
||||
@ -112,10 +112,10 @@ impl Wizard {
|
||||
fn input_time_slider(
|
||||
&mut self,
|
||||
query: &str,
|
||||
low: Duration,
|
||||
high: Duration,
|
||||
low: Time,
|
||||
high: Time,
|
||||
ctx: &mut EventCtx,
|
||||
) -> Option<Duration> {
|
||||
) -> Option<Time> {
|
||||
assert!(self.alive);
|
||||
|
||||
// Otherwise, we try to use one event for two inputs potentially
|
||||
@ -174,16 +174,11 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input_time_slider(
|
||||
&mut self,
|
||||
query: &str,
|
||||
low: Duration,
|
||||
high: Duration,
|
||||
) -> Option<Duration> {
|
||||
pub fn input_time_slider(&mut self, query: &str, low: Time, high: Time) -> Option<Time> {
|
||||
if !self.ready_results.is_empty() {
|
||||
let first = self.ready_results.pop_front().unwrap();
|
||||
// TODO Simplify?
|
||||
let item: &Duration = first.as_any().downcast_ref::<Duration>().unwrap();
|
||||
let item: &Time = first.as_any().downcast_ref::<Time>().unwrap();
|
||||
return Some(*item);
|
||||
}
|
||||
if let Some(obj) = self.wizard.input_time_slider(query, low, high, self.ctx) {
|
||||
|
@ -4,12 +4,12 @@ use crate::game::{msg, Transition, WizardState};
|
||||
use crate::render::{AgentColorScheme, MIN_ZOOM_FOR_DETAIL};
|
||||
use crate::ui::UI;
|
||||
use ezgui::{hotkey, Choice, EventCtx, GfxCtx, Key, MenuUnderButton, ModalMenu};
|
||||
use geom::{Duration, Pt2D};
|
||||
use geom::{Pt2D, Time};
|
||||
use sim::{TripID, TripResult};
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub struct AgentTools {
|
||||
following: Option<(TripID, Option<Pt2D>, Duration)>,
|
||||
following: Option<(TripID, Option<Pt2D>, Time)>,
|
||||
route_viewer: RouteViewer,
|
||||
// Weird to stash this here and lazily sync it, but...
|
||||
agent_cs_legend: RefCell<Option<(AgentColorScheme, ColorLegend)>>,
|
||||
|
@ -261,7 +261,7 @@ fn info_for(id: ID, ui: &UI, ctx: &EventCtx) -> Text {
|
||||
if let Some((t, car)) = arrivals.last() {
|
||||
txt.add(Line(format!(
|
||||
" Last bus arrived {} ago ({})",
|
||||
(sim.time().tmp_as_time() - *t).minimal_tostring(),
|
||||
(sim.time() - *t).minimal_tostring(),
|
||||
car
|
||||
)));
|
||||
} else {
|
||||
|
@ -2,14 +2,14 @@ use crate::helpers::ID;
|
||||
use crate::render::{dashed_lines, MIN_ZOOM_FOR_DETAIL};
|
||||
use crate::ui::UI;
|
||||
use ezgui::{hotkey, Color, Drawable, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu};
|
||||
use geom::{Distance, Duration};
|
||||
use geom::{Distance, Time};
|
||||
use sim::{AgentID, TripID, TripResult};
|
||||
|
||||
pub enum RouteViewer {
|
||||
Inactive,
|
||||
Hovering(Duration, AgentID, Drawable),
|
||||
Hovering(Time, AgentID, Drawable),
|
||||
// (zoomed, unzoomed)
|
||||
Active(Duration, TripID, Option<(Drawable, Drawable)>),
|
||||
Active(Time, TripID, Option<(Drawable, Drawable)>),
|
||||
}
|
||||
|
||||
impl RouteViewer {
|
||||
|
@ -4,7 +4,7 @@ use ezgui::{
|
||||
hotkey, Button, Color, Drawable, EventCtx, GeomBatch, GfxCtx, Key, Line, ScreenPt,
|
||||
ScreenRectangle, Slider, Text,
|
||||
};
|
||||
use geom::{Distance, Duration, Polygon, Pt2D};
|
||||
use geom::{Distance, Duration, Polygon, Pt2D, Time};
|
||||
use std::time::Instant;
|
||||
|
||||
const PANEL_RECT: ScreenRectangle = ScreenRectangle {
|
||||
@ -38,7 +38,7 @@ enum State {
|
||||
last_step: Instant,
|
||||
speed_description: String,
|
||||
last_measurement: Instant,
|
||||
last_measurement_sim: Duration,
|
||||
last_measurement_sim: Time,
|
||||
},
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ impl SpeedControls {
|
||||
}
|
||||
|
||||
// Returns the amount of simulation time to step, if running.
|
||||
pub fn event(&mut self, ctx: &mut EventCtx, current_sim_time: Duration) -> Option<Duration> {
|
||||
pub fn event(&mut self, ctx: &mut EventCtx, current_sim_time: Time) -> Option<Duration> {
|
||||
self.slow_down_btn.event(ctx);
|
||||
self.speed_up_btn.event(ctx);
|
||||
|
||||
|
@ -2,7 +2,7 @@ use crate::common::SpeedControls;
|
||||
use crate::game::{Transition, WizardState};
|
||||
use crate::ui::UI;
|
||||
use ezgui::{EventCtx, Wizard};
|
||||
use geom::Duration;
|
||||
use geom::{Duration, Time};
|
||||
|
||||
pub fn time_controls(
|
||||
ctx: &mut EventCtx,
|
||||
@ -49,7 +49,7 @@ fn jump_to_time(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<Tra
|
||||
let t = wiz.wrap(ctx).input_time_slider(
|
||||
"Jump to what time?",
|
||||
ui.primary.sim.time(),
|
||||
Duration::END_OF_DAY,
|
||||
Time::END_OF_DAY,
|
||||
)?;
|
||||
let dt = t - ui.primary.sim.time();
|
||||
ctx.loading_screen(&format!("step forwards {}", dt), |_, mut timer| {
|
||||
|
@ -2,7 +2,7 @@ use crate::helpers::rotating_color;
|
||||
use crate::render::DrawMap;
|
||||
use crate::ui::UI;
|
||||
use ezgui::{Color, Drawable, EventCtx, GfxCtx, Line, ModalMenu, Prerender, Text};
|
||||
use geom::{Duration, Polygon, Pt2D};
|
||||
use geom::{Polygon, Pt2D, Time};
|
||||
use map_model::{LaneID, Map, Neighborhood};
|
||||
use std::collections::HashSet;
|
||||
|
||||
@ -10,7 +10,7 @@ pub struct NeighborhoodSummary {
|
||||
regions: Vec<Region>,
|
||||
draw_all_regions: Drawable,
|
||||
pub active: bool,
|
||||
last_summary: Option<Duration>,
|
||||
last_summary: Option<Time>,
|
||||
}
|
||||
|
||||
impl NeighborhoodSummary {
|
||||
|
@ -1,12 +1,12 @@
|
||||
use crate::ui::UI;
|
||||
use ezgui::{EventCtx, GfxCtx, ModalMenu};
|
||||
use geom::{Duration, PolyLine};
|
||||
use geom::{PolyLine, Time};
|
||||
use map_model::LANE_THICKNESS;
|
||||
use sim::TripID;
|
||||
|
||||
pub enum AllRoutesViewer {
|
||||
Inactive,
|
||||
Active(Duration, Vec<PolyLine>),
|
||||
Active(Time, Vec<PolyLine>),
|
||||
}
|
||||
|
||||
impl AllRoutesViewer {
|
||||
|
@ -466,7 +466,7 @@ impl State for PreviewTrafficSignal {
|
||||
ctx,
|
||||
Text::from(Line(format!(
|
||||
"Time: {}",
|
||||
ui.primary.sim.time().minimal_tostring()
|
||||
ui.primary.sim.time().tmp_to_duration().minimal_tostring()
|
||||
))),
|
||||
);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use abstutil::prettyprint_usize;
|
||||
use ezgui::{
|
||||
hotkey, layout, EventCtx, EventLoopMode, GeomBatch, GfxCtx, Key, Line, ModalMenu, Slider, Text,
|
||||
};
|
||||
use geom::{Circle, Distance, Duration, PolyLine};
|
||||
use geom::{Circle, Distance, Duration, PolyLine, Time};
|
||||
use map_model::LANE_THICKNESS;
|
||||
use popdat::psrc::Mode;
|
||||
use popdat::{clip_trips, Trip};
|
||||
@ -88,8 +88,8 @@ impl TripsVisualizer {
|
||||
}
|
||||
}
|
||||
|
||||
fn current_time(&self) -> Duration {
|
||||
self.time_slider.get_percent() * Duration::END_OF_DAY
|
||||
fn current_time(&self) -> Time {
|
||||
Time::END_OF_DAY.percent_of(self.time_slider.get_percent())
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,23 +123,24 @@ impl State for TripsVisualizer {
|
||||
|
||||
if self.menu.action("quit") {
|
||||
return Transition::Pop;
|
||||
} else if time != Duration::END_OF_DAY && self.menu.action("forwards 10 seconds") {
|
||||
} else if time != Time::END_OF_DAY && self.menu.action("forwards 10 seconds") {
|
||||
self.time_slider
|
||||
.set_percent(ctx, (time + ten_secs) / Duration::END_OF_DAY);
|
||||
} else if time + thirty_mins <= Duration::END_OF_DAY
|
||||
&& self.menu.action("forwards 30 minutes")
|
||||
.set_percent(ctx, (time + ten_secs).to_percent(Time::END_OF_DAY));
|
||||
} else if time + thirty_mins <= Time::END_OF_DAY && self.menu.action("forwards 30 minutes")
|
||||
{
|
||||
self.time_slider
|
||||
.set_percent(ctx, (time + thirty_mins) / Duration::END_OF_DAY);
|
||||
} else if time != Duration::ZERO && self.menu.action("backwards 10 seconds") {
|
||||
.set_percent(ctx, (time + thirty_mins).to_percent(Time::END_OF_DAY));
|
||||
} else if time != Time::START_OF_DAY && self.menu.action("backwards 10 seconds") {
|
||||
self.time_slider
|
||||
.set_percent(ctx, (time - ten_secs) / Duration::END_OF_DAY);
|
||||
} else if time - thirty_mins >= Duration::ZERO && self.menu.action("backwards 30 minutes") {
|
||||
.set_percent(ctx, (time - ten_secs).to_percent(Time::START_OF_DAY));
|
||||
} else if time - thirty_mins >= Time::START_OF_DAY
|
||||
&& self.menu.action("backwards 30 minutes")
|
||||
{
|
||||
self.time_slider
|
||||
.set_percent(ctx, (time - thirty_mins) / Duration::END_OF_DAY);
|
||||
} else if time != Duration::ZERO && self.menu.action("goto start of day") {
|
||||
.set_percent(ctx, (time - thirty_mins).to_percent(Time::END_OF_DAY));
|
||||
} else if time != Time::START_OF_DAY && self.menu.action("goto start of day") {
|
||||
self.time_slider.set_percent(ctx, 0.0);
|
||||
} else if time != Duration::END_OF_DAY && self.menu.action("goto end of day") {
|
||||
} else if time != Time::END_OF_DAY && self.menu.action("goto end of day") {
|
||||
self.time_slider.set_percent(ctx, 1.0);
|
||||
} else if self.time_slider.event(ctx) {
|
||||
// Value changed, fall-through
|
||||
@ -147,7 +148,7 @@ impl State for TripsVisualizer {
|
||||
// TODO Speed description is briefly weird when we jump backwards with the other
|
||||
// control.
|
||||
self.time_slider
|
||||
.set_percent(ctx, ((time + dt) / Duration::END_OF_DAY).min(1.0));
|
||||
.set_percent(ctx, (time + dt).to_percent(Time::END_OF_DAY).min(1.0));
|
||||
} else {
|
||||
return Transition::Keep;
|
||||
}
|
||||
@ -158,7 +159,9 @@ impl State for TripsVisualizer {
|
||||
.trips
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, (trip, _))| time >= trip.depart_at && time <= trip.end_time())
|
||||
.filter(|(_, (trip, _))| {
|
||||
time >= trip.depart_at.tmp_as_time() && time <= trip.end_time().tmp_as_time()
|
||||
})
|
||||
.map(|(idx, _)| idx)
|
||||
.collect();
|
||||
|
||||
@ -174,7 +177,7 @@ impl State for TripsVisualizer {
|
||||
let mut batch = GeomBatch::new();
|
||||
for idx in &self.active_trips {
|
||||
let (trip, pl) = (&self.trips[*idx].0, &self.trips[*idx].1);
|
||||
let percent = (time - trip.depart_at) / trip.trip_time;
|
||||
let percent = (time - trip.depart_at.tmp_as_time()) / trip.trip_time;
|
||||
|
||||
let color = match trip.mode {
|
||||
Mode::Drive => ui.cs.get("unzoomed car"),
|
||||
|
@ -8,7 +8,7 @@ use crate::game::{State, Transition, WizardState};
|
||||
use crate::ui::UI;
|
||||
use abstutil::Timer;
|
||||
use ezgui::{hotkey, EventCtx, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
|
||||
use geom::Duration;
|
||||
use geom::Time;
|
||||
use sim::Scenario;
|
||||
|
||||
pub struct MissionEditMode {
|
||||
@ -92,8 +92,8 @@ pub fn pick_time_range(
|
||||
wizard: &mut WrappedWizard,
|
||||
low_query: &str,
|
||||
high_query: &str,
|
||||
) -> Option<(Duration, Duration)> {
|
||||
let t1 = wizard.input_time_slider(low_query, Duration::ZERO, Duration::END_OF_DAY)?;
|
||||
let t2 = wizard.input_time_slider(high_query, t1, Duration::END_OF_DAY)?;
|
||||
) -> Option<(Time, Time)> {
|
||||
let t1 = wizard.input_time_slider(low_query, Time::START_OF_DAY, Time::END_OF_DAY)?;
|
||||
let t2 = wizard.input_time_slider(high_query, t1, Time::END_OF_DAY)?;
|
||||
Some((t1, t2))
|
||||
}
|
||||
|
@ -369,8 +369,8 @@ fn edit_scenario(map: &Map, scenario: &mut Scenario, mut wizard: WrappedWizard)
|
||||
pick_time_range(&mut wizard, "Start spawning when?", "Stop spawning when?")?;
|
||||
scenario.spawn_over_time.push(SpawnOverTime {
|
||||
num_agents: wizard.input_usize("Spawn how many agents?")?,
|
||||
start_time,
|
||||
stop_time,
|
||||
start_time: start_time.tmp_to_duration(),
|
||||
stop_time: stop_time.tmp_to_duration(),
|
||||
start_from_neighborhood: choose_neighborhood(
|
||||
map,
|
||||
&mut wizard,
|
||||
@ -391,8 +391,8 @@ fn edit_scenario(map: &Map, scenario: &mut Scenario, mut wizard: WrappedWizard)
|
||||
num_peds: wizard.input_usize("Spawn how many pedestrians?")?,
|
||||
num_cars: wizard.input_usize("Spawn how many cars?")?,
|
||||
num_bikes: wizard.input_usize("Spawn how many bikes?")?,
|
||||
start_time,
|
||||
stop_time,
|
||||
start_time: start_time.tmp_to_duration(),
|
||||
stop_time: stop_time.tmp_to_duration(),
|
||||
// TODO validate it's a border!
|
||||
start_from_border: choose_intersection(
|
||||
&mut wizard,
|
||||
|
@ -5,7 +5,7 @@ use crate::render::{
|
||||
};
|
||||
use abstutil::Timer;
|
||||
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
|
||||
use geom::{Angle, Distance, Duration, Line, PolyLine, Polygon, Pt2D, Ring, EPSILON_DIST};
|
||||
use geom::{Angle, Distance, Line, PolyLine, Polygon, Pt2D, Ring, Time, EPSILON_DIST};
|
||||
use map_model::{
|
||||
Intersection, IntersectionID, IntersectionType, Map, Road, RoadWithStopSign, Turn, TurnID,
|
||||
TurnType, LANE_THICKNESS,
|
||||
@ -18,7 +18,7 @@ pub struct DrawIntersection {
|
||||
zorder: isize,
|
||||
|
||||
draw_default: Drawable,
|
||||
draw_traffic_signal: RefCell<Option<(Drawable, Duration)>>,
|
||||
draw_traffic_signal: RefCell<Option<(Drawable, Time)>>,
|
||||
// Only for traffic signals
|
||||
pub crosswalks: Vec<(TurnID, GeomBatch)>,
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use crate::ui::Flags;
|
||||
use aabb_quadtree::QuadTree;
|
||||
use abstutil::{Cloneable, Timer};
|
||||
use ezgui::{Color, Drawable, EventCtx, GeomBatch, GfxCtx, Text};
|
||||
use geom::{Bounds, Circle, Distance, Duration, FindClosest};
|
||||
use geom::{Bounds, Circle, Distance, Duration, FindClosest, Time};
|
||||
use map_model::{
|
||||
AreaID, BuildingID, BusStopID, DirectedRoadID, Intersection, IntersectionID, LaneID, Map, Road,
|
||||
RoadID, Traversable, LANE_THICKNESS,
|
||||
@ -297,14 +297,14 @@ impl DrawMap {
|
||||
}
|
||||
|
||||
pub struct AgentCache {
|
||||
time: Option<Duration>,
|
||||
time: Option<Time>,
|
||||
agents_per_on: HashMap<Traversable, Vec<Box<dyn Renderable>>>,
|
||||
// cam_zoom also matters
|
||||
unzoomed: Option<(f64, Drawable)>,
|
||||
}
|
||||
|
||||
impl AgentCache {
|
||||
pub fn has(&self, now: Duration, on: Traversable) -> bool {
|
||||
pub fn has(&self, now: Time, on: Traversable) -> bool {
|
||||
if Some(now) != self.time {
|
||||
return false;
|
||||
}
|
||||
@ -319,7 +319,7 @@ impl AgentCache {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn put(&mut self, now: Duration, on: Traversable, agents: Vec<Box<dyn Renderable>>) {
|
||||
pub fn put(&mut self, now: Time, on: Traversable, agents: Vec<Box<dyn Renderable>>) {
|
||||
if Some(now) != self.time {
|
||||
self.agents_per_on.clear();
|
||||
self.time = Some(now);
|
||||
|
@ -5,11 +5,11 @@ use crate::sandbox::overlays::Overlays;
|
||||
use crate::ui::UI;
|
||||
use abstutil::prettyprint_usize;
|
||||
use ezgui::{hotkey, EventCtx, Key, Line, ModalMenu, Text};
|
||||
use geom::Duration;
|
||||
use geom::Time;
|
||||
use sim::TripMode;
|
||||
|
||||
pub struct CreateGridlock {
|
||||
time: Duration,
|
||||
time: Time,
|
||||
}
|
||||
|
||||
impl CreateGridlock {
|
||||
@ -24,7 +24,7 @@ impl CreateGridlock {
|
||||
ctx,
|
||||
),
|
||||
Box::new(CreateGridlock {
|
||||
time: Duration::ZERO,
|
||||
time: Time::START_OF_DAY,
|
||||
}),
|
||||
)
|
||||
}
|
||||
@ -69,10 +69,9 @@ fn gridlock_panel(ui: &UI) -> Text {
|
||||
.primary
|
||||
.sim
|
||||
.get_analytics()
|
||||
.all_finished_trips(ui.primary.sim.time().tmp_as_time());
|
||||
let (baseline_all, _, baseline_per_mode) = ui
|
||||
.prebaked
|
||||
.all_finished_trips(ui.primary.sim.time().tmp_as_time());
|
||||
.all_finished_trips(ui.primary.sim.time());
|
||||
let (baseline_all, _, baseline_per_mode) =
|
||||
ui.prebaked.all_finished_trips(ui.primary.sim.time());
|
||||
|
||||
let mut txt = Text::new();
|
||||
txt.add_appended(vec![
|
||||
|
@ -4,12 +4,12 @@ use crate::sandbox::overlays::Overlays;
|
||||
use crate::ui::UI;
|
||||
use abstutil::prettyprint_usize;
|
||||
use ezgui::{hotkey, EventCtx, Key, Line, ModalMenu, Text};
|
||||
use geom::{Duration, Statistic};
|
||||
use geom::{Statistic, Time};
|
||||
use sim::TripMode;
|
||||
|
||||
pub struct FasterTrips {
|
||||
mode: TripMode,
|
||||
time: Duration,
|
||||
time: Time,
|
||||
}
|
||||
|
||||
impl FasterTrips {
|
||||
@ -22,7 +22,7 @@ impl FasterTrips {
|
||||
),
|
||||
Box::new(FasterTrips {
|
||||
mode: trip_mode,
|
||||
time: Duration::ZERO,
|
||||
time: Time::START_OF_DAY,
|
||||
}),
|
||||
)
|
||||
}
|
||||
@ -54,7 +54,7 @@ impl GameplayState for FasterTrips {
|
||||
}
|
||||
|
||||
pub fn faster_trips_panel(mode: TripMode, ui: &UI) -> Text {
|
||||
let time = ui.primary.sim.time().tmp_as_time();
|
||||
let time = ui.primary.sim.time();
|
||||
let now = ui.primary.sim.get_analytics().finished_trips(time, mode);
|
||||
let baseline = ui.prebaked.finished_trips(time, mode);
|
||||
|
||||
|
@ -4,11 +4,11 @@ use crate::sandbox::gameplay::{manage_overlays, GameplayState};
|
||||
use crate::sandbox::overlays::Overlays;
|
||||
use crate::ui::UI;
|
||||
use ezgui::{hotkey, EventCtx, Key, ModalMenu};
|
||||
use geom::Duration;
|
||||
use geom::Time;
|
||||
use sim::TripMode;
|
||||
|
||||
pub struct FixTrafficSignals {
|
||||
time: Duration,
|
||||
time: Time,
|
||||
}
|
||||
|
||||
impl FixTrafficSignals {
|
||||
@ -23,7 +23,7 @@ impl FixTrafficSignals {
|
||||
ctx,
|
||||
),
|
||||
Box::new(FixTrafficSignals {
|
||||
time: Duration::ZERO,
|
||||
time: Time::START_OF_DAY,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
@ -6,12 +6,12 @@ use crate::sandbox::overlays::Overlays;
|
||||
use crate::sandbox::{bus_explorer, SandboxMode};
|
||||
use crate::ui::UI;
|
||||
use ezgui::{hotkey, Choice, EventCtx, Key, Line, ModalMenu, Text};
|
||||
use geom::{Duration, Statistic};
|
||||
use geom::{Duration, Statistic, Time};
|
||||
use map_model::BusRouteID;
|
||||
|
||||
pub struct OptimizeBus {
|
||||
route: BusRouteID,
|
||||
time: Duration,
|
||||
time: Time,
|
||||
stat: Statistic,
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ impl OptimizeBus {
|
||||
),
|
||||
Box::new(OptimizeBus {
|
||||
route: route.id,
|
||||
time: Duration::ZERO,
|
||||
time: Time::START_OF_DAY,
|
||||
stat: Statistic::Max,
|
||||
}),
|
||||
)
|
||||
@ -107,7 +107,7 @@ impl GameplayState for OptimizeBus {
|
||||
.downcast_mut::<OptimizeBus>()
|
||||
.unwrap();
|
||||
// Force recalculation
|
||||
opt.time = Duration::ZERO;
|
||||
opt.time = Time::START_OF_DAY;
|
||||
opt.stat = new_stat;
|
||||
})))
|
||||
},
|
||||
@ -133,10 +133,8 @@ fn bus_route_panel(id: BusRouteID, ui: &UI, stat: Statistic) -> Text {
|
||||
.primary
|
||||
.sim
|
||||
.get_analytics()
|
||||
.bus_arrivals(ui.primary.sim.time().tmp_as_time(), id);
|
||||
let baseline = ui
|
||||
.prebaked
|
||||
.bus_arrivals(ui.primary.sim.time().tmp_as_time(), id);
|
||||
.bus_arrivals(ui.primary.sim.time(), id);
|
||||
let baseline = ui.prebaked.bus_arrivals(ui.primary.sim.time(), id);
|
||||
|
||||
let route = ui.primary.map.get_br(id);
|
||||
let mut txt = Text::new();
|
||||
@ -169,7 +167,7 @@ fn bus_delays(id: BusRouteID, ui: &UI, ctx: &mut EventCtx) -> Plot<Duration> {
|
||||
.primary
|
||||
.sim
|
||||
.get_analytics()
|
||||
.bus_arrivals_over_time(ui.primary.sim.time().tmp_as_time(), id);
|
||||
.bus_arrivals_over_time(ui.primary.sim.time(), id);
|
||||
|
||||
let mut series = Vec::new();
|
||||
for idx1 in 0..route.stops.len() {
|
||||
|
@ -318,7 +318,7 @@ pub fn spawn_agents_around(i: IntersectionID, ui: &mut UI, ctx: &EventCtx) {
|
||||
continue;
|
||||
}
|
||||
sim.schedule_trip(
|
||||
sim.time(),
|
||||
sim.time().tmp_to_duration(),
|
||||
TripSpec::CarAppearing {
|
||||
start_pos: Position::new(
|
||||
lane.id,
|
||||
@ -336,7 +336,7 @@ pub fn spawn_agents_around(i: IntersectionID, ui: &mut UI, ctx: &EventCtx) {
|
||||
} else if lane.is_sidewalk() {
|
||||
for _ in 0..5 {
|
||||
sim.schedule_trip(
|
||||
sim.time(),
|
||||
sim.time().tmp_to_duration(),
|
||||
TripSpec::JustWalking {
|
||||
start: SidewalkSpot::suddenly_appear(
|
||||
lane.id,
|
||||
@ -392,7 +392,7 @@ fn schedule_trip(
|
||||
map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos)
|
||||
{
|
||||
sim.schedule_trip(
|
||||
sim.time(),
|
||||
sim.time().tmp_to_duration(),
|
||||
TripSpec::UsingTransit {
|
||||
start,
|
||||
goal,
|
||||
@ -405,7 +405,7 @@ fn schedule_trip(
|
||||
);
|
||||
} else {
|
||||
sim.schedule_trip(
|
||||
sim.time(),
|
||||
sim.time().tmp_to_duration(),
|
||||
TripSpec::JustWalking {
|
||||
start,
|
||||
goal,
|
||||
@ -431,7 +431,7 @@ fn schedule_trip(
|
||||
}
|
||||
};
|
||||
sim.schedule_trip(
|
||||
sim.time(),
|
||||
sim.time().tmp_to_duration(),
|
||||
TripSpec::UsingBike {
|
||||
start: SidewalkSpot::building(*b, map),
|
||||
vehicle: Scenario::rand_bike(rng),
|
||||
@ -461,7 +461,7 @@ fn schedule_trip(
|
||||
Source::Drive(from) => {
|
||||
if let Some(start_pos) = TripSpec::spawn_car_at(*from, map) {
|
||||
sim.schedule_trip(
|
||||
sim.time(),
|
||||
sim.time().tmp_to_duration(),
|
||||
TripSpec::CarAppearing {
|
||||
start_pos,
|
||||
vehicle_spec: Scenario::rand_car(rng),
|
||||
@ -476,7 +476,7 @@ fn schedule_trip(
|
||||
}
|
||||
Source::WalkFromBldgThenMaybeUseCar(b) => {
|
||||
sim.schedule_trip(
|
||||
sim.time(),
|
||||
sim.time().tmp_to_duration(),
|
||||
TripSpec::MaybeUsingParkedCar {
|
||||
start_bldg: *b,
|
||||
goal,
|
||||
@ -634,8 +634,8 @@ fn create_swarm(ui: &mut UI, from: LaneID, to: LaneID, count: usize, duration: D
|
||||
num_peds: 0,
|
||||
num_cars: count,
|
||||
num_bikes: 0,
|
||||
start_time: ui.primary.sim.time() + SMALL_DT,
|
||||
stop_time: ui.primary.sim.time() + SMALL_DT + duration,
|
||||
start_time: (ui.primary.sim.time() + SMALL_DT).tmp_to_duration(),
|
||||
stop_time: (ui.primary.sim.time() + SMALL_DT + duration).tmp_to_duration(),
|
||||
start_from_border: ui
|
||||
.primary
|
||||
.map
|
||||
|
@ -16,11 +16,11 @@ use std::collections::{BTreeMap, HashSet};
|
||||
|
||||
pub enum Overlays {
|
||||
Inactive,
|
||||
ParkingAvailability(Duration, RoadColorer),
|
||||
IntersectionDelay(Duration, ObjectColorer),
|
||||
CumulativeThroughput(Duration, ObjectColorer),
|
||||
FinishedTrips(Duration, Plot<usize>),
|
||||
Chokepoints(Duration, ObjectColorer),
|
||||
ParkingAvailability(Time, RoadColorer),
|
||||
IntersectionDelay(Time, ObjectColorer),
|
||||
CumulativeThroughput(Time, ObjectColorer),
|
||||
FinishedTrips(Time, Plot<usize>),
|
||||
Chokepoints(Time, ObjectColorer),
|
||||
BikeNetwork(RoadColorer),
|
||||
BikePathCosts(RoadColorer),
|
||||
BusNetwork(RoadColorer),
|
||||
@ -28,13 +28,13 @@ pub enum Overlays {
|
||||
BusRoute(ShowBusRoute),
|
||||
BusDelaysOverTime(Plot<Duration>),
|
||||
RoadThroughput {
|
||||
t: Duration,
|
||||
t: Time,
|
||||
bucket: Duration,
|
||||
r: RoadID,
|
||||
plot: Plot<usize>,
|
||||
},
|
||||
IntersectionThroughput {
|
||||
t: Duration,
|
||||
t: Time,
|
||||
bucket: Duration,
|
||||
i: IntersectionID,
|
||||
plot: Plot<usize>,
|
||||
@ -326,7 +326,7 @@ impl Overlays {
|
||||
ui.primary
|
||||
.sim
|
||||
.get_analytics()
|
||||
.throughput_road(ui.primary.sim.time().tmp_as_time(), r, bucket)
|
||||
.throughput_road(ui.primary.sim.time(), r, bucket)
|
||||
.into_iter()
|
||||
.map(|(m, pts)| Series {
|
||||
label: m.to_string(),
|
||||
@ -360,7 +360,7 @@ impl Overlays {
|
||||
ui.primary
|
||||
.sim
|
||||
.get_analytics()
|
||||
.throughput_intersection(ui.primary.sim.time().tmp_as_time(), i, bucket)
|
||||
.throughput_intersection(ui.primary.sim.time(), i, bucket)
|
||||
.into_iter()
|
||||
.map(|(m, pts)| Series {
|
||||
label: m.to_string(),
|
||||
@ -459,7 +459,7 @@ impl Overlays {
|
||||
let mut times = Vec::new();
|
||||
for i in 0..num_x_pts {
|
||||
let percent_x = (i as f64) / ((num_x_pts - 1) as f64);
|
||||
let t = ui.primary.sim.time().tmp_as_time().percent_of(percent_x);
|
||||
let t = ui.primary.sim.time().percent_of(percent_x);
|
||||
times.push(t);
|
||||
}
|
||||
|
||||
@ -484,7 +484,7 @@ impl Overlays {
|
||||
pts_per_mode
|
||||
.get_mut(mode)
|
||||
.unwrap()
|
||||
.push((ui.primary.sim.time().tmp_as_time(), counts.get(*mode)));
|
||||
.push((ui.primary.sim.time(), counts.get(*mode)));
|
||||
}
|
||||
|
||||
let plot = Plot::new(
|
||||
|
@ -30,10 +30,9 @@ impl Scoreboard {
|
||||
.primary
|
||||
.sim
|
||||
.get_analytics()
|
||||
.all_finished_trips(ui.primary.sim.time().tmp_as_time());
|
||||
let (baseline_all, baseline_aborted, baseline_per_mode) = ui
|
||||
.prebaked
|
||||
.all_finished_trips(ui.primary.sim.time().tmp_as_time());
|
||||
.all_finished_trips(ui.primary.sim.time());
|
||||
let (baseline_all, baseline_aborted, baseline_per_mode) =
|
||||
ui.prebaked.all_finished_trips(ui.primary.sim.time());
|
||||
|
||||
// TODO Include unfinished count
|
||||
let mut txt = Text::new();
|
||||
|
@ -145,14 +145,6 @@ impl Duration {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn as_filename(self) -> String {
|
||||
let (hours, minutes, seconds, remainder) = self.get_parts();
|
||||
format!(
|
||||
"{0:02}h{1:02}m{2:02}.{3:01}s",
|
||||
hours, minutes, seconds, remainder
|
||||
)
|
||||
}
|
||||
|
||||
pub fn parse(string: &str) -> Result<Duration, abstutil::Error> {
|
||||
let parts: Vec<&str> = string.split(':').collect();
|
||||
if parts.is_empty() {
|
||||
|
@ -35,5 +35,5 @@ pub(crate) fn trim_f64(x: f64) -> f64 {
|
||||
(x * 10_000.0).round() / 10_000.0
|
||||
}
|
||||
|
||||
impl abstutil::Cloneable for Duration {}
|
||||
impl abstutil::Cloneable for Time {}
|
||||
impl abstutil::Cloneable for Statistic {}
|
||||
|
@ -143,6 +143,10 @@ impl Time {
|
||||
pub fn to_percent(self, other: Time) -> f64 {
|
||||
self.0 / other.0
|
||||
}
|
||||
|
||||
pub fn tmp_to_duration(self) -> Duration {
|
||||
Duration::seconds(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Time {
|
||||
@ -164,6 +168,14 @@ impl ops::Add<Duration> for Time {
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub<Duration> for Time {
|
||||
type Output = Time;
|
||||
|
||||
fn sub(self, other: Duration) -> Time {
|
||||
Time::seconds_since_midnight(self.0 - other.inner_seconds())
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Sub for Time {
|
||||
type Output = Duration;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{IntersectionID, Map, RoadID, TurnGroup, TurnGroupID, TurnID, TurnPriority, TurnType};
|
||||
use abstutil::{deserialize_btreemap, retain_btreeset, serialize_btreemap, Timer};
|
||||
use geom::Duration;
|
||||
use geom::{Duration, Time};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
@ -67,13 +67,13 @@ impl ControlTrafficSignal {
|
||||
results
|
||||
}
|
||||
|
||||
pub fn current_phase_and_remaining_time(&self, now: Duration) -> (usize, &Phase, Duration) {
|
||||
pub fn current_phase_and_remaining_time(&self, now: Time) -> (usize, &Phase, Duration) {
|
||||
let mut cycle_length = Duration::ZERO;
|
||||
for p in &self.phases {
|
||||
cycle_length += p.duration;
|
||||
}
|
||||
|
||||
let mut now_offset = (now + self.offset) % cycle_length;
|
||||
let mut now_offset = (now + self.offset).tmp_to_duration() % cycle_length;
|
||||
for (idx, p) in self.phases.iter().enumerate() {
|
||||
if now_offset < p.duration {
|
||||
return (idx, p, p.duration - now_offset);
|
||||
|
@ -133,7 +133,7 @@ impl IntersectionSimState {
|
||||
protected.push(req);
|
||||
}
|
||||
} else if let Some(ref signal) = map.maybe_get_traffic_signal(i) {
|
||||
let (_, phase, _) = signal.current_phase_and_remaining_time(now);
|
||||
let (_, phase, _) = signal.current_phase_and_remaining_time(now.tmp_as_time());
|
||||
for (req, _) in all {
|
||||
match phase.get_priority_of_turn(req.turn, signal) {
|
||||
TurnPriority::Protected => {
|
||||
@ -185,7 +185,7 @@ impl IntersectionSimState {
|
||||
self.wakeup_waiting(now, id, scheduler, map);
|
||||
let (_, _, remaining) = map
|
||||
.get_traffic_signal(id)
|
||||
.current_phase_and_remaining_time(now);
|
||||
.current_phase_and_remaining_time(now.tmp_as_time());
|
||||
scheduler.push(now + remaining, Command::UpdateIntersection(id));
|
||||
}
|
||||
|
||||
@ -348,7 +348,8 @@ impl State {
|
||||
return true;
|
||||
}
|
||||
|
||||
let (_, phase, remaining_phase_time) = signal.current_phase_and_remaining_time(now);
|
||||
let (_, phase, remaining_phase_time) =
|
||||
signal.current_phase_and_remaining_time(now.tmp_as_time());
|
||||
|
||||
// Can't go at all this phase.
|
||||
if phase.get_priority_of_turn(new_req.turn, signal) == TurnPriority::Banned {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{CarID, PedestrianID, VehicleType};
|
||||
use geom::{Angle, Distance, Duration, PolyLine, Pt2D};
|
||||
use geom::{Angle, Distance, Duration, PolyLine, Pt2D, Time};
|
||||
use map_model::{BuildingID, Map, Traversable, TurnID};
|
||||
|
||||
// Intermediate structures so that sim and game crates don't have a cyclic dependency.
|
||||
@ -66,7 +66,7 @@ pub struct UnzoomedAgent {
|
||||
// actually good for main sim too; we're constantly calculating stuff while sim is paused
|
||||
// otherwise? except we don't know what to calculate. maybe cache it?
|
||||
pub trait GetDrawAgents {
|
||||
fn time(&self) -> Duration;
|
||||
fn time(&self) -> Time;
|
||||
// Every time the time changes, this should increase. For smoothly animating stuff.
|
||||
fn step_count(&self) -> usize;
|
||||
fn get_draw_car(&self, id: CarID, map: &Map) -> Option<DrawCarInput>;
|
||||
@ -85,8 +85,8 @@ pub trait GetDrawAgents {
|
||||
pub struct DontDrawAgents;
|
||||
|
||||
impl GetDrawAgents for DontDrawAgents {
|
||||
fn time(&self) -> Duration {
|
||||
Duration::ZERO
|
||||
fn time(&self) -> Time {
|
||||
Time::START_OF_DAY
|
||||
}
|
||||
fn step_count(&self) -> usize {
|
||||
0
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
};
|
||||
use abstutil::{elapsed_seconds, Timer};
|
||||
use derivative::Derivative;
|
||||
use geom::{Distance, Duration, DurationHistogram, PolyLine, Pt2D};
|
||||
use geom::{Distance, Duration, DurationHistogram, PolyLine, Pt2D, Time};
|
||||
use map_model::{
|
||||
BuildingID, BusRoute, BusRouteID, IntersectionID, LaneID, Map, Path, PathConstraints,
|
||||
PathRequest, PathStep, Traversable,
|
||||
@ -293,8 +293,8 @@ impl Sim {
|
||||
|
||||
// Drawing
|
||||
impl GetDrawAgents for Sim {
|
||||
fn time(&self) -> Duration {
|
||||
self.time
|
||||
fn time(&self) -> Time {
|
||||
self.time.tmp_as_time()
|
||||
}
|
||||
|
||||
fn step_count(&self) -> usize {
|
||||
@ -594,7 +594,7 @@ impl Sim {
|
||||
"********************************************************************************"
|
||||
);
|
||||
println!("At {}", self.time);
|
||||
if let Some(path) = self.find_previous_savestate(self.time) {
|
||||
if let Some(path) = self.find_previous_savestate(self.time.tmp_as_time()) {
|
||||
println!("Debug from {}", path);
|
||||
}
|
||||
}
|
||||
@ -617,12 +617,8 @@ impl Sim {
|
||||
let mut last_sim_time = self.time();
|
||||
|
||||
loop {
|
||||
let dt = if let Some(lim) = time_limit {
|
||||
// TODO Regular printing then doesn't happen :\
|
||||
self.time() + lim
|
||||
} else {
|
||||
Duration::seconds(30.0)
|
||||
};
|
||||
// TODO Regular printing doesn't happen if we use a time_limit :\
|
||||
let dt = time_limit.unwrap_or(Duration::seconds(30.0));
|
||||
|
||||
match panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
self.step(&map, dt);
|
||||
@ -677,7 +673,7 @@ impl Sim {
|
||||
// TODO No benchmark printing at all this way.
|
||||
// TODO Doesn't stop early once all expectations are met.
|
||||
self.analytics.test_expectations.extend(all_expectations);
|
||||
self.step(&map, self.time() + time_limit);
|
||||
self.step(&map, time_limit);
|
||||
if self.analytics.test_expectations.is_empty() {
|
||||
return;
|
||||
}
|
||||
@ -698,7 +694,7 @@ impl Sim {
|
||||
)
|
||||
}
|
||||
|
||||
fn save_path(&self, base_time: Duration) -> String {
|
||||
fn save_path(&self, base_time: Time) -> String {
|
||||
// If we wanted to be even more reproducible, we'd encode RNG seed, version of code, etc,
|
||||
// but that's overkill right now.
|
||||
abstutil::path2_bin(
|
||||
@ -710,17 +706,17 @@ impl Sim {
|
||||
}
|
||||
|
||||
pub fn save(&self) -> String {
|
||||
let path = self.save_path(self.time);
|
||||
let path = self.save_path(self.time.tmp_as_time());
|
||||
abstutil::write_binary(&path, &self).expect("Writing sim state failed");
|
||||
println!("Saved to {}", path);
|
||||
path
|
||||
}
|
||||
|
||||
pub fn find_previous_savestate(&self, base_time: Duration) -> Option<String> {
|
||||
pub fn find_previous_savestate(&self, base_time: Time) -> Option<String> {
|
||||
abstutil::find_prev_file(self.save_path(base_time))
|
||||
}
|
||||
|
||||
pub fn find_next_savestate(&self, base_time: Duration) -> Option<String> {
|
||||
pub fn find_next_savestate(&self, base_time: Time) -> Option<String> {
|
||||
abstutil::find_next_file(self.save_path(base_time))
|
||||
}
|
||||
|
||||
@ -732,8 +728,8 @@ impl Sim {
|
||||
|
||||
// Queries of all sorts
|
||||
impl Sim {
|
||||
pub fn time(&self) -> Duration {
|
||||
self.time
|
||||
pub fn time(&self) -> Time {
|
||||
self.time.tmp_as_time()
|
||||
}
|
||||
|
||||
pub fn is_done(&self) -> bool {
|
||||
|
Loading…
Reference in New Issue
Block a user