From 940d2265c0f0e7cd4ba67cfff1c0b4d6587eca31 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Mon, 3 Aug 2020 11:08:21 -0700 Subject: [PATCH] spawning buses at 0.01m on a non-border lane can break, because other cars approach, and the buffer distance gets broken. instead, spawn the buses a few lanes away, if needed. fixes #260 now only ~400 agents left in lakeslice by end! --- data/MANIFEST.txt | 32 ++++---- game/src/info/bus.rs | 4 +- map_model/src/make/mod.rs | 3 +- map_model/src/make/transit.rs | 118 +++++++++++++++++++----------- map_model/src/objects/bus_stop.rs | 15 ++-- sim/src/mechanics/car.rs | 7 +- sim/src/sim.rs | 9 ++- sim/src/transit.rs | 6 +- 8 files changed, 116 insertions(+), 78 deletions(-) diff --git a/data/MANIFEST.txt b/data/MANIFEST.txt index 99425902ed..e18ebba5f1 100644 --- a/data/MANIFEST.txt +++ b/data/MANIFEST.txt @@ -34,29 +34,29 @@ data/input/seattle/osm/south_seattle.osm,1107f8b545b09731c4619fde63bdbaed,https: data/input/seattle/osm/udistrict.osm,ed26f2405c07c63161e902bcb5049fab,https://www.dropbox.com/s/ozqk7lb5nn0wace/udistrict.osm.zip?dl=0 data/input/seattle/osm/washington-latest.osm.pbf,332c0bbd80621a52e3765381718f3454,https://www.dropbox.com/s/iitat4cnhj5dop8/washington-latest.osm.pbf.zip?dl=0 data/input/seattle/osm/west_seattle.osm,f829d6a1c87e782fafbc1552acc5a523,https://www.dropbox.com/s/3vlyve59lfo9s99/west_seattle.osm.zip?dl=0 -data/input/seattle/parcels.bin,97e8be05694e2f4a1f5194dbc7523c40,https://www.dropbox.com/s/pue16ui1bq4s17w/parcels.bin.zip?dl=0 +data/input/seattle/parcels.bin,f30df790f1f3d00ad92f255045958920,https://www.dropbox.com/s/rdmtdcfntflgi31/parcels.bin.zip?dl=0 data/input/seattle/parcels_urbansim.txt,db63d7d606e8702d12f9399e87e6a00f,https://www.dropbox.com/s/6g8rbsf200dssj3/parcels_urbansim.txt.zip?dl=0 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,e27bd39957c52599f70f841114048f7b,https://www.dropbox.com/s/y0d4b9ppeibkljn/ballard.bin.zip?dl=0 -data/system/maps/berlin_center.bin,548313aaed159d2ebd3c034f09a9b5d0,https://www.dropbox.com/s/o4wqefgcywlvmng/berlin_center.bin.zip?dl=0 -data/system/maps/downtown.bin,134b2db03a9bdd1eecabb700b3335a35,https://www.dropbox.com/s/8h3nzu0zqpj2kr8/downtown.bin.zip?dl=0 -data/system/maps/huge_seattle.bin,2e9bdc736ab93e00c986480199be0994,https://www.dropbox.com/s/ui8u1k76avtn70h/huge_seattle.bin.zip?dl=0 -data/system/maps/krakow_center.bin,9cb4922363683950d99e4f8c466eab99,https://www.dropbox.com/s/fmyw0fkwrnpvcnf/krakow_center.bin.zip?dl=0 -data/system/maps/lakeslice.bin,f2ee2ed0b5eb8b754dc10d720e18f25f,https://www.dropbox.com/s/bdukilqzhxkicjf/lakeslice.bin.zip?dl=0 -data/system/maps/montlake.bin,a5561eb511d4267c636cbb7b0f47e23f,https://www.dropbox.com/s/cehp7etb10h9xq9/montlake.bin.zip?dl=0 -data/system/maps/south_seattle.bin,a7543a7724d9db41aa325aafaba1d184,https://www.dropbox.com/s/cdtlva0t547siy0/south_seattle.bin.zip?dl=0 -data/system/maps/udistrict.bin,efd51f101306b243cd80052d8dfd3828,https://www.dropbox.com/s/nn5opbmncdhou2g/udistrict.bin.zip?dl=0 -data/system/maps/west_seattle.bin,c7d36900c1f7eec758dbec2ab6dc745c,https://www.dropbox.com/s/oyfvegdlnpwzk43/west_seattle.bin.zip?dl=0 -data/system/prebaked_results/lakeslice/weekday.bin,9040df55be360864e545d1d69f59796c,https://www.dropbox.com/s/yevdoe50z109sjc/weekday.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,f0002cbb7321dbff62ba47f3d3dfcc4f,https://www.dropbox.com/s/hxjwhzgbgymackt/weekday.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/scenarios/ballard/weekday.bin,b5252821a3e5e7b1f5bdb83191e9890b,https://www.dropbox.com/s/wam0a5q0mhzxm6x/weekday.bin.zip?dl=0 -data/system/scenarios/downtown/weekday.bin,91cd32de750bcfe18af307178be770c3,https://www.dropbox.com/s/glytrwccwuwnctc/weekday.bin.zip?dl=0 -data/system/scenarios/huge_seattle/weekday.bin,0d66a38e299332a485afd342e03ca0e2,https://www.dropbox.com/s/op07w7s03bjedlv/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 data/system/scenarios/lakeslice/weekday.bin,50fb819b17a145c1bccffaac8d0bd2fa,https://www.dropbox.com/s/aoy3zwm88y7yeyi/weekday.bin.zip?dl=0 data/system/scenarios/montlake/weekday.bin,49a9f4ad7b8c051d0a278425d1926976,https://www.dropbox.com/s/828ub49rvcdhibu/weekday.bin.zip?dl=0 -data/system/scenarios/south_seattle/weekday.bin,01268d0e74e3da44f9dff89cc7a9f86d,https://www.dropbox.com/s/4k0sk5c7rlzi80t/weekday.bin.zip?dl=0 +data/system/scenarios/south_seattle/weekday.bin,ef98b4b688ee4c6490885896fe0e16ea,https://www.dropbox.com/s/amz9jgx4gp7y7pw/weekday.bin.zip?dl=0 data/system/scenarios/udistrict/weekday.bin,1065f846a26222f4c12553d3c7116904,https://www.dropbox.com/s/qrm5veac663ni7v/weekday.bin.zip?dl=0 data/system/scenarios/west_seattle/weekday.bin,f8a7b2bbe88e952a5e7e3c4a4b998174,https://www.dropbox.com/s/2ryk24mofqdyxaq/weekday.bin.zip?dl=0 diff --git a/game/src/info/bus.rs b/game/src/info/bus.rs index 755ae3894b..ef9e92dd7e 100644 --- a/game/src/info/bus.rs +++ b/game/src/info/bus.rs @@ -231,8 +231,8 @@ pub fn route(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusRouteI ); rows.push(format!("{} stops", route.stops.len()).draw_text(ctx)); - if let Some(l) = route.start_border { - let i = map.get_i(map.get_l(l).src_i); + { + let i = map.get_i(map.get_l(route.start).src_i); let name = format!("Starts at {}", i.name(map)); rows.push(Widget::row(vec![ Btn::svg( diff --git a/map_model/src/make/mod.rs b/map_model/src/make/mod.rs index 98586c1cf2..b86ae2e631 100644 --- a/map_model/src/make/mod.rs +++ b/map_model/src/make/mod.rs @@ -200,7 +200,8 @@ impl Map { .osm_tags .get(osm::HIGHWAY) .map(|x| x.ends_with("_link")) - .unwrap_or(false)) + .unwrap_or(false) + || road.osm_tags.is("railway", "rail")) { timer.warn(format!( "{} has no name. Tags: {:?}", diff --git a/map_model/src/make/transit.rs b/map_model/src/make/transit.rs index 4961c67313..652f729e28 100644 --- a/map_model/src/make/transit.rs +++ b/map_model/src/make/transit.rs @@ -1,9 +1,11 @@ use crate::make::match_points_to_lanes; use crate::raw::{RawBusRoute, RawBusStop}; -use crate::{BusRoute, BusRouteID, BusStop, BusStopID, LaneType, Map, PathConstraints, Position}; +use crate::{ + BusRoute, BusRouteID, BusStop, BusStopID, LaneID, LaneType, Map, PathConstraints, Position, +}; use abstutil::Timer; use geom::{Distance, HashablePt2D}; -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::error::Error; pub fn make_stops_and_routes(map: &mut Map, raw_routes: &Vec, timer: &mut Timer) { @@ -85,26 +87,28 @@ fn make_route( }; // Start or end at a border? - let mut start_border = None; let mut end_border = None; - if let Some(i) = r.border_start { + let start = if let Some(i) = r.border_start { let i = map.get_i(map.find_i_by_osm_id(i.osm_node_id).unwrap()); if !i.is_border() { panic!("Route starts at {}, but isn't a border?", i.orig_id); } if let Some(l) = i.get_outgoing_lanes(map, route_type).get(0) { - start_border = Some(*l); + *l } else { - // TODO Should panic - println!( + return Err(format!( "Route {} starts at {} ({}), but no starting lane for a {:?}?", rel_url(r.osm_rel_id), i.id, i.orig_id, route_type - ); + ) + .into()); } - } + } else { + // Not starting at a border. Find a lane at or before the first stop that's at least 13m. + pick_start_lane(map.get_bs(stops[0]).driving_pos, route_type, map)? + }; if let Some(i) = r.border_end { let i = map.get_i(map.find_i_by_osm_id(i.osm_node_id).unwrap()); if !i.is_border() { @@ -130,7 +134,7 @@ fn make_route( short_name: r.short_name.clone(), stops, route_type, - start_border, + start, end_border, }; @@ -227,9 +231,6 @@ impl Matcher { stop: &RawBusStop, map: &Map, ) -> Result<(Position, Position), Box> { - // Buses are spawned at 0.01m along a lane; make sure a potential first stop is past that. - let buffer = Distance::meters(0.1); - if !is_bus { // Light rail needs explicit platforms. let sidewalk_pt = stop.ped_pos.ok_or("light rail missing platform")?; @@ -249,45 +250,76 @@ impl Matcher { // Because the stop is usually mapped on the road center-line, the matched side-of-the-road // is often wrong. If we have the bus stop, actually use that and get the equivalent // position on the closest driving/bus lane. - if let Some(pt) = stop.ped_pos { - let sidewalk_pos = *self + let sidewalk_pos = if let Some(pt) = stop.ped_pos { + *self .sidewalk_pts .get(&pt.to_hashable()) - .ok_or("sidewalk didnt match")?; - let lane = map - .get_parent(sidewalk_pos.lane()) - .find_closest_lane(sidewalk_pos.lane(), vec![LaneType::Bus, LaneType::Driving])?; - return if let Some(driving_pos) = - sidewalk_pos.equiv_pos(lane, map).min_dist(buffer, map) - { - Ok((sidewalk_pos, driving_pos)) - } else { - Err(format!("Driving position {} is too short", lane).into()) - }; - } - - // We only have the vehicle position. First find the sidewalk, then snap it to the - // rightmost driving/bus lane. - let orig_driving_pos = *self - .bus_pts - .get(&stop.vehicle_pos.to_hashable()) - .ok_or("vehicle for bus didnt match")?; - let sidewalk = map.get_parent(orig_driving_pos.lane()).find_closest_lane( - orig_driving_pos.lane(), - vec![LaneType::Sidewalk, LaneType::Shoulder], - )?; - let sidewalk_pos = orig_driving_pos.equiv_pos(sidewalk, map); + .ok_or("sidewalk didnt match")? + } else { + // We only have the vehicle position. First find the sidewalk, then snap it to the + // rightmost driving/bus lane. + let orig_driving_pos = *self + .bus_pts + .get(&stop.vehicle_pos.to_hashable()) + .ok_or("vehicle for bus didnt match")?; + let sidewalk = map.get_parent(orig_driving_pos.lane()).find_closest_lane( + orig_driving_pos.lane(), + vec![LaneType::Sidewalk, LaneType::Shoulder], + )?; + orig_driving_pos.equiv_pos(sidewalk, map) + }; let lane = map .get_parent(sidewalk_pos.lane()) .find_closest_lane(sidewalk_pos.lane(), vec![LaneType::Bus, LaneType::Driving])?; - if let Some(driving_pos) = sidewalk_pos.equiv_pos(lane, map).min_dist(buffer, map) { - Ok((sidewalk_pos, driving_pos)) - } else { - Err(format!("Driving position {} is too short", lane).into()) + let mut driving_pos = sidewalk_pos.equiv_pos(lane, map); + // If we're a stop right at an incoming border, make sure to be at least past where the bus + // will spawn from the border. pick_start_lane() can't do anything for borders. + if map + .get_i(map.get_l(driving_pos.lane()).src_i) + .is_incoming_border() + { + if let Some(pos) = driving_pos.min_dist(Distance::meters(1.0), map) { + driving_pos = pos; + } else { + return Err( + format!("too close to start of a border {}", driving_pos.lane()).into(), + ); + } } + Ok((sidewalk_pos, driving_pos)) } } fn rel_url(id: i64) -> String { format!("https://www.openstreetmap.org/relation/{}", id) } + +fn pick_start_lane( + first_stop: Position, + constraints: PathConstraints, + map: &Map, +) -> Result { + let min_len = Distance::meters(13.0); + if first_stop.dist_along() >= min_len { + return Ok(first_stop.lane()); + } + + // Flood backwards until we find a long enough lane + let mut queue = VecDeque::new(); + queue.push_back(first_stop.lane()); + while !queue.is_empty() { + let current = queue.pop_front().unwrap(); + if current != first_stop.lane() && map.get_l(current).length() >= min_len { + return Ok(current); + } + for t in map.get_turns_to_lane(current) { + if constraints.can_use(map.get_l(t.id.src), map) { + queue.push_back(t.id.src); + } + } + } + Err(format!( + "couldn't find any lanes leading to {} that're long enough for a bus to spawn", + first_stop.lane() + )) +} diff --git a/map_model/src/objects/bus_stop.rs b/map_model/src/objects/bus_stop.rs index 358db347e9..eddb88dc5d 100644 --- a/map_model/src/objects/bus_stop.rs +++ b/map_model/src/objects/bus_stop.rs @@ -49,7 +49,8 @@ pub struct BusRoute { pub full_name: String, pub short_name: String, pub stops: Vec, - pub start_border: Option, + // May be a border or not. If not, is long enough for buses to spawn fully. + pub start: LaneID, pub end_border: Option, pub route_type: PathConstraints, } @@ -57,13 +58,11 @@ pub struct BusRoute { impl BusRoute { pub fn all_steps(&self, map: &Map) -> Vec { let mut steps = Vec::new(); - if let Some(start) = self.start_border { - steps.push(PathRequest { - start: Position::start(start), - end: map.get_bs(self.stops[0]).driving_pos, - constraints: self.route_type, - }); - } + steps.push(PathRequest { + start: Position::start(self.start), + end: map.get_bs(self.stops[0]).driving_pos, + constraints: self.route_type, + }); for pair in self.stops.windows(2) { steps.push(PathRequest { start: map.get_bs(pair[0]).driving_pos, diff --git a/sim/src/mechanics/car.rs b/sim/src/mechanics/car.rs index 92df817bb8..a013a02bb6 100644 --- a/sim/src/mechanics/car.rs +++ b/sim/src/mechanics/car.rs @@ -104,8 +104,11 @@ impl Car { if result.len() < 2 { panic!( - "{} at {} has front at {}. Didn't even wind up with two points", - self.vehicle.id, now, front + "{} at {} has front at {} of {:?}. Didn't even wind up with two points", + self.vehicle.id, + now, + front, + self.router.head() ); } match PolyLine::new(result) { diff --git a/sim/src/sim.rs b/sim/src/sim.rs index 3aafb32dce..01e443e67f 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -245,12 +245,19 @@ impl Sim { max_speed: None, } .make(CarID(self.trips.new_car_id(), vehicle_type), None); + let start_lane = map.get_l(path.current_step().as_lane()); + let start_dist = if map.get_i(start_lane.src_i).is_incoming_border() { + EPSILON_DIST + } else { + assert!(start_lane.length() > vehicle.length); + vehicle.length + }; self.scheduler.push( self.time, Command::SpawnCar( CreateCar { - start_dist: EPSILON_DIST, + start_dist, router: Router::follow_bus_route( vehicle.id, path.clone(), diff --git a/sim/src/transit.rs b/sim/src/transit.rs index b7bbed3cd6..344072b29e 100644 --- a/sim/src/transit.rs +++ b/sim/src/transit.rs @@ -116,11 +116,7 @@ impl TransitSimState { } } let start_req = PathRequest { - start: Position::start( - bus_route - .start_border - .unwrap_or(stops[0].driving_pos.lane()), - ), + start: Position::start(bus_route.start), end: map.get_bs(bus_route.stops[0]).driving_pos, constraints: bus_route.route_type, };