tab-ify lanes and intersections, in a really messy quick way

This commit is contained in:
Dustin Carlino 2020-03-24 11:26:17 -07:00
parent 8b1f66a3ed
commit cbc214ed38
4 changed files with 207 additions and 90 deletions

View File

@ -123,6 +123,7 @@ pub fn info(
inner.extend(person::info(ctx, app, ppl[idx], None, Vec::new()));
rows.push(Widget::col(inner).bg(colors::INNER_PANEL_BG));
}
_ => unreachable!(),
}
for p in app.primary.sim.get_parked_cars_by_owner(id) {

View File

@ -1,17 +1,24 @@
use crate::app::App;
use crate::helpers::rotating_color_map;
use crate::info::throughput;
use crate::info::{throughput, InfoTab};
use abstutil::prettyprint_usize;
use ezgui::{EventCtx, Line, Plot, PlotOptions, Series, Text, Widget};
use ezgui::{Btn, EventCtx, Line, Plot, PlotOptions, Series, Text, Widget};
use geom::{Duration, Statistic, Time};
use map_model::{IntersectionID, IntersectionType};
use sim::Analytics;
use std::collections::BTreeSet;
#[derive(Clone)]
pub enum Tab {
Throughput,
Delay,
}
pub fn info(
ctx: &EventCtx,
app: &App,
id: IntersectionID,
tab: InfoTab,
header_btns: Widget,
action_btns: Vec<Widget>,
) -> Vec<Widget> {
@ -39,46 +46,67 @@ pub fn info(
// TODO The spacing is ignored, so use -
txt.add(Line(format!("- {}", r)));
}
rows.extend(action_btns);
let trip_lines = app.primary.sim.count_trips_involving_border(id).describe();
if !trip_lines.is_empty() {
txt.add(Line(""));
for line in trip_lines {
txt.add(Line(line));
}
}
txt.add(Line("Throughput").roboto_bold());
txt.add(Line(format!(
"Since midnight: {} agents crossed",
prettyprint_usize(
app.primary
.sim
.get_analytics()
.thruput_stats
.count_per_intersection
.get(id)
)
)));
txt.add(Line(format!("In 20 minute buckets:")));
rows.push(txt.draw(ctx));
rows.push(
throughput(ctx, app, move |a, t| {
a.throughput_intersection(t, id, Duration::minutes(20))
})
.margin(10),
);
// TODO Inactive
// TODO Naming, style...
rows.push(Widget::row(vec![
Btn::text_bg2("Main").build_def(ctx, None),
Btn::text_bg2("Throughput").build_def(ctx, None), // TODO temporary name
if app.primary.map.get_i(id).is_traffic_signal() {
Btn::text_bg2("Delay").build_def(ctx, None)
} else {
Widget::nothing()
},
]));
if app.primary.map.get_i(id).is_traffic_signal() {
let mut txt = Text::from(Line(""));
txt.add(Line("Delay").roboto_bold());
txt.add(Line(format!("In 20 minute buckets:")));
rows.push(txt.draw(ctx));
match tab {
InfoTab::Nil => {
rows.extend(action_btns);
rows.push(delay(ctx, app, id, Duration::minutes(20)).margin(10));
let trip_lines = app.primary.sim.count_trips_involving_border(id).describe();
if !trip_lines.is_empty() {
let mut txt = Text::new();
for line in trip_lines {
txt.add(Line(line));
}
rows.push(txt.draw(ctx));
}
}
InfoTab::Intersection(Tab::Throughput) => {
let mut txt = Text::new();
txt.add(Line("Throughput").roboto_bold());
txt.add(Line(format!(
"Since midnight: {} agents crossed",
prettyprint_usize(
app.primary
.sim
.get_analytics()
.thruput_stats
.count_per_intersection
.get(id)
)
)));
txt.add(Line(format!("In 20 minute buckets:")));
rows.push(txt.draw(ctx));
rows.push(
throughput(ctx, app, move |a, t| {
a.throughput_intersection(t, id, Duration::minutes(20))
})
.margin(10),
);
}
InfoTab::Intersection(Tab::Delay) => {
assert!(app.primary.map.get_i(id).is_traffic_signal());
let mut txt = Text::from(Line("Delay").roboto_bold());
txt.add(Line(format!("In 20 minute buckets:")));
rows.push(txt.draw(ctx));
rows.push(delay(ctx, app, id, Duration::minutes(20)).margin(10));
}
_ => unreachable!(),
}
rows

View File

@ -1,21 +1,28 @@
use crate::app::App;
use crate::info::{make_table, throughput};
use crate::info::{make_table, throughput, InfoTab};
use abstutil::prettyprint_usize;
use ezgui::{EventCtx, Line, Text, TextExt, Widget};
use ezgui::{Btn, EventCtx, Line, Text, TextExt, Widget};
use geom::Duration;
use map_model::LaneID;
#[derive(Clone)]
pub enum Tab {
OSM,
Debug,
Throughput,
}
pub fn info(
ctx: &EventCtx,
app: &App,
id: LaneID,
tab: InfoTab,
header_btns: Widget,
action_btns: Vec<Widget>,
) -> Vec<Widget> {
let mut rows = vec![];
let map = &app.primary.map;
let l = map.get_l(id);
let r = map.get_r(l.parent);
@ -25,28 +32,45 @@ pub fn info(
header_btns,
]));
rows.push(format!("@ {}", r.get_name()).draw_text(ctx));
rows.extend(action_btns);
// Properties
{
let mut kv = Vec::new();
// TODO Inactive
// TODO Naming, style...
rows.push(Widget::row(vec![
Btn::text_bg2("Main").build_def(ctx, None),
Btn::text_bg2("OpenStreetMap").build_def(ctx, None),
Btn::text_bg2("Debug").build_def(ctx, None),
Btn::text_bg2("Traffic").build_def(ctx, None),
]));
if !l.is_sidewalk() {
kv.push(("Type".to_string(), l.lane_type.describe().to_string()));
match tab {
InfoTab::Nil => {
rows.extend(action_btns);
let mut kv = Vec::new();
if !l.is_sidewalk() {
kv.push(("Type".to_string(), l.lane_type.describe().to_string()));
}
if l.is_parking() {
kv.push((
"Parking".to_string(),
format!("{} spots, parallel parking", l.number_parking_spots()),
));
} else {
kv.push(("Speed limit".to_string(), r.get_speed_limit().to_string()));
}
kv.push(("Length".to_string(), l.length().describe_rounded()));
rows.extend(make_table(ctx, kv));
}
if l.is_parking() {
kv.push((
"Parking".to_string(),
format!("{} spots, parallel parking", l.number_parking_spots()),
));
} else {
kv.push(("Speed limit".to_string(), r.get_speed_limit().to_string()));
InfoTab::Lane(Tab::OSM) => {
rows.extend(make_table(ctx, r.osm_tags.clone().into_iter().collect()));
}
InfoTab::Lane(Tab::Debug) => {
let mut kv = Vec::new();
kv.push(("Length".to_string(), l.length().describe_rounded()));
if app.opts.dev {
kv.push(("Parent".to_string(), r.id.to_string()));
if l.is_driving() {
@ -88,38 +112,35 @@ pub fn info(
),
));
for (k, v) in &r.osm_tags {
kv.push((k.to_string(), v.to_string()));
}
rows.extend(make_table(ctx, kv));
}
InfoTab::Lane(Tab::Throughput) => {
// Since this applies to the entire road, ignore lane type.
let mut txt = Text::from(Line(""));
txt.add(Line("Throughput (entire road)").roboto_bold());
txt.add(Line(format!(
"Since midnight: {} agents crossed",
prettyprint_usize(
app.primary
.sim
.get_analytics()
.thruput_stats
.count_per_road
.get(r.id)
)
)));
txt.add(Line(format!("In 20 minute buckets:")));
rows.push(txt.draw(ctx));
rows.extend(make_table(ctx, kv));
}
if !l.is_parking() {
let mut txt = Text::from(Line(""));
txt.add(Line("Throughput (entire road)").roboto_bold());
txt.add(Line(format!(
"Since midnight: {} agents crossed",
prettyprint_usize(
app.primary
.sim
.get_analytics()
.thruput_stats
.count_per_road
.get(r.id)
)
)));
txt.add(Line(format!("In 20 minute buckets:")));
rows.push(txt.draw(ctx));
let r = app.primary.map.get_l(id).parent;
rows.push(
throughput(ctx, app, move |a, t| {
a.throughput_road(t, r, Duration::minutes(20))
})
.margin(10),
);
let r = app.primary.map.get_l(id).parent;
rows.push(
throughput(ctx, app, move |a, t| {
a.throughput_road(t, r, Duration::minutes(20))
})
.margin(10),
);
}
_ => unreachable!(),
}
rows

View File

@ -42,6 +42,8 @@ pub enum InfoTab {
// If we're live updating, the people inside could change! We're choosing to freeze the list
// here.
BldgPeople(Vec<PersonID>, usize),
Lane(lane::Tab),
Intersection(intersection::Tab),
}
pub struct TripDetails {
@ -139,9 +141,12 @@ impl InfoPanel {
.align_right();
let (col, trip_details) = match id.clone() {
ID::Road(_) => unreachable!(),
ID::Lane(id) => (lane::info(ctx, app, id, header_btns, action_btns), None),
ID::Lane(id) => (
lane::info(ctx, app, id, tab.clone(), header_btns, action_btns),
None,
),
ID::Intersection(id) => (
intersection::info(ctx, app, id, header_btns, action_btns),
intersection::info(ctx, app, id, tab.clone(), header_btns, action_btns),
None,
),
ID::Turn(_) => unreachable!(),
@ -407,6 +412,68 @@ impl InfoPanel {
maybe_speed,
);
return (false, None);
// TODO For lanes. This is an insane mess...
} else if action == "Main" {
*self = InfoPanel::new(
self.id.clone(),
// TODO For both lanes and intersections...
InfoTab::Nil,
ctx,
app,
self.actions.clone(),
maybe_speed,
);
return (false, None);
} else if action == "OpenStreetMap" {
*self = InfoPanel::new(
self.id.clone(),
InfoTab::Lane(lane::Tab::OSM),
ctx,
app,
self.actions.clone(),
maybe_speed,
);
return (false, None);
} else if action == "Debug" {
*self = InfoPanel::new(
self.id.clone(),
InfoTab::Lane(lane::Tab::Debug),
ctx,
app,
self.actions.clone(),
maybe_speed,
);
return (false, None);
} else if action == "Traffic" {
*self = InfoPanel::new(
self.id.clone(),
InfoTab::Lane(lane::Tab::Throughput),
ctx,
app,
self.actions.clone(),
maybe_speed,
);
return (false, None);
} else if action == "Throughput" {
*self = InfoPanel::new(
self.id.clone(),
InfoTab::Intersection(intersection::Tab::Throughput),
ctx,
app,
self.actions.clone(),
maybe_speed,
);
return (false, None);
} else if action == "Delay" {
*self = InfoPanel::new(
self.id.clone(),
InfoTab::Intersection(intersection::Tab::Delay),
ctx,
app,
self.actions.clone(),
maybe_speed,
);
return (false, None);
} else {
app.primary.current_selection = Some(self.id.clone());
(true, Some(Transition::ApplyObjectAction(action)))