1use std::collections::BTreeSet;
2use std::fmt;
3
4use anyhow::Result;
5use enumset::EnumSet;
6use serde::{Deserialize, Serialize};
7
8use abstutil::{deserialize_usize, serialize_usize, Tags};
9use geom::{Distance, PolyLine, Polygon, Speed};
10
11use crate::{
12 osm, AccessRestrictions, CommonEndpoint, CrossingType, Direction, DrivingSide, IntersectionID,
13 Lane, LaneID, LaneSpec, LaneType, Map, PathConstraints, RestrictionType, RoadFilter,
14 TransitStopID, Zone,
15};
16
17#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
18pub struct RoadID(
19 #[serde(
20 serialize_with = "serialize_usize",
21 deserialize_with = "deserialize_usize"
22 )]
23 pub usize,
24);
25
26impl fmt::Display for RoadID {
27 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28 write!(f, "Road #{}", self.0)
29 }
30}
31
32impl RoadID {
33 pub fn both_directions(self) -> Vec<DirectedRoadID> {
34 vec![
35 DirectedRoadID {
36 road: self,
37 dir: Direction::Fwd,
38 },
39 DirectedRoadID {
40 road: self,
41 dir: Direction::Back,
42 },
43 ]
44 }
45
46 pub fn both_sides(self) -> [RoadSideID; 2] {
47 [
48 RoadSideID {
49 road: self,
50 side: SideOfRoad::Right,
51 },
52 RoadSideID {
53 road: self,
54 side: SideOfRoad::Left,
55 },
56 ]
57 }
58}
59
60#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
61pub struct DirectedRoadID {
62 pub road: RoadID,
63 pub dir: Direction,
64}
65
66impl fmt::Display for DirectedRoadID {
67 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 write!(f, "DirectedRoadID({}, {})", self.road.0, self.dir,)
69 }
70}
71
72impl DirectedRoadID {
73 pub fn src_i(self, map: &Map) -> IntersectionID {
74 let r = map.get_r(self.road);
75 if self.dir == Direction::Fwd {
76 r.src_i
77 } else {
78 r.dst_i
79 }
80 }
81
82 pub fn dst_i(self, map: &Map) -> IntersectionID {
83 let r = map.get_r(self.road);
84 if self.dir == Direction::Fwd {
85 r.dst_i
86 } else {
87 r.src_i
88 }
89 }
90
91 pub fn lanes(self, constraints: PathConstraints, map: &Map) -> Vec<LaneID> {
93 let r = map.get_r(self.road);
94 constraints.filter_lanes(r.children(self.dir).iter().map(|(l, _)| *l).collect(), map)
95 }
96
97 pub fn must_get_sidewalk(self, map: &Map) -> LaneID {
99 let mut found = Vec::new();
100 for (l, lt) in map.get_r(self.road).children(self.dir) {
101 if lt.is_walkable() {
102 found.push(l);
103 }
104 }
105 if found.len() != 1 {
106 panic!(
107 "must_get_sidewalk broken by {} ({}). Found lanes {:?}",
108 self,
109 map.get_r(self.road).orig_id,
110 found
111 );
112 }
113 found[0]
114 }
115
116 pub fn has_lanes(self, lane_type: LaneType, map: &Map) -> bool {
118 for (_, lt) in map.get_r(self.road).children(self.dir) {
119 if lt == lane_type {
120 return true;
121 }
122 }
123 false
124 }
125}
126
127#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
129pub enum SideOfRoad {
130 Right,
131 Left,
132}
133
134#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
135pub struct RoadSideID {
136 pub road: RoadID,
137 pub side: SideOfRoad,
138}
139
140impl RoadSideID {
141 pub fn get_outermost_lane(self, map: &Map) -> &Lane {
142 let r = map.get_r(self.road);
143 match self.side {
144 SideOfRoad::Right => r.lanes.last().unwrap(),
145 SideOfRoad::Left => &r.lanes[0],
146 }
147 }
148
149 pub fn other_side(self) -> RoadSideID {
150 RoadSideID {
151 road: self.road,
152 side: if self.side == SideOfRoad::Left {
153 SideOfRoad::Right
154 } else {
155 SideOfRoad::Left
156 },
157 }
158 }
159}
160
161#[derive(Serialize, Deserialize, Clone, Debug)]
163pub struct Road {
164 pub id: RoadID,
165 pub osm_tags: Tags,
166 pub turn_restrictions: Vec<(RestrictionType, RoadID)>,
168 pub complicated_turn_restrictions: Vec<(RoadID, RoadID)>,
170 pub orig_id: OriginalRoad,
171 pub speed_limit: Speed,
172 pub access_restrictions: AccessRestrictions,
173 pub zorder: isize,
174 pub percent_incline: f64,
177
178 pub lanes: Vec<Lane>,
181
182 pub center_pts: PolyLine,
185 pub untrimmed_center_pts: PolyLine,
188 pub trim_start: Distance,
189 pub trim_end: Distance,
190
191 pub src_i: IntersectionID,
192 pub dst_i: IntersectionID,
193 pub crosswalk_forward: bool,
195 pub crosswalk_backward: bool,
196
197 pub transit_stops: BTreeSet<TransitStopID>,
199
200 pub modal_filter: Option<RoadFilter>,
202
203 pub barrier_nodes: Vec<Distance>,
205 pub crossing_nodes: Vec<(Distance, CrossingType)>,
208 pub crossings: Vec<Crossing>,
210}
211
212impl Road {
213 pub fn lane_specs(&self) -> Vec<LaneSpec> {
214 self.lanes
215 .iter()
216 .map(|l| LaneSpec {
217 lt: l.lane_type,
218 dir: l.dir,
219 width: l.width,
220 allowed_turns: Default::default(),
222 })
223 .collect()
224 }
225
226 pub fn shift_from_left_side(&self, width_from_left_side: Distance) -> Result<PolyLine> {
227 self.center_pts
228 .shift_from_center(self.get_width(), width_from_left_side)
229 }
230
231 pub(crate) fn dir_and_offset(&self, lane: LaneID) -> (Direction, usize) {
234 for dir in [Direction::Fwd, Direction::Back] {
235 if let Some(idx) = self.children(dir).iter().position(|pair| pair.0 == lane) {
236 return (dir, idx);
237 }
238 }
239 panic!("{} doesn't contain {}", self.id, lane);
240 }
241
242 pub fn parking_to_driving(&self, parking: LaneID) -> Option<LaneID> {
243 self.find_closest_lane(parking, |l| l.is_driving())
244 }
245
246 pub(crate) fn speed_limit_from_osm(&self) -> Speed {
247 if let Some(limit) = self.osm_tags.get("maxspeed") {
248 if let Some(speed) = if let Ok(kmph) = limit.parse::<f64>() {
249 Some(Speed::km_per_hour(kmph))
250 } else if let Some(mph) = limit
251 .strip_suffix(" mph")
252 .and_then(|x| x.parse::<f64>().ok())
253 {
254 Some(Speed::miles_per_hour(mph))
255 } else {
256 None
257 } {
258 if speed == Speed::ZERO {
259 warn!("{} has a speed limit of 0", self.orig_id.osm_way_id);
260 return Speed::miles_per_hour(1.0);
261 }
262 return speed;
263 }
264
265 }
267
268 if self
270 .osm_tags
271 .is_any(osm::HIGHWAY, vec!["primary", "secondary", "motorway_link"])
272 {
273 return Speed::miles_per_hour(40.0);
274 }
275 if self.osm_tags.is(osm::HIGHWAY, "living_street") {
276 return Speed::km_per_hour(20.0);
278 }
279 if self.is_service() {
280 return Speed::miles_per_hour(10.0);
281 }
282 Speed::miles_per_hour(20.0)
283 }
284
285 pub fn find_closest_lane<F: Fn(&Lane) -> bool>(
289 &self,
290 from: LaneID,
291 filter: F,
292 ) -> Option<LaneID> {
293 let our_idx = from.offset as isize;
294 self.lanes
295 .iter()
296 .enumerate()
297 .filter_map(|(idx, l)| {
298 if (idx as isize) != our_idx && filter(l) {
299 Some((idx, l.id))
300 } else {
301 None
302 }
303 })
304 .min_by_key(|(idx, _)| (our_idx - (*idx as isize)).abs())
305 .map(|(_, l)| l)
306 }
307
308 pub fn get_dir_change_pl(&self, map: &Map) -> PolyLine {
311 let mut found: Option<&Lane> = None;
312 for pair in self.lanes.windows(2) {
313 if pair[0].dir != pair[1].dir {
314 found = Some(&pair[0]);
315 break;
316 }
317 }
318 let lane = found.unwrap_or(&self.lanes[0]);
319 let shifted = if map.get_config().driving_side == DrivingSide::Right || found.is_none() {
321 lane.lane_center_pts.must_shift_left(lane.width / 2.0)
322 } else {
323 lane.lane_center_pts.must_shift_right(lane.width / 2.0)
324 };
325 if lane.dir == Direction::Fwd {
326 shifted
327 } else {
328 shifted.reversed()
329 }
330 }
331
332 pub fn get_half_width(&self) -> Distance {
333 self.get_width() / 2.0
334 }
335
336 pub fn get_width(&self) -> Distance {
337 self.lanes.iter().map(|l| l.width).sum::<Distance>()
338 }
339
340 pub fn get_thick_polygon(&self) -> Polygon {
341 self.center_pts.make_polygons(self.get_width())
342 }
343
344 pub fn length(&self) -> Distance {
345 self.center_pts.length()
346 }
347
348 pub fn get_half_polygon(&self, dir: Direction, map: &Map) -> Result<Polygon> {
352 let mut width_fwd = Distance::ZERO;
353 let mut width_back = Distance::ZERO;
354 for l in &self.lanes {
355 if l.dir == Direction::Fwd {
356 width_fwd += l.width;
357 } else {
358 width_back += l.width;
359 }
360 }
361 let center = self.get_dir_change_pl(map);
362
363 let shift = if map.get_config().driving_side == DrivingSide::Right {
365 1.0
366 } else {
367 -1.0
368 };
369 if dir == Direction::Fwd {
370 Ok(center
371 .shift_right(shift * width_fwd / 2.0)?
372 .make_polygons(width_fwd))
373 } else {
374 Ok(center
375 .shift_left(shift * width_back / 2.0)?
376 .make_polygons(width_back))
377 }
378 }
379
380 pub fn get_name(&self, lang: Option<&String>) -> String {
381 if let Some(lang) = lang {
382 if let Some(name) = self.osm_tags.get(&format!("name:{}", lang)) {
383 return name.to_string();
384 }
385 }
386
387 if let Some(name) = self.osm_tags.get("name") {
388 if name.is_empty() {
389 return "???".to_string();
390 } else {
391 return name.to_string();
392 }
393 }
394 if let Some(name) = self.osm_tags.get("ref") {
395 return name.to_string();
396 }
397 if self
398 .osm_tags
399 .get(osm::HIGHWAY)
400 .map(|hwy| hwy.ends_with("_link"))
401 .unwrap_or(false)
402 {
403 if let Some(name) = self.osm_tags.get("destination:street") {
404 return format!("Exit for {}", name);
405 }
406 if let Some(name) = self.osm_tags.get("destination:ref") {
407 return format!("Exit for {}", name);
408 }
409 if let Some(name) = self.osm_tags.get("destination") {
410 return format!("Exit for {}", name);
411 }
412 }
414 "???".to_string()
415 }
416
417 pub fn get_rank(&self) -> osm::RoadRank {
418 if let Some(x) = self.osm_tags.get(osm::HIGHWAY) {
419 if x == "construction" {
420 if let Some(x) = self.osm_tags.get("construction") {
422 osm::RoadRank::from_highway(x)
423 } else {
424 osm::RoadRank::Local
425 }
426 } else {
427 osm::RoadRank::from_highway(x)
428 }
429 } else {
430 osm::RoadRank::Local
431 }
432 }
433
434 pub fn get_detailed_rank(&self) -> usize {
435 self.osm_tags
436 .get(osm::HIGHWAY)
437 .map(|hwy| osm::RoadRank::detailed_from_highway(hwy))
438 .unwrap_or(0)
439 }
440
441 pub fn is_light_rail(&self) -> bool {
442 self.lanes.len() == 1 && self.lanes[0].lane_type == LaneType::LightRail
443 }
444
445 pub fn is_footway(&self) -> bool {
446 self.lanes.len() == 1
447 && matches!(
448 self.lanes[0].lane_type,
449 LaneType::Footway | LaneType::SharedUse
450 )
451 }
452
453 pub fn is_service(&self) -> bool {
454 self.osm_tags.is(osm::HIGHWAY, "service")
455 }
456
457 pub fn is_cycleway(&self) -> bool {
458 let mut bike = false;
459 for lane in &self.lanes {
460 if lane.lane_type == LaneType::Biking {
461 bike = true;
462 } else if !lane.is_walkable() {
463 return false;
464 }
465 }
466 bike
467 }
468
469 pub fn is_driveable(&self) -> bool {
470 self.lanes.iter().any(|l| l.is_driving())
471 }
472
473 pub fn common_endpoint(&self, other: &Road) -> CommonEndpoint {
474 CommonEndpoint::new((self.src_i, self.dst_i), (other.src_i, other.dst_i))
475 }
476
477 pub fn endpoints(&self) -> Vec<IntersectionID> {
478 vec![self.src_i, self.dst_i]
479 }
480
481 pub fn other_endpt(&self, i: IntersectionID) -> IntersectionID {
485 if self.src_i == i {
486 self.dst_i
487 } else if self.dst_i == i {
488 self.src_i
489 } else {
490 panic!("{} doesn't touch {}", self.id, i);
491 }
492 }
493
494 pub fn is_private(&self) -> bool {
495 self.access_restrictions != AccessRestrictions::new() && !self.is_light_rail()
496 }
497
498 pub(crate) fn access_restrictions_from_osm(&self) -> AccessRestrictions {
499 let allow_through_traffic = if self.osm_tags.is("access", "private") {
500 EnumSet::new()
501 } else if self.osm_tags.is(osm::HIGHWAY, "living_street") {
502 let mut allow = PathConstraints::Pedestrian | PathConstraints::Bike;
503 if self.osm_tags.is("psv", "yes") || self.osm_tags.is("bus", "yes") {
504 allow |= PathConstraints::Bus;
505 }
506 allow
507 } else {
508 EnumSet::all()
509 };
510 AccessRestrictions {
511 allow_through_traffic,
512 }
513 }
514
515 pub fn get_zone<'a>(&self, map: &'a Map) -> Option<&'a Zone> {
516 if !self.is_private() {
517 return None;
518 }
519 Some(
521 map.zones
522 .iter()
523 .find(|z| z.members.contains(&self.id))
524 .unwrap(),
525 )
526 }
527
528 pub fn is_extremely_short(&self) -> bool {
532 self.length() < Distance::meters(2.0)
533 }
534
535 pub fn directed_id_from(&self, i: IntersectionID) -> DirectedRoadID {
538 DirectedRoadID {
539 road: self.id,
540 dir: if self.src_i == i {
541 Direction::Fwd
542 } else if self.dst_i == i {
543 Direction::Back
544 } else {
545 panic!("{} doesn't point to {}", self.id, i);
546 },
547 }
548 }
549
550 pub fn directed_id_to(&self, i: IntersectionID) -> DirectedRoadID {
553 let mut id = self.directed_id_from(i);
554 id.dir = id.dir.opposite();
555 id
556 }
557
558 pub(crate) fn recreate_lanes(&mut self, lane_specs_ltr: Vec<LaneSpec>) {
559 self.lanes.clear();
560
561 let total_width = lane_specs_ltr.iter().map(|x| x.width).sum();
562
563 let mut width_so_far = Distance::ZERO;
564 for lane in lane_specs_ltr {
565 let id = LaneID {
566 road: self.id,
567 offset: self.lanes.len(),
568 };
569
570 let (src_i, dst_i) = if lane.dir == Direction::Fwd {
571 (self.src_i, self.dst_i)
572 } else {
573 (self.dst_i, self.src_i)
574 };
575
576 width_so_far += lane.width / 2.0;
577 let pl = self
578 .center_pts
579 .shift_from_center(total_width, width_so_far)
580 .unwrap_or_else(|_| self.center_pts.clone());
581 width_so_far += lane.width / 2.0;
582
583 let lane_center_pts = if lane.dir == Direction::Fwd {
584 pl
585 } else {
586 pl.reversed()
587 };
588
589 self.lanes.push(Lane {
590 id,
591 lane_center_pts,
592 width: lane.width,
593 src_i,
594 dst_i,
595 lane_type: lane.lt,
596 dir: lane.dir,
597 driving_blackhole: false,
598 biking_blackhole: false,
599 });
600 }
601 }
602
603 pub fn get_lanes_between(&self, l1: LaneID, l2: LaneID) -> Vec<LaneID> {
605 let mut results = Vec::new();
606 let mut found_start = false;
607 for l in &self.lanes {
608 if found_start {
609 if l.id == l1 || l.id == l2 {
610 return results;
611 }
612 results.push(l.id);
613 } else if l.id == l1 || l.id == l2 {
614 found_start = true;
615 }
616 }
617 panic!("{} doesn't contain both {} and {}", self.id, l1, l2);
618 }
619
620 pub fn high_stress_for_bikes(&self, map: &Map, dir: Direction) -> bool {
627 let mut bike_lanes = false;
628 let mut can_use = false;
629 for l in &self.lanes {
631 if l.lane_type == LaneType::Biking && l.dir == dir {
632 bike_lanes = true;
633 }
634 if PathConstraints::Bike.can_use(l, map) {
635 can_use = true;
636 }
637 }
638 if !can_use || bike_lanes {
639 return false;
640 }
641 self.get_rank() != osm::RoadRank::Local
642 }
643
644 pub fn oneway_for_driving(&self) -> Option<Direction> {
645 LaneSpec::oneway_for_driving(&self.lane_specs())
646 }
647
648 pub fn is_deadend_for_driving(&self, map: &Map) -> bool {
651 map.get_i(self.src_i).is_deadend_for_driving(map)
652 || map.get_i(self.dst_i).is_deadend_for_driving(map)
653 }
654}
655
656impl Road {
660 pub(crate) fn children_forwards(&self) -> Vec<(LaneID, LaneType)> {
663 let mut result = Vec::new();
664 for l in &self.lanes {
665 if l.dir == Direction::Fwd {
666 result.push((l.id, l.lane_type));
667 }
668 }
669 result
670 }
671 pub(crate) fn children_backwards(&self) -> Vec<(LaneID, LaneType)> {
672 let mut result = Vec::new();
673 for l in &self.lanes {
674 if l.dir == Direction::Back {
675 result.push((l.id, l.lane_type));
676 }
677 }
678 result.reverse();
679 result
680 }
681
682 pub(crate) fn children(&self, dir: Direction) -> Vec<(LaneID, LaneType)> {
684 if dir == Direction::Fwd {
685 self.children_forwards()
686 } else {
687 self.children_backwards()
688 }
689 }
690
691 pub(crate) fn incoming_lanes(&self, i: IntersectionID) -> Vec<(LaneID, LaneType)> {
693 if self.src_i == i {
694 self.children_backwards()
695 } else if self.dst_i == i {
696 self.children_forwards()
697 } else {
698 panic!("{} doesn't have an endpoint at {}", self.id, i);
699 }
700 }
701}
702
703#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
706pub struct OriginalRoad {
707 pub osm_way_id: osm::WayID,
708 pub i1: osm::NodeID,
709 pub i2: osm::NodeID,
710}
711
712impl fmt::Display for OriginalRoad {
713 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
714 write!(
715 f,
716 "OriginalRoad({} from {} to {}",
717 self.osm_way_id, self.i1, self.i2
718 )
719 }
720}
721impl fmt::Debug for OriginalRoad {
722 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
723 write!(f, "{}", self)
724 }
725}
726
727impl OriginalRoad {
728 pub fn new(way: i64, (i1, i2): (i64, i64)) -> OriginalRoad {
729 OriginalRoad {
730 osm_way_id: osm::WayID(way),
731 i1: osm::NodeID(i1),
732 i2: osm::NodeID(i2),
733 }
734 }
735}
736
737#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
738pub struct Crossing {
739 pub kind: CrossingType,
740 pub dist: Distance,
741}