mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
just use 3 turn priorities, interpret them a bit differently.
temporarily kinda breaking stop signs
This commit is contained in:
parent
e6fcc50696
commit
7b2a0b87b3
@ -78,8 +78,8 @@ impl State for TrafficSignalEditor {
|
||||
let next_priority = match phase.get_priority(id) {
|
||||
TurnPriority::Banned => {
|
||||
if ui.primary.map.get_t(id).turn_type == TurnType::Crosswalk {
|
||||
if phase.could_be_priority_turn(id, &ui.primary.map) {
|
||||
Some(TurnPriority::Priority)
|
||||
if phase.could_be_protected_turn(id, &ui.primary.map) {
|
||||
Some(TurnPriority::Protected)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -87,17 +87,14 @@ impl State for TrafficSignalEditor {
|
||||
Some(TurnPriority::Yield)
|
||||
}
|
||||
}
|
||||
TurnPriority::Stop => {
|
||||
panic!("Can't have TurnPriority::Stop in a traffic signal");
|
||||
}
|
||||
TurnPriority::Yield => {
|
||||
if phase.could_be_priority_turn(id, &ui.primary.map) {
|
||||
Some(TurnPriority::Priority)
|
||||
if phase.could_be_protected_turn(id, &ui.primary.map) {
|
||||
Some(TurnPriority::Protected)
|
||||
} else {
|
||||
Some(TurnPriority::Banned)
|
||||
}
|
||||
}
|
||||
TurnPriority::Priority => Some(TurnPriority::Banned),
|
||||
TurnPriority::Protected => Some(TurnPriority::Banned),
|
||||
};
|
||||
if let Some(pri) = next_priority {
|
||||
if ctx.input.contextual_action(
|
||||
@ -173,7 +170,7 @@ impl State for TrafficSignalEditor {
|
||||
let mut phase = Phase::new(self.diagram.i);
|
||||
for t in ui.primary.map.get_turns_in_intersection(self.diagram.i) {
|
||||
if t.between_sidewalks() {
|
||||
phase.edit_turn(t, TurnPriority::Priority);
|
||||
phase.edit_turn(t, TurnPriority::Protected);
|
||||
}
|
||||
}
|
||||
signal.phases.insert(current_phase, phase);
|
||||
@ -205,14 +202,13 @@ impl State for TrafficSignalEditor {
|
||||
let phase = &map.get_traffic_signal(self.diagram.i).phases[self.diagram.current_phase()];
|
||||
for t in &ui.primary.draw_map.get_turns(self.diagram.i, map) {
|
||||
let arrow_color = match phase.get_priority(t.id) {
|
||||
TurnPriority::Priority => ui
|
||||
TurnPriority::Protected => ui
|
||||
.cs
|
||||
.get_def("priority turn in current phase", Color::GREEN),
|
||||
TurnPriority::Yield => ui
|
||||
.cs
|
||||
.get_def("yield turn in current phase", Color::rgb(255, 105, 180)),
|
||||
TurnPriority::Banned => ui.cs.get_def("turn not in current phase", Color::BLACK),
|
||||
TurnPriority::Stop => panic!("Can't have TurnPriority::Stop in a traffic signal"),
|
||||
};
|
||||
t.draw_icon(
|
||||
&mut batch,
|
||||
|
@ -28,12 +28,12 @@ pub fn draw_signal_phase(
|
||||
);
|
||||
|
||||
for (id, crosswalk) in &ctx.draw_map.get_i(phase.parent).crosswalks {
|
||||
if phase.get_priority(*id) == TurnPriority::Priority {
|
||||
if phase.get_priority(*id) == TurnPriority::Protected {
|
||||
batch.append(crosswalk.clone());
|
||||
}
|
||||
}
|
||||
|
||||
for t in &phase.priority_turns {
|
||||
for t in &phase.protected_turns {
|
||||
let turn = ctx.map.get_t(*t);
|
||||
if !turn.between_sidewalks() {
|
||||
DrawTurn::full_geom(turn, batch, priority_color);
|
||||
@ -83,7 +83,7 @@ pub fn draw_signal_phase(
|
||||
// TODO Written in a complicated way, and still doesn't look right.
|
||||
fn draw_signal_phase_with_icons(phase: &Phase, batch: &mut GeomBatch, ctx: &DrawCtx) {
|
||||
for (id, crosswalk) in &ctx.draw_map.get_i(phase.parent).crosswalks {
|
||||
if phase.get_priority(*id) == TurnPriority::Priority {
|
||||
if phase.get_priority(*id) == TurnPriority::Protected {
|
||||
batch.append(crosswalk.clone());
|
||||
}
|
||||
}
|
||||
@ -106,7 +106,7 @@ fn draw_signal_phase_with_icons(phase: &Phase, batch: &mut GeomBatch, ctx: &Draw
|
||||
}
|
||||
|
||||
match phase.get_priority(turn.id) {
|
||||
TurnPriority::Priority => {
|
||||
TurnPriority::Protected => {
|
||||
green.push(turn.id);
|
||||
}
|
||||
TurnPriority::Yield => {
|
||||
@ -115,7 +115,6 @@ fn draw_signal_phase_with_icons(phase: &Phase, batch: &mut GeomBatch, ctx: &Draw
|
||||
TurnPriority::Banned => {
|
||||
red.push(turn.id);
|
||||
}
|
||||
TurnPriority::Stop => unreachable!(),
|
||||
}
|
||||
}
|
||||
let count = vec![&green, &yellow, &red]
|
||||
|
@ -85,9 +85,10 @@ impl ControlStopSign {
|
||||
self.turns[&turn]
|
||||
}
|
||||
|
||||
// TODO rm
|
||||
pub fn could_be_priority_turn(&self, id: TurnID, map: &Map) -> bool {
|
||||
for (t, pri) in &self.turns {
|
||||
if *pri == TurnPriority::Priority && map.get_t(id).conflicts_with(map.get_t(*t)) {
|
||||
if *pri == TurnPriority::Protected && map.get_t(id).conflicts_with(map.get_t(*t)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -124,7 +125,7 @@ impl ControlStopSign {
|
||||
}
|
||||
// Are all of the SharedSidewalkCorner prioritized?
|
||||
if map.get_t(*t).turn_type == TurnType::SharedSidewalkCorner {
|
||||
assert_eq!(self.turns[t], TurnPriority::Priority);
|
||||
assert_eq!(self.turns[t], TurnPriority::Protected);
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +134,7 @@ impl ControlStopSign {
|
||||
.turns
|
||||
.iter()
|
||||
.filter_map(|(turn, pri)| {
|
||||
if *pri == TurnPriority::Priority {
|
||||
if *pri == TurnPriority::Protected {
|
||||
Some(*turn)
|
||||
} else {
|
||||
None
|
||||
@ -171,9 +172,9 @@ impl ControlStopSign {
|
||||
let ss = self.roads.get_mut(&r).unwrap();
|
||||
ss.enabled = !ss.enabled;
|
||||
let new_pri = if ss.enabled {
|
||||
TurnPriority::Stop
|
||||
} else {
|
||||
TurnPriority::Yield
|
||||
} else {
|
||||
TurnPriority::Protected
|
||||
};
|
||||
for l in ss.travel_lanes.clone() {
|
||||
for (turn, _) in map.get_next_turns_and_lanes(l, self.id) {
|
||||
@ -183,7 +184,7 @@ impl ControlStopSign {
|
||||
if new_pri == TurnPriority::Yield && self.could_be_priority_turn(turn.id, map) {
|
||||
match turn.turn_type {
|
||||
TurnType::Straight | TurnType::Right | TurnType::Crosswalk => {
|
||||
self.turns.insert(turn.id, TurnPriority::Priority);
|
||||
self.turns.insert(turn.id, TurnPriority::Protected);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -198,7 +199,7 @@ impl ControlStopSign {
|
||||
for l in &ss.travel_lanes {
|
||||
for (turn, _) in map.get_next_turns_and_lanes(*l, self.id) {
|
||||
match self.turns[&turn.id] {
|
||||
TurnPriority::Stop | TurnPriority::Banned => {
|
||||
TurnPriority::Yield | TurnPriority::Banned => {
|
||||
ss.enabled = true;
|
||||
}
|
||||
_ => {}
|
||||
@ -250,21 +251,21 @@ fn smart_assignment(map: &Map, id: IntersectionID) -> Warn<ControlStopSign> {
|
||||
};
|
||||
for t in &map.get_i(id).turns {
|
||||
if map.get_t(*t).turn_type == TurnType::SharedSidewalkCorner {
|
||||
ss.turns.insert(*t, TurnPriority::Priority);
|
||||
ss.turns.insert(*t, TurnPriority::Protected);
|
||||
} else if rank_per_incoming_lane[&t.src] == highest_rank {
|
||||
// If it's the highest rank road, prioritize main turns and make others yield.
|
||||
ss.turns.insert(*t, TurnPriority::Yield);
|
||||
if ss.could_be_priority_turn(*t, map) {
|
||||
match map.get_t(*t).turn_type {
|
||||
TurnType::Straight | TurnType::Right | TurnType::Crosswalk => {
|
||||
ss.turns.insert(*t, TurnPriority::Priority);
|
||||
ss.turns.insert(*t, TurnPriority::Protected);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Lower rank roads have to stop.
|
||||
ss.turns.insert(*t, TurnPriority::Stop);
|
||||
ss.turns.insert(*t, TurnPriority::Yield);
|
||||
}
|
||||
}
|
||||
Warn::ok(ss)
|
||||
@ -278,9 +279,9 @@ fn all_way_stop(map: &Map, id: IntersectionID) -> ControlStopSign {
|
||||
};
|
||||
for t in &map.get_i(id).turns {
|
||||
if map.get_t(*t).turn_type == TurnType::SharedSidewalkCorner {
|
||||
ss.turns.insert(*t, TurnPriority::Priority);
|
||||
ss.turns.insert(*t, TurnPriority::Protected);
|
||||
} else {
|
||||
ss.turns.insert(*t, TurnPriority::Stop);
|
||||
ss.turns.insert(*t, TurnPriority::Yield);
|
||||
}
|
||||
}
|
||||
ss
|
||||
@ -295,9 +296,9 @@ fn for_degenerate_and_deadend(map: &Map, id: IntersectionID) -> Warn<ControlStop
|
||||
for t in &map.get_i(id).turns {
|
||||
// Only the crosswalks should conflict with other turns.
|
||||
let priority = match map.get_t(*t).turn_type {
|
||||
TurnType::Crosswalk => TurnPriority::Stop,
|
||||
TurnType::Crosswalk => TurnPriority::Yield,
|
||||
TurnType::LaneChangeLeft | TurnType::LaneChangeRight => TurnPriority::Yield,
|
||||
_ => TurnPriority::Priority,
|
||||
_ => TurnPriority::Protected,
|
||||
};
|
||||
ss.turns.insert(*t, priority);
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ impl ControlTrafficSignal {
|
||||
let expected_turns: BTreeSet<TurnID> = map.get_i(self.id).turns.iter().cloned().collect();
|
||||
let mut actual_turns: BTreeSet<TurnID> = BTreeSet::new();
|
||||
for phase in &self.phases {
|
||||
actual_turns.extend(phase.priority_turns.iter());
|
||||
actual_turns.extend(phase.protected_turns.iter());
|
||||
actual_turns.extend(phase.yield_turns.iter());
|
||||
}
|
||||
if expected_turns != actual_turns {
|
||||
@ -86,8 +86,8 @@ impl ControlTrafficSignal {
|
||||
|
||||
for phase in &self.phases {
|
||||
// Do any of the priority turns in one phase conflict?
|
||||
for t1 in phase.priority_turns.iter().map(|t| map.get_t(*t)) {
|
||||
for t2 in phase.priority_turns.iter().map(|t| map.get_t(*t)) {
|
||||
for t1 in phase.protected_turns.iter().map(|t| map.get_t(*t)) {
|
||||
for t2 in phase.protected_turns.iter().map(|t| map.get_t(*t)) {
|
||||
if t1.conflicts_with(t2) {
|
||||
return Err(Error::new(format!(
|
||||
"Traffic signal has conflicting priority turns in one phase:\n{:?}\n\n{:?}",
|
||||
@ -104,7 +104,7 @@ impl ControlTrafficSignal {
|
||||
assert!(!phase.yield_turns.contains(&t.id));
|
||||
}
|
||||
TurnType::SharedSidewalkCorner => {
|
||||
assert!(phase.priority_turns.contains(&t.id));
|
||||
assert!(phase.protected_turns.contains(&t.id));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -131,11 +131,11 @@ impl ControlTrafficSignal {
|
||||
loop {
|
||||
let add_turn = remaining_turns
|
||||
.iter()
|
||||
.position(|&t| current_phase.could_be_priority_turn(t, map));
|
||||
.position(|&t| current_phase.could_be_protected_turn(t, map));
|
||||
match add_turn {
|
||||
Some(idx) => {
|
||||
current_phase
|
||||
.priority_turns
|
||||
.protected_turns
|
||||
.insert(remaining_turns.remove(idx));
|
||||
}
|
||||
None => {
|
||||
@ -375,11 +375,11 @@ impl ControlTrafficSignal {
|
||||
for turn in map.get_turns_in_intersection(i) {
|
||||
match turn.turn_type {
|
||||
TurnType::SharedSidewalkCorner => {
|
||||
all_walk.priority_turns.insert(turn.id);
|
||||
all_yield.priority_turns.insert(turn.id);
|
||||
all_walk.protected_turns.insert(turn.id);
|
||||
all_yield.protected_turns.insert(turn.id);
|
||||
}
|
||||
TurnType::Crosswalk => {
|
||||
all_walk.priority_turns.insert(turn.id);
|
||||
all_walk.protected_turns.insert(turn.id);
|
||||
}
|
||||
_ => {
|
||||
all_yield.yield_turns.insert(turn.id);
|
||||
@ -409,10 +409,10 @@ impl ControlTrafficSignal {
|
||||
for turn in map.get_turns_in_intersection(i) {
|
||||
let parent = map.get_l(turn.id.src).parent;
|
||||
if turn.turn_type == TurnType::SharedSidewalkCorner {
|
||||
phase.priority_turns.insert(turn.id);
|
||||
phase.protected_turns.insert(turn.id);
|
||||
} else if turn.turn_type == TurnType::Crosswalk {
|
||||
if parent == adj1 || parent == adj2 {
|
||||
phase.priority_turns.insert(turn.id);
|
||||
phase.protected_turns.insert(turn.id);
|
||||
}
|
||||
} else if parent == r {
|
||||
phase.yield_turns.insert(turn.id);
|
||||
@ -430,10 +430,10 @@ impl ControlTrafficSignal {
|
||||
pub fn convert_to_ped_scramble(&mut self, map: &Map) {
|
||||
// Remove Crosswalk turns from existing phases.
|
||||
for phase in self.phases.iter_mut() {
|
||||
// Crosswalks are usually only priority_turns, but also clear out from yield_turns.
|
||||
// Crosswalks are usually only protected_turns, but also clear out from yield_turns.
|
||||
for t in map.get_turns_in_intersection(self.id) {
|
||||
if t.turn_type == TurnType::Crosswalk {
|
||||
phase.priority_turns.remove(&t.id);
|
||||
phase.protected_turns.remove(&t.id);
|
||||
phase.yield_turns.remove(&t.id);
|
||||
}
|
||||
}
|
||||
@ -441,8 +441,8 @@ impl ControlTrafficSignal {
|
||||
// Blindly try to promote yield turns to protected, now that crosswalks are gone.
|
||||
let mut promoted = Vec::new();
|
||||
for t in &phase.yield_turns {
|
||||
if phase.could_be_priority_turn(*t, map) {
|
||||
phase.priority_turns.insert(*t);
|
||||
if phase.could_be_protected_turn(*t, map) {
|
||||
phase.protected_turns.insert(*t);
|
||||
promoted.push(*t);
|
||||
}
|
||||
}
|
||||
@ -454,7 +454,7 @@ impl ControlTrafficSignal {
|
||||
let mut phase = Phase::new(self.id);
|
||||
for t in map.get_turns_in_intersection(self.id) {
|
||||
if t.between_sidewalks() {
|
||||
phase.edit_turn(t, TurnPriority::Priority);
|
||||
phase.edit_turn(t, TurnPriority::Protected);
|
||||
}
|
||||
}
|
||||
self.phases.push(phase);
|
||||
@ -464,7 +464,7 @@ impl ControlTrafficSignal {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Phase {
|
||||
pub parent: IntersectionID,
|
||||
pub priority_turns: BTreeSet<TurnID>,
|
||||
pub protected_turns: BTreeSet<TurnID>,
|
||||
pub yield_turns: BTreeSet<TurnID>,
|
||||
pub duration: Duration,
|
||||
}
|
||||
@ -473,15 +473,15 @@ impl Phase {
|
||||
pub fn new(parent: IntersectionID) -> Phase {
|
||||
Phase {
|
||||
parent,
|
||||
priority_turns: BTreeSet::new(),
|
||||
protected_turns: BTreeSet::new(),
|
||||
yield_turns: BTreeSet::new(),
|
||||
duration: Duration::seconds(30.0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn could_be_priority_turn(&self, t1: TurnID, map: &Map) -> bool {
|
||||
pub fn could_be_protected_turn(&self, t1: TurnID, map: &Map) -> bool {
|
||||
let turn1 = map.get_t(t1);
|
||||
for t2 in &self.priority_turns {
|
||||
for t2 in &self.protected_turns {
|
||||
if t1 == *t2 || turn1.conflicts_with(map.get_t(*t2)) {
|
||||
return false;
|
||||
}
|
||||
@ -490,8 +490,8 @@ impl Phase {
|
||||
}
|
||||
|
||||
pub fn get_priority(&self, t: TurnID) -> TurnPriority {
|
||||
if self.priority_turns.contains(&t) {
|
||||
TurnPriority::Priority
|
||||
if self.protected_turns.contains(&t) {
|
||||
TurnPriority::Protected
|
||||
} else if self.yield_turns.contains(&t) {
|
||||
TurnPriority::Yield
|
||||
} else {
|
||||
@ -505,10 +505,10 @@ impl Phase {
|
||||
ids.extend(t.other_crosswalk_ids.clone());
|
||||
}
|
||||
for id in ids {
|
||||
self.priority_turns.remove(&id);
|
||||
self.protected_turns.remove(&id);
|
||||
self.yield_turns.remove(&id);
|
||||
if pri == TurnPriority::Priority {
|
||||
self.priority_turns.insert(id);
|
||||
if pri == TurnPriority::Protected {
|
||||
self.protected_turns.insert(id);
|
||||
} else if pri == TurnPriority::Yield {
|
||||
self.yield_turns.insert(id);
|
||||
}
|
||||
@ -516,7 +516,7 @@ impl Phase {
|
||||
}
|
||||
}
|
||||
|
||||
// Add all legal priority turns to existing phases.
|
||||
// Add all legal protected turns to existing phases.
|
||||
fn expand_all_phases(phases: &mut Vec<Phase>, map: &Map, intersection: IntersectionID) {
|
||||
let all_turns: Vec<TurnID> = map
|
||||
.get_turns_in_intersection(intersection)
|
||||
@ -525,8 +525,8 @@ fn expand_all_phases(phases: &mut Vec<Phase>, map: &Map, intersection: Intersect
|
||||
.collect();
|
||||
for phase in phases.iter_mut() {
|
||||
for t in &all_turns {
|
||||
if !phase.priority_turns.contains(t) && phase.could_be_priority_turn(*t, map) {
|
||||
phase.priority_turns.insert(*t);
|
||||
if !phase.protected_turns.contains(t) && phase.could_be_protected_turn(*t, map) {
|
||||
phase.protected_turns.insert(*t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -550,7 +550,7 @@ fn make_phases(
|
||||
for turn in map.get_turns_in_intersection(i) {
|
||||
// These never conflict with anything.
|
||||
if turn.turn_type == TurnType::SharedSidewalkCorner {
|
||||
phase.priority_turns.insert(turn.id);
|
||||
phase.protected_turns.insert(turn.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -561,7 +561,7 @@ fn make_phases(
|
||||
phase.edit_turn(
|
||||
turn,
|
||||
if protected {
|
||||
TurnPriority::Priority
|
||||
TurnPriority::Protected
|
||||
} else {
|
||||
TurnPriority::Yield
|
||||
},
|
||||
|
@ -54,14 +54,11 @@ pub enum TurnPriority {
|
||||
// Can't do this turn at all!
|
||||
Banned,
|
||||
// For stop signs: cars have to stop before doing this turn, and are accepted with the lowest priority.
|
||||
// For traffic signals: this priority doesn't make sense; can't be used.
|
||||
Stop,
|
||||
// Cars can do this immediately if there are no previously accepted conflicting turns.
|
||||
// For traffic signals: Cars can do this immediately if there are no previously accepted conflicting turns.
|
||||
Yield,
|
||||
// These must be non-conflicting, and cars don't have to stop before doing this turn (unless a
|
||||
// conflicting Yield has been accepted).
|
||||
// TODO Rename Protected?
|
||||
Priority,
|
||||
// For stop signs: cars can do this without stopping. These can conflict!
|
||||
// For traffic signals: Must be non-conflicting.
|
||||
Protected,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
|
@ -99,6 +99,7 @@ impl IntersectionSimState {
|
||||
// TODO Only wake up agents that would then be accepted.
|
||||
|
||||
// Sort by waiting time, so things like stop signs actually are first-come, first-served.
|
||||
// TODO Actually, this should be by priority first.
|
||||
let mut waiting: Vec<(Request, Duration)> = self.state[&i]
|
||||
.waiting
|
||||
.iter()
|
||||
@ -132,11 +133,10 @@ impl IntersectionSimState {
|
||||
for req in state.waiting.keys() {
|
||||
match phase.get_priority(req.turn) {
|
||||
TurnPriority::Banned => {}
|
||||
TurnPriority::Stop => unreachable!(),
|
||||
TurnPriority::Yield => {
|
||||
yields.push(req.agent);
|
||||
}
|
||||
TurnPriority::Priority => {
|
||||
TurnPriority::Protected => {
|
||||
// TODO Use update in case turn_finished scheduled an event for them already.
|
||||
scheduler.update(now, Command::update_agent(req.agent));
|
||||
}
|
||||
@ -254,7 +254,7 @@ impl State {
|
||||
assert!(our_priority != TurnPriority::Banned);
|
||||
let our_time = self.waiting[req];
|
||||
|
||||
if our_priority == TurnPriority::Stop && now < our_time + WAIT_AT_STOP_SIGN {
|
||||
if our_priority == TurnPriority::Yield && now < our_time + WAIT_AT_STOP_SIGN {
|
||||
// Since we have "ownership" of scheduling for req.agent, don't need to use
|
||||
// scheduler.update.
|
||||
scheduler.push(
|
||||
|
Loading…
Reference in New Issue
Block a user