1 use crate::{osm, DirectedRoadID, LaneID, Map, PathConstraints, Road, RoadID, TurnID}; 2 use abstutil::{deserialize_usize, serialize_usize}; 3 use geom::{Distance, Polygon}; 4 use serde::{Deserialize, Serialize}; 5 use std::collections::BTreeSet; 6 use std::fmt; 7 8 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] 9 pub struct IntersectionID( 10 #[serde( 11 serialize_with = "serialize_usize", 12 deserialize_with = "deserialize_usize" 13 )] 14 pub usize, 15 ); 16 17 impl fmt::Display for IntersectionID { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result18 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 19 write!(f, "Intersection #{}", self.0) 20 } 21 } 22 23 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] 24 pub enum IntersectionType { 25 StopSign, 26 TrafficSignal, 27 Border, 28 Construction, 29 } 30 31 #[derive(Serialize, Deserialize, Debug)] 32 pub struct Intersection { 33 pub id: IntersectionID, 34 // This needs to be in clockwise orientation, or later rendering of sidewalk corners breaks. 35 pub polygon: Polygon, 36 pub turns: BTreeSet<TurnID>, 37 pub elevation: Distance, 38 39 pub intersection_type: IntersectionType, 40 pub orig_id: osm::NodeID, 41 42 // Note that a lane may belong to both incoming_lanes and outgoing_lanes. 43 // TODO narrow down when and why. is it just sidewalks in weird cases? 44 // TODO Change to BTreeSet, or otherwise emphasize to callers that the order of these isn't 45 // meaningful 46 pub incoming_lanes: Vec<LaneID>, 47 pub outgoing_lanes: Vec<LaneID>, 48 49 // TODO Maybe DirectedRoadIDs 50 pub roads: BTreeSet<RoadID>, 51 } 52 53 impl Intersection { is_border(&self) -> bool54 pub fn is_border(&self) -> bool { 55 self.intersection_type == IntersectionType::Border 56 } is_incoming_border(&self) -> bool57 pub fn is_incoming_border(&self) -> bool { 58 self.intersection_type == IntersectionType::Border && !self.outgoing_lanes.is_empty() 59 } is_outgoing_border(&self) -> bool60 pub fn is_outgoing_border(&self) -> bool { 61 self.intersection_type == IntersectionType::Border && !self.incoming_lanes.is_empty() 62 } 63 is_closed(&self) -> bool64 pub fn is_closed(&self) -> bool { 65 self.intersection_type == IntersectionType::Construction 66 } 67 is_stop_sign(&self) -> bool68 pub fn is_stop_sign(&self) -> bool { 69 self.intersection_type == IntersectionType::StopSign 70 } 71 is_traffic_signal(&self) -> bool72 pub fn is_traffic_signal(&self) -> bool { 73 self.intersection_type == IntersectionType::TrafficSignal 74 } 75 is_light_rail(&self, map: &Map) -> bool76 pub fn is_light_rail(&self, map: &Map) -> bool { 77 self.roads.iter().all(|r| map.get_r(*r).is_light_rail()) 78 } 79 is_private(&self, map: &Map) -> bool80 pub fn is_private(&self, map: &Map) -> bool { 81 self.roads.iter().all(|r| map.get_r(*r).is_private()) 82 } 83 get_incoming_lanes<'a>( &'a self, map: &'a Map, constraints: PathConstraints, ) -> impl Iterator<Item = LaneID> + 'a84 pub fn get_incoming_lanes<'a>( 85 &'a self, 86 map: &'a Map, 87 constraints: PathConstraints, 88 ) -> impl Iterator<Item = LaneID> + 'a { 89 self.incoming_lanes 90 .iter() 91 .filter(move |l| constraints.can_use(map.get_l(**l), map)) 92 .cloned() 93 } 94 95 // Strict for bikes. If there are bike lanes, not allowed to use other lanes. get_outgoing_lanes(&self, map: &Map, constraints: PathConstraints) -> Vec<LaneID>96 pub fn get_outgoing_lanes(&self, map: &Map, constraints: PathConstraints) -> Vec<LaneID> { 97 constraints.filter_lanes(self.outgoing_lanes.clone(), map) 98 } 99 get_zorder(&self, map: &Map) -> isize100 pub fn get_zorder(&self, map: &Map) -> isize { 101 // TODO Not sure min makes sense -- what about a 1 and a 0? Prefer the nonzeros. If there's 102 // a -1 and a 1... need to see it to know what to do. 103 self.roads 104 .iter() 105 .map(|r| map.get_r(*r).zorder) 106 .min() 107 .unwrap() 108 } 109 get_rank(&self, map: &Map) -> osm::RoadRank110 pub fn get_rank(&self, map: &Map) -> osm::RoadRank { 111 self.roads 112 .iter() 113 .map(|r| map.get_r(*r).get_rank()) 114 .max() 115 .unwrap() 116 } 117 get_roads_sorted_by_incoming_angle(&self, all_roads: &Vec<Road>) -> Vec<RoadID>118 pub(crate) fn get_roads_sorted_by_incoming_angle(&self, all_roads: &Vec<Road>) -> Vec<RoadID> { 119 let center = self.polygon.center(); 120 let mut roads: Vec<RoadID> = self.roads.iter().cloned().collect(); 121 roads.sort_by_key(|id| { 122 let r = &all_roads[id.0]; 123 let endpt = if r.src_i == self.id { 124 r.center_pts.first_pt() 125 } else if r.dst_i == self.id { 126 r.center_pts.last_pt() 127 } else { 128 unreachable!(); 129 }; 130 endpt.angle_to(center).normalized_degrees() as i64 131 }); 132 roads 133 } 134 some_outgoing_road(&self, map: &Map) -> Option<DirectedRoadID>135 pub fn some_outgoing_road(&self, map: &Map) -> Option<DirectedRoadID> { 136 self.outgoing_lanes 137 .get(0) 138 .map(|l| map.get_l(*l).get_directed_parent(map)) 139 } 140 some_incoming_road(&self, map: &Map) -> Option<DirectedRoadID>141 pub fn some_incoming_road(&self, map: &Map) -> Option<DirectedRoadID> { 142 self.incoming_lanes 143 .get(0) 144 .map(|l| map.get_l(*l).get_directed_parent(map)) 145 } 146 name(&self, lang: Option<&String>, map: &Map) -> String147 pub fn name(&self, lang: Option<&String>, map: &Map) -> String { 148 let road_names = self 149 .roads 150 .iter() 151 .map(|r| map.get_r(*r).get_name(lang)) 152 .collect::<BTreeSet<_>>(); 153 abstutil::plain_list_names(road_names) 154 } 155 } 156