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!
This commit is contained in:
Dustin Carlino 2020-08-03 11:08:21 -07:00
parent b7ed2615b1
commit 940d2265c0
8 changed files with 116 additions and 78 deletions

View File

@ -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

View File

@ -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(

View File

@ -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: {:?}",

View File

@ -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<RawBusRoute>, 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<dyn Error>> {
// 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,23 +250,12 @@ 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))
.ok_or("sidewalk didnt match")?
} 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
@ -276,18 +266,60 @@ impl Matcher {
orig_driving_pos.lane(),
vec![LaneType::Sidewalk, LaneType::Shoulder],
)?;
let sidewalk_pos = orig_driving_pos.equiv_pos(sidewalk, map);
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))
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 {
Err(format!("Driving position {} is too short", lane).into())
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<LaneID, String> {
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()
))
}

View File

@ -49,7 +49,8 @@ pub struct BusRoute {
pub full_name: String,
pub short_name: String,
pub stops: Vec<BusStopID>,
pub start_border: Option<LaneID>,
// May be a border or not. If not, is long enough for buses to spawn fully.
pub start: LaneID,
pub end_border: Option<LaneID>,
pub route_type: PathConstraints,
}
@ -57,13 +58,11 @@ pub struct BusRoute {
impl BusRoute {
pub fn all_steps(&self, map: &Map) -> Vec<PathRequest> {
let mut steps = Vec::new();
if let Some(start) = self.start_border {
steps.push(PathRequest {
start: Position::start(start),
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,

View File

@ -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) {

View File

@ -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(),

View File

@ -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,
};