mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-18 03:41:52 +03:00
Add a flag to detect drivers who're destined to pass through a currently delayed area. #325
This commit is contained in:
parent
06f088afcc
commit
0259750eb3
@ -537,13 +537,13 @@ impl Map {
|
||||
assert!(!self.pathfinder_dirty);
|
||||
self.pathfinder.pathfind(req, self)
|
||||
}
|
||||
pub fn pathfind_avoiding_zones(
|
||||
pub fn pathfind_avoiding_lanes(
|
||||
&self,
|
||||
req: PathRequest,
|
||||
avoid: BTreeSet<LaneID>,
|
||||
) -> Option<Path> {
|
||||
assert!(!self.pathfinder_dirty);
|
||||
self.pathfinder.pathfind_avoiding_zones(req, avoid, self)
|
||||
self.pathfinder.pathfind_avoiding_lanes(req, avoid, self)
|
||||
}
|
||||
|
||||
pub fn should_use_transit(
|
||||
|
@ -34,7 +34,7 @@ pub fn pathfind(req: PathRequest, map: &Map) -> Option<Path> {
|
||||
calc_path(graph, req, map)
|
||||
}
|
||||
|
||||
pub fn pathfind_avoiding_zones(
|
||||
pub fn pathfind_avoiding_lanes(
|
||||
req: PathRequest,
|
||||
avoid: BTreeSet<LaneID>,
|
||||
map: &Map,
|
||||
|
@ -606,13 +606,13 @@ impl Pathfinder {
|
||||
Pathfinder::CH(ref p) => p.pathfind(req, map),
|
||||
}
|
||||
}
|
||||
pub fn pathfind_avoiding_zones(
|
||||
pub fn pathfind_avoiding_lanes(
|
||||
&self,
|
||||
req: PathRequest,
|
||||
avoid: BTreeSet<LaneID>,
|
||||
map: &Map,
|
||||
) -> Option<Path> {
|
||||
dijkstra::pathfind_avoiding_zones(req, avoid, map)
|
||||
dijkstra::pathfind_avoiding_lanes(req, avoid, map)
|
||||
}
|
||||
|
||||
pub fn should_use_transit(
|
||||
|
@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
|
||||
use geom::{Duration, Time};
|
||||
use map_model::{LaneID, Map, Path, PathConstraints, PathRequest, PathStep};
|
||||
|
||||
use crate::{CarID, VehicleType};
|
||||
use crate::mechanics::IntersectionSimState;
|
||||
use crate::{CarID, SimOptions, VehicleType};
|
||||
|
||||
// Note this only indexes into the zones we track here, not all of them in the map.
|
||||
type ZoneIdx = usize;
|
||||
@ -16,6 +17,7 @@ type ZoneIdx = usize;
|
||||
pub struct CapSimState {
|
||||
lane_to_zone: BTreeMap<LaneID, ZoneIdx>,
|
||||
zones: Vec<Zone>,
|
||||
avoid_congestion: Option<AvoidCongestion>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
@ -27,10 +29,13 @@ struct Zone {
|
||||
}
|
||||
|
||||
impl CapSimState {
|
||||
pub fn new(map: &Map) -> CapSimState {
|
||||
pub fn new(map: &Map, opts: &SimOptions) -> CapSimState {
|
||||
let mut sim = CapSimState {
|
||||
lane_to_zone: BTreeMap::new(),
|
||||
zones: Vec::new(),
|
||||
avoid_congestion: opts
|
||||
.cancel_drivers_delay_threshold
|
||||
.map(|delay_threshold| AvoidCongestion { delay_threshold }),
|
||||
};
|
||||
for z in map.all_zones() {
|
||||
if let Some(cap) = z.restrictions.cap_vehicles_per_hour {
|
||||
@ -53,7 +58,7 @@ impl CapSimState {
|
||||
}
|
||||
|
||||
fn allow_trip(&mut self, now: Time, car: CarID, path: &Path) -> bool {
|
||||
if car.1 != VehicleType::Car {
|
||||
if car.1 != VehicleType::Car || self.lane_to_zone.is_empty() {
|
||||
return true;
|
||||
}
|
||||
for step in path.get_steps() {
|
||||
@ -87,8 +92,17 @@ impl CapSimState {
|
||||
now: Time,
|
||||
car: CarID,
|
||||
capped: &mut bool,
|
||||
intersections: &IntersectionSimState,
|
||||
map: &Map,
|
||||
) -> Option<Path> {
|
||||
if let Some(ref avoid) = self.avoid_congestion {
|
||||
if avoid.path_crosses_delay(now, &path, intersections, map) {
|
||||
*capped = true;
|
||||
// TODO More responses
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
if self.allow_trip(now, car, &path) {
|
||||
return Some(path);
|
||||
}
|
||||
@ -106,7 +120,7 @@ impl CapSimState {
|
||||
avoid_lanes.insert(*l);
|
||||
}
|
||||
}
|
||||
map.pathfind_avoiding_zones(req.clone(), avoid_lanes)
|
||||
map.pathfind_avoiding_lanes(req.clone(), avoid_lanes)
|
||||
}
|
||||
|
||||
pub fn get_cap_counter(&self, l: LaneID) -> usize {
|
||||
@ -117,3 +131,47 @@ impl CapSimState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Before the driving portion of a trip begins, check that the desired path doesn't pass through
|
||||
/// any road with agents currently experiencing some delay.
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
struct AvoidCongestion {
|
||||
delay_threshold: Duration,
|
||||
}
|
||||
|
||||
impl AvoidCongestion {
|
||||
fn path_crosses_delay(
|
||||
&self,
|
||||
now: Time,
|
||||
path: &Path,
|
||||
intersections: &IntersectionSimState,
|
||||
map: &Map,
|
||||
) -> bool {
|
||||
for step in path.get_steps() {
|
||||
if let PathStep::Lane(l) = step {
|
||||
let lane = map.get_l(*l);
|
||||
for (agent, turn, start) in intersections.get_waiting_agents(lane.dst_i) {
|
||||
if now - start < self.delay_threshold {
|
||||
continue;
|
||||
}
|
||||
if agent.to_vehicle_type() != Some(VehicleType::Car) {
|
||||
continue;
|
||||
}
|
||||
if map.get_l(turn.src).parent != lane.parent {
|
||||
continue;
|
||||
}
|
||||
// TODO Should we make sure the delayed agent is also trying to go the same
|
||||
// direction? For example, people turning left somewhere might be delayed, while
|
||||
// people going straight are fine. But then the presence of a turn lane matters.
|
||||
debug!(
|
||||
"Someone's path crosses a delay of {} at {}",
|
||||
now - start,
|
||||
turn
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -105,6 +105,9 @@ pub struct SimOptions {
|
||||
/// agent. Obviously this destroys realism of the simulation, but can be used to debug
|
||||
/// gridlock. Also implies freeform_policy, so vehicles ignore traffic signals.
|
||||
pub disable_turn_conflicts: bool,
|
||||
/// If present, cancel any driving trips who will pass through a road currently experiencing
|
||||
/// delays beyond this threshold.
|
||||
pub cancel_drivers_delay_threshold: Option<Duration>,
|
||||
}
|
||||
|
||||
impl std::default::Default for SimOptions {
|
||||
@ -141,6 +144,8 @@ impl SimOptions {
|
||||
pathfinding_upfront: args.enabled("--pathfinding_upfront"),
|
||||
infinite_parking: args.enabled("--infinite_parking"),
|
||||
disable_turn_conflicts: args.enabled("--disable_turn_conflicts"),
|
||||
cancel_drivers_delay_threshold: args
|
||||
.optional_parse("--cancel_drivers_delay_threshold", Duration::parse),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,6 +180,7 @@ impl SimOptions {
|
||||
pathfinding_upfront: false,
|
||||
infinite_parking: false,
|
||||
disable_turn_conflicts: false,
|
||||
cancel_drivers_delay_threshold: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -189,7 +195,7 @@ impl Sim {
|
||||
walking: WalkingSimState::new(),
|
||||
intersections: IntersectionSimState::new(map, &mut scheduler, &opts),
|
||||
transit: TransitSimState::new(map),
|
||||
cap: CapSimState::new(map),
|
||||
cap: CapSimState::new(map, &opts),
|
||||
trips: TripManager::new(opts.pathfinding_upfront),
|
||||
pandemic: if let Some(rng) = opts.enable_pandemic_model {
|
||||
Some(PandemicModel::new(rng))
|
||||
|
@ -298,6 +298,7 @@ impl TripManager {
|
||||
now,
|
||||
parked_car.vehicle.id,
|
||||
&mut trip.info.capped,
|
||||
ctx.intersections,
|
||||
ctx.map,
|
||||
)
|
||||
}) {
|
||||
@ -1046,6 +1047,7 @@ impl TripManager {
|
||||
now,
|
||||
vehicle.id,
|
||||
&mut self.trips[trip.0].info.capped,
|
||||
ctx.intersections,
|
||||
ctx.map,
|
||||
)
|
||||
}) {
|
||||
|
Loading…
Reference in New Issue
Block a user