1use std::collections::{BTreeMap, HashSet};
23use anyhow::Result;
4use lyon::geom::{CubicBezierSegment, Point, QuadraticBezierSegment};
56use geom::{PolyLine, Pt2D};
78use crate::{
9 map::turn_type_from_road_geom, Intersection, Lane, LaneID, LaneType, Map, RoadID, Turn, TurnID,
10 TurnType,
11};
1213/// Generate all driving and walking turns at an intersection, accounting for OSM turn restrictions.
14pub fn make_all_turns(map: &Map, i: &Intersection) -> Vec<Turn> {
15let mut raw_turns: Vec<Turn> = Vec::new();
16 raw_turns.extend(make_vehicle_turns(i, map));
17 raw_turns.extend(crate::make::walking_turns::filter_turns(
18crate::make::walking_turns::make_walking_turns(map, i),
19 map,
20 i,
21 ));
22let unique_turns = ensure_unique(raw_turns);
23// Never allow turns that go against road-level turn restrictions; that upstream OSM data is
24 // usually not extremely broken.
25let all_turns: Vec<Turn> = unique_turns
26 .into_iter()
27 .filter(|t| t.permitted_by_road(i, map))
28 .collect();
2930// Try to use turn lane tags...
31let filtered_turns: Vec<Turn> = all_turns
32 .clone()
33 .into_iter()
34 .filter(|t| t.permitted_by_lane(map))
35 .collect();
36// And remove merging left or right turns. If we wanted to remove the "lane-changing at
37 // intersections" behavior, we could do this for TurnType::Straight too.
38let filtered_turns = remove_merging_turns(map, filtered_turns, TurnType::Right);
39let mut filtered_turns = remove_merging_turns(map, filtered_turns, TurnType::Left);
40if i.merged {
41 filtered_turns.retain(|turn| {
42if turn.turn_type == TurnType::UTurn {
43let src_lane = map.get_l(turn.id.src);
44// U-turns at divided highways are sometimes legal (and a common movement --
45 // https://www.openstreetmap.org/way/361443212), so let OSM turn:lanes override.
46if src_lane
47 .get_lane_level_turn_restrictions(map.get_r(src_lane.id.road), false)
48 .map(|set| !set.contains(&TurnType::UTurn))
49 .unwrap_or(true)
50 {
51warn!("Removing u-turn from merged intersection: {}", turn.id);
52false
53} else {
54true
55}
56 } else {
57true
58}
59 });
60 }
6162// But then see how all of that filtering affects lane connectivity.
63match verify_vehicle_connectivity(&filtered_turns, i, map) {
64Ok(()) => filtered_turns,
65Err(err) => {
66warn!("Not filtering turns. {}", err);
67 all_turns
68 }
69 }
70}
7172fn ensure_unique(turns: Vec<Turn>) -> Vec<Turn> {
73let mut ids = HashSet::new();
74let mut keep: Vec<Turn> = Vec::new();
75for t in turns.into_iter() {
76if ids.contains(&t.id) {
77// TODO This was once an assertion, but disabled for
78 // https://github.com/a-b-street/abstreet/issues/84. A crosswalk gets created twice
79 // and deduplicated here. Not sure why it was double-created in the first place.
80warn!("Duplicate turns {}!", t.id);
81 } else {
82 ids.insert(t.id);
83 keep.push(t);
84 }
85 }
86 keep
87}
8889/// Ideally, we want every incoming lane to lead to at least one lane of the same type, and every
90/// outgoing lane to be reachable by at least one lane of the same type. But if it's a bus or bike
91/// lane, settle for being connected to anything -- even just a driving lane. There's naturally
92/// places where these dedicated lanes start and end.
93///
94/// Why is this definition strict for driving lanes connected to other driving lanes? See
95/// https://www.openstreetmap.org/node/491979474 for a motivating example. When a dedicated bike
96/// path crosses a road with turn restrictions marked on a segment before the intersection, the
97/// turn restrictions _probably_ indicate the vehicle movements allowed further on, and _don't_
98/// describe the turns between the road and the trail.
99pub fn verify_vehicle_connectivity(turns: &[Turn], i: &Intersection, map: &Map) -> Result<()> {
100let mut incoming_missing: HashSet<LaneID> = HashSet::new();
101for l in &i.incoming_lanes {
102if map.get_l(*l).lane_type.is_for_moving_vehicles() {
103 incoming_missing.insert(*l);
104 }
105 }
106let mut outgoing_missing: HashSet<LaneID> = HashSet::new();
107for l in &i.outgoing_lanes {
108if map.get_l(*l).lane_type.is_for_moving_vehicles() {
109 outgoing_missing.insert(*l);
110 }
111 }
112113for turn in turns {
114let src_lt = map.get_l(turn.id.src).lane_type;
115let dst_lt = map.get_l(turn.id.dst).lane_type;
116117if src_lt == dst_lt {
118 incoming_missing.remove(&turn.id.src);
119 outgoing_missing.remove(&turn.id.dst);
120 }
121122if src_lt == LaneType::Biking || src_lt == LaneType::Bus {
123 incoming_missing.remove(&turn.id.src);
124 }
125if dst_lt == LaneType::Biking || dst_lt == LaneType::Bus {
126 outgoing_missing.remove(&turn.id.dst);
127 }
128 }
129130if !incoming_missing.is_empty() || !outgoing_missing.is_empty() {
131bail!(
132"Turns for {} orphan some lanes. Incoming: {:?}, outgoing: {:?}",
133 i.id,
134 incoming_missing,
135 outgoing_missing
136 );
137 }
138Ok(())
139}
140141fn make_vehicle_turns(i: &Intersection, map: &Map) -> Vec<Turn> {
142let mut turns = Vec::new();
143144// Just generate every possible combination of turns between incoming and outgoing lanes.
145let is_deadend = i.is_deadend_for_driving(map);
146for src in &i.incoming_lanes {
147let src = map.get_l(*src);
148if !src.lane_type.is_for_moving_vehicles() {
149continue;
150 }
151for dst in &i.outgoing_lanes {
152let dst = map.get_l(*dst);
153if !dst.lane_type.is_for_moving_vehicles() {
154continue;
155 }
156// Only allow U-turns at deadends
157if src.id.road == dst.id.road && !is_deadend {
158continue;
159 }
160// Can't go between light rail and normal roads
161if src.is_light_rail() != dst.is_light_rail() {
162continue;
163 }
164if src.last_pt() == dst.first_pt() {
165warn!(
166"No turn from {} to {}; the endpoints are the same",
167 src.id, dst.id
168 );
169continue;
170 }
171172let turn_type = turn_type_from_lane_geom(src, dst, i, map);
173174let geom = curvey_turn(src, dst, i)
175 .unwrap_or_else(|_| PolyLine::must_new(vec![src.last_pt(), dst.first_pt()]));
176177 turns.push(Turn {
178 id: TurnID {
179 parent: i.id,
180 src: src.id,
181 dst: dst.id,
182 },
183 turn_type,
184 geom,
185 });
186 }
187 }
188189 turns
190}
191192fn turn_type_from_lane_geom(src: &Lane, dst: &Lane, i: &Intersection, map: &Map) -> TurnType {
193 turn_type_from_road_geom(
194 map.get_r(src.id.road),
195 src.last_line().angle(),
196 map.get_r(dst.id.road),
197 dst.last_line().angle(),
198 i,
199 map,
200 )
201}
202203fn curvey_turn(src: &Lane, dst: &Lane, i: &Intersection) -> Result<PolyLine> {
204fn to_pt(pt: Pt2D) -> Point<f64> {
205 Point::new(pt.x(), pt.y())
206 }
207208fn from_pt(pt: Point<f64>) -> Pt2D {
209 Pt2D::new(pt.x, pt.y)
210 }
211212// The control points are straight out/in from the source/destination lanes, so
213 // that the car exits and enters at the same angle as the road.
214let src_line = src.last_line();
215let dst_line = dst.first_line();
216217let src_pt = src.last_pt();
218let dst_pt = dst.first_pt();
219220let src_angle = src_line.angle();
221let dst_angle = dst_line.angle();
222223let intersection = src_line
224 .infinite()
225 .intersection(&dst_line.infinite())
226 .unwrap_or(src_pt);
227228let curve =
229// U-turns and straight turns
230if src_angle.approx_parallel(dst_angle, 5.0)
231// Zero length intersections (this results in PolyLine::new returning none)
232|| src_pt.approx_eq(intersection, geom::EPSILON_DIST)
233 || dst_pt.approx_eq(intersection, geom::EPSILON_DIST)
234// Weirdly shaped intersections where the lane lines intersect outside the intersection
235|| !i.polygon.contains_pt(intersection)
236 {
237// All get a curve scaled to the distance between the points
238CubicBezierSegment {
239 from: to_pt(src_pt),
240 ctrl1: to_pt(src_pt.project_away(src_pt.dist_to(dst_pt) / 2.0, src_angle)),
241 ctrl2: to_pt(dst_pt.project_away(src_pt.dist_to(dst_pt) / 2.0, dst_angle.opposite())),
242 to: to_pt(dst_pt),
243 }
244 } else {
245// Regular intersections get a quadratic bezier curve
246QuadraticBezierSegment {
247 from: to_pt(src_pt),
248 ctrl: to_pt(intersection),
249 to: to_pt(dst_pt),
250 }.to_cubic()
251 };
252253let pieces = 5;
254let mut curve: Vec<Pt2D> = (0..=pieces)
255 .map(|i| from_pt(curve.sample(1.0 / f64::from(pieces) * f64::from(i))))
256 .collect();
257 curve.dedup();
258 PolyLine::new(curve)
259}
260261fn remove_merging_turns(map: &Map, input: Vec<Turn>, turn_type: TurnType) -> Vec<Turn> {
262let mut turns = Vec::new();
263264// Group turns of the specified type by (from, to) road
265let mut pairs: BTreeMap<(RoadID, RoadID), Vec<Turn>> = BTreeMap::new();
266for t in input {
267// Only do this for driving lanes
268if !map.get_l(t.id.src).is_driving() || !map.get_l(t.id.dst).is_driving() {
269 turns.push(t);
270continue;
271 }
272273if t.turn_type == turn_type {
274 pairs
275 .entry((t.id.src.road, t.id.dst.road))
276 .or_insert_with(Vec::new)
277 .push(t);
278 } else {
279// Other turn types always pass through
280turns.push(t);
281 }
282 }
283284for (_, group) in pairs {
285if group.len() == 1 {
286 turns.extend(group);
287continue;
288 }
289290let num_src_lanes = group.iter().map(|t| t.id.src).collect::<HashSet<_>>().len();
291let num_dst_lanes = group.iter().map(|t| t.id.dst).collect::<HashSet<_>>().len();
292293// Allow all turns from one to many
294if num_src_lanes == 1 {
295 turns.extend(group);
296continue;
297 }
298299// If the number of source and destination lanes is the same, match them up in order,
300 // without any crossing.
301if num_src_lanes == num_dst_lanes {
302// But we want to match things up -- leftmost turn lane leads to leftmost destination.
303let mut src_lanes_in_order: Vec<LaneID> = group.iter().map(|t| t.id.src).collect();
304 src_lanes_in_order.sort_by_key(|l| map.get_parent(*l).dir_and_offset(*l).1);
305let mut dst_lanes_in_order: Vec<LaneID> = group.iter().map(|t| t.id.dst).collect();
306 dst_lanes_in_order.sort_by_key(|l| map.get_parent(*l).dir_and_offset(*l).1);
307308for t in group {
309let src_order = src_lanes_in_order
310 .iter()
311 .position(|l| t.id.src == *l)
312 .unwrap();
313let dst_order = dst_lanes_in_order
314 .iter()
315 .position(|l| t.id.dst == *l)
316 .unwrap();
317if src_order == dst_order {
318 turns.push(t);
319 }
320 }
321continue;
322 }
323324// If src < dst and src isn't 1, then one source lane gets to access multiple destination
325 // lanes. For now, just give up figuring this out, and allow all combinations.
326 //
327 // TODO https://wiki.openstreetmap.org/wiki/Relation:connectivity may have hints about a
328 // better algorithm.
329if num_src_lanes < num_dst_lanes {
330 turns.extend(group);
331continue;
332 }
333334// If we get here, then multiple source lanes are forced to merge into one destination
335 // lane.
336 //
337 // Just kind of give up on these cases for now, and fall-back to only allowing the leftmost
338 // or rightmost source lane to make these turns.
339 //
340 // That left or rightmost lane can turn into all lanes on the destination road. Tempting to
341 // remove this, but it may remove some valid U-turn movements (like on Mercer).
342let road = map.get_parent(group[0].id.src);
343let src = if turn_type == TurnType::Right {
344 group
345 .iter()
346 .max_by_key(|t| road.dir_and_offset(t.id.src).1)
347 .unwrap()
348 .id
349 .src
350 } else if turn_type == TurnType::Left {
351 group
352 .iter()
353 .min_by_key(|t| road.dir_and_offset(t.id.src).1)
354 .unwrap()
355 .id
356 .src
357 } else {
358unreachable!()
359 };
360for t in group {
361if t.id.src == src {
362 turns.push(t);
363 }
364 }
365 }
366 turns
367}