map_model/pathfind/mod.rs
1//! Everything related to pathfinding through a map for different types of agents.
2
3use std::collections::BTreeSet;
4
5use enumset::EnumSetType;
6use serde::{Deserialize, Serialize};
7
8use geom::Duration;
9
10pub use self::engine::CreateEngine;
11pub use self::pathfinder::{Pathfinder, PathfinderCache, PathfinderCaching};
12pub use self::v1::{Path, PathRequest, PathStep};
13pub use self::v2::{PathStepV2, PathV2};
14pub use self::vehicles::vehicle_cost;
15pub use self::walking::WalkingNode;
16use crate::{osm, Lane, LaneID, LaneType, Map, MovementID, Road, RoadID, TurnType};
17
18mod engine;
19mod node_map;
20mod pathfinder;
21// TODO tmp
22pub mod uber_turns;
23mod v1;
24mod v2;
25mod vehicles;
26mod walking;
27
28/// Who's asking for a path?
29// TODO This is an awful name.
30#[derive(Debug, Serialize, Deserialize, PartialOrd, Ord, EnumSetType)]
31pub enum PathConstraints {
32 Pedestrian,
33 Car,
34 Bike,
35 Bus,
36 Train,
37}
38
39impl PathConstraints {
40 pub fn all() -> Vec<PathConstraints> {
41 vec![
42 PathConstraints::Pedestrian,
43 PathConstraints::Car,
44 PathConstraints::Bike,
45 PathConstraints::Bus,
46 PathConstraints::Train,
47 ]
48 }
49
50 /// Not bijective, but this is the best guess of user intent
51 pub fn from_lt(lt: LaneType) -> PathConstraints {
52 match lt {
53 LaneType::Sidewalk | LaneType::Shoulder => PathConstraints::Pedestrian,
54 LaneType::Driving => PathConstraints::Car,
55 LaneType::Biking => PathConstraints::Bike,
56 LaneType::Bus => PathConstraints::Bus,
57 LaneType::LightRail => PathConstraints::Train,
58 _ => panic!("PathConstraints::from_lt({:?}) doesn't make sense", lt),
59 }
60 }
61
62 /// Can an agent use a lane? There are some subtle exceptions with using bus-only lanes for
63 /// turns.
64 pub fn can_use(self, lane: &Lane, map: &Map) -> bool {
65 let result = match self {
66 PathConstraints::Pedestrian => {
67 return lane.is_walkable();
68 }
69 PathConstraints::Car => lane.is_driving(),
70 PathConstraints::Bike => {
71 if lane.is_biking() {
72 true
73 } else if lane.is_driving() || (lane.is_bus() && map.config.bikes_can_use_bus_lanes)
74 {
75 let road = map.get_r(lane.id.road);
76 !road.osm_tags.is("bicycle", "no")
77 && !road
78 .osm_tags
79 .is_any(osm::HIGHWAY, vec!["motorway", "motorway_link"])
80 } else {
81 false
82 }
83 }
84 PathConstraints::Bus => {
85 return lane.is_driving() || lane.is_bus();
86 }
87 PathConstraints::Train => {
88 return lane.is_light_rail();
89 }
90 };
91 if result {
92 return true;
93 }
94 // Second chance for cars and bikes trying to use a bus-only lane that also happens to be a
95 // turn lane.
96 //
97 // TODO This check could be made stricter in two ways:
98 // 1) Verify that the bus-only lanes are the ONLY way to make this movement; if there's a
99 // general purpose lane that can also turn, we shouldn't allow this.
100 // 2) Verify that the turn->lane->turn sequence is the only way to reach the destination
101 // road. Since this function operates on a single lane, a vehicle could abuse this to
102 // stay in the bus lane and go straight, even if there was another lane for that. Fixing
103 // this is hard, since it requires so much context about the sequence of movements. In
104 // practice this isn't an issue; a bus lane often leads to another one, but the next bus
105 // lane won't also be an exclusive turn lane.
106 if lane.is_bus() {
107 if let Some(types) =
108 lane.get_lane_level_turn_restrictions(map.get_r(lane.id.road), true)
109 {
110 if types.contains(&TurnType::Right) || types.contains(&TurnType::Left) {
111 return true;
112 }
113 }
114 }
115 false
116 }
117
118 /// Can an agent use a road in either direction? There are some subtle exceptions with using
119 /// bus-only lanes for turns.
120 pub fn can_use_road(self, road: &Road, map: &Map) -> bool {
121 road.lanes.iter().any(|lane| self.can_use(lane, map))
122 }
123
124 /// Strict for bikes. If there are bike lanes, not allowed to use other lanes.
125 pub(crate) fn filter_lanes(self, mut choices: Vec<LaneID>, map: &Map) -> Vec<LaneID> {
126 choices.retain(|l| self.can_use(map.get_l(*l), map));
127 if self == PathConstraints::Bike {
128 let just_bike_lanes: Vec<LaneID> = choices
129 .iter()
130 .copied()
131 .filter(|l| map.get_l(*l).is_biking())
132 .collect();
133 if !just_bike_lanes.is_empty() {
134 return just_bike_lanes;
135 }
136 }
137 choices
138 }
139}
140
141/// Heavily penalize crossing into an access-restricted zone that doesn't allow this mode.
142pub(crate) fn zone_cost(mvmnt: MovementID, constraints: PathConstraints, map: &Map) -> Duration {
143 // Detect when we cross into a new zone that doesn't allow constraints.
144 if map
145 .get_r(mvmnt.from.road)
146 .access_restrictions
147 .allow_through_traffic
148 .contains(constraints)
149 && !map
150 .get_r(mvmnt.to.road)
151 .access_restrictions
152 .allow_through_traffic
153 .contains(constraints)
154 {
155 // This should be high enough to achieve the desired effect of somebody not entering
156 // the zone unless absolutely necessary. Someone would violate that and cut through anyway
157 // only when the alternative route would take more than 3 hours longer!
158 Duration::hours(3)
159 } else {
160 Duration::ZERO
161 }
162}
163
164/// Tuneable parameters for all types of routing.
165// These will maybe become part of the PathRequest later, but that's an extremely invasive and
166// space-expensive change right now.
167#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
168pub struct RoutingParams {
169 // For all vehicles. This is added to the cost of a movement as an additional delay.
170 pub unprotected_turn_penalty: Duration,
171
172 // For bike routing. Multiplied by the base cost, since spending more time on the wrong lane
173 // type matters.
174 pub bike_lane_penalty: f64,
175 pub bus_lane_penalty: f64,
176 pub driving_lane_penalty: f64,
177
178 // For bike routing.
179 // "Steep" is a fixed threshold of 8% incline, uphill only. Multiply by the base cost. (Note
180 // that cost already includes a reduction of speed to account for the incline -- this is a
181 // further "delay" on top of that!)
182 // TODO But even steeper roads matter more!
183 pub avoid_steep_incline_penalty: f64,
184 // If the road is `high_stress_for_bikes`, multiply by the base cost.
185 pub avoid_high_stress: f64,
186
187 /// When crossing an arterial or highway road, multiply the base cost by this penalty. When
188 /// greater than 1, this will encourage routes to use local roads more.
189 pub main_road_penalty: f64,
190
191 /// Don't allow crossing these roads at all. Only affects vehicle routing, not pedestrian.
192 ///
193 /// TODO The route may cross one of these roads if it's the start or end!
194 pub avoid_roads: BTreeSet<RoadID>,
195 /// Related to `avoid_roads`, but used as an optimization in map construction
196 pub only_use_roads: BTreeSet<RoadID>,
197
198 /// Don't allow movements between these roads at all. Only affects vehicle routing, not
199 /// pedestrian.
200 pub avoid_movements_between: BTreeSet<(RoadID, RoadID)>,
201}
202
203impl Default for RoutingParams {
204 fn default() -> Self {
205 Self {
206 // This is a total guess -- it really depends on the traffic patterns of the particular
207 // road at the time we're routing.
208 unprotected_turn_penalty: Duration::const_seconds(30.0),
209
210 bike_lane_penalty: 1.0,
211 bus_lane_penalty: 1.1,
212 driving_lane_penalty: 1.5,
213
214 avoid_steep_incline_penalty: 1.0,
215 avoid_high_stress: 1.0,
216
217 main_road_penalty: 1.0,
218
219 avoid_roads: BTreeSet::new(),
220 avoid_movements_between: BTreeSet::new(),
221 only_use_roads: BTreeSet::new(),
222 }
223 }
224}
225
226pub fn round(cost: Duration) -> usize {
227 // Round up! 0 cost edges are ignored
228 (cost.inner_seconds().round() as usize).max(1)
229}
230
231pub fn unround(cost: usize) -> Duration {
232 Duration::seconds(cost as f64)
233}