diff --git a/control/src/stop_signs.rs b/control/src/stop_signs.rs index 62add4c185..efd11701b0 100644 --- a/control/src/stop_signs.rs +++ b/control/src/stop_signs.rs @@ -38,8 +38,8 @@ impl ControlStopSign { } fn smart_assignment(map: &Map, intersection: IntersectionID) -> ControlStopSign { - if map.get_i(intersection).get_roads(map).len() <= 2 { - return ControlStopSign::for_degenerate_intersection(map, intersection); + if map.get_i(intersection).roads.len() <= 2 { + return ControlStopSign::for_degenerate_and_deadend(map, intersection); } // Higher numbers are higher rank roads @@ -127,7 +127,7 @@ impl ControlStopSign { ss } - fn for_degenerate_intersection(map: &Map, i: IntersectionID) -> ControlStopSign { + fn for_degenerate_and_deadend(map: &Map, i: IntersectionID) -> ControlStopSign { let mut ss = ControlStopSign { intersection: i, turns: BTreeMap::new(), @@ -146,7 +146,7 @@ impl ControlStopSign { // intersection geometry), sometimes more turns conflict than really should. For now, just // detect and fallback to an all-way stop. if let Err(err) = ss.validate(map, i) { - warn!("Giving up on for_degenerate_intersection({}): {}", i, err); + warn!("Giving up on for_degenerate_and_deadend({}): {}", i, err); return ControlStopSign::all_way_stop(map, i); } diff --git a/editor/src/render/intersection.rs b/editor/src/render/intersection.rs index 0f174ce7ea..97ff659c88 100644 --- a/editor/src/render/intersection.rs +++ b/editor/src/render/intersection.rs @@ -35,7 +35,7 @@ impl DrawIntersection { crosswalks: calculate_crosswalks(inter.id, map), sidewalk_corners: calculate_corners(inter.id, map), has_traffic_signal: inter.has_traffic_signal, - should_draw_stop_sign: !inter.has_traffic_signal && !inter.is_degenerate(map), + should_draw_stop_sign: !inter.has_traffic_signal && !inter.is_degenerate(), } } diff --git a/map_model/src/intersection.rs b/map_model/src/intersection.rs index d0a154300b..a1f9e04d0f 100644 --- a/map_model/src/intersection.rs +++ b/map_model/src/intersection.rs @@ -5,7 +5,7 @@ use dimensioned::si; use geom::Pt2D; use std::collections::BTreeSet; use std::fmt; -use {LaneID, Map, RoadID, TurnID}; +use {LaneID, RoadID, TurnID}; // TODO reconsider pub usize. maybe outside world shouldnt know. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] @@ -32,6 +32,8 @@ pub struct Intersection { // TODO narrow down when and why. is it just sidewalks in weird cases? pub incoming_lanes: Vec, pub outgoing_lanes: Vec, + + pub roads: BTreeSet, } impl PartialEq for Intersection { @@ -41,20 +43,12 @@ impl PartialEq for Intersection { } impl Intersection { - pub fn get_roads(&self, map: &Map) -> BTreeSet { - let mut roads: BTreeSet = BTreeSet::new(); - for l in self.incoming_lanes.iter().chain(self.outgoing_lanes.iter()) { - roads.insert(map.get_l(*l).parent); - } - roads + pub fn is_dead_end(&self) -> bool { + self.roads.len() == 1 } - pub fn is_dead_end(&self, map: &Map) -> bool { - self.get_roads(map).len() == 1 - } - - pub fn is_degenerate(&self, map: &Map) -> bool { - self.get_roads(map).len() == 2 + pub fn is_degenerate(&self) -> bool { + self.roads.len() == 2 } pub fn dump_debug(&self) { diff --git a/map_model/src/make/intersections.rs b/map_model/src/make/intersections.rs index a17f8e6cc2..8c5d4d8b2d 100644 --- a/map_model/src/make/intersections.rs +++ b/map_model/src/make/intersections.rs @@ -1,7 +1,6 @@ use abstutil::wraparound_get; use dimensioned::si; use geom::{Angle, PolyLine, Pt2D}; -use std::collections::BTreeSet; use std::marker; use {Intersection, Road, RoadID, LANE_THICKNESS}; @@ -12,16 +11,13 @@ const DEGENERATE_INTERSECTION_HALF_LENGTH: si::Meter = si::Meter { // The polygon should exist entirely within the thick bands around all original roads -- it just // carves up part of that space, doesn't reach past it. -pub fn intersection_polygon( - i: &Intersection, - road_ids: BTreeSet, - roads: &Vec, -) -> Vec { +pub fn intersection_polygon(i: &Intersection, roads: &Vec) -> Vec { // Turn all of the incident roads into two PolyLines (the "forwards" and "backwards" borders of // the road), both with an endpoint at i.point, and the angle of the last segment of the center // line. - let mut lines: Vec<(RoadID, Angle, PolyLine, PolyLine)> = road_ids - .into_iter() + let mut lines: Vec<(RoadID, Angle, PolyLine, PolyLine)> = i + .roads + .iter() .map(|id| { let r = &roads[id.0]; let fwd_width = LANE_THICKNESS * (r.children_forwards.len() as f64); @@ -37,7 +33,7 @@ pub fn intersection_polygon( let pl_normal = line.shift(width_normal).unwrap(); let pl_reverse = line.reversed().shift(width_reverse).unwrap().reversed(); - (id, line.last_line().angle(), pl_normal, pl_reverse) + (*id, line.last_line().angle(), pl_normal, pl_reverse) }).collect(); // Sort the polylines by the angle of their last segment. diff --git a/map_model/src/make/turns.rs b/map_model/src/make/turns.rs index cb5a32a4fd..83422163c0 100644 --- a/map_model/src/make/turns.rs +++ b/map_model/src/make/turns.rs @@ -57,12 +57,11 @@ fn dedupe(turns: Vec) -> Vec { } fn make_driving_turns(i: &Intersection, map: &Map) -> Vec { - if i.is_dead_end(map) { + if i.is_dead_end() { return make_driving_turns_for_dead_end(i, map); } - // TODO make get_roads do this? - let roads: Vec<&Road> = i.get_roads(map).into_iter().map(|r| map.get_r(r)).collect(); + let roads: Vec<&Road> = i.roads.iter().map(|r| map.get_r(*r)).collect(); let mut result = Vec::new(); @@ -148,7 +147,7 @@ fn match_up_driving_lanes( } fn make_driving_turns_for_dead_end(i: &Intersection, map: &Map) -> Vec { - let road = map.get_r(i.get_roads(map).into_iter().next().unwrap()); + let road = map.get_r(*i.roads.iter().next().unwrap()); let incoming = filter_driving_lanes(road.incoming_lanes(i.id)); let outgoing = filter_driving_lanes(road.outgoing_lanes(i.id)); if incoming.is_empty() || outgoing.is_empty() { @@ -248,7 +247,7 @@ fn make_turns( assert_eq!(map.get_l(*l).src_i, parent); } - let dead_end = map.get_i(parent).is_dead_end(map); + let dead_end = map.get_i(parent).is_dead_end(); let mut result = Vec::new(); for src in incoming { @@ -276,10 +275,10 @@ fn make_walking_turns(i: &Intersection, map: &Map) -> Vec { // Sort roads by the angle into the intersection, so we can reason about sidewalks of adjacent // roads. let mut roads: Vec<(RoadID, Angle)> = i - .get_roads(map) - .into_iter() + .roads + .iter() .map(|id| { - let r = map.get_r(id); + let r = map.get_r(*id); if r.src_i == i.id { (r.id, r.center_pts.reversed().last_line().angle()) diff --git a/map_model/src/map.rs b/map_model/src/map.rs index 6c288beead..50c4b74b08 100644 --- a/map_model/src/map.rs +++ b/map_model/src/map.rs @@ -95,6 +95,7 @@ impl Map { has_traffic_signal: i.has_traffic_signal, incoming_lanes: Vec::new(), outgoing_lanes: Vec::new(), + roads: BTreeSet::new(), }); pt_to_intersection.insert(HashablePt2D::from(pt), id); } @@ -135,7 +136,9 @@ impl Map { } let (src_i, dst_i) = if lane.reverse_pts { (i2, i1) } else { (i1, i2) }; m.intersections[src_i.0].outgoing_lanes.push(id); + m.intersections[src_i.0].roads.insert(road_id); m.intersections[dst_i.0].incoming_lanes.push(id); + m.intersections[dst_i.0].roads.insert(road_id); // TODO probably different behavior for oneways // TODO need to factor in yellow center lines (but what's the right thing to even do? @@ -181,8 +184,7 @@ impl Map { panic!("{:?} is orphaned!", i); } - let incident_roads = i.get_roads(&m); - intersection_polygons.push(make::intersection_polygon(i, incident_roads, &m.roads)); + intersection_polygons.push(make::intersection_polygon(i, &m.roads)); } for (idx, p) in intersection_polygons.into_iter().enumerate() { m.intersections[idx].polygon = p; @@ -423,7 +425,7 @@ impl Map { let r = self.get_r(from); for id in vec![r.src_i, r.dst_i].into_iter() { - roads.extend(self.get_i(id).get_roads(self)); + roads.extend(self.get_i(id).roads.clone()); } roads.into_iter().collect()