use super::*;
pub fn make_traffic_signal(map: &Map, i: &Intersection) -> Option<ControlTrafficSignal> {
if let Some(ts) = make_signal(i, map) {
return optimize(ts, i);
}
None
}
fn make_signal(i: &Intersection, map: &Map) -> Option<ControlTrafficSignal> {
let mut ts = new(i.id);
if let Some(other) = three_way_three_stage(i, map) {
ts.stages = other.stages;
} else if let Some(other) = four_way_four_stage(i, map) {
ts.stages = other.stages;
}
ts.convert_to_ped_scramble_without_promotion(i);
if ts.validate(i).is_err() {
if let Some(other) = multi_way_stages(i) {
ts.stages = other.stages;
ts.convert_to_ped_scramble_without_promotion(i);
}
}
if let Err(err) = ts.validate(i) {
debug!("multi-way validation_error={} ts={:#?}", err, ts);
ts = stage_per_road(i);
ts.convert_to_ped_scramble(i);
}
Some(ts)
}
fn optimize(mut ts: ControlTrafficSignal, i: &Intersection) -> Option<ControlTrafficSignal> {
ts.stages.retain(|s| !s.protected_movements.is_empty());
while let Some(merged_ts) = merge_stages(&ts, i) {
ts = merged_ts;
}
make_lagging_green_variable(&mut ts);
make_crosswalk_variable(&mut ts, i);
Some(ts)
}
fn make_crosswalk_variable(ts: &mut ControlTrafficSignal, i: &Intersection) {
const MIN_CROSSWALK_TIME: Duration = Duration::const_seconds(15.0);
for s in &mut ts.stages {
if let Some(duration) = s.max_crosswalk_time(i) {
if let StageType::Fixed(_) = s.stage_type {
s.stage_type = StageType::Variable(
duration.max(MIN_CROSSWALK_TIME),
Duration::const_seconds(1.0),
Duration::const_seconds(1.0),
)
}
}
}
}
fn merge_stages(ts: &ControlTrafficSignal, i: &Intersection) -> Option<ControlTrafficSignal> {
for s_src in &ts.stages {
for s_dst in &ts.stages {
if s_src == s_dst {
continue;
}
let mut merged_stage = s_dst.clone();
merged_stage
.protected_movements
.extend(s_src.protected_movements.clone());
let mut maybe_ts = ts.clone();
maybe_ts.stages.insert(0, merged_stage);
if maybe_ts.validate(i).is_ok() {
let mut stages: Vec<Stage> = Vec::new();
for s in maybe_ts.stages {
if s != *s_src && s != *s_dst {
stages.push(s);
}
}
maybe_ts.stages = stages;
return Some(maybe_ts);
}
}
}
None
}
fn is_conflict(stage: &Stage, i: &Intersection) -> Option<(MovementID, MovementID)> {
for m1 in stage.protected_movements.iter().map(|m| &i.movements[m]) {
for m2 in stage.protected_movements.iter().map(|m| &i.movements[m]) {
if m1.id != m2.id && m1.geom.intersection(&m2.geom).is_some() {
return Some((m1.id, m2.id));
}
}
}
None
}
fn protected_yield_stage(p: MovementID, y: MovementID) -> Stage {
let mut stage = Stage::new();
stage.protected_movements.insert(p);
stage.yield_movements.insert(y);
stage
}
fn multi_way_stages(i: &Intersection) -> Option<ControlTrafficSignal> {
let mut ts = new(i.id);
let (mut right, mut left, straight, mut roads) = movements(i);
let (one_way, two_way) = straight_types(&straight);
for m in &one_way {
let mut stage = Stage::new();
stage.protected_movements.insert(*m);
for t in movements_from(m.from.road, &right) {
stage.protected_movements.insert(t);
}
for t in movements_from(m.from.road, &left) {
stage.protected_movements.insert(t);
}
add_stage(&mut ts, stage);
roads.remove(&m.from.road);
}
for (m1, m2) in &two_way {
let mut stage1 = Stage::new();
let mut stage2 = Stage::new();
stage1.protected_movements.insert(*m1);
stage1.protected_movements.insert(*m2);
stage1
.protected_movements
.extend(movements_from(m1.from.road, &right));
stage1
.protected_movements
.extend(movements_from(m2.from.road, &right));
for t in movements_from(m1.from.road, &left) {
stage1.yield_movements.insert(t);
stage2.protected_movements.insert(t);
}
for t in movements_from(m2.from.road, &left) {
stage1.yield_movements.insert(t);
stage2.protected_movements.insert(t);
}
add_stage(&mut ts, stage1);
if let Some((m1, m2)) = is_conflict(&stage2, i) {
add_stage(&mut ts, protected_yield_stage(m1, m2));
add_stage(&mut ts, protected_yield_stage(m2, m1));
} else {
add_stage(&mut ts, stage2);
}
roads.remove(&m1.from.road);
roads.remove(&m2.from.road);
}
let mut vec: Vec<_> = roads.into_iter().collect();
while let Some(r1) = vec.pop() {
let mut stage1 = Stage::new();
let mut stage2 = Stage::new();
if let Some(r2) = vec.pop() {
if let Some(m) = remove_movement(r1, r2, &mut right) {
stage1.protected_movements.insert(m);
} else if let Some(m) = remove_movement(r1, r2, &mut left) {
stage1.protected_movements.insert(m);
}
if let Some(m) = remove_movement(r2, r1, &mut right) {
stage1.protected_movements.insert(m);
} else if let Some(m) = remove_movement(r2, r1, &mut left) {
stage1.protected_movements.insert(m);
}
stage1
.protected_movements
.extend(movements_from(r1, &right));
stage1
.protected_movements
.extend(movements_from(r2, &right));
for t in movements_from(r1, &left) {
stage1.yield_movements.insert(t);
stage2.protected_movements.insert(t);
}
for t in movements_from(r2, &left) {
stage1.yield_movements.insert(t);
stage2.protected_movements.insert(t);
}
add_stage(&mut ts, stage1);
add_stage(&mut ts, stage2);
} else {
stage1
.protected_movements
.extend(movements_from(r1, &right));
stage1.protected_movements.extend(movements_from(r1, &left));
add_stage(&mut ts, stage1);
}
}
Some(ts)
}
fn add_stage(ts: &mut ControlTrafficSignal, stage: Stage) {
if stage.protected_movements.is_empty() {
return;
}
if ts.stages.iter().all(|s| *s != stage) {
ts.stages.push(stage)
}
}
fn movements_from(from: RoadID, movements: &[MovementID]) -> Vec<MovementID> {
movements
.iter()
.filter_map(|mvmnt| {
if from == mvmnt.from.road {
Some(*mvmnt)
} else {
None
}
})
.collect()
}
fn remove_movement(
from: RoadID,
to: RoadID,
movements: &mut Vec<MovementID>,
) -> Option<MovementID> {
let idx = movements
.iter()
.position(|mvmnt| mvmnt.from.road == from && mvmnt.to.road == to)?;
Some(movements.remove(idx))
}
fn three_way_three_stage(i: &Intersection, map: &Map) -> Option<ControlTrafficSignal> {
let roads = i.get_sorted_incoming_roads(map);
if roads.len() != 3 {
return None;
}
let mut ts = new(i.id);
let straight = i
.movements
.values()
.find(|g| g.turn_type == TurnType::Straight)?;
let (north, south) = (straight.id.from.road, straight.id.to.road);
let east = roads
.into_iter()
.find(|r| *r != north && *r != south)
.unwrap();
make_stages(
&mut ts,
&map.config,
i,
vec![
vec![
(vec![north, south], TurnType::Straight, PROTECTED),
(vec![north, south], TurnType::Right, PROTECTED),
(vec![north, south], TurnType::Left, YIELD),
(vec![east], TurnType::Right, YIELD),
],
vec![
(vec![north, south], TurnType::Left, PROTECTED),
(vec![east], TurnType::Right, YIELD),
],
vec![
(vec![east], TurnType::Straight, PROTECTED),
(vec![east], TurnType::Right, PROTECTED),
(vec![east], TurnType::Left, PROTECTED),
(vec![north, south], TurnType::Right, YIELD),
],
],
);
Some(ts)
}
fn four_way_four_stage(i: &Intersection, map: &Map) -> Option<ControlTrafficSignal> {
let roads = i.get_sorted_incoming_roads(map);
if roads.len() != 4 {
return None;
}
let (north, west, south, east) = (roads[0], roads[1], roads[2], roads[3]);
let mut ts = new(i.id);
make_stages(
&mut ts,
&map.config,
i,
vec![
vec![
(vec![north, south], TurnType::Straight, PROTECTED),
(vec![north, south], TurnType::Left, YIELD),
(vec![north, south], TurnType::Right, PROTECTED),
(vec![east, west], TurnType::Right, YIELD),
],
vec![
(vec![north, south], TurnType::Left, PROTECTED),
(vec![east, west], TurnType::Right, YIELD),
],
vec![
(vec![east, west], TurnType::Straight, PROTECTED),
(vec![east, west], TurnType::Left, YIELD),
(vec![east, west], TurnType::Right, PROTECTED),
(vec![north, south], TurnType::Right, YIELD),
],
vec![
(vec![east, west], TurnType::Left, PROTECTED),
(vec![north, south], TurnType::Right, YIELD),
],
],
);
Some(ts)
}
fn movements(
i: &Intersection,
) -> (
Vec<MovementID>,
Vec<MovementID>,
Vec<MovementID>,
BTreeSet<RoadID>,
) {
let mut right: Vec<MovementID> = Vec::new();
let mut left: Vec<MovementID> = Vec::new();
let mut straight: Vec<MovementID> = Vec::new();
let mut set: BTreeSet<RoadID> = BTreeSet::new();
for (id, m) in &i.movements {
if !id.crosswalk {
match m.turn_type {
TurnType::Right => right.push(*id),
TurnType::Left => left.push(*id),
TurnType::Straight => straight.push(*id),
_ => (),
}
set.insert(id.from.road);
}
}
(right, left, straight, set)
}
fn straight_types(movements: &[MovementID]) -> (Vec<MovementID>, Vec<(MovementID, MovementID)>) {
let mut one_way: Vec<MovementID> = Vec::new();
let mut two_way: Vec<(MovementID, MovementID)> = Vec::new();
for m in movements {
if let Some(other) = movements
.iter()
.find(|&other| m.from.road == other.to.road && m.to.road == other.from.road)
{
two_way.push((*m, *other));
} else {
one_way.push(*m);
}
}
(one_way, two_way)
}
fn make_lagging_green_variable(ts: &mut ControlTrafficSignal) {
const EXTENT_DURATION: Duration = Duration::const_seconds(10.0);
const MAX_DURATION: Duration = Duration::const_seconds(20.0);
let mut prev_stage: Option<&mut Stage> = None;
for stage in ts.stages.iter_mut() {
if let Some(prev) = prev_stage {
if stage
.protected_movements
.iter()
.all(|m| prev.yield_movements.contains(m))
{
if let StageType::Fixed(_) = stage.stage_type {
stage.stage_type =
StageType::Variable(Duration::ZERO, EXTENT_DURATION, MAX_DURATION);
}
}
}
prev_stage = Some(stage);
}
}