1use std::collections::HashMap;
4
5use fast_paths::InputGraph;
6use serde::{Deserialize, Serialize};
7
8use abstutil::MultiMap;
9use geom::Duration;
10
11use crate::pathfind::engine::{CreateEngine, PathfindEngine};
12use crate::pathfind::node_map::{deserialize_nodemap, NodeMap};
13use crate::pathfind::uber_turns::{IntersectionCluster, UberTurnV2};
14use crate::pathfind::zone_cost;
15use crate::pathfind::{round, unround};
16use crate::{
17 osm, DirectedRoadID, Direction, LaneType, Map, MovementID, PathConstraints, PathRequest,
18 PathV2, Position, RoutingParams, Traversable,
19};
20
21#[derive(Clone, Serialize, Deserialize)]
22pub struct VehiclePathfinder {
23 #[serde(deserialize_with = "deserialize_nodemap")]
24 nodes: NodeMap<Node>,
25 uber_turns: Vec<UberTurnV2>,
26 constraints: PathConstraints,
27 params: RoutingParams,
28 pub engine: PathfindEngine,
29}
30
31#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize)]
32pub enum Node {
33 Road(DirectedRoadID),
34 UberTurn(usize),
35}
36
37impl VehiclePathfinder {
38 pub fn empty() -> VehiclePathfinder {
39 VehiclePathfinder {
40 nodes: NodeMap::new(),
41 uber_turns: Vec::new(),
42 constraints: PathConstraints::Car,
43 params: RoutingParams::default(),
44 engine: PathfindEngine::Empty,
45 }
46 }
47
48 pub fn new(
49 map: &Map,
50 constraints: PathConstraints,
51 params: &RoutingParams,
52 engine: &CreateEngine,
53 ) -> VehiclePathfinder {
54 let mut nodes = NodeMap::new();
56 for r in map.all_roads() {
57 nodes.get_or_insert(Node::Road(DirectedRoadID {
60 road: r.id,
61 dir: Direction::Fwd,
62 }));
63 nodes.get_or_insert(Node::Road(DirectedRoadID {
64 road: r.id,
65 dir: Direction::Back,
66 }));
67 }
68
69 let mut uber_turns = Vec::new();
71 for ic in IntersectionCluster::find_all(map) {
72 for ut in ic.into_v2(map) {
73 nodes.get_or_insert(Node::UberTurn(uber_turns.len()));
74 uber_turns.push(ut);
75 }
76 }
77
78 let input_graph = make_input_graph(constraints, &nodes, &uber_turns, params, map);
79 let engine = engine.create(input_graph);
80
81 VehiclePathfinder {
82 nodes,
83 uber_turns,
84 constraints,
85 params: params.clone(),
86 engine,
87 }
88 }
89
90 pub fn pathfind(&self, req: PathRequest, map: &Map) -> Option<PathV2> {
91 if matches!(self.engine, PathfindEngine::Empty) {
92 return None;
93 }
94
95 assert!(!map.get_l(req.start.lane()).is_walkable());
96 let mut starts = vec![(
97 self.nodes.get(Node::Road(
98 map.get_l(req.start.lane()).get_directed_parent(),
99 )),
100 0,
101 )];
102 if let Some((pos, cost)) = req.alt_start {
103 starts.push((
104 self.nodes
105 .get(Node::Road(map.get_l(pos.lane()).get_directed_parent())),
106 round(cost),
107 ));
108 }
109 let (raw_weight, raw_nodes) = self.engine.calculate_path_multiple_sources_and_targets(
110 starts,
111 vec![(
112 self.nodes
113 .get(Node::Road(map.get_l(req.end.lane()).get_directed_parent())),
114 0,
115 )],
116 )?;
117
118 let mut road_steps = Vec::new();
119 let mut uber_turns = Vec::new();
120 for node in raw_nodes.into_iter().map(|id| self.nodes.translate_id(id)) {
121 match node {
122 Node::Road(dr) => {
123 road_steps.push(dr);
124 }
125 Node::UberTurn(ut) => {
126 for mvmnt in &self.uber_turns[ut].path {
128 road_steps.push(mvmnt.to);
129 }
130 road_steps.pop();
131 uber_turns.push(self.uber_turns[ut].clone());
133 }
134 }
135 }
136 let cost = unround(raw_weight);
137 Some(PathV2::from_roads(road_steps, req, cost, uber_turns, map))
138 }
139
140 pub fn apply_edits(&mut self, map: &Map) {
141 if matches!(self.engine, PathfindEngine::Empty) {
142 return;
143 }
144
145 let input_graph = make_input_graph(
150 self.constraints,
151 &self.nodes,
152 &self.uber_turns,
153 &self.params,
154 map,
155 );
156 let engine = self.engine.reuse_ordering().create(input_graph);
157 self.engine = engine;
158 }
159
160 pub fn all_costs_from(&self, start: Position, map: &Map) -> HashMap<DirectedRoadID, Duration> {
161 if matches!(self.engine, PathfindEngine::Empty) {
162 return HashMap::new();
163 }
164
165 let start = self
166 .nodes
167 .get(Node::Road(map.get_l(start.lane()).get_directed_parent()));
168 let raw_costs = if self.engine.is_dijkstra() {
169 self.engine.all_costs_from(start)
170 } else {
171 let input_graph = make_input_graph(
173 self.constraints,
174 &self.nodes,
175 &self.uber_turns,
176 &self.params,
177 map,
178 );
179 CreateEngine::Dijkstra
180 .create(input_graph)
181 .all_costs_from(start)
182 };
183 raw_costs
184 .into_iter()
185 .filter_map(|(k, v)| {
186 if let Node::Road(dr) = self.nodes.translate_id(k) {
187 Some((dr, unround(v)))
188 } else {
189 None
190 }
191 })
192 .collect()
193 }
194}
195
196fn make_input_graph(
197 constraints: PathConstraints,
198 nodes: &NodeMap<Node>,
199 uber_turns: &[UberTurnV2],
200 params: &RoutingParams,
201 map: &Map,
202) -> InputGraph {
203 let mut input_graph = InputGraph::new();
204
205 let mut uber_turn_entrances: MultiMap<DirectedRoadID, usize> = MultiMap::new();
208 for (idx, ut) in uber_turns.iter().enumerate() {
209 nodes.get(Node::UberTurn(idx));
211
212 if ut
217 .path
218 .iter()
219 .all(|mvmnt| !mvmnt.to.lanes(constraints, map).is_empty())
220 {
221 uber_turn_entrances.insert(ut.entry(), idx);
222 }
223 }
224
225 let roads_to_consider = if params.only_use_roads.is_empty() {
226 map.all_roads().iter().collect::<Vec<_>>()
227 } else {
228 params
229 .only_use_roads
230 .iter()
231 .map(|r| map.get_r(*r))
232 .collect()
233 };
234
235 for r in roads_to_consider {
236 for dr in r.id.both_directions() {
237 let from = nodes.get(Node::Road(dr));
238 if !dr.lanes(constraints, map).is_empty() {
239 let indices = uber_turn_entrances.get(dr);
240 if indices.is_empty() {
241 for mvmnt in map.get_movements_for(dr, constraints) {
242 if let Some(cost) =
243 vehicle_cost(mvmnt.from, mvmnt, constraints, params, map)
244 {
245 input_graph.add_edge(
246 from,
247 nodes.get(Node::Road(mvmnt.to)),
248 round(cost),
249 );
250 }
251 }
252 } else {
253 for idx in indices {
254 let ut = &uber_turns[*idx];
255
256 let mut sum_cost = Duration::ZERO;
257 let mut ok = true;
258 for mvmnt in &ut.path {
259 if let Some(cost) =
260 vehicle_cost(mvmnt.from, *mvmnt, constraints, params, map)
261 {
262 sum_cost += cost;
263 } else {
264 ok = false;
267 break;
268 }
269 }
270 if ok {
271 input_graph.add_edge(
272 from,
273 nodes.get(Node::UberTurn(*idx)),
274 round(sum_cost),
275 );
276 input_graph.add_edge(
277 nodes.get(Node::UberTurn(*idx)),
278 nodes.get(Node::Road(ut.exit())),
279 1,
281 );
282 }
283 }
284 }
285 }
286 }
287 }
288
289 nodes.guarantee_node_ordering(&mut input_graph);
290 input_graph.freeze();
291 input_graph
292}
293
294pub fn vehicle_cost(
299 dr: DirectedRoadID,
300 mvmnt: MovementID,
301 constraints: PathConstraints,
302 params: &RoutingParams,
303 map: &Map,
304) -> Option<Duration> {
305 if params.avoid_roads.contains(&dr.road)
306 || params
307 .avoid_movements_between
308 .contains(&(mvmnt.from.road, mvmnt.to.road))
309 {
310 return None;
311 }
312
313 let road = map.get_r(dr.road);
314 let movement = &map.get_i(mvmnt.parent).movements[&mvmnt];
315 let max_speed = match constraints {
316 PathConstraints::Car | PathConstraints::Bus | PathConstraints::Train => None,
317 PathConstraints::Bike => Some(crate::MAX_BIKE_SPEED),
318 PathConstraints::Pedestrian => unreachable!(),
319 };
320 let t1 = road.length() / Traversable::max_speed_along_road(dr, max_speed, constraints, map).0;
321
322 let t2 = movement.geom.length()
323 / Traversable::max_speed_along_movement(mvmnt, max_speed, constraints, map);
324
325 let base = match constraints {
326 PathConstraints::Car | PathConstraints::Train => t1 + t2,
327 PathConstraints::Bike => {
328 let lt_penalty = if dr.has_lanes(LaneType::Biking, map) {
333 params.bike_lane_penalty
334 } else if dr.has_lanes(LaneType::Bus, map) {
335 params.bus_lane_penalty
336 } else {
337 params.driving_lane_penalty
338 };
339
340 lt_penalty * (t1 + t2)
341 }
342 PathConstraints::Bus => {
343 let lt_penalty = if dr.has_lanes(LaneType::Bus, map) {
345 1.0
346 } else {
347 1.1
348 };
349 lt_penalty * (t1 + t2)
350 }
351 PathConstraints::Pedestrian => unreachable!(),
352 };
353
354 let mut multiplier = 1.0;
355 if constraints == PathConstraints::Bike
356 && (params.avoid_steep_incline_penalty - 1.0).abs() > f64::EPSILON
357 {
358 let percent_incline = if dr.dir == Direction::Fwd {
359 road.percent_incline
360 } else {
361 -road.percent_incline
362 };
363 if percent_incline >= 0.08 {
364 multiplier *= params.avoid_steep_incline_penalty;
365 }
366 }
367
368 if constraints == PathConstraints::Bike
369 && (params.avoid_high_stress - 1.0).abs() > f64::EPSILON
370 && road.high_stress_for_bikes(map, dr.dir)
371 {
372 multiplier *= params.avoid_high_stress;
373 }
374
375 let mut extra = zone_cost(mvmnt, constraints, map);
376 if map.is_unprotected_turn(dr.road, mvmnt.to.road, movement.turn_type) {
378 extra += params.unprotected_turn_penalty
379 }
380
381 if (params.main_road_penalty - 1.0).abs() > f64::EPSILON
382 && road.get_rank() != osm::RoadRank::Local
383 {
384 multiplier *= params.main_road_penalty;
385 }
386
387 Some(multiplier * base + extra)
388}