cutover sim time (via the API) to time

This commit is contained in:
Dustin Carlino 2019-11-27 11:49:57 -08:00
parent e109c6b5a4
commit 819e27aa5d
29 changed files with 144 additions and 149 deletions

View File

@ -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));

View File

@ -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) {

View File

@ -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)>>,

View File

@ -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 {

View File

@ -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 {

View File

@ -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);

View File

@ -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| {

View File

@ -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 {

View File

@ -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 {

View File

@ -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()
))),
);
}

View File

@ -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"),

View File

@ -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))
}

View File

@ -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,

View File

@ -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)>,
}

View File

@ -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);

View File

@ -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![

View File

@ -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);

View File

@ -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,
}),
)
}

View File

@ -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() {

View File

@ -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

View File

@ -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(

View File

@ -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();

View File

@ -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() {

View File

@ -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 {}

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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

View File

@ -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 {