1 use crate::mechanics::car::{Car, CarState};
2 use crate::{CarID, VehicleType, FOLLOWING_DISTANCE};
3 use geom::{Distance, Time};
4 use map_model::{Map, Traversable};
5 use serde::{Deserialize, Serialize};
6 use std::collections::{BTreeMap, BTreeSet, VecDeque};
7 
8 #[derive(Serialize, Deserialize, Clone)]
9 pub struct Queue {
10     pub id: Traversable,
11     pub cars: VecDeque<CarID>,
12     // This car's back is still partly in this queue.
13     pub laggy_head: Option<CarID>,
14 
15     pub geom_len: Distance,
16     // When a car's turn is accepted, reserve the vehicle length + FOLLOWING_DISTANCE for the
17     // target lane. When the car completely leaves (stops being the laggy_head), free up that
18     // space. To prevent blocking the box for possibly scary amounts of time, allocate some of this
19     // length first. This is unused for turns themselves. This value can exceed geom_len (for the
20     // edge case of ONE long car on a short queue).
21     pub reserved_length: Distance,
22 }
23 
24 impl Queue {
new(id: Traversable, map: &Map) -> Queue25     pub fn new(id: Traversable, map: &Map) -> Queue {
26         Queue {
27             id,
28             cars: VecDeque::new(),
29             laggy_head: None,
30             geom_len: id.length(map),
31             reserved_length: Distance::ZERO,
32         }
33     }
34 
35     // Farthest along (greatest distance) is first.
get_car_positions( &self, now: Time, cars: &BTreeMap<CarID, Car>, queues: &BTreeMap<Traversable, Queue>, ) -> Vec<(CarID, Distance)>36     pub fn get_car_positions(
37         &self,
38         now: Time,
39         cars: &BTreeMap<CarID, Car>,
40         queues: &BTreeMap<Traversable, Queue>,
41     ) -> Vec<(CarID, Distance)> {
42         self.inner_get_car_positions(now, cars, queues, &mut BTreeSet::new())
43     }
44 
inner_get_car_positions( &self, now: Time, cars: &BTreeMap<CarID, Car>, queues: &BTreeMap<Traversable, Queue>, recursed_queues: &mut BTreeSet<Traversable>, ) -> Vec<(CarID, Distance)>45     fn inner_get_car_positions(
46         &self,
47         now: Time,
48         cars: &BTreeMap<CarID, Car>,
49         queues: &BTreeMap<Traversable, Queue>,
50         recursed_queues: &mut BTreeSet<Traversable>,
51     ) -> Vec<(CarID, Distance)> {
52         if self.cars.is_empty() {
53             return Vec::new();
54         }
55 
56         let mut result: Vec<(CarID, Distance)> = Vec::new();
57 
58         for id in &self.cars {
59             let bound = match result.last() {
60                 Some((leader, last_dist)) => {
61                     *last_dist - cars[leader].vehicle.length - FOLLOWING_DISTANCE
62                 }
63                 None => match self.laggy_head {
64                     Some(id) => {
65                         // The simple but broken version:
66                         //self.geom_len - cars[&id].vehicle.length - FOLLOWING_DISTANCE
67 
68                         // The expensive case. We need to figure out exactly where the laggy head
69                         // is on their queue.
70                         let leader = &cars[&id];
71 
72                         // But don't create a cycle!
73                         let recurse_to = leader.router.head();
74                         if recursed_queues.contains(&recurse_to) {
75                             // See the picture in
76                             // https://github.com/dabreegster/abstreet/issues/30. We have two
77                             // extremes to break the cycle.
78                             //
79                             // 1) Hope that the last person in this queue isn't bounded by the
80                             //    agent in front of them yet. geom_len
81                             // 2) Assume the leader has advanced minimally into the next lane.
82                             //    geom_len - laggy head's length - FOLLOWING_DISTANCE.
83                             //
84                             // For now, optimistically assume 1. If we're wrong, consequences could
85                             // be queue spillover (we're too optimistic about the number of
86                             // vehicles that can fit on a lane) or cars jumping positions slightly
87                             // while the cycle occurs.
88                             self.geom_len
89                         } else {
90                             recursed_queues.insert(recurse_to);
91 
92                             let (head, head_dist) = *queues[&leader.router.head()]
93                                 .inner_get_car_positions(now, cars, queues, recursed_queues)
94                                 .last()
95                                 .unwrap();
96                             assert_eq!(head, id);
97 
98                             let mut dist_away_from_this_queue = head_dist;
99                             for on in &leader.last_steps {
100                                 if *on == self.id {
101                                     break;
102                                 }
103                                 dist_away_from_this_queue += queues[on].geom_len;
104                             }
105                             // They might actually be out of the way, but laggy_head hasn't been
106                             // updated yet.
107                             if dist_away_from_this_queue
108                                 < leader.vehicle.length + FOLLOWING_DISTANCE
109                             {
110                                 self.geom_len
111                                     - (cars[&id].vehicle.length - dist_away_from_this_queue)
112                                     - FOLLOWING_DISTANCE
113                             } else {
114                                 self.geom_len
115                             }
116                         }
117                     }
118                     None => self.geom_len,
119                 },
120             };
121 
122             // There's spillover and a car shouldn't have been able to enter yet.
123             if bound < Distance::ZERO {
124                 dump_cars(&result, cars, self.id, now);
125                 panic!(
126                     "Queue has spillover on {} at {} -- can't draw {}, bound is {}. Laggy head is \
127                      {:?}. This is usually a geometry bug; check for duplicate roads going \
128                      between the same intersections.",
129                     self.id, now, id, bound, self.laggy_head
130                 );
131             }
132 
133             let car = &cars[id];
134             let front = match car.state {
135                 CarState::Queued { .. } => {
136                     if car.router.last_step() {
137                         car.router.get_end_dist().min(bound)
138                     } else {
139                         bound
140                     }
141                 }
142                 CarState::WaitingToAdvance { .. } => {
143                     assert_eq!(bound, self.geom_len);
144                     self.geom_len
145                 }
146                 CarState::Crossing(ref time_int, ref dist_int) => {
147                     // TODO Why percent_clamp_end? We process car updates in any order, so we might
148                     // calculate this before moving this car from Crossing to another state.
149                     dist_int.lerp(time_int.percent_clamp_end(now)).min(bound)
150                 }
151                 CarState::Unparking(front, _, _) => front,
152                 CarState::Parking(front, _, _) => front,
153                 CarState::IdlingAtStop(front, _) => front,
154             };
155 
156             result.push((*id, front));
157         }
158         validate_positions(result, cars, now, self.id)
159     }
160 
get_idx_to_insert_car( &self, start_dist: Distance, vehicle_len: Distance, now: Time, cars: &BTreeMap<CarID, Car>, queues: &BTreeMap<Traversable, Queue>, ) -> Option<usize>161     pub fn get_idx_to_insert_car(
162         &self,
163         start_dist: Distance,
164         vehicle_len: Distance,
165         now: Time,
166         cars: &BTreeMap<CarID, Car>,
167         queues: &BTreeMap<Traversable, Queue>,
168     ) -> Option<usize> {
169         if self.laggy_head.is_none() && self.cars.is_empty() {
170             return Some(0);
171         }
172 
173         let dists = self.get_car_positions(now, cars, queues);
174         // TODO Binary search
175         let idx = match dists.iter().position(|(_, dist)| start_dist >= *dist) {
176             Some(i) => i,
177             None => dists.len(),
178         };
179 
180         // Nope, there's not actually room at the front right now.
181         if self.laggy_head.is_some() && idx == 0 {
182             return None;
183         }
184 
185         // Are we too close to the leader?
186         if idx != 0
187             && dists[idx - 1].1 - cars[&dists[idx - 1].0].vehicle.length - FOLLOWING_DISTANCE
188                 < start_dist
189         {
190             return None;
191         }
192         // Or the follower?
193         if idx != dists.len() && start_dist - vehicle_len - FOLLOWING_DISTANCE < dists[idx].1 {
194             return None;
195         }
196 
197         Some(idx)
198     }
199 
200     // If true, there's room and the car must actually start the turn (because the space is
201     // reserved).
try_to_reserve_entry(&mut self, car: &Car, force_entry: bool) -> bool202     pub fn try_to_reserve_entry(&mut self, car: &Car, force_entry: bool) -> bool {
203         // Sometimes a car + FOLLOWING_DISTANCE might be longer than the geom_len entirely. In that
204         // case, it just means the car won't totally fit on the queue at once, which is fine.
205         // Reserve the normal amount of space; the next car trying to enter will get rejected.
206         // Also allow this don't-block-the-box prevention to be disabled.
207         let dist = car.vehicle.length + FOLLOWING_DISTANCE;
208         if self.reserved_length + dist < self.geom_len
209             || self.reserved_length == Distance::ZERO
210             || force_entry
211         {
212             self.reserved_length += dist;
213             return true;
214         }
215         false
216     }
217 
218     // TODO Refactor
room_for_car(&self, car: &Car) -> bool219     pub fn room_for_car(&self, car: &Car) -> bool {
220         self.reserved_length == Distance::ZERO
221             || self.reserved_length + car.vehicle.length + FOLLOWING_DISTANCE < self.geom_len
222     }
223 
free_reserved_space(&mut self, car: &Car)224     pub fn free_reserved_space(&mut self, car: &Car) {
225         self.reserved_length -= car.vehicle.length + FOLLOWING_DISTANCE;
226         assert!(self.reserved_length >= Distance::ZERO);
227     }
228 
target_lane_penalty(&self) -> (usize, usize)229     pub fn target_lane_penalty(&self) -> (usize, usize) {
230         let mut num_vehicles = self.cars.len();
231         if self.laggy_head.is_some() {
232             num_vehicles += 1;
233         }
234 
235         let bike_cost = if self.cars.iter().any(|c| c.1 == VehicleType::Bike)
236             || self
237                 .laggy_head
238                 .map(|c| c.1 == VehicleType::Bike)
239                 .unwrap_or(false)
240         {
241             1
242         } else {
243             0
244         };
245 
246         (num_vehicles, bike_cost)
247     }
248 }
249 
validate_positions( dists: Vec<(CarID, Distance)>, cars: &BTreeMap<CarID, Car>, now: Time, id: Traversable, ) -> Vec<(CarID, Distance)>250 fn validate_positions(
251     dists: Vec<(CarID, Distance)>,
252     cars: &BTreeMap<CarID, Car>,
253     now: Time,
254     id: Traversable,
255 ) -> Vec<(CarID, Distance)> {
256     for pair in dists.windows(2) {
257         if pair[0].1 - cars[&pair[0].0].vehicle.length - FOLLOWING_DISTANCE < pair[1].1 {
258             dump_cars(&dists, cars, id, now);
259             panic!(
260                 "get_car_positions wound up with bad positioning: {} then {}\n{:?}",
261                 pair[0].1, pair[1].1, dists
262             );
263         }
264     }
265     dists
266 }
267 
dump_cars( dists: &Vec<(CarID, Distance)>, cars: &BTreeMap<CarID, Car>, id: Traversable, now: Time, )268 fn dump_cars(
269     dists: &Vec<(CarID, Distance)>,
270     cars: &BTreeMap<CarID, Car>,
271     id: Traversable,
272     now: Time,
273 ) {
274     println!("\nOn {} at {}...", id, now);
275     for (id, dist) in dists {
276         let car = &cars[id];
277         println!("- {} @ {} (length {})", id, dist, car.vehicle.length);
278         match car.state {
279             CarState::Crossing(ref time_int, ref dist_int) => {
280                 println!(
281                     "  Going {} .. {} during {} .. {}",
282                     dist_int.start, dist_int.end, time_int.start, time_int.end
283                 );
284             }
285             CarState::Queued { .. } => {
286                 println!("  Queued currently");
287             }
288             CarState::WaitingToAdvance { .. } => {
289                 println!("  WaitingToAdvance currently");
290             }
291             CarState::Unparking(_, _, ref time_int) => {
292                 println!("  Unparking during {} .. {}", time_int.start, time_int.end);
293             }
294             CarState::Parking(_, _, ref time_int) => {
295                 println!("  Parking during {} .. {}", time_int.start, time_int.end);
296             }
297             CarState::IdlingAtStop(_, ref time_int) => {
298                 println!("  Idling during {} .. {}", time_int.start, time_int.end);
299             }
300         }
301     }
302     println!();
303 }
304