mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
collect and draw info on road throughput per some bucket of time. much
work needed.
This commit is contained in:
parent
0fb358b38d
commit
b24100caba
@ -2,6 +2,7 @@ use crate::common::CommonState;
|
||||
use crate::game::{State, Transition};
|
||||
use crate::helpers::ID;
|
||||
use crate::ui::UI;
|
||||
use abstutil::prettyprint_usize;
|
||||
use ezgui::{hotkey, Color, EventCtx, GfxCtx, Key, Line, ModalMenu, Text};
|
||||
use geom::Duration;
|
||||
use sim::CarID;
|
||||
@ -106,6 +107,12 @@ fn info_for(id: ID, ui: &UI, ctx: &EventCtx) -> Text {
|
||||
to, restriction
|
||||
)));
|
||||
}
|
||||
|
||||
txt.add(Line(""));
|
||||
txt.add(Line(format!(
|
||||
"{} total agents crossed",
|
||||
prettyprint_usize(sim.get_analytics().thruput_stats.count_per_road.get(r.id))
|
||||
)));
|
||||
}
|
||||
ID::Intersection(id) => {
|
||||
let i = map.get_i(id);
|
||||
@ -146,6 +153,17 @@ fn info_for(id: ID, ui: &UI, ctx: &EventCtx) -> Text {
|
||||
txt.add(Line(line));
|
||||
}
|
||||
}
|
||||
|
||||
txt.add(Line(""));
|
||||
txt.add(Line(format!(
|
||||
"{} total agents crossed",
|
||||
prettyprint_usize(
|
||||
sim.get_analytics()
|
||||
.thruput_stats
|
||||
.count_per_intersection
|
||||
.get(id)
|
||||
)
|
||||
)));
|
||||
}
|
||||
// TODO No way to trigger the info panel for this yet.
|
||||
ID::Turn(id) => {
|
||||
@ -238,7 +256,7 @@ fn info_for(id: ID, ui: &UI, ctx: &EventCtx) -> Text {
|
||||
}
|
||||
txt.add(Line(format!(
|
||||
" {} passengers total (any stop)",
|
||||
abstutil::prettyprint_usize(passengers.get(r.id))
|
||||
prettyprint_usize(passengers.get(r.id))
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +172,11 @@ impl Yvalue<usize> for usize {
|
||||
((*self as f64) * percent) as usize
|
||||
}
|
||||
fn to_percent(self, max: usize) -> f64 {
|
||||
(self as f64) / (max as f64)
|
||||
if max == 0 {
|
||||
0.0
|
||||
} else {
|
||||
(self as f64) / (max as f64)
|
||||
}
|
||||
}
|
||||
fn prettyprint(self) -> String {
|
||||
abstutil::prettyprint_usize(self)
|
||||
@ -183,7 +187,11 @@ impl Yvalue<Duration> for Duration {
|
||||
percent * *self
|
||||
}
|
||||
fn to_percent(self, max: Duration) -> f64 {
|
||||
self / max
|
||||
if max == Duration::ZERO {
|
||||
0.0
|
||||
} else {
|
||||
self / max
|
||||
}
|
||||
}
|
||||
fn prettyprint(self) -> String {
|
||||
self.minimal_tostring()
|
||||
|
@ -205,6 +205,37 @@ impl State for SandboxMode {
|
||||
})));
|
||||
}
|
||||
}
|
||||
if let Some(ID::Lane(l)) = ui.primary.current_selection {
|
||||
if ctx
|
||||
.input
|
||||
.contextual_action(Key::T, "throughput over 1-hour buckets")
|
||||
{
|
||||
let r = ui.primary.map.get_l(l).parent;
|
||||
let t = ui.primary.sim.time();
|
||||
let bucket = Duration::minutes(60);
|
||||
self.overlay = overlays::Overlays::RoadThroughput {
|
||||
t,
|
||||
bucket,
|
||||
r,
|
||||
plot: overlays::calculate_road_thruput(r, bucket, ctx, ui),
|
||||
};
|
||||
}
|
||||
}
|
||||
if let Some(ID::Intersection(i)) = ui.primary.current_selection {
|
||||
if ctx
|
||||
.input
|
||||
.contextual_action(Key::T, "throughput over 1-hour buckets")
|
||||
{
|
||||
let t = ui.primary.sim.time();
|
||||
let bucket = Duration::minutes(60);
|
||||
self.overlay = overlays::Overlays::IntersectionThroughput {
|
||||
t,
|
||||
bucket,
|
||||
i,
|
||||
plot: overlays::calculate_intersection_thruput(i, bucket, ctx, ui),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if self.save_tools.action("save sim state") {
|
||||
self.speed.pause();
|
||||
|
@ -10,7 +10,7 @@ use crate::ui::{ShowEverything, UI};
|
||||
use abstutil::{prettyprint_usize, Counter};
|
||||
use ezgui::{Choice, Color, EventCtx, GfxCtx, Key, Line, MenuUnderButton, Text};
|
||||
use geom::Duration;
|
||||
use map_model::{LaneType, PathStep};
|
||||
use map_model::{IntersectionID, LaneType, PathStep, RoadID};
|
||||
use sim::{ParkingSpot, TripMode};
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
|
||||
@ -19,6 +19,18 @@ pub enum Overlays {
|
||||
ParkingAvailability(Duration, RoadColorer),
|
||||
IntersectionDelay(Duration, ObjectColorer),
|
||||
Throughput(Duration, ObjectColorer),
|
||||
RoadThroughput {
|
||||
t: Duration,
|
||||
bucket: Duration,
|
||||
r: RoadID,
|
||||
plot: Plot<usize>,
|
||||
},
|
||||
IntersectionThroughput {
|
||||
t: Duration,
|
||||
bucket: Duration,
|
||||
i: IntersectionID,
|
||||
plot: Plot<usize>,
|
||||
},
|
||||
FinishedTrips(Duration, Plot<usize>),
|
||||
Chokepoints(Duration, ObjectColorer),
|
||||
BikeNetwork(RoadColorer),
|
||||
@ -54,31 +66,79 @@ impl Overlays {
|
||||
})?;
|
||||
Some(Transition::PopWithData(Box::new(move |state, ui, ctx| {
|
||||
let mut sandbox = state.downcast_mut::<SandboxMode>().unwrap();
|
||||
sandbox.overlay = Overlays::recalc(&choice, ui, ctx);
|
||||
let time = ui.primary.sim.time();
|
||||
sandbox.overlay = match choice.as_ref() {
|
||||
"none" => Overlays::Inactive,
|
||||
"parking availability" => Overlays::ParkingAvailability(
|
||||
time,
|
||||
calculate_parking_heatmap(ctx, ui),
|
||||
),
|
||||
"intersection delay" => Overlays::IntersectionDelay(
|
||||
time,
|
||||
calculate_intersection_delay(ctx, ui),
|
||||
),
|
||||
"cumulative throughput" => {
|
||||
Overlays::Throughput(time, calculate_thruput(ctx, ui))
|
||||
}
|
||||
"finished trips" => Overlays::FinishedTrips(time, trip_stats(ctx, ui)),
|
||||
"chokepoints" => {
|
||||
Overlays::Chokepoints(time, calculate_chokepoints(ctx, ui))
|
||||
}
|
||||
"bike network" => {
|
||||
Overlays::BikeNetwork(calculate_bike_network(ctx, ui))
|
||||
}
|
||||
"bus network" => Overlays::BusNetwork(calculate_bus_network(ctx, ui)),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
})))
|
||||
},
|
||||
))));
|
||||
}
|
||||
|
||||
let (choice, time) = match self {
|
||||
Overlays::Inactive => {
|
||||
return None;
|
||||
let now = ui.primary.sim.time();
|
||||
match self {
|
||||
// Don't bother with Inactive, BusRoute, BusDelaysOverTime, BikeNetwork, BusNetwork --
|
||||
// nothing needed or the gameplay mode will update it.
|
||||
Overlays::ParkingAvailability(ref mut t, ref mut x) if now != *t => {
|
||||
*t = now;
|
||||
*x = calculate_parking_heatmap(ctx, ui);
|
||||
}
|
||||
Overlays::ParkingAvailability(t, _) => ("parking availability", *t),
|
||||
Overlays::IntersectionDelay(t, _) => ("intersection delay", *t),
|
||||
Overlays::Throughput(t, _) => ("cumulative throughput", *t),
|
||||
Overlays::FinishedTrips(t, _) => ("finished trips", *t),
|
||||
Overlays::Chokepoints(t, _) => ("chokepoints", *t),
|
||||
Overlays::BikeNetwork(_) => ("bike network", ui.primary.sim.time()),
|
||||
Overlays::BusNetwork(_) => ("bus network", ui.primary.sim.time()),
|
||||
Overlays::BusRoute(_) | Overlays::BusDelaysOverTime(_) => {
|
||||
// The gameplay mode will update it.
|
||||
return None;
|
||||
Overlays::IntersectionDelay(t, x) if now != *t => {
|
||||
*t = now;
|
||||
*x = calculate_intersection_delay(ctx, ui);
|
||||
}
|
||||
Overlays::Throughput(t, x) if now != *t => {
|
||||
*t = now;
|
||||
*x = calculate_thruput(ctx, ui);
|
||||
}
|
||||
Overlays::FinishedTrips(t, x) if now != *t => {
|
||||
*t = now;
|
||||
*x = trip_stats(ctx, ui);
|
||||
}
|
||||
Overlays::RoadThroughput {
|
||||
ref mut t,
|
||||
bucket,
|
||||
r,
|
||||
ref mut plot,
|
||||
} if now != *t => {
|
||||
*t = now;
|
||||
*plot = calculate_road_thruput(*r, *bucket, ctx, ui);
|
||||
}
|
||||
Overlays::IntersectionThroughput {
|
||||
ref mut t,
|
||||
bucket,
|
||||
i,
|
||||
ref mut plot,
|
||||
} if now != *t => {
|
||||
*t = now;
|
||||
*plot = calculate_intersection_thruput(*i, *bucket, ctx, ui);
|
||||
}
|
||||
Overlays::Chokepoints(t, x) if now != *t => {
|
||||
*t = now;
|
||||
*x = calculate_chokepoints(ctx, ui);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
if time != ui.primary.sim.time() {
|
||||
*self = Overlays::recalc(choice, ui, ctx);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@ -98,14 +158,16 @@ impl Overlays {
|
||||
heatmap.draw(g, ui);
|
||||
true
|
||||
}
|
||||
Overlays::FinishedTrips(_, ref s) => {
|
||||
Overlays::RoadThroughput { ref plot, .. }
|
||||
| Overlays::IntersectionThroughput { ref plot, .. }
|
||||
| Overlays::FinishedTrips(_, ref plot) => {
|
||||
ui.draw(
|
||||
g,
|
||||
DrawOptions::new(),
|
||||
&ui.primary.sim,
|
||||
&ShowEverything::new(),
|
||||
);
|
||||
s.draw(g);
|
||||
plot.draw(g);
|
||||
true
|
||||
}
|
||||
Overlays::BusDelaysOverTime(ref s) => {
|
||||
@ -124,28 +186,9 @@ impl Overlays {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn recalc(choice: &str, ui: &UI, ctx: &mut EventCtx) -> Overlays {
|
||||
let time = ui.primary.sim.time();
|
||||
match choice {
|
||||
"none" => Overlays::Inactive,
|
||||
"parking availability" => {
|
||||
Overlays::ParkingAvailability(time, calculate_parking_heatmap(ctx, ui))
|
||||
}
|
||||
"intersection delay" => {
|
||||
Overlays::IntersectionDelay(time, calculate_intersection_delay(ctx, ui))
|
||||
}
|
||||
"cumulative throughput" => Overlays::Throughput(time, calculate_thruput(ctx, ui)),
|
||||
"finished trips" => Overlays::FinishedTrips(time, trip_stats(ui, ctx)),
|
||||
"chokepoints" => Overlays::Chokepoints(time, calculate_chokepoints(ctx, ui)),
|
||||
"bike network" => Overlays::BikeNetwork(calculate_bike_network(ctx, ui)),
|
||||
"bus network" => Overlays::BusNetwork(calculate_bus_network(ctx, ui)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_parking_heatmap(ctx: &mut EventCtx, ui: &UI) -> RoadColorer {
|
||||
fn calculate_parking_heatmap(ctx: &EventCtx, ui: &UI) -> RoadColorer {
|
||||
let (filled_spots, avail_spots) = ui.primary.sim.get_all_parking_spots();
|
||||
let mut txt = Text::prompt("parking availability");
|
||||
txt.add(Line(format!(
|
||||
@ -217,7 +260,7 @@ fn calculate_parking_heatmap(ctx: &mut EventCtx, ui: &UI) -> RoadColorer {
|
||||
colorer.build(ctx, &ui.primary.map)
|
||||
}
|
||||
|
||||
fn calculate_intersection_delay(ctx: &mut EventCtx, ui: &UI) -> ObjectColorer {
|
||||
fn calculate_intersection_delay(ctx: &EventCtx, ui: &UI) -> ObjectColorer {
|
||||
let fast = Color::GREEN;
|
||||
let meh = Color::YELLOW;
|
||||
let slow = Color::RED;
|
||||
@ -243,7 +286,7 @@ fn calculate_intersection_delay(ctx: &mut EventCtx, ui: &UI) -> ObjectColorer {
|
||||
colorer.build(ctx, &ui.primary.map)
|
||||
}
|
||||
|
||||
fn calculate_chokepoints(ctx: &mut EventCtx, ui: &UI) -> ObjectColorer {
|
||||
fn calculate_chokepoints(ctx: &EventCtx, ui: &UI) -> ObjectColorer {
|
||||
const TOP_N: usize = 10;
|
||||
|
||||
let mut colorer = ObjectColorerBuilder::new(
|
||||
@ -285,7 +328,7 @@ fn calculate_chokepoints(ctx: &mut EventCtx, ui: &UI) -> ObjectColorer {
|
||||
colorer.build(ctx, &ui.primary.map)
|
||||
}
|
||||
|
||||
fn calculate_thruput(ctx: &mut EventCtx, ui: &UI) -> ObjectColorer {
|
||||
fn calculate_thruput(ctx: &EventCtx, ui: &UI) -> ObjectColorer {
|
||||
let light = Color::GREEN;
|
||||
let medium = Color::YELLOW;
|
||||
let heavy = Color::RED;
|
||||
@ -339,7 +382,7 @@ fn calculate_thruput(ctx: &mut EventCtx, ui: &UI) -> ObjectColorer {
|
||||
colorer.build(ctx, &ui.primary.map)
|
||||
}
|
||||
|
||||
fn calculate_bike_network(ctx: &mut EventCtx, ui: &UI) -> RoadColorer {
|
||||
fn calculate_bike_network(ctx: &EventCtx, ui: &UI) -> RoadColorer {
|
||||
let mut colorer = RoadColorerBuilder::new(
|
||||
Text::prompt("bike networks"),
|
||||
vec![("bike lanes", Color::GREEN)],
|
||||
@ -352,7 +395,7 @@ fn calculate_bike_network(ctx: &mut EventCtx, ui: &UI) -> RoadColorer {
|
||||
colorer.build(ctx, &ui.primary.map)
|
||||
}
|
||||
|
||||
fn calculate_bus_network(ctx: &mut EventCtx, ui: &UI) -> RoadColorer {
|
||||
fn calculate_bus_network(ctx: &EventCtx, ui: &UI) -> RoadColorer {
|
||||
let mut colorer = RoadColorerBuilder::new(
|
||||
Text::prompt("bus networks"),
|
||||
vec![("bike lanes", Color::GREEN)],
|
||||
@ -365,22 +408,21 @@ fn calculate_bus_network(ctx: &mut EventCtx, ui: &UI) -> RoadColorer {
|
||||
colorer.build(ctx, &ui.primary.map)
|
||||
}
|
||||
|
||||
fn trip_stats(ui: &UI, ctx: &mut EventCtx) -> Plot<usize> {
|
||||
let lines: Vec<(&str, Color, Option<TripMode>)> = vec![
|
||||
(
|
||||
"walking",
|
||||
ui.cs.get("unzoomed pedestrian"),
|
||||
Some(TripMode::Walk),
|
||||
),
|
||||
("biking", ui.cs.get("unzoomed bike"), Some(TripMode::Bike)),
|
||||
(
|
||||
"transit",
|
||||
ui.cs.get("unzoomed bus"),
|
||||
Some(TripMode::Transit),
|
||||
),
|
||||
("driving", ui.cs.get("unzoomed car"), Some(TripMode::Drive)),
|
||||
("aborted", Color::PURPLE.alpha(0.5), None),
|
||||
];
|
||||
fn color_for_mode(m: TripMode, ui: &UI) -> Color {
|
||||
match m {
|
||||
TripMode::Walk => ui.cs.get("unzoomed pedestrian"),
|
||||
TripMode::Bike => ui.cs.get("unzoomed bike"),
|
||||
TripMode::Transit => ui.cs.get("unzoomed bus"),
|
||||
TripMode::Drive => ui.cs.get("unzoomed car"),
|
||||
}
|
||||
}
|
||||
|
||||
fn trip_stats(ctx: &EventCtx, ui: &UI) -> Plot<usize> {
|
||||
let mut lines: Vec<(String, Color, Option<TripMode>)> = TripMode::all()
|
||||
.into_iter()
|
||||
.map(|m| (m.to_string(), color_for_mode(m, ui), Some(m)))
|
||||
.collect();
|
||||
lines.push(("aborted".to_string(), Color::PURPLE.alpha(0.5), None));
|
||||
|
||||
// What times do we use for interpolation?
|
||||
let num_x_pts = 100;
|
||||
@ -419,8 +461,8 @@ fn trip_stats(ui: &UI, ctx: &mut EventCtx) -> Plot<usize> {
|
||||
"finished trips",
|
||||
lines
|
||||
.into_iter()
|
||||
.map(|(name, color, m)| Series {
|
||||
label: name.to_string(),
|
||||
.map(|(label, color, m)| Series {
|
||||
label,
|
||||
color,
|
||||
pts: pts_per_mode.remove(&m).unwrap(),
|
||||
})
|
||||
@ -429,3 +471,55 @@ fn trip_stats(ui: &UI, ctx: &mut EventCtx) -> Plot<usize> {
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO Refactor
|
||||
pub fn calculate_road_thruput(r: RoadID, bucket: Duration, ctx: &EventCtx, ui: &UI) -> Plot<usize> {
|
||||
Plot::new(
|
||||
&format!(
|
||||
"throughput of {} in {} buckets",
|
||||
ui.primary.map.get_r(r).get_name(),
|
||||
bucket.minimal_tostring()
|
||||
),
|
||||
ui.primary
|
||||
.sim
|
||||
.get_analytics()
|
||||
.throughput_road(ui.primary.sim.time(), r, bucket)
|
||||
.into_iter()
|
||||
.map(|(m, pts)| Series {
|
||||
label: m.to_string(),
|
||||
color: color_for_mode(m, ui),
|
||||
pts,
|
||||
})
|
||||
.collect(),
|
||||
0,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn calculate_intersection_thruput(
|
||||
i: IntersectionID,
|
||||
bucket: Duration,
|
||||
ctx: &EventCtx,
|
||||
ui: &UI,
|
||||
) -> Plot<usize> {
|
||||
Plot::new(
|
||||
&format!(
|
||||
"throughput of {} in {} buckets",
|
||||
i,
|
||||
bucket.minimal_tostring()
|
||||
),
|
||||
ui.primary
|
||||
.sim
|
||||
.get_analytics()
|
||||
.throughput_intersection(ui.primary.sim.time(), i, bucket)
|
||||
.into_iter()
|
||||
.map(|(m, pts)| Series {
|
||||
label: m.to_string(),
|
||||
color: color_for_mode(m, ui),
|
||||
pts,
|
||||
})
|
||||
.collect(),
|
||||
0,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{CarID, Event, TripMode};
|
||||
use crate::{AgentID, CarID, Event, TripMode, VehicleType};
|
||||
use abstutil::Counter;
|
||||
use derivative::Derivative;
|
||||
use geom::{Duration, DurationHistogram};
|
||||
@ -27,6 +27,9 @@ pub struct ThruputStats {
|
||||
pub count_per_road: Counter<RoadID>,
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub count_per_intersection: Counter<IntersectionID>,
|
||||
|
||||
raw_per_road: Vec<(Duration, TripMode, RoadID)>,
|
||||
raw_per_intersection: Vec<(Duration, TripMode, IntersectionID)>,
|
||||
}
|
||||
|
||||
impl Analytics {
|
||||
@ -35,6 +38,8 @@ impl Analytics {
|
||||
thruput_stats: ThruputStats {
|
||||
count_per_road: Counter::new(),
|
||||
count_per_intersection: Counter::new(),
|
||||
raw_per_road: Vec::new(),
|
||||
raw_per_intersection: Vec::new(),
|
||||
},
|
||||
test_expectations: VecDeque::new(),
|
||||
bus_arrivals: Vec::new(),
|
||||
@ -44,11 +49,36 @@ impl Analytics {
|
||||
}
|
||||
|
||||
pub fn event(&mut self, ev: Event, time: Duration, map: &Map) {
|
||||
// TODO Plumb a flag
|
||||
let raw_thruput = true;
|
||||
|
||||
// Throughput
|
||||
if let Event::AgentEntersTraversable(_, to) = ev {
|
||||
if let Event::AgentEntersTraversable(a, to) = ev {
|
||||
let mode = match a {
|
||||
AgentID::Pedestrian(_) => TripMode::Walk,
|
||||
AgentID::Car(c) => match c.1 {
|
||||
VehicleType::Car => TripMode::Drive,
|
||||
VehicleType::Bike => TripMode::Bike,
|
||||
VehicleType::Bus => TripMode::Transit,
|
||||
},
|
||||
};
|
||||
|
||||
match to {
|
||||
Traversable::Lane(l) => self.thruput_stats.count_per_road.inc(map.get_l(l).parent),
|
||||
Traversable::Turn(t) => self.thruput_stats.count_per_intersection.inc(t.parent),
|
||||
Traversable::Lane(l) => {
|
||||
let r = map.get_l(l).parent;
|
||||
self.thruput_stats.count_per_road.inc(r);
|
||||
if raw_thruput {
|
||||
self.thruput_stats.raw_per_road.push((time, mode, r));
|
||||
}
|
||||
}
|
||||
Traversable::Turn(t) => {
|
||||
self.thruput_stats.count_per_intersection.inc(t.parent);
|
||||
if raw_thruput {
|
||||
self.thruput_stats
|
||||
.raw_per_intersection
|
||||
.push((time, mode, t.parent));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -173,4 +203,64 @@ impl Analytics {
|
||||
}
|
||||
delays_to_stop
|
||||
}
|
||||
|
||||
// Slightly misleading -- TripMode::Transit means buses, not pedestrians taking transit
|
||||
pub fn throughput_road(
|
||||
&self,
|
||||
now: Duration,
|
||||
road: RoadID,
|
||||
bucket: Duration,
|
||||
) -> BTreeMap<TripMode, Vec<(Duration, usize)>> {
|
||||
let mut max_this_bucket = now.min(bucket);
|
||||
let mut per_mode = TripMode::all()
|
||||
.into_iter()
|
||||
.map(|m| (m, vec![(Duration::ZERO, 0), (max_this_bucket, 0)]))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
for (t, m, r) in &self.thruput_stats.raw_per_road {
|
||||
if *r != road {
|
||||
continue;
|
||||
}
|
||||
if *t > now {
|
||||
break;
|
||||
}
|
||||
if *t > max_this_bucket {
|
||||
max_this_bucket = now.min(max_this_bucket + bucket);
|
||||
for vec in per_mode.values_mut() {
|
||||
vec.push((max_this_bucket, 0));
|
||||
}
|
||||
}
|
||||
per_mode.get_mut(m).unwrap().last_mut().unwrap().1 += 1;
|
||||
}
|
||||
per_mode
|
||||
}
|
||||
|
||||
// TODO Refactor!
|
||||
pub fn throughput_intersection(
|
||||
&self,
|
||||
now: Duration,
|
||||
intersection: IntersectionID,
|
||||
bucket: Duration,
|
||||
) -> BTreeMap<TripMode, Vec<(Duration, usize)>> {
|
||||
let mut per_mode = TripMode::all()
|
||||
.into_iter()
|
||||
.map(|m| (m, vec![(Duration::ZERO, 0)]))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let mut max_this_bucket = bucket;
|
||||
for (t, m, i) in &self.thruput_stats.raw_per_intersection {
|
||||
if *i != intersection {
|
||||
continue;
|
||||
}
|
||||
if *t > now {
|
||||
break;
|
||||
}
|
||||
if *t > max_this_bucket {
|
||||
max_this_bucket = now.min(max_this_bucket + bucket);
|
||||
for vec in per_mode.values_mut() {
|
||||
vec.push((max_this_bucket, 0));
|
||||
}
|
||||
}
|
||||
per_mode.get_mut(m).unwrap().last_mut().unwrap().1 += 1;
|
||||
}
|
||||
per_mode
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user