mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-28 08:53:26 +03:00
see modified trips in the table and info panels
This commit is contained in:
parent
e691545b63
commit
614354271a
@ -794,6 +794,13 @@ impl Composite {
|
|||||||
pub fn is_checked(&self, name: &str) -> bool {
|
pub fn is_checked(&self, name: &str) -> bool {
|
||||||
self.find::<Checkbox>(name).enabled
|
self.find::<Checkbox>(name).enabled
|
||||||
}
|
}
|
||||||
|
pub fn maybe_is_checked(&self, name: &str) -> Option<bool> {
|
||||||
|
if self.has_widget(name) {
|
||||||
|
Some(self.find::<Checkbox>(name).enabled)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn text_box(&self, name: &str) -> String {
|
pub fn text_box(&self, name: &str) -> String {
|
||||||
self.find::<TextBox>(name).get_line()
|
self.find::<TextBox>(name).get_line()
|
||||||
|
@ -522,6 +522,8 @@ pub struct PerMap {
|
|||||||
pub zorder_range: (isize, isize),
|
pub zorder_range: (isize, isize),
|
||||||
// If we ever left edit mode and resumed without restarting from midnight, this is true.
|
// If we ever left edit mode and resumed without restarting from midnight, this is true.
|
||||||
pub dirty_from_edits: bool,
|
pub dirty_from_edits: bool,
|
||||||
|
// Any ScenarioModifiers in effect?
|
||||||
|
pub has_modified_trips: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PerMap {
|
impl PerMap {
|
||||||
@ -553,6 +555,7 @@ impl PerMap {
|
|||||||
zorder_range: (low_z, high_z),
|
zorder_range: (low_z, high_z),
|
||||||
show_zorder: high_z,
|
show_zorder: high_z,
|
||||||
dirty_from_edits: false,
|
dirty_from_edits: false,
|
||||||
|
has_modified_trips: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ pub fn people(ctx: &mut EventCtx, app: &App, details: &mut Details, id: Building
|
|||||||
for t in &person.trips {
|
for t in &person.trips {
|
||||||
match app.primary.sim.trip_to_agent(*t) {
|
match app.primary.sim.trip_to_agent(*t) {
|
||||||
TripResult::TripNotStarted => {
|
TripResult::TripNotStarted => {
|
||||||
let (start_time, _, _, mode) = app.primary.sim.trip_info(*t);
|
let (start_time, _, _, mode, _) = app.primary.sim.trip_info(*t);
|
||||||
next_trip = Some((start_time, mode));
|
next_trip = Some((start_time, mode));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -721,20 +721,17 @@ impl DataOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_controls(c: &Composite) -> DataOptions {
|
pub fn from_controls(c: &Composite) -> DataOptions {
|
||||||
let show_before =
|
let show_before = c.maybe_is_checked("Show before changes").unwrap_or(false);
|
||||||
c.has_widget("Show before changes") && c.is_checked("Show before changes");
|
|
||||||
let mut disabled_modes = BTreeSet::new();
|
let mut disabled_modes = BTreeSet::new();
|
||||||
for m in TripMode::all() {
|
for m in TripMode::all() {
|
||||||
let label = m.noun();
|
let label = m.noun();
|
||||||
if c.has_widget(label) && !c.is_checked(label) {
|
if !c.maybe_is_checked(label).unwrap_or(true) {
|
||||||
disabled_modes.insert(m);
|
disabled_modes.insert(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataOptions {
|
DataOptions {
|
||||||
show_before,
|
show_before,
|
||||||
show_end_of_day: show_before
|
show_end_of_day: show_before && c.maybe_is_checked("Show full day").unwrap_or(false),
|
||||||
&& c.has_widget("Show full day")
|
|
||||||
&& c.is_checked("Show full day"),
|
|
||||||
disabled_modes,
|
disabled_modes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,12 +117,15 @@ pub fn trips(
|
|||||||
}
|
}
|
||||||
TripResult::TripDoesntExist => unreachable!(),
|
TripResult::TripDoesntExist => unreachable!(),
|
||||||
};
|
};
|
||||||
let (_, _, _, trip_mode) = sim.trip_info(*t);
|
let (_, _, _, trip_mode, modified) = sim.trip_info(*t);
|
||||||
|
|
||||||
// TODO Style wrong. Button should be the entire row.
|
// TODO Style wrong. Button should be the entire row.
|
||||||
rows.push(
|
rows.push(
|
||||||
Widget::custom_row(vec![
|
Widget::custom_row(vec![
|
||||||
format!("Trip {} ", idx + 1).draw_text(ctx).margin_right(21),
|
format!("Trip {} ", idx + 1)
|
||||||
|
.draw_text(ctx)
|
||||||
|
.centered_vert()
|
||||||
|
.margin_right(21),
|
||||||
Widget::row(vec![
|
Widget::row(vec![
|
||||||
Widget::draw_svg_transform(
|
Widget::draw_svg_transform(
|
||||||
ctx,
|
ctx,
|
||||||
@ -134,20 +137,31 @@ pub fn trips(
|
|||||||
},
|
},
|
||||||
RewriteColor::ChangeAll(color),
|
RewriteColor::ChangeAll(color),
|
||||||
),
|
),
|
||||||
Line(trip_status).small().fg(color).draw(ctx),
|
Line(trip_status)
|
||||||
|
.small()
|
||||||
|
.fg(color)
|
||||||
|
.draw(ctx)
|
||||||
|
.centered_vert(),
|
||||||
])
|
])
|
||||||
.fully_rounded()
|
.fully_rounded()
|
||||||
.outline(1.0, color)
|
.outline(1.0, color)
|
||||||
.bg(color.alpha(0.2))
|
.bg(color.alpha(0.2))
|
||||||
.padding(5)
|
.padding(10)
|
||||||
.margin_right(21),
|
.margin_right(21),
|
||||||
|
if modified {
|
||||||
|
Line("modified").draw(ctx).centered_vert().margin_right(15)
|
||||||
|
} else {
|
||||||
|
Widget::nothing()
|
||||||
|
},
|
||||||
if trip_status == "finished" {
|
if trip_status == "finished" {
|
||||||
if let Some(before) = app
|
if let Some(before) = app
|
||||||
.has_prebaked()
|
.has_prebaked()
|
||||||
.and_then(|_| app.prebaked().finished_trip_time(*t))
|
.and_then(|_| app.prebaked().finished_trip_time(*t))
|
||||||
{
|
{
|
||||||
let (after, _) = app.primary.sim.finished_trip_time(*t).unwrap();
|
let (after, _) = app.primary.sim.finished_trip_time(*t).unwrap();
|
||||||
Text::from(cmp_duration_shorter(after, before)).draw(ctx)
|
Text::from(cmp_duration_shorter(after, before))
|
||||||
|
.draw(ctx)
|
||||||
|
.centered_vert()
|
||||||
} else {
|
} else {
|
||||||
Widget::nothing()
|
Widget::nothing()
|
||||||
}
|
}
|
||||||
@ -172,6 +186,7 @@ pub fn trips(
|
|||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
.centered_vert()
|
||||||
.align_right(),
|
.align_right(),
|
||||||
])
|
])
|
||||||
.outline(2.0, Color::WHITE)
|
.outline(2.0, Color::WHITE)
|
||||||
@ -314,7 +329,7 @@ pub fn schedule(
|
|||||||
// TODO Proportional 24-hour timeline would be easier to understand
|
// TODO Proportional 24-hour timeline would be easier to understand
|
||||||
let mut last_t = Time::START_OF_DAY;
|
let mut last_t = Time::START_OF_DAY;
|
||||||
for t in &person.trips {
|
for t in &person.trips {
|
||||||
let (start_time, from, _, _) = app.primary.sim.trip_info(*t);
|
let (start_time, from, _, _, _) = app.primary.sim.trip_info(*t);
|
||||||
let at = match from {
|
let at = match from {
|
||||||
TripEndpoint::Bldg(b) => {
|
TripEndpoint::Bldg(b) => {
|
||||||
let b = app.primary.map.get_b(b);
|
let b = app.primary.map.get_b(b);
|
||||||
@ -334,7 +349,7 @@ pub fn schedule(
|
|||||||
last_t = start_time;
|
last_t = start_time;
|
||||||
}
|
}
|
||||||
// Where do they spend the night?
|
// Where do they spend the night?
|
||||||
let (start_time, _, to, _) = app.primary.sim.trip_info(*person.trips.last().unwrap());
|
let (start_time, _, to, _, _) = app.primary.sim.trip_info(*person.trips.last().unwrap());
|
||||||
let at = match to {
|
let at = match to {
|
||||||
TripEndpoint::Bldg(b) => {
|
TripEndpoint::Bldg(b) => {
|
||||||
let b = app.primary.map.get_b(b);
|
let b = app.primary.map.get_b(b);
|
||||||
|
@ -50,7 +50,7 @@ pub fn ongoing(
|
|||||||
.sim
|
.sim
|
||||||
.get_analytics()
|
.get_analytics()
|
||||||
.get_trip_phases(trip, &app.primary.map);
|
.get_trip_phases(trip, &app.primary.map);
|
||||||
let (start_time, _, _, _) = app.primary.sim.trip_info(trip);
|
let (start_time, _, _, _, _) = app.primary.sim.trip_info(trip);
|
||||||
|
|
||||||
let col_width = 7;
|
let col_width = 7;
|
||||||
let props = app.primary.sim.agent_properties(agent);
|
let props = app.primary.sim.agent_properties(agent);
|
||||||
@ -143,7 +143,7 @@ pub fn future(
|
|||||||
open_trip: &mut OpenTrip,
|
open_trip: &mut OpenTrip,
|
||||||
details: &mut Details,
|
details: &mut Details,
|
||||||
) -> Widget {
|
) -> Widget {
|
||||||
let (start_time, trip_start, trip_end, _) = app.primary.sim.trip_info(trip);
|
let (start_time, trip_start, trip_end, _, _) = app.primary.sim.trip_info(trip);
|
||||||
|
|
||||||
let mut col = Vec::new();
|
let mut col = Vec::new();
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ pub fn finished(
|
|||||||
trip: TripID,
|
trip: TripID,
|
||||||
details: &mut Details,
|
details: &mut Details,
|
||||||
) -> Widget {
|
) -> Widget {
|
||||||
let (start_time, _, _, _) = app.primary.sim.trip_info(trip);
|
let (start_time, _, _, _, _) = app.primary.sim.trip_info(trip);
|
||||||
let phases = if open_trips[&trip].show_after {
|
let phases = if open_trips[&trip].show_after {
|
||||||
app.primary
|
app.primary
|
||||||
.sim
|
.sim
|
||||||
@ -300,7 +300,7 @@ pub fn finished(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn aborted(ctx: &mut EventCtx, app: &App, trip: TripID) -> Widget {
|
pub fn aborted(ctx: &mut EventCtx, app: &App, trip: TripID) -> Widget {
|
||||||
let (start_time, trip_start, trip_end, _) = app.primary.sim.trip_info(trip);
|
let (start_time, trip_start, trip_end, _, _) = app.primary.sim.trip_info(trip);
|
||||||
|
|
||||||
let mut col = vec![Text::from_multiline(vec![
|
let mut col = vec![Text::from_multiline(vec![
|
||||||
Line("A glitch in the simulation happened."),
|
Line("A glitch in the simulation happened."),
|
||||||
@ -336,7 +336,7 @@ fn make_timeline(
|
|||||||
let map = &app.primary.map;
|
let map = &app.primary.map;
|
||||||
let sim = &app.primary.sim;
|
let sim = &app.primary.sim;
|
||||||
// TODO Repeating stuff
|
// TODO Repeating stuff
|
||||||
let (start_time, trip_start, trip_end, _) = sim.trip_info(trip);
|
let (start_time, trip_start, trip_end, _, _) = sim.trip_info(trip);
|
||||||
let end_time = phases.last().as_ref().and_then(|p| p.end_time);
|
let end_time = phases.last().as_ref().and_then(|p| p.end_time);
|
||||||
|
|
||||||
let start_btn = {
|
let start_btn = {
|
||||||
|
@ -133,8 +133,10 @@ impl Layer for Throughput {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let new_compare = self.composite.has_widget("Compare before edits")
|
let new_compare = self
|
||||||
&& self.composite.is_checked("Compare before edits");
|
.composite
|
||||||
|
.maybe_is_checked("Compare before edits")
|
||||||
|
.unwrap_or(false);
|
||||||
if new_compare != self.compare {
|
if new_compare != self.compare {
|
||||||
*self = Throughput::new(ctx, app, new_compare);
|
*self = Throughput::new(ctx, app, new_compare);
|
||||||
self.composite.align_above(ctx, minimap);
|
self.composite.align_above(ctx, minimap);
|
||||||
@ -312,8 +314,10 @@ impl Layer for Delay {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let new_compare = self.composite.has_widget("Compare before edits")
|
let new_compare = self
|
||||||
&& self.composite.is_checked("Compare before edits");
|
.composite
|
||||||
|
.maybe_is_checked("Compare before edits")
|
||||||
|
.unwrap_or(false);
|
||||||
if new_compare != self.compare {
|
if new_compare != self.compare {
|
||||||
*self = Delay::new(ctx, app, new_compare);
|
*self = Delay::new(ctx, app, new_compare);
|
||||||
self.composite.align_above(ctx, minimap);
|
self.composite.align_above(ctx, minimap);
|
||||||
|
@ -165,7 +165,7 @@ fn make(ctx: &mut EventCtx, app: &App, opts: &Options) -> Composite {
|
|||||||
// Gather raw data
|
// Gather raw data
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
for (id, phases) in app.primary.sim.get_analytics().get_all_trip_phases() {
|
for (id, phases) in app.primary.sim.get_analytics().get_all_trip_phases() {
|
||||||
let (_, start, end, _) = app.primary.sim.trip_info(id);
|
let (_, start, end, _, _) = app.primary.sim.trip_info(id);
|
||||||
if !opts.off_map_starts {
|
if !opts.off_map_starts {
|
||||||
if let TripEndpoint::Border(_, _) = start {
|
if let TripEndpoint::Border(_, _) = start {
|
||||||
continue;
|
continue;
|
||||||
|
@ -28,6 +28,8 @@ struct Options {
|
|||||||
modes: BTreeSet<TripMode>,
|
modes: BTreeSet<TripMode>,
|
||||||
off_map_starts: bool,
|
off_map_starts: bool,
|
||||||
off_map_ends: bool,
|
off_map_ends: bool,
|
||||||
|
unmodified_trips: bool,
|
||||||
|
modified_trips: bool,
|
||||||
skip: usize,
|
skip: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +64,8 @@ impl TripTable {
|
|||||||
modes: TripMode::all().into_iter().collect(),
|
modes: TripMode::all().into_iter().collect(),
|
||||||
off_map_starts: true,
|
off_map_starts: true,
|
||||||
off_map_ends: true,
|
off_map_ends: true,
|
||||||
|
unmodified_trips: true,
|
||||||
|
modified_trips: true,
|
||||||
skip: 0,
|
skip: 0,
|
||||||
};
|
};
|
||||||
Box::new(TripTable {
|
Box::new(TripTable {
|
||||||
@ -145,11 +149,23 @@ impl State for TripTable {
|
|||||||
}
|
}
|
||||||
let off_map_starts = self.composite.is_checked("starting off-map");
|
let off_map_starts = self.composite.is_checked("starting off-map");
|
||||||
let off_map_ends = self.composite.is_checked("ending off-map");
|
let off_map_ends = self.composite.is_checked("ending off-map");
|
||||||
|
let unmodified_trips = self
|
||||||
|
.composite
|
||||||
|
.maybe_is_checked("trips unmodified by experiment")
|
||||||
|
.unwrap_or(true);
|
||||||
|
let modified_trips = self
|
||||||
|
.composite
|
||||||
|
.maybe_is_checked("trips modified by experiment")
|
||||||
|
.unwrap_or(true);
|
||||||
if self.opts.off_map_starts != off_map_starts
|
if self.opts.off_map_starts != off_map_starts
|
||||||
|| self.opts.off_map_ends != off_map_ends
|
|| self.opts.off_map_ends != off_map_ends
|
||||||
|
|| self.opts.unmodified_trips != unmodified_trips
|
||||||
|
|| self.opts.modified_trips != modified_trips
|
||||||
{
|
{
|
||||||
self.opts.off_map_starts = off_map_starts;
|
self.opts.off_map_starts = off_map_starts;
|
||||||
self.opts.off_map_ends = off_map_ends;
|
self.opts.off_map_ends = off_map_ends;
|
||||||
|
self.opts.unmodified_trips = unmodified_trips;
|
||||||
|
self.opts.modified_trips = modified_trips;
|
||||||
self.opts.skip = 0;
|
self.opts.skip = 0;
|
||||||
self.recalc(ctx, app);
|
self.recalc(ctx, app);
|
||||||
}
|
}
|
||||||
@ -173,6 +189,7 @@ impl State for TripTable {
|
|||||||
struct Entry {
|
struct Entry {
|
||||||
trip: TripID,
|
trip: TripID,
|
||||||
mode: TripMode,
|
mode: TripMode,
|
||||||
|
modified: bool,
|
||||||
departure: Time,
|
departure: Time,
|
||||||
duration_after: Duration,
|
duration_after: Duration,
|
||||||
duration_before: Duration,
|
duration_before: Duration,
|
||||||
@ -208,7 +225,7 @@ fn make(ctx: &mut EventCtx, app: &App, opts: &Options) -> Composite {
|
|||||||
aborted += 1;
|
aborted += 1;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let (departure, start, end, _) = sim.trip_info(*id);
|
let (departure, start, end, _, modified) = sim.trip_info(*id);
|
||||||
if !opts.off_map_starts {
|
if !opts.off_map_starts {
|
||||||
if let TripEndpoint::Border(_, _) = start {
|
if let TripEndpoint::Border(_, _) = start {
|
||||||
continue;
|
continue;
|
||||||
@ -219,6 +236,12 @@ fn make(ctx: &mut EventCtx, app: &App, opts: &Options) -> Composite {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !opts.unmodified_trips && !modified {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !opts.modified_trips && modified {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let (_, waiting) = sim.finished_trip_time(*id).unwrap();
|
let (_, waiting) = sim.finished_trip_time(*id).unwrap();
|
||||||
let duration_before = if let Some(ref times) = trip_times_before {
|
let duration_before = if let Some(ref times) = trip_times_before {
|
||||||
@ -237,6 +260,7 @@ fn make(ctx: &mut EventCtx, app: &App, opts: &Options) -> Composite {
|
|||||||
trip: *id,
|
trip: *id,
|
||||||
mode,
|
mode,
|
||||||
departure,
|
departure,
|
||||||
|
modified,
|
||||||
duration_after: *duration_after,
|
duration_after: *duration_after,
|
||||||
duration_before,
|
duration_before,
|
||||||
waiting,
|
waiting,
|
||||||
@ -263,12 +287,15 @@ fn make(ctx: &mut EventCtx, app: &App, opts: &Options) -> Composite {
|
|||||||
// Render data
|
// Render data
|
||||||
let mut rows = Vec::new();
|
let mut rows = Vec::new();
|
||||||
for x in data.into_iter().skip(opts.skip).take(ROWS) {
|
for x in data.into_iter().skip(opts.skip).take(ROWS) {
|
||||||
let mut row = vec![
|
let mut row = vec![Text::from(Line(x.trip.0.to_string())).render_ctx(ctx)];
|
||||||
Text::from(Line(x.trip.0.to_string())).render_ctx(ctx),
|
if app.primary.has_modified_trips {
|
||||||
|
row.push(Text::from(Line(if x.modified { "Yes" } else { "No" })).render_ctx(ctx));
|
||||||
|
}
|
||||||
|
row.extend(vec![
|
||||||
Text::from(Line(x.mode.ongoing_verb()).fg(color_for_mode(app, x.mode))).render_ctx(ctx),
|
Text::from(Line(x.mode.ongoing_verb()).fg(color_for_mode(app, x.mode))).render_ctx(ctx),
|
||||||
Text::from(Line(x.departure.ampm_tostring())).render_ctx(ctx),
|
Text::from(Line(x.departure.ampm_tostring())).render_ctx(ctx),
|
||||||
Text::from(Line(x.duration_after.to_string())).render_ctx(ctx),
|
Text::from(Line(x.duration_after.to_string())).render_ctx(ctx),
|
||||||
];
|
]);
|
||||||
if app.has_prebaked().is_some() {
|
if app.has_prebaked().is_some() {
|
||||||
row.push(
|
row.push(
|
||||||
Text::from_all(cmp_duration_shorter(x.duration_after, x.duration_before))
|
Text::from_all(cmp_duration_shorter(x.duration_after, x.duration_before))
|
||||||
@ -312,12 +339,15 @@ fn make(ctx: &mut EventCtx, app: &App, opts: &Options) -> Composite {
|
|||||||
Btn::text_bg2(name).build_def(ctx, None)
|
Btn::text_bg2(name).build_def(ctx, None)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut headers = vec![
|
let mut headers = vec![Line("Trip ID").draw(ctx)];
|
||||||
Line("Trip ID").draw(ctx),
|
if app.primary.has_modified_trips {
|
||||||
|
headers.push(Line("Modified").draw(ctx));
|
||||||
|
}
|
||||||
|
headers.extend(vec![
|
||||||
Line("Type").draw(ctx),
|
Line("Type").draw(ctx),
|
||||||
btn(SortBy::Departure, "Departure"),
|
btn(SortBy::Departure, "Departure"),
|
||||||
btn(SortBy::Duration, "Duration"),
|
btn(SortBy::Duration, "Duration"),
|
||||||
];
|
]);
|
||||||
if app.has_prebaked().is_some() {
|
if app.has_prebaked().is_some() {
|
||||||
headers.push(btn(SortBy::RelativeDuration, "Comparison"));
|
headers.push(btn(SortBy::RelativeDuration, "Comparison"));
|
||||||
headers.push(btn(SortBy::PercentChangeDuration, "Normalized"));
|
headers.push(btn(SortBy::PercentChangeDuration, "Normalized"));
|
||||||
@ -330,6 +360,26 @@ fn make(ctx: &mut EventCtx, app: &App, opts: &Options) -> Composite {
|
|||||||
col.push(Widget::row(vec![
|
col.push(Widget::row(vec![
|
||||||
Checkbox::text(ctx, "starting off-map", None, opts.off_map_starts),
|
Checkbox::text(ctx, "starting off-map", None, opts.off_map_starts),
|
||||||
Checkbox::text(ctx, "ending off-map", None, opts.off_map_ends),
|
Checkbox::text(ctx, "ending off-map", None, opts.off_map_ends),
|
||||||
|
if app.primary.has_modified_trips {
|
||||||
|
Checkbox::text(
|
||||||
|
ctx,
|
||||||
|
"trips unmodified by experiment",
|
||||||
|
None,
|
||||||
|
opts.unmodified_trips,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Widget::nothing()
|
||||||
|
},
|
||||||
|
if app.primary.has_modified_trips {
|
||||||
|
Checkbox::text(
|
||||||
|
ctx,
|
||||||
|
"trips modified by experiment",
|
||||||
|
None,
|
||||||
|
opts.modified_trips,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Widget::nothing()
|
||||||
|
},
|
||||||
]));
|
]));
|
||||||
let (_, unfinished, _) = app.primary.sim.num_trips();
|
let (_, unfinished, _) = app.primary.sim.num_trips();
|
||||||
col.push(
|
col.push(
|
||||||
@ -503,7 +553,7 @@ fn preview_route(g: &mut GfxCtx, app: &App, trip: TripID) -> GeomBatch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (_, start, end, _) = app.primary.sim.trip_info(trip);
|
let (_, start, end, _, _) = app.primary.sim.trip_info(trip);
|
||||||
batch.append(
|
batch.append(
|
||||||
GeomBatch::mapspace_svg(g.prerender, "system/assets/timeline/start_pos.svg")
|
GeomBatch::mapspace_svg(g.prerender, "system/assets/timeline/start_pos.svg")
|
||||||
.scale(10.0)
|
.scale(10.0)
|
||||||
|
@ -533,6 +533,7 @@ pub fn spawn_agents_around(i: IntersectionID, app: &mut App) {
|
|||||||
},
|
},
|
||||||
TripEndpoint::Border(lane.src_i, None),
|
TripEndpoint::Border(lane.src_i, None),
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
map,
|
map,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -554,6 +555,7 @@ pub fn spawn_agents_around(i: IntersectionID, app: &mut App) {
|
|||||||
},
|
},
|
||||||
TripEndpoint::Border(lane.src_i, None),
|
TripEndpoint::Border(lane.src_i, None),
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
map,
|
map,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ use ezgui::{
|
|||||||
HorizontalAlignment, Key, Line, Outcome, Spinner, Text, TextExt, VerticalAlignment, Widget,
|
HorizontalAlignment, Key, Line, Outcome, Spinner, Text, TextExt, VerticalAlignment, Widget,
|
||||||
};
|
};
|
||||||
use geom::Polygon;
|
use geom::Polygon;
|
||||||
|
use maplit::btreeset;
|
||||||
use sim::{ScenarioModifier, TripMode};
|
use sim::{ScenarioModifier, TripMode};
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ pub struct PlayScenario {
|
|||||||
impl PlayScenario {
|
impl PlayScenario {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ctx: &mut EventCtx,
|
ctx: &mut EventCtx,
|
||||||
app: &App,
|
app: &mut App,
|
||||||
name: &String,
|
name: &String,
|
||||||
modifiers: Vec<ScenarioModifier>,
|
modifiers: Vec<ScenarioModifier>,
|
||||||
) -> Box<dyn GameplayState> {
|
) -> Box<dyn GameplayState> {
|
||||||
@ -42,6 +43,10 @@ impl GameplayState for PlayScenario {
|
|||||||
app: &mut App,
|
app: &mut App,
|
||||||
_: &mut SandboxControls,
|
_: &mut SandboxControls,
|
||||||
) -> Option<Transition> {
|
) -> Option<Transition> {
|
||||||
|
// This should really happen in the constructor once, but the old PlayScenario's
|
||||||
|
// on_destroy can wipe this out.
|
||||||
|
app.primary.has_modified_trips = !self.modifiers.is_empty();
|
||||||
|
|
||||||
match self.top_center.event(ctx) {
|
match self.top_center.event(ctx) {
|
||||||
Some(Outcome::Clicked(x)) => match x.as_ref() {
|
Some(Outcome::Clicked(x)) => match x.as_ref() {
|
||||||
"change map" => {
|
"change map" => {
|
||||||
@ -92,6 +97,10 @@ impl GameplayState for PlayScenario {
|
|||||||
fn draw(&self, g: &mut GfxCtx, _: &App) {
|
fn draw(&self, g: &mut GfxCtx, _: &App) {
|
||||||
self.top_center.draw(g);
|
self.top_center.draw(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_destroy(&self, app: &mut App) {
|
||||||
|
app.primary.has_modified_trips = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_top_center(
|
fn make_top_center(
|
||||||
@ -308,7 +317,7 @@ impl ChangeMode {
|
|||||||
Widget::dropdown(
|
Widget::dropdown(
|
||||||
ctx,
|
ctx,
|
||||||
"to_mode",
|
"to_mode",
|
||||||
TripMode::Drive,
|
TripMode::Bike,
|
||||||
TripMode::all()
|
TripMode::all()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|m| Choice::new(m.ongoing_verb(), m))
|
.map(|m| Choice::new(m.ongoing_verb(), m))
|
||||||
@ -322,10 +331,10 @@ impl ChangeMode {
|
|||||||
Spinner::new(ctx, (1, 100), 50).named("pct_ppl"),
|
Spinner::new(ctx, (1, 100), 50).named("pct_ppl"),
|
||||||
]),
|
]),
|
||||||
"Types of trips to convert:".draw_text(ctx),
|
"Types of trips to convert:".draw_text(ctx),
|
||||||
checkbox_per_mode(ctx, app, &BTreeSet::new()),
|
checkbox_per_mode(ctx, app, &btreeset! { TripMode::Drive }),
|
||||||
Widget::row(vec![
|
Widget::row(vec![
|
||||||
"Departing from:".draw_text(ctx),
|
"Departing from:".draw_text(ctx),
|
||||||
AreaSlider::new(ctx, 0.25 * ctx.canvas.window_width, 0.3).named("depart from"),
|
AreaSlider::new(ctx, 0.25 * ctx.canvas.window_width, 0.0).named("depart from"),
|
||||||
]),
|
]),
|
||||||
Widget::row(vec![
|
Widget::row(vec![
|
||||||
"Departing until:".draw_text(ctx),
|
"Departing until:".draw_text(ctx),
|
||||||
|
@ -138,7 +138,15 @@ impl Scenario {
|
|||||||
&mut tmp_rng,
|
&mut tmp_rng,
|
||||||
map,
|
map,
|
||||||
);
|
);
|
||||||
spawner.schedule_trip(person, t.depart, spec, t.trip.start(map), t.cancelled, map);
|
spawner.schedule_trip(
|
||||||
|
person,
|
||||||
|
t.depart,
|
||||||
|
spec,
|
||||||
|
t.trip.start(map),
|
||||||
|
t.cancelled,
|
||||||
|
t.modified,
|
||||||
|
map,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ pub enum TripSpec {
|
|||||||
|
|
||||||
// This structure is created temporarily by a Scenario or to interactively spawn agents.
|
// This structure is created temporarily by a Scenario or to interactively spawn agents.
|
||||||
pub struct TripSpawner {
|
pub struct TripSpawner {
|
||||||
trips: Vec<(PersonID, Time, TripSpec, TripEndpoint, bool)>,
|
trips: Vec<(PersonID, Time, TripSpec, TripEndpoint, bool, bool)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TripSpawner {
|
impl TripSpawner {
|
||||||
@ -77,6 +77,7 @@ impl TripSpawner {
|
|||||||
mut spec: TripSpec,
|
mut spec: TripSpec,
|
||||||
trip_start: TripEndpoint,
|
trip_start: TripEndpoint,
|
||||||
cancelled: bool,
|
cancelled: bool,
|
||||||
|
modified: bool,
|
||||||
map: &Map,
|
map: &Map,
|
||||||
) {
|
) {
|
||||||
// TODO We'll want to repeat this validation when we spawn stuff later for a second leg...
|
// TODO We'll want to repeat this validation when we spawn stuff later for a second leg...
|
||||||
@ -187,7 +188,7 @@ impl TripSpawner {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.trips
|
self.trips
|
||||||
.push((person.id, start_time, spec, trip_start, cancelled));
|
.push((person.id, start_time, spec, trip_start, cancelled, modified));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finalize(
|
pub fn finalize(
|
||||||
@ -223,7 +224,8 @@ impl TripSpawner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
timer.start_iter("spawn trips", paths.len());
|
timer.start_iter("spawn trips", paths.len());
|
||||||
for ((p, start_time, spec, trip_start, cancelled), maybe_req, maybe_path) in paths {
|
for ((p, start_time, spec, trip_start, cancelled, modified), maybe_req, maybe_path) in paths
|
||||||
|
{
|
||||||
timer.next();
|
timer.next();
|
||||||
|
|
||||||
// TODO clone() is super weird to do here, but we just need to make the borrow checker
|
// TODO clone() is super weird to do here, but we just need to make the borrow checker
|
||||||
@ -248,6 +250,7 @@ impl TripSpawner {
|
|||||||
} else {
|
} else {
|
||||||
TripMode::Drive
|
TripMode::Drive
|
||||||
},
|
},
|
||||||
|
modified,
|
||||||
legs,
|
legs,
|
||||||
map,
|
map,
|
||||||
)
|
)
|
||||||
@ -268,6 +271,7 @@ impl TripSpawner {
|
|||||||
} else {
|
} else {
|
||||||
TripMode::Drive
|
TripMode::Drive
|
||||||
},
|
},
|
||||||
|
modified,
|
||||||
legs,
|
legs,
|
||||||
map,
|
map,
|
||||||
)
|
)
|
||||||
@ -288,6 +292,7 @@ impl TripSpawner {
|
|||||||
start_time,
|
start_time,
|
||||||
trip_start,
|
trip_start,
|
||||||
TripMode::Drive,
|
TripMode::Drive,
|
||||||
|
modified,
|
||||||
legs,
|
legs,
|
||||||
map,
|
map,
|
||||||
)
|
)
|
||||||
@ -297,6 +302,7 @@ impl TripSpawner {
|
|||||||
start_time,
|
start_time,
|
||||||
trip_start,
|
trip_start,
|
||||||
TripMode::Walk,
|
TripMode::Walk,
|
||||||
|
modified,
|
||||||
vec![TripLeg::Walk(goal.clone())],
|
vec![TripLeg::Walk(goal.clone())],
|
||||||
map,
|
map,
|
||||||
),
|
),
|
||||||
@ -313,7 +319,15 @@ impl TripSpawner {
|
|||||||
}
|
}
|
||||||
DrivingGoal::Border(_, _, _) => {}
|
DrivingGoal::Border(_, _, _) => {}
|
||||||
};
|
};
|
||||||
trips.new_trip(person.id, start_time, trip_start, TripMode::Bike, legs, map)
|
trips.new_trip(
|
||||||
|
person.id,
|
||||||
|
start_time,
|
||||||
|
trip_start,
|
||||||
|
TripMode::Bike,
|
||||||
|
modified,
|
||||||
|
legs,
|
||||||
|
map,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
TripSpec::UsingTransit {
|
TripSpec::UsingTransit {
|
||||||
route,
|
route,
|
||||||
@ -328,6 +342,7 @@ impl TripSpawner {
|
|||||||
start_time,
|
start_time,
|
||||||
trip_start,
|
trip_start,
|
||||||
TripMode::Transit,
|
TripMode::Transit,
|
||||||
|
modified,
|
||||||
vec![
|
vec![
|
||||||
TripLeg::Walk(walk_to.clone()),
|
TripLeg::Walk(walk_to.clone()),
|
||||||
TripLeg::RideBus(route, stop2),
|
TripLeg::RideBus(route, stop2),
|
||||||
@ -341,6 +356,7 @@ impl TripSpawner {
|
|||||||
start_time,
|
start_time,
|
||||||
trip_start,
|
trip_start,
|
||||||
mode,
|
mode,
|
||||||
|
modified,
|
||||||
vec![TripLeg::Remote(to)],
|
vec![TripLeg::Remote(to)],
|
||||||
map,
|
map,
|
||||||
),
|
),
|
||||||
|
@ -964,8 +964,9 @@ impl Sim {
|
|||||||
self.trips.trip_to_agent(id)
|
self.trips.trip_to_agent(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// (start time, start position, end position, trip type)
|
// (start time, start position, end position, trip type, modified)
|
||||||
pub fn trip_info(&self, id: TripID) -> (Time, TripEndpoint, TripEndpoint, TripMode) {
|
// TODO Time for a struct
|
||||||
|
pub fn trip_info(&self, id: TripID) -> (Time, TripEndpoint, TripEndpoint, TripMode, bool) {
|
||||||
self.trips.trip_info(id)
|
self.trips.trip_info(id)
|
||||||
}
|
}
|
||||||
// If trip is finished, returns (total time, total waiting time)
|
// If trip is finished, returns (total time, total waiting time)
|
||||||
|
@ -91,6 +91,7 @@ impl TripManager {
|
|||||||
departure: Time,
|
departure: Time,
|
||||||
start: TripEndpoint,
|
start: TripEndpoint,
|
||||||
mode: TripMode,
|
mode: TripMode,
|
||||||
|
modified: bool,
|
||||||
legs: Vec<TripLeg>,
|
legs: Vec<TripLeg>,
|
||||||
map: &Map,
|
map: &Map,
|
||||||
) -> TripID {
|
) -> TripID {
|
||||||
@ -125,6 +126,7 @@ impl TripManager {
|
|||||||
legs: VecDeque::from(legs),
|
legs: VecDeque::from(legs),
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
|
modified,
|
||||||
};
|
};
|
||||||
self.unfinished_trips += 1;
|
self.unfinished_trips += 1;
|
||||||
let person = &mut self.people[trip.person.0];
|
let person = &mut self.people[trip.person.0];
|
||||||
@ -855,9 +857,15 @@ impl TripManager {
|
|||||||
std::mem::replace(&mut self.events, Vec::new())
|
std::mem::replace(&mut self.events, Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trip_info(&self, id: TripID) -> (Time, TripEndpoint, TripEndpoint, TripMode) {
|
pub fn trip_info(&self, id: TripID) -> (Time, TripEndpoint, TripEndpoint, TripMode, bool) {
|
||||||
let t = &self.trips[id.0];
|
let t = &self.trips[id.0];
|
||||||
(t.departure, t.start.clone(), t.end.clone(), t.mode)
|
(
|
||||||
|
t.departure,
|
||||||
|
t.start.clone(),
|
||||||
|
t.end.clone(),
|
||||||
|
t.mode,
|
||||||
|
t.modified,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
pub fn finished_trip_time(&self, id: TripID) -> Option<(Duration, Duration)> {
|
pub fn finished_trip_time(&self, id: TripID) -> Option<(Duration, Duration)> {
|
||||||
let t = &self.trips[id.0];
|
let t = &self.trips[id.0];
|
||||||
@ -1272,6 +1280,7 @@ struct Trip {
|
|||||||
start: TripEndpoint,
|
start: TripEndpoint,
|
||||||
end: TripEndpoint,
|
end: TripEndpoint,
|
||||||
person: PersonID,
|
person: PersonID,
|
||||||
|
modified: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Trip {
|
impl Trip {
|
||||||
|
Loading…
Reference in New Issue
Block a user