mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 00:12:55 +03:00
start representing bus spawn rates explicitly
This commit is contained in:
parent
22afb60421
commit
f73516d183
@ -39,19 +39,19 @@ data/input/seattle/parcels_urbansim.txt,db63d7d606e8702d12f9399e87e6a00f,https:/
|
||||
data/input/seattle/popdat.bin,0fd10698d2c6bf41da3d57804c617d15,https://www.dropbox.com/s/iboctakleznvslq/popdat.bin.zip?dl=0
|
||||
data/input/seattle/trips_2014.csv,d4a8e733045b28c0385fb81359d6df03,https://www.dropbox.com/s/5ppravwmk6bf20d/trips_2014.csv.zip?dl=0
|
||||
data/system/cities/seattle.bin,4ddc0f99d53ae3171f0c4ad2e4c646bd,https://www.dropbox.com/s/m7q6y6w9gw3ubjs/seattle.bin.zip?dl=0
|
||||
data/system/maps/ballard.bin,82ced46cda865fb65bc11e7ff68ff877,https://www.dropbox.com/s/ilwsscuwtdhv2wu/ballard.bin.zip?dl=0
|
||||
data/system/maps/berlin_center.bin,bfb07f2bb165fabcdaf7779c6fc5a71d,https://www.dropbox.com/s/f9m84s5ilcys3ah/berlin_center.bin.zip?dl=0
|
||||
data/system/maps/downtown.bin,8f51a3079520982d61418e3ef8c3ffb3,https://www.dropbox.com/s/rh3netnh4p7qv5w/downtown.bin.zip?dl=0
|
||||
data/system/maps/huge_seattle.bin,2a758381fd5f94417bb5646025842e50,https://www.dropbox.com/s/n5cstox0s8czqhx/huge_seattle.bin.zip?dl=0
|
||||
data/system/maps/krakow_center.bin,ee128d15bd8c65b70b0a4ad090a7e736,https://www.dropbox.com/s/bkri62r9se3s46y/krakow_center.bin.zip?dl=0
|
||||
data/system/maps/lakeslice.bin,10269590012e297df17acf6195770b96,https://www.dropbox.com/s/xcp4s1dvdy414nz/lakeslice.bin.zip?dl=0
|
||||
data/system/maps/montlake.bin,34a67457c7411291ff03772fd785c98d,https://www.dropbox.com/s/sjl8j4or361e7bc/montlake.bin.zip?dl=0
|
||||
data/system/maps/south_seattle.bin,97ec71f95acb4db29abe58cee88d2a21,https://www.dropbox.com/s/wa1azyqelse3t1e/south_seattle.bin.zip?dl=0
|
||||
data/system/maps/udistrict.bin,475e177d37876ac1b49f03646e147371,https://www.dropbox.com/s/qcxcqy3xe0m9dv2/udistrict.bin.zip?dl=0
|
||||
data/system/maps/west_seattle.bin,32cd4866c222a56c543ae9a31256f08e,https://www.dropbox.com/s/gw8hjjrl4cahm0j/west_seattle.bin.zip?dl=0
|
||||
data/system/prebaked_results/lakeslice/weekday.bin,872d2c49b63659b2dbe3d9424f5448b5,https://www.dropbox.com/s/dg5lalw3caec0ra/weekday.bin.zip?dl=0
|
||||
data/system/prebaked_results/montlake/car vs bike contention.bin,b0ae18d18936d1ae32e20bfc1afbe726,https://www.dropbox.com/s/jefg0ikjy9dsrdd/car%20vs%20bike%20contention.bin.zip?dl=0
|
||||
data/system/prebaked_results/montlake/weekday.bin,f32fd37202433a4b6a4515db68e70012,https://www.dropbox.com/s/mus8cpyc1q58tq4/weekday.bin.zip?dl=0
|
||||
data/system/maps/ballard.bin,907a708c024c000028088d43602f9647,https://www.dropbox.com/s/racyl5o04700rth/ballard.bin.zip?dl=0
|
||||
data/system/maps/berlin_center.bin,496e1f7384de1a10421d413992b524ce,https://www.dropbox.com/s/vmtmypye5w2bovt/berlin_center.bin.zip?dl=0
|
||||
data/system/maps/downtown.bin,5ff683efaea52e2e132cee573aa6ac41,https://www.dropbox.com/s/v5hwild4luavcie/downtown.bin.zip?dl=0
|
||||
data/system/maps/huge_seattle.bin,3c91184af8f24323e2c2d9cd858748f8,https://www.dropbox.com/s/kckex9w5c6099xv/huge_seattle.bin.zip?dl=0
|
||||
data/system/maps/krakow_center.bin,41940148947fa64aff85694afee49e8e,https://www.dropbox.com/s/2zctje85ht9yxxo/krakow_center.bin.zip?dl=0
|
||||
data/system/maps/lakeslice.bin,ce2f18ddb9d078d99ec79af1876dd654,https://www.dropbox.com/s/aqwpe0uiiktmbfj/lakeslice.bin.zip?dl=0
|
||||
data/system/maps/montlake.bin,ea576940ceeca71fbf67661dec3d08ee,https://www.dropbox.com/s/593up23e6k67c00/montlake.bin.zip?dl=0
|
||||
data/system/maps/south_seattle.bin,9017d61af15518419fd0d883e407a988,https://www.dropbox.com/s/u9w8wdwun0x6wy1/south_seattle.bin.zip?dl=0
|
||||
data/system/maps/udistrict.bin,d077fef667a6a7ff9b14f94d24bd843b,https://www.dropbox.com/s/cwcxxggn1hzzrdr/udistrict.bin.zip?dl=0
|
||||
data/system/maps/west_seattle.bin,00c05db8bb2b0ef88a89addfe9edd751,https://www.dropbox.com/s/urcz6x43ejfrzqz/west_seattle.bin.zip?dl=0
|
||||
data/system/prebaked_results/lakeslice/weekday.bin,e0bc89230f2f26659b8c5ff469130e7d,https://www.dropbox.com/s/jc66uhy4p037b2c/weekday.bin.zip?dl=0
|
||||
data/system/prebaked_results/montlake/car vs bike contention.bin,e3d09d3f71fb6c3f39ce9b73291fba5a,https://www.dropbox.com/s/jefg0ikjy9dsrdd/car%20vs%20bike%20contention.bin.zip?dl=0
|
||||
data/system/prebaked_results/montlake/weekday.bin,d5058f6aedfe7a6320e60b192de0f962,https://www.dropbox.com/s/zkny87kygnxd30b/weekday.bin.zip?dl=0
|
||||
data/system/scenarios/ballard/weekday.bin,b5252821a3e5e7b1f5bdb83191e9890b,https://www.dropbox.com/s/wam0a5q0mhzxm6x/weekday.bin.zip?dl=0
|
||||
data/system/scenarios/downtown/weekday.bin,bc31ac91a67eaa6d865b507432330f5e,https://www.dropbox.com/s/vrhsp920swdgdgk/weekday.bin.zip?dl=0
|
||||
data/system/scenarios/huge_seattle/weekday.bin,cce3d979adb1126ffc159884858fc900,https://www.dropbox.com/s/3jldfrhmhcbofmw/weekday.bin.zip?dl=0
|
||||
|
@ -5,7 +5,7 @@ use crate::info::{header_btns, make_tabs, Details, Tab};
|
||||
use abstutil::{prettyprint_usize, Counter};
|
||||
use ezgui::{Btn, Color, EventCtx, Line, RewriteColor, Text, TextExt, Widget};
|
||||
use geom::{Circle, Distance, Time};
|
||||
use map_model::{BusRouteID, BusStopID, PathConstraints, PathStep};
|
||||
use map_model::{BusRoute, BusRouteID, BusStopID, PathStep};
|
||||
use sim::{AgentID, CarID};
|
||||
|
||||
pub fn stop(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusStopID) -> Vec<Widget> {
|
||||
@ -175,11 +175,7 @@ pub fn route(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusRouteI
|
||||
let buses = app.primary.sim.status_of_buses(id, map);
|
||||
let mut bus_locations = Vec::new();
|
||||
if buses.is_empty() {
|
||||
if route.route_type == PathConstraints::Bus {
|
||||
rows.push("No buses running".draw_text(ctx));
|
||||
} else {
|
||||
rows.push("No trains running".draw_text(ctx));
|
||||
}
|
||||
rows.push(format!("No {} running", route.plural_noun()).draw_text(ctx));
|
||||
} else {
|
||||
for (bus, _, _, pt) in buses {
|
||||
rows.push(Btn::text_fg(bus.to_string()).build_def(ctx, None));
|
||||
@ -281,6 +277,11 @@ pub fn route(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusRouteI
|
||||
details.warpers.insert(name, ID::Intersection(i.id));
|
||||
}
|
||||
|
||||
// TODO Soon it'll be time to split into tabs
|
||||
{
|
||||
rows.push(describe_schedule(route).draw(ctx));
|
||||
}
|
||||
|
||||
// Draw the route, label stops, and show location of buses
|
||||
{
|
||||
let mut colorer = ColorNetwork::new(app);
|
||||
@ -325,3 +326,47 @@ pub fn route(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusRouteI
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
// TODO Unit test
|
||||
fn describe_schedule(route: &BusRoute) -> Text {
|
||||
let mut txt = Text::new();
|
||||
txt.add(Line(format!(
|
||||
"{} {}s run this route daily",
|
||||
route.spawn_times.len(),
|
||||
route.plural_noun()
|
||||
)));
|
||||
|
||||
// Compress the times
|
||||
let mut start = route.spawn_times[0];
|
||||
let mut last = None;
|
||||
let mut dt = None;
|
||||
for t in route.spawn_times.iter().skip(1) {
|
||||
if let Some(l) = last {
|
||||
let new_dt = *t - l;
|
||||
if Some(new_dt) == dt {
|
||||
last = Some(*t);
|
||||
} else {
|
||||
txt.add(Line(format!(
|
||||
"Every {} from {} to {}",
|
||||
dt.unwrap(),
|
||||
start.ampm_tostring(),
|
||||
l.ampm_tostring()
|
||||
)));
|
||||
start = l;
|
||||
last = Some(*t);
|
||||
dt = Some(new_dt);
|
||||
}
|
||||
} else {
|
||||
last = Some(*t);
|
||||
dt = Some(*t - start);
|
||||
}
|
||||
}
|
||||
// Handle end
|
||||
txt.add(Line(format!(
|
||||
"Every {} from {} to {}",
|
||||
dt.unwrap(),
|
||||
start.ampm_tostring(),
|
||||
last.unwrap().ampm_tostring()
|
||||
)));
|
||||
txt
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
BusRoute, BusRouteID, BusStop, BusStopID, LaneID, LaneType, Map, PathConstraints, Position,
|
||||
};
|
||||
use abstutil::Timer;
|
||||
use geom::{Distance, HashablePt2D};
|
||||
use geom::{Distance, Duration, HashablePt2D, Time};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
|
||||
use std::error::Error;
|
||||
|
||||
@ -136,6 +136,7 @@ fn make_route(
|
||||
route_type,
|
||||
start,
|
||||
end_border,
|
||||
spawn_times: default_spawn_times(),
|
||||
};
|
||||
|
||||
// Make sure the route is connected
|
||||
@ -323,3 +324,16 @@ fn pick_start_lane(
|
||||
first_stop.lane()
|
||||
))
|
||||
}
|
||||
|
||||
fn default_spawn_times() -> Vec<Time> {
|
||||
// Hourly spawning from midnight to 7, then every 30 minutes till 7, then hourly again
|
||||
let mut times = Vec::new();
|
||||
for i in 0..24 {
|
||||
let hour = Time::START_OF_DAY + Duration::hours(i);
|
||||
times.push(hour);
|
||||
if i >= 7 && i <= 19 {
|
||||
times.push(hour + Duration::minutes(30));
|
||||
}
|
||||
}
|
||||
times
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::{LaneID, Map, PathConstraints, PathRequest, Position};
|
||||
use abstutil::{deserialize_usize, serialize_usize};
|
||||
use geom::Time;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
@ -53,6 +54,8 @@ pub struct BusRoute {
|
||||
pub start: LaneID,
|
||||
pub end_border: Option<LaneID>,
|
||||
pub route_type: PathConstraints,
|
||||
// Non-empty, times in order for one day when a vehicle should begin at start.
|
||||
pub spawn_times: Vec<Time>,
|
||||
}
|
||||
|
||||
impl BusRoute {
|
||||
@ -79,4 +82,12 @@ impl BusRoute {
|
||||
}
|
||||
steps
|
||||
}
|
||||
|
||||
pub fn plural_noun(&self) -> &'static str {
|
||||
if self.route_type == PathConstraints::Bus {
|
||||
"buses"
|
||||
} else {
|
||||
"trains"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,13 +104,13 @@ impl Scenario {
|
||||
if let Some(ref routes) = self.only_seed_buses {
|
||||
for route in map.all_bus_routes() {
|
||||
if routes.contains(&route.full_name) {
|
||||
sim.seed_bus_route(route, map);
|
||||
sim.seed_bus_route(route);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// All of them
|
||||
for route in map.all_bus_routes() {
|
||||
sim.seed_bus_route(route, map);
|
||||
sim.seed_bus_route(route);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,8 @@ pub enum Command {
|
||||
Callback(Duration),
|
||||
Pandemic(pandemic::Cmd),
|
||||
FinishRemoteTrip(TripID),
|
||||
SeedBus(BusRouteID),
|
||||
// The Time is redundant, just used to dedupe commands
|
||||
StartBus(BusRouteID, Time),
|
||||
}
|
||||
|
||||
impl Command {
|
||||
@ -47,7 +48,7 @@ impl Command {
|
||||
Command::Callback(_) => CommandType::Callback,
|
||||
Command::Pandemic(ref p) => CommandType::Pandemic(p.clone()),
|
||||
Command::FinishRemoteTrip(t) => CommandType::FinishRemoteTrip(*t),
|
||||
Command::SeedBus(r) => CommandType::SeedBus(*r),
|
||||
Command::StartBus(r, t) => CommandType::StartBus(*r, *t),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,7 +65,7 @@ pub enum CommandType {
|
||||
Callback,
|
||||
Pandemic(pandemic::Cmd),
|
||||
FinishRemoteTrip(TripID),
|
||||
SeedBus(BusRouteID),
|
||||
StartBus(BusRouteID, Time),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)]
|
||||
|
@ -228,7 +228,13 @@ impl Sim {
|
||||
self.parking.add_parked_car(ParkedCar { vehicle, spot });
|
||||
}
|
||||
|
||||
pub(crate) fn seed_bus_route(&mut self, route: &BusRoute, map: &Map) {
|
||||
pub(crate) fn seed_bus_route(&mut self, route: &BusRoute) {
|
||||
for t in &route.spawn_times {
|
||||
self.scheduler.push(*t, Command::StartBus(route.id, *t));
|
||||
}
|
||||
}
|
||||
|
||||
fn start_bus(&mut self, route: &BusRoute, map: &Map) {
|
||||
// Spawn one bus for the first leg.
|
||||
let (req, path) = self.transit.create_empty_route(route, map);
|
||||
|
||||
@ -272,10 +278,6 @@ impl Sim {
|
||||
true,
|
||||
),
|
||||
);
|
||||
|
||||
// TODO Change the rate of spawning based on a schedule from GTFS or player's choice
|
||||
self.scheduler
|
||||
.push(self.time + Duration::hours(1), Command::SeedBus(route.id));
|
||||
}
|
||||
|
||||
pub fn set_name(&mut self, name: String) {
|
||||
@ -571,8 +573,8 @@ impl Sim {
|
||||
&mut self.scheduler,
|
||||
);
|
||||
}
|
||||
Command::SeedBus(r) => {
|
||||
self.seed_bus_route(map.get_br(r), map);
|
||||
Command::StartBus(r, _) => {
|
||||
self.start_bus(map.get_br(r), map);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user