use super::{GeoLocation, Movable, MultipleTargets, NextTarget, RailwayObject};
use crate::types::{NodeId, RailwayObjectId};
use geo::Coord;
use std::any::Any;
use std::collections::VecDeque;
use uom::si::f64::{Acceleration, Velocity};
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Train {
pub id: i64,
pub position: Option<NodeId>,
pub geo_location: Option<Coord<f64>>,
pub next_target: Option<NodeId>,
pub targets: VecDeque<NodeId>,
pub speed: Velocity,
pub max_speed: Velocity,
pub acceleration: Acceleration,
}
impl RailwayObject for Train {
fn id(&self) -> RailwayObjectId {
self.id
}
fn position(&self) -> Option<NodeId> {
self.position
}
fn set_position(&mut self, position: Option<NodeId>) {
self.position = position;
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl NextTarget for Train {
fn next_target(&self) -> Option<NodeId> {
self.next_target
}
fn set_next_target(&mut self, target: Option<NodeId>) {
self.next_target = target;
}
}
impl MultipleTargets for Train {
fn targets(&self) -> &VecDeque<NodeId> {
&self.targets
}
fn add_target(&mut self, target: NodeId) {
self.targets.push_back(target);
}
fn remove_target(&mut self) -> Option<NodeId> {
self.targets.pop_front()
}
}
impl GeoLocation for Train {
fn geo_location(&self) -> Option<Coord<f64>> {
self.geo_location
}
fn set_geo_location(&mut self, location: Option<Coord<f64>>) {
self.geo_location = location;
}
}
impl Movable for Train {
fn max_speed(&self) -> Velocity {
self.max_speed
}
fn set_max_speed(&mut self, max_speed: Velocity) {
self.max_speed = max_speed;
}
fn speed(&self) -> Velocity {
self.speed
}
fn set_speed(&mut self, speed: Velocity) {
self.speed = speed;
}
fn acceleration(&self) -> Acceleration {
self.acceleration
}
fn set_acceleration(&mut self, acceleration: Acceleration) {
self.acceleration = acceleration;
}
}
#[cfg(test)]
mod tests {
use geo::coord;
use uom::si::{acceleration::meter_per_second_squared, velocity::kilometer_per_hour};
use super::*;
#[test]
fn test_train() {
let mut train = Train {
id: 1,
position: Some(1),
geo_location: Some(coord! { x:1.0, y: 2.0}),
next_target: Some(2),
targets: VecDeque::from(vec![2, 3, 4]),
..Default::default()
};
assert_eq!(train.id(), 1);
assert_eq!(train.position(), Some(1));
assert_eq!(train.geo_location(), Some(coord! {x:1.0, y:2.0}));
assert_eq!(train.next_target(), Some(2));
assert_eq!(train.targets(), &VecDeque::from(vec![2, 3, 4]));
train.set_next_target(None);
assert_eq!(train.next_target(), None);
train.add_target(5);
assert_eq!(train.targets(), &VecDeque::from(vec![2, 3, 4, 5]));
let removed_target = train.remove_target();
assert_eq!(removed_target, Some(2));
assert_eq!(train.targets(), &VecDeque::from(vec![3, 4, 5]));
}
#[test]
fn test_train_speed() {
let mut train = Train {
id: 1,
position: Some(0),
geo_location: Some(coord! { x:1.0, y: 2.0}),
next_target: Some(2),
targets: VecDeque::from(vec![2, 3, 4]),
max_speed: Velocity::new::<kilometer_per_hour>(80.0),
speed: Velocity::new::<kilometer_per_hour>(0.0),
acceleration: Acceleration::new::<meter_per_second_squared>(0.0),
};
assert_eq!(train.speed(), Velocity::new::<kilometer_per_hour>(0.0));
train.set_speed(Velocity::new::<kilometer_per_hour>(100.0));
assert_eq!(train.speed(), Velocity::new::<kilometer_per_hour>(100.0));
}
#[test]
fn test_train_acceleration() {
let mut train = Train {
id: 1,
position: Some(0),
geo_location: Some(coord! { x:1.0, y: 2.0}),
next_target: Some(2),
targets: VecDeque::from(vec![2, 3, 4]),
max_speed: Velocity::new::<kilometer_per_hour>(80.0),
speed: Velocity::new::<kilometer_per_hour>(0.0),
acceleration: Acceleration::new::<meter_per_second_squared>(0.0),
};
assert_eq!(
train.acceleration(),
Acceleration::new::<meter_per_second_squared>(0.0)
);
train.set_acceleration(Acceleration::new::<meter_per_second_squared>(1.5));
assert_eq!(
train.acceleration(),
Acceleration::new::<meter_per_second_squared>(1.5)
);
}
}