1use std::collections::{BTreeMap, VecDeque};
2use std::fmt;
3
4use anyhow::Result;
5use serde::{Deserialize, Serialize};
6
7use abstutil::prettyprint_usize;
8use geom::{Distance, Duration, PolyLine, Polygon, Ring, Speed, EPSILON_DIST};
9
10use crate::{
11 BuildingID, DirectedRoadID, LaneID, Map, PathConstraints, Position, RoadID, Traversable,
12 TurnID, UberTurn,
13};
14
15#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)]
16pub enum PathStep {
17 Lane(LaneID),
19 ContraflowLane(LaneID),
21 Turn(TurnID),
22 ContraflowTurn(TurnID),
23}
24
25impl PathStep {
26 pub fn as_traversable(&self) -> Traversable {
27 match self {
28 PathStep::Lane(id) => Traversable::Lane(*id),
29 PathStep::ContraflowLane(id) => Traversable::Lane(*id),
30 PathStep::Turn(id) => Traversable::Turn(*id),
31 PathStep::ContraflowTurn(id) => Traversable::Turn(*id),
32 }
33 }
34
35 pub fn as_lane(&self) -> LaneID {
36 self.as_traversable().as_lane()
37 }
38
39 pub fn as_turn(&self) -> TurnID {
40 self.as_traversable().as_turn()
41 }
42
43 fn exact_slice(
46 &self,
47 map: &Map,
48 start: Distance,
49 dist_ahead: Option<Distance>,
50 ) -> Result<PolyLine> {
51 if let Some(d) = dist_ahead {
52 if d < Distance::ZERO {
53 panic!("Negative dist_ahead?! {}", d);
54 }
55 if d == Distance::ZERO {
56 bail!("0 dist ahead for slice");
57 }
58 }
59
60 match self {
61 PathStep::Lane(id) => {
62 let pts = &map.get_l(*id).lane_center_pts;
63 if let Some(d) = dist_ahead {
64 pts.maybe_exact_slice(start, start + d)
65 } else {
66 pts.maybe_exact_slice(start, pts.length())
67 }
68 }
69 PathStep::ContraflowLane(id) => {
70 let pts = map.get_l(*id).lane_center_pts.reversed();
71 let reversed_start = pts.length() - start;
72 if let Some(d) = dist_ahead {
73 pts.maybe_exact_slice(reversed_start, reversed_start + d)
74 } else {
75 pts.maybe_exact_slice(reversed_start, pts.length())
76 }
77 }
78 PathStep::Turn(id) => {
79 let pts = &map.get_t(*id).geom;
80 if let Some(d) = dist_ahead {
81 pts.maybe_exact_slice(start, start + d)
82 } else {
83 pts.maybe_exact_slice(start, pts.length())
84 }
85 }
86 PathStep::ContraflowTurn(id) => {
87 let pts = &map.get_t(*id).geom.reversed();
88 let reversed_start = pts.length() - start;
89 if let Some(d) = dist_ahead {
90 pts.maybe_exact_slice(reversed_start, reversed_start + d)
91 } else {
92 pts.maybe_exact_slice(reversed_start, pts.length())
93 }
94 }
95 }
96 }
97
98 pub fn max_speed_along(
101 &self,
102 max_speed_on_flat_ground: Option<Speed>,
103 constraints: PathConstraints,
104 map: &Map,
105 ) -> Speed {
106 self.max_speed_and_incline_along(max_speed_on_flat_ground, constraints, map)
107 .0
108 }
109
110 pub fn max_speed_and_incline_along(
113 &self,
114 max_speed_on_flat_ground: Option<Speed>,
115 constraints: PathConstraints,
116 map: &Map,
117 ) -> (Speed, f64) {
118 match self {
119 PathStep::Lane(l) => Traversable::max_speed_along_road(
120 map.get_l(*l).get_directed_parent(),
121 max_speed_on_flat_ground,
122 constraints,
123 map,
124 ),
125 PathStep::ContraflowLane(l) => Traversable::max_speed_along_road(
126 {
127 let mut dr = map.get_l(*l).get_directed_parent();
128 dr.dir = dr.dir.opposite();
129 dr
130 },
131 max_speed_on_flat_ground,
132 constraints,
133 map,
134 ),
135 PathStep::Turn(t) | PathStep::ContraflowTurn(t) => (
136 Traversable::max_speed_along_movement(
137 t.to_movement(map),
138 max_speed_on_flat_ground,
139 constraints,
140 map,
141 ),
142 0.0,
143 ),
144 }
145 }
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
149pub struct Path {
150 steps: VecDeque<PathStep>,
151 orig_req: PathRequest,
154
155 total_length: Distance,
157 crossed_so_far: Distance,
158
159 uber_turns: VecDeque<UberTurn>,
162 currently_inside_ut: Option<UberTurn>,
164
165 blocked_starts: Vec<LaneID>,
166}
167
168impl Path {
169 pub(crate) fn new(
170 map: &Map,
171 steps: Vec<PathStep>,
172 orig_req: PathRequest,
173 uber_turns: Vec<UberTurn>,
174 blocked_starts: Vec<LaneID>,
175 ) -> Path {
176 if false {
178 validate_continuity(map, &steps);
179 }
180 if false {
181 validate_restrictions(map, &steps);
182 }
183 if false {
184 validate_zones(map, &steps, &orig_req);
185 }
186 let mut path = Path {
187 steps: VecDeque::from(steps),
188 orig_req,
189 total_length: Distance::ZERO,
190 crossed_so_far: Distance::ZERO,
191 uber_turns: uber_turns.into_iter().collect(),
192 currently_inside_ut: None,
193 blocked_starts,
194 };
195 for step in &path.steps {
196 path.total_length += path.dist_crossed_from_step(map, step);
197 }
198 path
199 }
200
201 pub fn dist_crossed_from_step(&self, map: &Map, step: &PathStep) -> Distance {
204 match step {
205 PathStep::Lane(l) => {
206 let lane = map.get_l(*l);
207 if self.orig_req.start.lane() == lane.id {
208 lane.length() - self.orig_req.start.dist_along()
209 } else if self.orig_req.end.lane() == lane.id {
210 self.orig_req.end.dist_along()
211 } else {
212 lane.length()
213 }
214 }
215 PathStep::ContraflowLane(l) => {
216 let lane = map.get_l(*l);
217 if self.orig_req.start.lane() == lane.id {
218 self.orig_req.start.dist_along()
219 } else if self.orig_req.end.lane() == lane.id {
220 lane.length() - self.orig_req.end.dist_along()
221 } else {
222 lane.length()
223 }
224 }
225 PathStep::Turn(t) | PathStep::ContraflowTurn(t) => map.get_t(*t).geom.length(),
226 }
227 }
228
229 pub fn get_req(&self) -> &PathRequest {
232 &self.orig_req
233 }
234
235 pub fn crossed_so_far(&self) -> Distance {
236 self.crossed_so_far
237 }
238
239 pub fn total_length(&self) -> Distance {
240 self.total_length
241 }
242
243 pub fn percent_dist_crossed(&self) -> f64 {
244 if self.total_length == Distance::ZERO {
246 return 1.0;
247 }
248 self.crossed_so_far / self.total_length
249 }
250
251 pub fn is_empty(&self) -> bool {
252 self.steps.is_empty()
253 }
254
255 pub fn is_last_step(&self) -> bool {
256 self.steps.len() == 1
257 }
258
259 pub fn isnt_last_step(&self) -> bool {
260 self.steps.len() > 1
261 }
262
263 pub fn currently_inside_ut(&self) -> &Option<UberTurn> {
264 &self.currently_inside_ut
265 }
266 pub fn about_to_start_ut(&self) -> Option<&UberTurn> {
267 if self.steps.len() < 2 || self.uber_turns.is_empty() {
268 return None;
269 }
270 if let PathStep::Turn(t) = self.steps[1] {
271 if self.uber_turns[0].path[0] == t {
272 return Some(&self.uber_turns[0]);
273 }
274 }
275 None
276 }
277
278 pub fn shift(&mut self, map: &Map) -> PathStep {
279 let step = self.steps.pop_front().unwrap();
280 self.crossed_so_far += self.dist_crossed_from_step(map, &step);
281
282 #[allow(clippy::collapsible_if)] if let Some(ref ut) = self.currently_inside_ut {
284 if step == PathStep::Turn(*ut.path.last().unwrap()) {
285 self.currently_inside_ut = None;
286 }
287 } else if !self.steps.is_empty() && !self.uber_turns.is_empty() {
288 if self.steps[0] == PathStep::Turn(self.uber_turns[0].path[0]) {
289 self.currently_inside_ut = Some(self.uber_turns.pop_front().unwrap());
290 }
291 }
292
293 if self.steps.len() == 1 {
294 assert!(self.uber_turns.is_empty());
296 assert!(self.currently_inside_ut.is_none());
297 }
298
299 step
300 }
301
302 pub fn add(&mut self, step: PathStep, map: &Map) {
303 if let Some(PathStep::Lane(l)) = self.steps.back() {
304 if *l == self.orig_req.end.lane() {
305 self.total_length += map.get_l(*l).length() - self.orig_req.end.dist_along();
306 }
307 }
308 self.total_length += step.as_traversable().get_polyline(map).length();
310
311 self.steps.push_back(step);
312 }
314
315 pub fn is_upcoming_uber_turn_component(&self, t: TurnID) -> bool {
316 self.uber_turns
317 .front()
318 .map(|ut| ut.path.contains(&t))
319 .unwrap_or(false)
320 }
321
322 pub fn modify_step(&mut self, idx: usize, step: PathStep, map: &Map) {
324 assert!(self.currently_inside_ut.is_none());
325 self.total_length -= self.steps[idx].as_traversable().get_polyline(map).length();
328
329 if let PathStep::Turn(old_turn) = self.steps[idx] {
331 for uts in &mut self.uber_turns {
332 if let Some(turn_idx) = uts.path.iter().position(|i| i == &old_turn) {
333 if let PathStep::Turn(new_turn) = step {
334 uts.path[turn_idx] = new_turn;
335 } else {
336 panic!("expected turn, but found {:?}", step);
337 }
338 }
339 }
340 }
341
342 self.steps[idx] = step;
343 self.total_length += self.steps[idx].as_traversable().get_polyline(map).length();
344
345 if self.total_length < Distance::ZERO {
346 panic!(
347 "modify_step broke total_length, it's now {}",
348 self.total_length
349 );
350 }
351 }
352
353 pub fn current_step(&self) -> PathStep {
354 self.steps[0]
355 }
356
357 pub fn next_step(&self) -> PathStep {
358 self.steps[1]
359 }
360 pub fn maybe_next_step(&self) -> Option<PathStep> {
361 if self.is_last_step() {
362 None
363 } else {
364 Some(self.next_step())
365 }
366 }
367
368 pub fn last_step(&self) -> PathStep {
369 self.steps[self.steps.len() - 1]
370 }
371
372 pub fn trace(&self, map: &Map) -> Option<PolyLine> {
378 let t1 = self.steps[0].as_traversable();
379 let t2 = Traversable::Lane(self.orig_req.start.lane());
380 if t1 != t2 {
381 warn!(
382 "Can't trace modified path; first step is {}, but requested started from {}",
383 t1, t2
384 );
385 return None;
386 }
387 self.trace_from_start(map, self.orig_req.start.dist_along())
388 }
389
390 pub fn trace_from_start(&self, map: &Map, start_dist: Distance) -> Option<PolyLine> {
392 let orig_end_dist = self.orig_req.end.dist_along();
393
394 if self.steps.len() == 1 {
395 let dist_ahead = if start_dist < orig_end_dist {
396 orig_end_dist - start_dist
397 } else {
398 start_dist - orig_end_dist
399 };
400
401 return self.steps[0]
405 .exact_slice(map, start_dist, Some(dist_ahead))
406 .ok();
407 }
408
409 let mut pts_so_far: Option<PolyLine> = None;
410
411 if let Ok(pts) = self.steps[0].exact_slice(map, start_dist, None) {
413 pts_so_far = Some(pts);
414 }
415
416 for i in 1..self.steps.len() {
418 let dist_ahead = if i == self.steps.len() - 1 {
420 Some(match self.steps[i] {
421 PathStep::ContraflowLane(l) => {
422 map.get_l(l).lane_center_pts.reversed().length() - orig_end_dist
423 }
424 PathStep::ContraflowTurn(t) => {
425 map.get_t(t).geom.reversed().length() - orig_end_dist
426 }
427 _ => orig_end_dist,
428 })
429 } else {
430 None
431 };
432
433 let start_dist_this_step = match self.steps[i] {
434 PathStep::ContraflowLane(l) => map.get_l(l).lane_center_pts.reversed().length(),
437 PathStep::ContraflowTurn(t) => map.get_t(t).geom.reversed().length(),
438 _ => Distance::ZERO,
439 };
440 if let Ok(new_pts) = self.steps[i].exact_slice(map, start_dist_this_step, dist_ahead) {
441 if pts_so_far.is_some() {
442 match pts_so_far.unwrap().extend(new_pts) {
443 Ok(new) => {
444 pts_so_far = Some(new);
445 }
446 Err(err) => {
447 println!("WARNING: Couldn't trace some path: {}", err);
448 return None;
449 }
450 }
451 } else {
452 pts_so_far = Some(new_pts);
453 }
454 }
455 }
456
457 Some(pts_so_far.unwrap())
458 }
459
460 pub fn trace_v2(&self, map: &Map) -> Result<Polygon> {
463 let mut left_pts = Vec::new();
464 let mut right_pts = Vec::new();
465 for step in &self.steps {
466 match step {
467 PathStep::Lane(l) => {
468 let road = map.get_parent(*l);
469 let width = road.get_half_width();
470 if map.get_l(*l).dst_i == road.dst_i {
471 left_pts.extend(road.center_pts.shift_left(width)?.into_points());
472 right_pts.extend(road.center_pts.shift_right(width)?.into_points());
473 } else {
474 left_pts
475 .extend(road.center_pts.shift_right(width)?.reversed().into_points());
476 right_pts
477 .extend(road.center_pts.shift_left(width)?.reversed().into_points());
478 }
479 }
480 PathStep::ContraflowLane(_) => todo!(),
481 PathStep::Turn(_) | PathStep::ContraflowTurn(_) => {}
484 }
485 }
486 right_pts.reverse();
487 left_pts.extend(right_pts);
488 left_pts.push(left_pts[0]);
489 Ok(Ring::deduping_new(left_pts)?.into_polygon())
490 }
491
492 pub fn get_steps(&self) -> &VecDeque<PathStep> {
493 &self.steps
494 }
495
496 pub fn estimate_duration(&self, map: &Map, max_speed: Option<Speed>) -> Duration {
500 let mut total = Duration::ZERO;
501 for step in &self.steps {
502 let dist = self.dist_crossed_from_step(map, step);
503 let speed = step.max_speed_along(max_speed, self.orig_req.constraints, map);
504 total += dist / speed;
505 }
506 total
507 }
508
509 pub fn get_blocked_starts(&self) -> Vec<LaneID> {
512 self.blocked_starts.clone()
513 }
514
515 pub fn get_total_elevation_change(&self, map: &Map) -> (Distance, Distance) {
517 let mut gain = Distance::ZERO;
518 let mut loss = Distance::ZERO;
519 for step in &self.steps {
520 let (from, to) = match step {
521 PathStep::Lane(l) => {
522 let lane = map.get_l(*l);
523 (
524 map.get_i(lane.src_i).elevation,
525 map.get_i(lane.dst_i).elevation,
526 )
527 }
528 PathStep::ContraflowLane(l) => {
529 let lane = map.get_l(*l);
530 (
531 map.get_i(lane.dst_i).elevation,
532 map.get_i(lane.src_i).elevation,
533 )
534 }
535 PathStep::Turn(_) | PathStep::ContraflowTurn(_) => {
536 continue;
537 }
538 };
539 if from < to {
540 gain += to - from;
541 } else {
542 loss += from - to;
543 }
544 }
545 (gain, loss)
546 }
547
548 pub fn get_step_at_dist_along(&self, map: &Map, mut dist_along: Distance) -> Result<PathStep> {
549 for step in &self.steps {
550 let dist_here = self.dist_crossed_from_step(map, step);
551 if dist_along <= dist_here {
552 return Ok(*step);
553 }
554 dist_along -= dist_here;
555 }
556 bail!(
557 "get_step_at_dist_along has leftover distance of {}",
558 dist_along
559 );
560 }
561
562 pub fn crosses_road(&self, r: RoadID) -> bool {
563 for step in &self.steps {
564 if let PathStep::Lane(l) | PathStep::ContraflowLane(l) = step {
565 if l.road == r {
566 return true;
567 }
568 }
569 }
570 false
571 }
572}
573
574#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
575pub struct PathRequest {
576 pub start: Position,
577 pub end: Position,
578 pub constraints: PathConstraints,
579 pub(crate) alt_start: Option<(Position, Duration)>,
584}
585
586impl fmt::Display for PathRequest {
587 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
588 write!(
589 f,
590 "PathRequest({} along {}... to {} along {} for {:?})",
591 self.start.dist_along(),
592 self.start.lane(),
593 self.end.dist_along(),
594 self.end.lane(),
595 self.constraints,
596 )
597 }
598}
599
600impl PathRequest {
601 pub fn between_buildings(
605 map: &Map,
606 from: BuildingID,
607 to: BuildingID,
608 constraints: PathConstraints,
609 ) -> Option<PathRequest> {
610 let from = map.get_b(from);
611 let to = map.get_b(to);
612 let (start, end) = match constraints {
613 PathConstraints::Pedestrian => (from.sidewalk_pos, to.sidewalk_pos),
614 PathConstraints::Bike => (from.biking_connection(map)?.0, to.biking_connection(map)?.0),
615 PathConstraints::Car => (
616 from.driving_connection(map)?.0,
617 to.driving_connection(map)?.0,
618 ),
619 PathConstraints::Bus | PathConstraints::Train => unimplemented!(),
623 };
624 if constraints == PathConstraints::Car {
625 Some(PathRequest::leave_from_driveway(
626 start,
627 end,
628 constraints,
629 map,
630 ))
631 } else {
632 Some(PathRequest {
633 start,
634 end,
635 constraints,
636 alt_start: None,
637 })
638 }
639 }
640
641 pub fn walking(start: Position, end: Position) -> PathRequest {
643 PathRequest {
644 start,
645 end,
646 constraints: PathConstraints::Pedestrian,
647 alt_start: None,
648 }
649 }
650
651 pub fn vehicle(start: Position, end: Position, constraints: PathConstraints) -> PathRequest {
654 PathRequest {
655 start,
656 end,
657 constraints,
658 alt_start: None,
659 }
660 }
661
662 pub fn leave_from_driveway(
665 start: Position,
666 end: Position,
667 constraints: PathConstraints,
668 map: &Map,
669 ) -> PathRequest {
670 let alt_start = (|| {
671 let start_lane = map.get_l(start.lane());
672 let road = map.get_r(start_lane.id.road);
673 if road.id == end.lane().road {
676 return None;
677 }
678 let offside_dir = start_lane.dir.opposite();
679 let alt_lane = road.find_closest_lane(start_lane.id, |l| {
680 l.dir == offside_dir && constraints.can_use(l, map)
681 })?;
682 let pos = start.equiv_pos(alt_lane, map);
684 let number_lanes_between =
685 ((start_lane.id.offset as f64) - (alt_lane.offset as f64)).abs();
686 let cost = Duration::seconds(10.0) * number_lanes_between;
688 Some((pos, cost))
689 })();
690 PathRequest {
691 start,
692 end,
693 constraints,
694 alt_start,
695 }
696 }
697
698 pub fn between_directed_roads(
701 map: &Map,
702 from: DirectedRoadID,
703 to: DirectedRoadID,
704 constraints: PathConstraints,
705 ) -> Option<PathRequest> {
706 let start = Position::start(from.lanes(constraints, map).pop()?);
707 let end = Position::end(to.lanes(constraints, map).pop()?, map);
708 Some(PathRequest {
709 start,
710 end,
711 constraints,
712 alt_start: None,
713 })
714 }
715
716 pub fn deduplicate(map: &Map, requests: Vec<PathRequest>) -> Vec<(PathRequest, usize)> {
722 let count_before = requests.len();
723 let mut common: BTreeMap<
724 (PathConstraints, DirectedRoadID, DirectedRoadID),
725 (PathRequest, usize),
726 > = BTreeMap::new();
727 for req in requests {
728 let key = (
729 req.constraints,
730 map.get_l(req.start.lane()).get_directed_parent(),
731 map.get_l(req.end.lane()).get_directed_parent(),
732 );
733 let pair = common.entry(key).or_insert_with(|| (req, 0));
734 pair.1 += 1;
735 }
736 if false {
737 info!(
738 "{} requests deduplicated down to {}",
739 prettyprint_usize(count_before),
740 prettyprint_usize(common.len())
741 );
742 }
743 common.into_values().collect()
744 }
745}
746
747fn validate_continuity(map: &Map, steps: &[PathStep]) {
748 if steps.is_empty() {
749 panic!("Empty path");
750 }
751 for pair in steps.windows(2) {
752 let from = match pair[0] {
753 PathStep::Lane(id) => map.get_l(id).last_pt(),
754 PathStep::ContraflowLane(id) => map.get_l(id).first_pt(),
755 PathStep::Turn(id) => map.get_t(id).geom.last_pt(),
756 PathStep::ContraflowTurn(id) => map.get_t(id).geom.first_pt(),
757 };
758 let to = match pair[1] {
759 PathStep::Lane(id) => map.get_l(id).first_pt(),
760 PathStep::ContraflowLane(id) => map.get_l(id).last_pt(),
761 PathStep::Turn(id) => map.get_t(id).geom.first_pt(),
762 PathStep::ContraflowTurn(id) => map.get_t(id).geom.last_pt(),
763 };
764 let len = from.dist_to(to);
765 if len > EPSILON_DIST {
766 println!("All steps in invalid path:");
767 for s in steps {
768 match s {
769 PathStep::Lane(l) => println!(
770 " {:?} from {} to {}",
771 s,
772 map.get_l(*l).src_i,
773 map.get_l(*l).dst_i
774 ),
775 PathStep::ContraflowLane(l) => println!(
776 " {:?} from {} to {}",
777 s,
778 map.get_l(*l).dst_i,
779 map.get_l(*l).src_i
780 ),
781 PathStep::Turn(_) | PathStep::ContraflowTurn(_) => println!(" {:?}", s),
782 }
783 }
784 panic!(
785 "pathfind() returned path that warps {} from {:?} to {:?}",
786 len, pair[0], pair[1]
787 );
788 }
789 }
790}
791
792fn validate_restrictions(map: &Map, steps: &[PathStep]) {
793 for triple in steps.windows(5) {
794 if let (PathStep::Lane(l1), PathStep::Lane(l2), PathStep::Lane(l3)) =
795 (triple[0], triple[2], triple[4])
796 {
797 let from = map.get_parent(l1);
798 let via = l2.road;
799 let to = l3.road;
800
801 for (dont_via, dont_to) in &from.complicated_turn_restrictions {
802 if via == *dont_via && to == *dont_to {
803 panic!(
804 "Some path does illegal uber-turn: {} -> {} -> {}",
805 l1, l2, l3
806 );
807 }
808 }
809 }
810 }
811}
812
813fn validate_zones(map: &Map, steps: &[PathStep], req: &PathRequest) {
814 let z1 = map.get_parent(req.start.lane()).get_zone(map);
815 let z2 = map.get_parent(req.end.lane()).get_zone(map);
816
817 for step in steps {
818 if let PathStep::Turn(t) | PathStep::ContraflowTurn(t) = step {
819 if map
820 .get_parent(t.src)
821 .access_restrictions
822 .allow_through_traffic
823 .contains(req.constraints)
824 && !map
825 .get_parent(t.dst)
826 .access_restrictions
827 .allow_through_traffic
828 .contains(req.constraints)
829 {
830 let into_zone = map.get_parent(t.dst).get_zone(map);
832 if into_zone != z1 && into_zone != z2 {
833 panic!("{} causes illegal entrance into a zone at {}", req, t);
838 }
839 }
840 }
841 }
842}