making bike lane turn handling use the common driving turn code too, with preferred lanes

This commit is contained in:
Dustin Carlino 2018-11-07 12:41:02 -08:00
parent 6e786d5630
commit 023bb5cf5d
2 changed files with 82 additions and 171 deletions

View File

@ -24,7 +24,7 @@ impl fmt::Display for LaneID {
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum LaneType {
Driving,
Parking,

View File

@ -1,6 +1,6 @@
use abstutil::{wraparound_get, MultiMap};
use abstutil::wraparound_get;
use geom::{Angle, Line};
use std::collections::HashSet;
use std::collections::{BTreeSet, HashSet};
use std::iter;
use {
Intersection, IntersectionID, Lane, LaneID, LaneType, Map, Road, RoadID, Turn, TurnID, TurnType,
@ -8,8 +8,7 @@ use {
pub fn make_all_turns(i: &Intersection, map: &Map) -> Vec<Turn> {
let mut turns: Vec<Turn> = Vec::new();
turns.extend(make_driving_turns(i, map));
turns.extend(make_biking_turns(i, map));
turns.extend(make_vehicle_turns(i, map));
turns.extend(make_walking_turns(i, map));
let turns = dedupe(turns);
@ -56,51 +55,73 @@ fn dedupe(turns: Vec<Turn>) -> Vec<Turn> {
keep
}
fn make_driving_turns(i: &Intersection, map: &Map) -> Vec<Turn> {
if i.is_dead_end() {
return make_driving_turns_for_dead_end(i, map);
}
fn make_vehicle_turns(i: &Intersection, map: &Map) -> Vec<Turn> {
let roads: Vec<&Road> = i.roads.iter().map(|r| map.get_r(*r)).collect();
let mut lane_types: BTreeSet<LaneType> = BTreeSet::new();
for r in &roads {
let (t1, t2) = r.get_lane_types();
for lt in t1.into_iter().chain(t2.into_iter()) {
lane_types.insert(lt);
}
}
lane_types.remove(&LaneType::Parking);
lane_types.remove(&LaneType::Sidewalk);
let mut result = Vec::new();
for r1 in &roads {
let incoming = filter_driving_lanes(r1.incoming_lanes(i.id));
if incoming.is_empty() {
for lane_type in lane_types.into_iter() {
if i.is_dead_end() {
result.extend(make_vehicle_turns_for_dead_end(i, map, lane_type));
continue;
}
for r2 in &roads {
if r1.id == r2.id {
continue;
}
let outgoing = filter_driving_lanes(r2.outgoing_lanes(i.id));
if outgoing.is_empty() {
for r1 in &roads {
// We can't filter incoming just on the preferred type, because we might be forced to
// make a turn from a driving lane to a bike/bus lane.
let incoming = filter_vehicle_lanes(r1.incoming_lanes(i.id), lane_type);
if incoming.is_empty() {
continue;
}
// Use an arbitrary lane from each road to get the angle between r1 and r2.
let angle1 = map.get_l(incoming[0]).last_line().angle();
let angle2 = map.get_l(outgoing[0]).first_line().angle();
let diff = angle1
.shortest_rotation_towards(angle2)
.normalized_degrees();
for r2 in &roads {
if r1.id == r2.id {
continue;
}
let outgoing = filter_vehicle_lanes(r2.outgoing_lanes(i.id), lane_type);
if outgoing.is_empty() {
continue;
}
if diff < 10.0 || diff > 350.0 {
// Straight. Match up based on the relative number of lanes.
result.extend(match_up_driving_lanes(map, i.id, &incoming, &outgoing));
} else if diff > 180.0 {
// Clockwise rotation means a right turn?
result.push(make_driving_turn(
map,
i.id,
*incoming.last().unwrap(),
*outgoing.last().unwrap(),
));
} else {
// Counter-clockwise rotation means a left turn
result.push(make_driving_turn(map, i.id, incoming[0], outgoing[0]));
// If we fell back to driving lanes for both incoming and outgoing and it's not
// time, then skip. This should prevent duplicates.
if map.get_l(incoming[0]).lane_type != lane_type
&& map.get_l(outgoing[0]).lane_type != lane_type
{
continue;
}
// Use an arbitrary lane from each road to get the angle between r1 and r2.
let angle1 = map.get_l(incoming[0]).last_line().angle();
let angle2 = map.get_l(outgoing[0]).first_line().angle();
let diff = angle1
.shortest_rotation_towards(angle2)
.normalized_degrees();
if diff < 10.0 || diff > 350.0 {
// Straight. Match up based on the relative number of lanes.
result.extend(match_up_lanes(map, i.id, &incoming, &outgoing));
} else if diff > 180.0 {
// Clockwise rotation means a right turn?
result.push(make_vehicle_turn(
map,
i.id,
*incoming.last().unwrap(),
*outgoing.last().unwrap(),
));
} else {
// Counter-clockwise rotation means a left turn
result.push(make_vehicle_turn(map, i.id, incoming[0], outgoing[0]));
}
}
}
}
@ -108,7 +129,7 @@ fn make_driving_turns(i: &Intersection, map: &Map) -> Vec<Turn> {
result
}
fn match_up_driving_lanes(
fn match_up_lanes(
map: &Map,
i: IntersectionID,
incoming: &Vec<LaneID>,
@ -123,7 +144,7 @@ fn match_up_driving_lanes(
.collect();
assert_eq!(padded_incoming.len(), outgoing.len());
for (l1, l2) in padded_incoming.iter().zip(outgoing.iter()) {
result.push(make_driving_turn(map, i, **l1, *l2));
result.push(make_vehicle_turn(map, i, **l1, *l2));
}
} else if incoming.len() > outgoing.len() {
// TODO For non-dead-ends: Ideally if the left/rightmost lanes are for turning, use the
@ -135,140 +156,27 @@ fn match_up_driving_lanes(
.collect();
assert_eq!(padded_outgoing.len(), incoming.len());
for (l1, l2) in incoming.iter().zip(&padded_outgoing) {
result.push(make_driving_turn(map, i, *l1, **l2));
result.push(make_vehicle_turn(map, i, *l1, **l2));
}
} else {
// The easy case!
for (l1, l2) in incoming.iter().zip(outgoing.iter()) {
result.push(make_driving_turn(map, i, *l1, *l2));
result.push(make_vehicle_turn(map, i, *l1, *l2));
}
}
result
}
fn make_driving_turns_for_dead_end(i: &Intersection, map: &Map) -> Vec<Turn> {
fn make_vehicle_turns_for_dead_end(i: &Intersection, map: &Map, lane_type: LaneType) -> Vec<Turn> {
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));
let incoming = filter_vehicle_lanes(road.incoming_lanes(i.id), lane_type);
let outgoing = filter_vehicle_lanes(road.outgoing_lanes(i.id), lane_type);
if incoming.is_empty() || outgoing.is_empty() {
error!("{} needs to be a border node!", i.id);
return Vec::new();
}
match_up_driving_lanes(map, i.id, &incoming, &outgoing)
}
fn make_biking_turns(i: &Intersection, m: &Map) -> Vec<Turn> {
// TODO Road should make this easier, but how?
let mut incoming_roads: HashSet<RoadID> = HashSet::new();
let mut incoming_bike_lanes_per_road: MultiMap<RoadID, LaneID> = MultiMap::new();
let mut incoming_driving_lanes_per_road: MultiMap<RoadID, LaneID> = MultiMap::new();
for id in &i.incoming_lanes {
let l = m.get_l(*id);
incoming_roads.insert(l.parent);
match l.lane_type {
LaneType::Biking => incoming_bike_lanes_per_road.insert(l.parent, *id),
LaneType::Driving => incoming_driving_lanes_per_road.insert(l.parent, *id),
_ => {}
};
}
let mut outgoing_roads: HashSet<RoadID> = HashSet::new();
let mut outgoing_bike_lanes_per_road: MultiMap<RoadID, LaneID> = MultiMap::new();
let mut outgoing_driving_lanes_per_road: MultiMap<RoadID, LaneID> = MultiMap::new();
for id in &i.outgoing_lanes {
let l = m.get_l(*id);
outgoing_roads.insert(l.parent);
match l.lane_type {
LaneType::Biking => outgoing_bike_lanes_per_road.insert(l.parent, *id),
LaneType::Driving => outgoing_driving_lanes_per_road.insert(l.parent, *id),
_ => {}
};
}
let mut incoming: Vec<LaneID> = Vec::new();
for incoming_road in &incoming_roads {
// Prefer a bike lane if it's there, otherwise use all driving lanes
let lanes = incoming_bike_lanes_per_road.get(*incoming_road);
if !lanes.is_empty() {
incoming.extend(lanes);
} else {
incoming.extend(incoming_driving_lanes_per_road.get(*incoming_road));
}
}
let mut outgoing: Vec<LaneID> = Vec::new();
for outgoing_road in &outgoing_roads {
let lanes = outgoing_bike_lanes_per_road.get(*outgoing_road);
if !lanes.is_empty() {
outgoing.extend(lanes);
} else {
outgoing.extend(outgoing_driving_lanes_per_road.get(*outgoing_road));
}
}
// Stay deterministic! Iteration earlier used HashSets.
incoming.sort();
outgoing.sort();
// Kind of a hack. We wind up making some driving->driving turns here, but make_driving_turns
// will create those, and duplicates are bad. Filter them out here.
make_turns(m, i.id, &incoming, &outgoing)
.into_iter()
.filter(|t| m.get_l(t.id.src).is_biking() || m.get_l(t.id.dst).is_biking())
.collect()
}
fn make_turns(
map: &Map,
parent: IntersectionID,
incoming: &Vec<LaneID>,
outgoing: &Vec<LaneID>,
) -> Vec<Turn> {
// TODO: Figure out why this happens in the huge map
if incoming.is_empty() {
if false {
warn!("{} has no incoming lanes of some type", parent);
}
return Vec::new();
}
if outgoing.is_empty() {
if false {
warn!("{} has no outgoing lanes of some type", parent);
}
return Vec::new();
}
// Sanity check...
for l in incoming {
assert_eq!(map.get_l(*l).dst_i, parent);
}
for l in outgoing {
assert_eq!(map.get_l(*l).src_i, parent);
}
let dead_end = map.get_i(parent).is_dead_end();
let mut result = Vec::new();
for src in incoming {
let src_l = map.get_l(*src);
for dst in outgoing {
let dst_l = map.get_l(*dst);
// Don't create U-turns unless it's a dead-end
if src_l.parent == dst_l.parent && !dead_end {
continue;
}
// TODO if it's a multi-lane dead-end, ideally match up lanes or something
result.push(Turn {
id: turn_id(parent, src_l.id, dst_l.id),
turn_type: TurnType::Other,
line: Line::new(src_l.last_pt(), dst_l.first_pt()),
});
}
}
result
match_up_lanes(map, i.id, &incoming, &outgoing)
}
fn make_walking_turns(i: &Intersection, map: &Map) -> Vec<Turn> {
@ -356,19 +264,22 @@ fn get_sidewalk<'a>(map: &'a Map, children: &Vec<(LaneID, LaneType)>) -> Option<
None
}
fn filter_driving_lanes(lanes: &Vec<(LaneID, LaneType)>) -> Vec<LaneID> {
lanes
.iter()
.filter_map(|(id, lt)| {
if *lt == LaneType::Driving {
Some(*id)
} else {
None
}
}).collect()
fn filter_vehicle_lanes(lanes: &Vec<(LaneID, LaneType)>, preferred: LaneType) -> Vec<LaneID> {
let preferred = filter_lanes(lanes, preferred);
if !preferred.is_empty() {
return preferred;
}
filter_lanes(lanes, LaneType::Driving)
}
fn make_driving_turn(map: &Map, i: IntersectionID, l1: LaneID, l2: LaneID) -> Turn {
fn filter_lanes(lanes: &Vec<(LaneID, LaneType)>, filter: LaneType) -> Vec<LaneID> {
lanes
.iter()
.filter_map(|(id, lt)| if *lt == filter { Some(*id) } else { None })
.collect()
}
fn make_vehicle_turn(map: &Map, i: IntersectionID, l1: LaneID, l2: LaneID) -> Turn {
Turn {
id: turn_id(i, l1, l2),
turn_type: TurnType::Other,