use crate::maneuver::LaneChangeType;
use crate::{
agents::VehicleID,
grid::{
cell::{Cell, CellID, CellState},
},
shortest_path::path::Path,
};
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct ObservablePath<'a> {
pub wanted_maneuver: LaneChangeType,
pub last_cell_state: CellState,
pub trimmed_path: Vec<&'a Cell>,
pub has_vehicle_on_path: bool,
pub speed_limit_reached: bool,
pub stopped_on_maneuver: bool,
pub stopped_speed_possible: bool,
}
pub fn process_path<'a>(
shortest_path: &'a mut Path,
speed_possible: i32,
destination: CellID,
current_state: &HashMap<CellID, VehicleID>,
) -> ObservablePath<'a> {
shortest_path.vertices_mut().remove(0);
if shortest_path.vertices().is_empty() || speed_possible == 0 {
return ObservablePath {
wanted_maneuver: LaneChangeType::NoChange,
last_cell_state: CellState::Free,
trimmed_path: vec![],
has_vehicle_on_path: false,
speed_limit_reached: false,
stopped_on_maneuver: false,
stopped_speed_possible: false,
};
}
let speed_limit = (speed_possible as usize - 1).min(shortest_path.vertices().len() - 1);
if shortest_path.vertices().len() > 1
&& shortest_path.vertices()[speed_limit].get_id() != destination
{
}
let maneuvers = shortest_path.maneuvers();
let vertices = shortest_path.vertices();
let mut wanted_maneuver = LaneChangeType::NoChange;
let mut last_cell_state = CellState::Free;
let mut success_forward_movement = 0;
let mut has_vehicle_on_path = false;
let mut speed_limit_reached = false;
let mut stopped_on_maneuver = false;
let stopped_speed_possible = false;
for (i, cell) in vertices.iter().enumerate() {
let maneuver = maneuvers[i];
if maneuver != LaneChangeType::NoChange {
if success_forward_movement == 0 {
wanted_maneuver = maneuver;
}
stopped_on_maneuver = true;
break;
}
if let Some(_vehicle_id) = current_state.get(&cell.get_id()) {
has_vehicle_on_path = true;
break;
}
if cell.get_state() != CellState::Free {
last_cell_state = cell.get_state();
break;
}
if speed_possible > cell.get_speed_limit() {
if success_forward_movement == 0 {
success_forward_movement = 1;
}
speed_limit_reached = true;
break;
}
success_forward_movement += 1;
if success_forward_movement >= speed_possible {
break;
}
}
ObservablePath {
wanted_maneuver,
last_cell_state,
trimmed_path: vertices[..success_forward_movement as usize].to_vec(),
has_vehicle_on_path,
speed_limit_reached,
stopped_on_maneuver,
stopped_speed_possible,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_observable_path() {
let speed_limit = 4;
let cell1 = Cell::new(1).with_speed_limit(speed_limit).build();
let cell2 = Cell::new(2).with_speed_limit(speed_limit).build();
let mut cell3 = Cell::new(3).with_speed_limit(speed_limit).build();
let cell4 = Cell::new(4).with_speed_limit(speed_limit).build();
let cell5 = Cell::new(5).with_speed_limit(speed_limit).build();
let mut path = Path::new(
vec![&cell1, &cell2, &cell3, &cell4, &cell5],
vec![
LaneChangeType::NoChange,
LaneChangeType::NoChange,
LaneChangeType::NoChange,
LaneChangeType::ChangeLeft,
],
10.0,
);
let mut current_state = HashMap::new();
let observable_path = process_path(&mut path, speed_limit, cell5.get_id(), ¤t_state);
let correct_path = ObservablePath {
wanted_maneuver: LaneChangeType::NoChange,
last_cell_state: CellState::Free,
trimmed_path: vec![&cell2, &cell3, &cell4],
has_vehicle_on_path: false,
speed_limit_reached: false,
stopped_on_maneuver: false,
stopped_speed_possible: false,
};
assert_eq!(
observable_path.wanted_maneuver, correct_path.wanted_maneuver,
"Incorrect maneuver for observable path"
);
assert_eq!(
observable_path.last_cell_state, correct_path.last_cell_state,
"Incorrect last cell state for observable path"
);
assert_eq!(
observable_path.trimmed_path.len(),
correct_path.trimmed_path.len(),
"Incorrect number of cells vehicle can move forward"
);
for i in 0..observable_path.trimmed_path.len() {
assert_eq!(
observable_path.trimmed_path[i].get_id(),
correct_path.trimmed_path[i].get_id(),
"Incorrect cell at pos #{} in observable path",
i
);
}
current_state.insert(cell4.get_id(), 1);
path = Path::new(
vec![&cell1, &cell2, &cell3, &cell4, &cell5],
vec![
LaneChangeType::NoChange,
LaneChangeType::NoChange,
LaneChangeType::NoChange,
LaneChangeType::ChangeLeft,
],
10.0,
);
let observable_path = process_path(&mut path, speed_limit, cell5.get_id(), ¤t_state);
let correct_path = ObservablePath {
wanted_maneuver: LaneChangeType::NoChange,
last_cell_state: CellState::Free,
trimmed_path: vec![&cell2, &cell3],
has_vehicle_on_path: false,
speed_limit_reached: false,
stopped_on_maneuver: false,
stopped_speed_possible: false,
};
assert_eq!(
observable_path.wanted_maneuver, correct_path.wanted_maneuver,
"Incorrect maneuver for observable path"
);
assert_eq!(
observable_path.last_cell_state, correct_path.last_cell_state,
"Incorrect last cell state for observable path"
);
assert_eq!(
observable_path.trimmed_path.len(),
correct_path.trimmed_path.len(),
"Incorrect number of cells vehicle can move forward"
);
for i in 0..observable_path.trimmed_path.len() {
assert_eq!(
observable_path.trimmed_path[i].get_id(),
correct_path.trimmed_path[i].get_id(),
"Incorrect cell at pos #{} in observable path",
i
);
}
current_state.remove(&cell4.get_id());
path = Path::new(
vec![&cell1, &cell2, &cell3, &cell4, &cell5],
vec![
LaneChangeType::NoChange,
LaneChangeType::ChangeLeft,
LaneChangeType::NoChange,
LaneChangeType::NoChange,
],
10.0,
);
let observable_path = process_path(&mut path, speed_limit, cell5.get_id(), ¤t_state);
let correct_path = ObservablePath {
wanted_maneuver: LaneChangeType::NoChange,
last_cell_state: CellState::Free,
trimmed_path: vec![&cell2],
has_vehicle_on_path: false,
speed_limit_reached: false,
stopped_on_maneuver: true,
stopped_speed_possible: false,
};
assert_eq!(
observable_path.wanted_maneuver, correct_path.wanted_maneuver,
"Incorrect maneuver for observable path"
);
assert_eq!(
observable_path.last_cell_state, correct_path.last_cell_state,
"Incorrect last cell state for observable path"
);
assert_eq!(
observable_path.trimmed_path.len(),
correct_path.trimmed_path.len(),
"Incorrect number of cells vehicle can move forward"
);
for i in 0..observable_path.trimmed_path.len() {
assert_eq!(
observable_path.trimmed_path[i].get_id(),
correct_path.trimmed_path[i].get_id(),
"Incorrect cell at pos #{} in observable path",
i
);
}
path = Path::new(
vec![&cell1, &cell2, &cell3, &cell4, &cell5],
vec![
LaneChangeType::ChangeLeft,
LaneChangeType::NoChange,
LaneChangeType::NoChange,
LaneChangeType::NoChange,
],
10.0,
);
let observable_path = process_path(&mut path, speed_limit, cell5.get_id(), ¤t_state);
let correct_path = ObservablePath {
wanted_maneuver: LaneChangeType::ChangeLeft,
last_cell_state: CellState::Free,
trimmed_path: vec![],
has_vehicle_on_path: false,
speed_limit_reached: false,
stopped_on_maneuver: true,
stopped_speed_possible: false,
};
assert_eq!(
observable_path.wanted_maneuver, correct_path.wanted_maneuver,
"Incorrect maneuver for observable path"
);
assert_eq!(
observable_path.last_cell_state, correct_path.last_cell_state,
"Incorrect last cell state for observable path"
);
assert_eq!(
observable_path.trimmed_path.len(),
correct_path.trimmed_path.len(),
"Incorrect number of cells vehicle can move forward"
);
for i in 0..observable_path.trimmed_path.len() {
assert_eq!(
observable_path.trimmed_path[i].get_id(),
correct_path.trimmed_path[i].get_id(),
"Incorrect cell at pos #{} in observable path",
i
);
}
let vehicle_speed = 1;
path = Path::new(
vec![&cell1, &cell2, &cell3, &cell4, &cell5],
vec![
LaneChangeType::NoChange,
LaneChangeType::NoChange,
LaneChangeType::NoChange,
LaneChangeType::NoChange,
],
10.0,
);
let observable_path =
process_path(&mut path, vehicle_speed, cell5.get_id(), ¤t_state);
let correct_path = ObservablePath {
wanted_maneuver: LaneChangeType::NoChange,
last_cell_state: CellState::Free,
trimmed_path: vec![&cell2],
has_vehicle_on_path: false,
speed_limit_reached: true,
stopped_on_maneuver: false,
stopped_speed_possible: false,
};
assert_eq!(
observable_path.wanted_maneuver, correct_path.wanted_maneuver,
"Incorrect maneuver for observable path"
);
assert_eq!(
observable_path.last_cell_state, correct_path.last_cell_state,
"Incorrect last cell state for observable path"
);
assert_eq!(
observable_path.trimmed_path.len(),
correct_path.trimmed_path.len(),
"Incorrect number of cells vehicle can move forward"
);
for i in 0..observable_path.trimmed_path.len() {
assert_eq!(
observable_path.trimmed_path[i].get_id(),
correct_path.trimmed_path[i].get_id(),
"Incorrect cell at pos #{} in observable path",
i
);
}
cell3.set_state(CellState::Banned);
path = Path::new(
vec![&cell1, &cell2, &cell3, &cell4, &cell5],
vec![
LaneChangeType::NoChange,
LaneChangeType::NoChange,
LaneChangeType::NoChange,
LaneChangeType::NoChange,
],
10.0,
);
let observable_path = process_path(&mut path, speed_limit, cell5.get_id(), ¤t_state);
let correct_path = ObservablePath {
wanted_maneuver: LaneChangeType::NoChange,
last_cell_state: CellState::Banned,
trimmed_path: vec![&cell2],
has_vehicle_on_path: false,
speed_limit_reached: false,
stopped_on_maneuver: false,
stopped_speed_possible: false,
};
assert_eq!(
observable_path.wanted_maneuver, correct_path.wanted_maneuver,
"Incorrect maneuver for observable path"
);
assert_eq!(
observable_path.last_cell_state, correct_path.last_cell_state,
"Incorrect last cell state for observable path"
);
assert_eq!(
observable_path.trimmed_path.len(),
correct_path.trimmed_path.len(),
"Incorrect number of cells vehicle can move forward"
);
for i in 0..observable_path.trimmed_path.len() {
assert_eq!(
observable_path.trimmed_path[i].get_id(),
correct_path.trimmed_path[i].get_id(),
"Incorrect cell at pos #{} in observable path",
i
);
}
}
}