gracefully degrade if we cant make TurnGroups for a traffic signal. this

gets SF, Tokyo, and London to import!!!
This commit is contained in:
Dustin Carlino 2020-08-12 11:05:19 -07:00
parent 7a0dbb28b1
commit 3b49353df2
7 changed files with 41 additions and 19 deletions

View File

@ -221,8 +221,12 @@ pub fn snap_bus_stops(
for idx in (0..idx_in_route).rev() { for idx in (0..idx_in_route).rev() {
let (i, pt) = route.all_pts[idx]; let (i, pt) = route.all_pts[idx];
if !raw.intersections.contains_key(&i) { if !raw.intersections.contains_key(&i) {
found = Some(pt_to_road[&pt.to_hashable()]); if let Some(r) = pt_to_road.get(&pt.to_hashable()) {
break; found = Some(*r);
break;
} else {
return Err(format!("Some point on the route isn't even on a road?!"));
}
} }
} }
if let Some(r) = found { if let Some(r) = found {

View File

@ -9,7 +9,7 @@ pub struct Line(Pt2D, Pt2D);
impl Line { impl Line {
pub fn new(pt1: Pt2D, pt2: Pt2D) -> Option<Line> { pub fn new(pt1: Pt2D, pt2: Pt2D) -> Option<Line> {
if pt1.dist_to(pt2) < EPSILON_DIST { if pt1.dist_to(pt2) <= EPSILON_DIST {
return None; return None;
} }
Some(Line(pt1, pt2)) Some(Line(pt1, pt2))

View File

@ -120,7 +120,7 @@ impl Ring {
for pt in pts.iter().cloned() { for pt in pts.iter().cloned() {
current.push(pt); current.push(pt);
if intersections.contains(&pt.to_hashable()) && current.len() > 1 { if intersections.contains(&pt.to_hashable()) && current.len() > 1 {
if current[0] == pt { if current[0] == pt && current.len() >= 3 {
rings.push(Ring::must_new(current.drain(..).collect())); rings.push(Ring::must_new(current.drain(..).collect()));
} else { } else {
polylines.push(PolyLine::new(current.drain(..).collect())?); polylines.push(PolyLine::new(current.drain(..).collect())?);

View File

@ -13,7 +13,7 @@ use crate::raw::{OriginalIntersection, OriginalRoad, RawMap};
use crate::{ use crate::{
connectivity, osm, Area, AreaID, ControlStopSign, ControlTrafficSignal, Intersection, connectivity, osm, Area, AreaID, ControlStopSign, ControlTrafficSignal, Intersection,
IntersectionID, IntersectionType, Lane, LaneID, Map, MapEdits, PathConstraints, Position, Road, IntersectionID, IntersectionType, Lane, LaneID, Map, MapEdits, PathConstraints, Position, Road,
RoadID, Zone, RoadID, TurnGroup, Zone,
}; };
use abstutil::{Parallelism, Timer}; use abstutil::{Parallelism, Timer};
use enumset::EnumSet; use enumset::EnumSet;
@ -141,7 +141,9 @@ impl Map {
} }
// TODO Maybe easier to use the road's "yellow center line" and shift left/right from // TODO Maybe easier to use the road's "yellow center line" and shift left/right from
// there. // there.
let road_left_pts = map.must_left_shift(road.center_pts.clone(), r.half_width); let road_left_pts = map
.left_shift(road.center_pts.clone(), r.half_width)
.unwrap_or_else(|_| road.center_pts.clone());
let mut fwd_width_so_far = Distance::ZERO; let mut fwd_width_so_far = Distance::ZERO;
let mut back_width_so_far = Distance::ZERO; let mut back_width_so_far = Distance::ZERO;
@ -306,14 +308,28 @@ impl Map {
IntersectionType::StopSign => { IntersectionType::StopSign => {
stop_signs.insert(i.id, ControlStopSign::new(&map, i.id)); stop_signs.insert(i.id, ControlStopSign::new(&map, i.id));
} }
IntersectionType::TrafficSignal => { IntersectionType::TrafficSignal => match TurnGroup::for_i(i.id, &map) {
traffic_signals.insert(i.id, ControlTrafficSignal::new(&map, i.id, timer)); Ok(_) => {
} traffic_signals.insert(i.id, ControlTrafficSignal::new(&map, i.id, timer));
}
Err(err) => {
timer.error(format!(
"Traffic signal at {} downgraded to stop sign because of weird \
problem: {}",
i.orig_id, err
));
stop_signs.insert(i.id, ControlStopSign::new(&map, i.id));
}
},
IntersectionType::Border | IntersectionType::Construction => {} IntersectionType::Border | IntersectionType::Construction => {}
}; };
} }
map.stop_signs = stop_signs; map.stop_signs = stop_signs;
map.traffic_signals = traffic_signals; map.traffic_signals = traffic_signals;
// Fix up the type for any problematic traffic signals
for i in map.stop_signs.keys() {
map.intersections[i.0].intersection_type = IntersectionType::StopSign;
}
traffic_signals::synchronize(&mut map); traffic_signals::synchronize(&mut map);

View File

@ -70,7 +70,7 @@ fn new(id: IntersectionID, map: &Map) -> ControlTrafficSignal {
id, id,
phases: Vec::new(), phases: Vec::new(),
offset: Duration::ZERO, offset: Duration::ZERO,
turn_groups: TurnGroup::for_i(id, map), turn_groups: TurnGroup::for_i(id, map).unwrap(),
} }
} }
@ -428,6 +428,7 @@ fn make_phases(
pub fn brute_force(map: &Map, i: IntersectionID) { pub fn brute_force(map: &Map, i: IntersectionID) {
let turn_groups: Vec<TurnGroup> = TurnGroup::for_i(i, map) let turn_groups: Vec<TurnGroup> = TurnGroup::for_i(i, map)
.unwrap()
.into_iter() .into_iter()
.filter_map(|(id, tg)| if id.crosswalk { None } else { Some(tg) }) .filter_map(|(id, tg)| if id.crosswalk { None } else { Some(tg) })
.collect(); .collect();

View File

@ -306,7 +306,7 @@ impl ControlTrafficSignal {
id, id,
phases, phases,
offset: Duration::seconds(raw.offset_seconds as f64), offset: Duration::seconds(raw.offset_seconds as f64),
turn_groups: TurnGroup::for_i(id, map), turn_groups: TurnGroup::for_i(id, map).unwrap(),
} }
.validate() .validate()
} }

View File

@ -197,7 +197,10 @@ pub struct TurnGroup {
} }
impl TurnGroup { impl TurnGroup {
pub(crate) fn for_i(i: IntersectionID, map: &Map) -> BTreeMap<TurnGroupID, TurnGroup> { pub(crate) fn for_i(
i: IntersectionID,
map: &Map,
) -> Result<BTreeMap<TurnGroupID, TurnGroup>, Box<dyn Error>> {
let mut results = BTreeMap::new(); let mut results = BTreeMap::new();
let mut groups: MultiMap<(DirectedRoadID, DirectedRoadID), TurnID> = MultiMap::new(); let mut groups: MultiMap<(DirectedRoadID, DirectedRoadID), TurnID> = MultiMap::new();
for turn in map.get_turns_in_intersection(i) { for turn in map.get_turns_in_intersection(i) {
@ -233,11 +236,7 @@ impl TurnGroup {
members.iter().map(|t| &map.get_t(*t).geom).collect(), members.iter().map(|t| &map.get_t(*t).geom).collect(),
from, from,
to, to,
) )?;
.expect(&format!(
"Weird turn group geometry near {}",
map.get_i(i).orig_id
));
let turn_types: BTreeSet<TurnType> = let turn_types: BTreeSet<TurnType> =
members.iter().map(|t| map.get_t(*t).turn_type).collect(); members.iter().map(|t| map.get_t(*t).turn_type).collect();
if turn_types.len() > 1 { if turn_types.len() > 1 {
@ -265,9 +264,11 @@ impl TurnGroup {
); );
} }
if results.is_empty() { if results.is_empty() {
panic!("{} has no TurnGroups!", map.get_i(i).orig_id); return Err(
format!("No TurnGroups! Does the intersection have at least 2 roads?").into(),
);
} }
results Ok(results)
} }
// Polyline points FROM intersection // Polyline points FROM intersection