sim/
router.rs

1//! For vehicles only, not pedestrians. Follows a Path from map_model, but can opportunistically
2//! lane-change to avoid a slow lane, can can handle re-planning to look for available parking.
3
4use std::collections::HashMap;
5
6use serde::{Deserialize, Serialize};
7
8use geom::Distance;
9use map_model::{
10    BuildingID, IntersectionID, LaneID, Map, Path, PathConstraints, PathRequest, PathStep,
11    Position, Traversable, Turn, TurnID,
12};
13
14use crate::mechanics::Queue;
15use crate::{
16    AlertLocation, CarID, Event, ParkingSim, ParkingSimState, ParkingSpot, PersonID, SidewalkSpot,
17    TripID, TripPhaseType, Vehicle, VehicleType,
18};
19
20#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
21pub(crate) struct Router {
22    /// Front is always the current step
23    path: Path,
24    goal: Goal,
25    owner: CarID,
26}
27
28#[derive(Debug)]
29pub(crate) enum ActionAtEnd {
30    VanishAtBorder(IntersectionID),
31    StartParking(ParkingSpot),
32    GotoLaneEnd,
33    StopBiking(SidewalkSpot),
34    BusAtStop,
35    GiveUpOnParking,
36}
37
38#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
39enum Goal {
40    /// Spot and cached distance along the last driving lane
41    ParkNearBuilding {
42        target: BuildingID,
43        spot: Option<(ParkingSpot, Distance)>,
44        /// No parking available at all!
45        stuck_end_dist: Option<Distance>,
46        started_looking: bool,
47    },
48    EndAtBorder {
49        end_dist: Distance,
50        i: IntersectionID,
51    },
52    BikeThenStop {
53        goal: SidewalkSpot,
54    },
55    FollowTransitRoute {
56        end_dist: Distance,
57    },
58}
59
60impl Router {
61    pub fn end_at_border(
62        owner: CarID,
63        path: Path,
64        end_dist: Distance,
65        i: IntersectionID,
66    ) -> Router {
67        Router {
68            path,
69            goal: Goal::EndAtBorder { end_dist, i },
70            owner,
71        }
72    }
73
74    pub fn park_near(owner: CarID, path: Path, bldg: BuildingID) -> Router {
75        Router {
76            path,
77            goal: Goal::ParkNearBuilding {
78                target: bldg,
79                spot: None,
80                stuck_end_dist: None,
81                started_looking: false,
82            },
83            owner,
84        }
85    }
86
87    pub fn bike_then_stop(owner: CarID, path: Path, goal: SidewalkSpot) -> Router {
88        Router {
89            goal: Goal::BikeThenStop { goal },
90            path,
91            owner,
92        }
93    }
94
95    pub fn follow_bus_route(owner: CarID, path: Path) -> Router {
96        Router {
97            goal: Goal::FollowTransitRoute {
98                end_dist: path.get_req().end.dist_along(),
99            },
100            path,
101            owner,
102        }
103    }
104
105    pub fn head(&self) -> Traversable {
106        self.path.current_step().as_traversable()
107    }
108
109    pub fn next(&self) -> Traversable {
110        self.path.next_step().as_traversable()
111    }
112
113    pub fn maybe_next(&self) -> Option<Traversable> {
114        self.path.maybe_next_step().map(|s| s.as_traversable())
115    }
116
117    pub fn last_step(&self) -> bool {
118        self.path.is_last_step()
119    }
120
121    pub fn get_end_dist(&self) -> Distance {
122        // Shouldn't ask earlier!
123        assert!(self.last_step());
124        match self.goal {
125            Goal::EndAtBorder { end_dist, .. } => end_dist,
126            Goal::ParkNearBuilding {
127                spot,
128                stuck_end_dist,
129                ..
130            } => stuck_end_dist.unwrap_or_else(|| spot.unwrap().1),
131            Goal::BikeThenStop { ref goal } => goal.sidewalk_pos.dist_along(),
132            Goal::FollowTransitRoute { end_dist } => end_dist,
133        }
134    }
135
136    pub fn get_path(&self) -> &Path {
137        &self.path
138    }
139
140    /// Returns the step just finished
141    pub fn advance(
142        &mut self,
143        vehicle: &Vehicle,
144        parking: &ParkingSimState,
145        map: &Map,
146        trip_and_person: Option<(TripID, PersonID)>,
147        events: &mut Vec<Event>,
148    ) -> Traversable {
149        let prev = self.path.shift(map).as_traversable();
150        if self.last_step() {
151            // Do this to trigger the side-effect of looking for parking.
152            self.maybe_handle_end(
153                Distance::ZERO,
154                vehicle,
155                parking,
156                map,
157                trip_and_person,
158                events,
159            );
160        }
161
162        // Sanity check laws haven't been broken
163        if let Traversable::Lane(l) = self.head() {
164            let lane = map.get_l(l);
165            if !vehicle.vehicle_type.to_constraints().can_use(lane, map) {
166                panic!(
167                    "{} just wound up on {}, a {:?} (check the OSM tags)",
168                    vehicle.id, l, lane.lane_type
169                );
170            }
171        }
172
173        prev
174    }
175
176    /// Called when the car is Queued at the last step, or when they initially advance to the last
177    /// step.
178    pub fn maybe_handle_end(
179        &mut self,
180        front: Distance,
181        vehicle: &Vehicle,
182        parking: &ParkingSimState,
183        map: &Map,
184        // TODO Not so nice to plumb all of this here
185        trip_and_person: Option<(TripID, PersonID)>,
186        events: &mut Vec<Event>,
187    ) -> Option<ActionAtEnd> {
188        assert!(self.path.is_last_step());
189
190        match self.goal {
191            Goal::EndAtBorder { end_dist, i } => {
192                if end_dist == front {
193                    Some(ActionAtEnd::VanishAtBorder(i))
194                } else {
195                    None
196                }
197            }
198            Goal::ParkNearBuilding {
199                ref mut spot,
200                ref mut stuck_end_dist,
201                target,
202                ref mut started_looking,
203            } => {
204                if let Some(d) = stuck_end_dist {
205                    if *d == front {
206                        return Some(ActionAtEnd::GiveUpOnParking);
207                    } else {
208                        return None;
209                    }
210                }
211
212                let need_new_spot = match spot {
213                    Some((s, _)) => !parking.is_free(*s),
214                    None => true,
215                };
216                if need_new_spot {
217                    *started_looking = true;
218                    let current_lane = self.path.current_step().as_lane();
219                    let candidates = parking.get_all_free_spots(
220                        Position::new(current_lane, front),
221                        vehicle,
222                        target,
223                        map,
224                    );
225                    let best =
226                        if let Some((driving_pos, _)) = map.get_b(target).driving_connection(map) {
227                            if driving_pos.lane() == current_lane {
228                                let target_dist = driving_pos.dist_along();
229                                // Closest to the building
230                                candidates
231                                    .into_iter()
232                                    .min_by_key(|(_, pos)| (pos.dist_along() - target_dist).abs())
233                            } else {
234                                // Closest to the road endpoint, I guess
235                                candidates
236                                    .into_iter()
237                                    .min_by_key(|(_, pos)| pos.dist_along())
238                            }
239                        } else {
240                            // Closest to the road endpoint, I guess
241                            candidates
242                                .into_iter()
243                                .min_by_key(|(_, pos)| pos.dist_along())
244                        };
245                    if let Some((new_spot, new_pos)) = best {
246                        if let Some((t, p)) = trip_and_person {
247                            events.push(Event::TripPhaseStarting(
248                                t,
249                                p,
250                                Some(PathRequest::vehicle(
251                                    Position::new(current_lane, front),
252                                    new_pos,
253                                    PathConstraints::Car,
254                                )),
255                                TripPhaseType::Parking,
256                            ));
257                        }
258                        assert_eq!(new_pos.lane(), current_lane);
259                        assert!(new_pos.dist_along() >= front);
260                        *spot = Some((new_spot, new_pos.dist_along()));
261                    } else {
262                        if let Some((new_path_steps, new_spot, new_pos)) =
263                            parking.path_to_free_parking_spot(current_lane, vehicle, target, map)
264                        {
265                            assert!(!new_path_steps.is_empty());
266                            for step in new_path_steps {
267                                self.path.add(step, map);
268                            }
269                            *spot = Some((new_spot, new_pos.dist_along()));
270                            events.push(Event::PathAmended(self.path.clone()));
271                            // TODO This path might not be the same as the one found here...
272                            if let Some((t, p)) = trip_and_person {
273                                events.push(Event::TripPhaseStarting(
274                                    t,
275                                    p,
276                                    Some(PathRequest::vehicle(
277                                        Position::new(current_lane, front),
278                                        new_pos,
279                                        PathConstraints::Car,
280                                    )),
281                                    TripPhaseType::Parking,
282                                ));
283                            }
284                        } else {
285                            if let Some((_, p)) = trip_and_person {
286                                events.push(Event::Alert(
287                                    AlertLocation::Person(p),
288                                    format!(
289                                        "{} can't find parking on {} or anywhere reachable from \
290                                         it. Possibly we're just totally out of parking space!",
291                                        vehicle.id, current_lane
292                                    ),
293                                ));
294                            }
295                            *stuck_end_dist = Some(map.get_l(current_lane).length());
296                        }
297                        return Some(ActionAtEnd::GotoLaneEnd);
298                    }
299                }
300
301                if spot.unwrap().1 == front {
302                    Some(ActionAtEnd::StartParking(spot.unwrap().0))
303                } else {
304                    None
305                }
306            }
307            Goal::BikeThenStop { ref goal } => {
308                if goal.sidewalk_pos.dist_along() == front {
309                    Some(ActionAtEnd::StopBiking(goal.clone()))
310                } else {
311                    None
312                }
313            }
314            Goal::FollowTransitRoute { end_dist } => {
315                if end_dist == front {
316                    Some(ActionAtEnd::BusAtStop)
317                } else {
318                    None
319                }
320            }
321        }
322    }
323
324    pub fn opportunistically_lanechange(
325        &mut self,
326        queues: &HashMap<Traversable, Queue>,
327        map: &Map,
328        handle_uber_turns: bool,
329    ) {
330        // if we're already in the uber-turn, we're committed, but if we're about to enter one, lock
331        // in the best path through it now.
332        if handle_uber_turns && self.path.currently_inside_ut().is_some() {
333            return;
334        }
335
336        let mut segment = 0;
337        loop {
338            let (current_turn, next_lane) = {
339                let steps = self.path.get_steps();
340                if steps.len() < 5 + segment * 2 {
341                    return;
342                }
343                match (steps[1 + segment * 2], steps[4 + segment * 2]) {
344                    (PathStep::Turn(t), PathStep::Lane(l)) => (t, l),
345                    _ => {
346                        return;
347                    }
348                }
349            };
350
351            let orig_target_lane = current_turn.dst;
352            let parent = map.get_parent(orig_target_lane);
353            let next_parent = map.get_l(next_lane).src_i;
354            let constraints = self.owner.vehicle_type.to_constraints();
355
356            let compute_cost = |turn1: &Turn, lane: LaneID| {
357                let (lt, lc, mut slow_lane) = turn1.penalty(constraints, map);
358                let (vehicles, mut bike) = queues[&Traversable::Lane(lane)].target_lane_penalty();
359
360                // The magic happens here. We have different penalties:
361                //
362                // 1) Are we headed towards a general purpose lane instead of a dedicated bike/bus
363                //    lane?
364                // 2) Are there any bikes in the target lane? This ONLY matters if we're a car. If
365                //    we're another bike, the speed difference won't matter.
366                // 3) IF we're a bike, are we headed to something other than the slow (rightmost in
367                //    the US) lane?
368                // 4) Are there lots of vehicles stacked up in one lane?
369                // 5) Are we changing lanes?
370                //
371                // A linear combination of these penalties is hard to reason about. We mostly
372                // make our choice based on each penalty in order, breaking ties by moving onto the
373                // next thing. With one exception: To produce more realistic behavior, we combine
374                // `vehicles + lc` as one score to avoid switching lanes just to get around one car.
375                if self.owner.vehicle_type == VehicleType::Bike {
376                    bike = 0;
377                } else {
378                    slow_lane = 0;
379                }
380
381                (lt, bike, slow_lane, vehicles + lc)
382            };
383
384            // Look for other candidates, and assign a cost to each.
385            let mut original_cost = None;
386            let dir = map.get_l(orig_target_lane).dir;
387            let best = parent
388                .lanes
389                .iter()
390                .filter(|l| l.dir == dir && constraints.can_use(l, map))
391                .filter_map(|l| {
392                    // Make sure we can go from this lane to next_lane.
393
394                    let t1 = TurnID {
395                        parent: current_turn.parent,
396                        src: current_turn.src,
397                        dst: l.id,
398                    };
399                    let turn1 = map.maybe_get_t(t1)?;
400
401                    let t2 = TurnID {
402                        parent: next_parent,
403                        src: l.id,
404                        dst: next_lane,
405                    };
406                    let turn2 = map.maybe_get_t(t2)?;
407
408                    Some((turn1, l.id, turn2))
409                })
410                .map(|(turn1, l, turn2)| {
411                    let cost = compute_cost(turn1, l);
412                    if turn1.id == current_turn {
413                        original_cost = Some(cost);
414                    }
415                    (cost, turn1, l, turn2)
416                })
417                .min_by_key(|(cost, _, _, _)| *cost);
418
419            if best.is_none() {
420                error!("no valid paths found: {:?}", self.owner);
421                return;
422            }
423            let (best_cost, turn1, best_lane, turn2) = best.unwrap();
424
425            if original_cost.is_none() {
426                error!("original_cost was unexpectedly None {:?}", self.owner);
427                return;
428            }
429            let original_cost = original_cost.unwrap();
430
431            // Only switch if the target queue is some amount better; don't oscillate
432            // unnecessarily.
433            if best_cost < original_cost {
434                debug!(
435                    "changing lanes {:?} -> {:?}, cost: {:?} -> {:?}",
436                    orig_target_lane, best_lane, original_cost, best_cost
437                );
438                self.path
439                    .modify_step(1 + segment * 2, PathStep::Turn(turn1.id), map);
440                self.path
441                    .modify_step(2 + segment * 2, PathStep::Lane(best_lane), map);
442                self.path
443                    .modify_step(3 + segment * 2, PathStep::Turn(turn2.id), map);
444            }
445
446            if self.path.is_upcoming_uber_turn_component(turn2.id) {
447                segment += 1;
448            } else {
449                // finished
450                break;
451            }
452        }
453    }
454
455    pub fn can_lanechange(&self, from: LaneID, to: LaneID, map: &Map) -> bool {
456        let steps = self.path.get_steps();
457        if steps.len() < 3 {
458            return false;
459        }
460        assert_eq!(PathStep::Lane(from), steps[0]);
461        let current_turn = match steps[1] {
462            PathStep::Turn(t) => t,
463            _ => unreachable!(),
464        };
465        let next_lane = current_turn.dst;
466        assert_eq!(PathStep::Lane(next_lane), steps[2]);
467        map.maybe_get_t(TurnID {
468            parent: current_turn.parent,
469            src: to,
470            dst: next_lane,
471        })
472        .is_some()
473    }
474
475    pub fn confirm_lanechange(&mut self, to: LaneID, map: &Map) {
476        // No assertions, blind trust!
477        self.path.modify_step(0, PathStep::Lane(to), map);
478        let mut turn = match self.path.get_steps()[1] {
479            PathStep::Turn(t) => t,
480            _ => unreachable!(),
481        };
482        turn.src = to;
483        self.path.modify_step(1, PathStep::Turn(turn), map);
484    }
485
486    pub fn is_parking(&self) -> bool {
487        match self.goal {
488            Goal::ParkNearBuilding {
489                started_looking, ..
490            } => started_looking,
491            _ => false,
492        }
493    }
494
495    pub fn get_parking_spot_goal(&self) -> Option<&ParkingSpot> {
496        match self.goal {
497            Goal::ParkNearBuilding { ref spot, .. } => spot.as_ref().map(|(s, _)| s),
498            _ => None,
499        }
500    }
501}