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