use crate::gmns::types::*;
#[derive(Debug, Clone)]
pub struct Link {
pub id: LinkID,
pub source_node_id: NodeID,
pub target_node_id: NodeID,
pub is_connection: bool,
pub macro_link_id: LinkID,
pub movement_id: MovementID,
pub length_meters: f64,
pub lanes_num: i32,
pub capacity: f64,
pub free_speed: f64,
pub max_speed: f64,
pub link_type: LinkType,
pub allowed_agent_types: Vec<AgentType>,
pub geom: Vec<[f64; 2]>,
}
impl Link {
pub fn new(id: LinkID, source_node_id: NodeID, target_node_id: NodeID) -> LinkBuilder {
LinkBuilder {
instance: Link {
id,
source_node_id,
target_node_id,
is_connection: false,
macro_link_id: -1,
movement_id: -1,
length_meters: 0.0,
lanes_num: 1,
capacity: 0.0,
free_speed: 0.0,
max_speed: 0.0,
link_type: LinkType::Undefined,
allowed_agent_types: Vec::new(),
geom: Vec::new(),
},
}
}
pub fn get_free_flow_time_hours(&self) -> f64 {
if self.free_speed <= 0.0 || self.length_meters <= 0.0 {
return f64::INFINITY;
}
(self.length_meters / 1000.0) / self.free_speed
}
pub fn get_total_capacity(&self) -> f64 {
if self.capacity <= 0.0 {
return 0.0;
}
if self.lanes_num > 0 {
self.capacity * self.lanes_num as f64
} else {
self.capacity
}
}
}
pub struct LinkBuilder {
instance: Link,
}
impl LinkBuilder {
pub fn with_is_connection(mut self, is_connection: bool) -> Self {
self.instance.is_connection = is_connection;
self
}
pub fn with_macro_link_id(mut self, macro_link_id: LinkID) -> Self {
self.instance.macro_link_id = macro_link_id;
self
}
pub fn with_movement_id(mut self, movement_id: MovementID) -> Self {
self.instance.movement_id = movement_id;
self
}
pub fn with_length_meters(mut self, length: f64) -> Self {
self.instance.length_meters = length;
self
}
pub fn with_lanes_num(mut self, lanes: i32) -> Self {
self.instance.lanes_num = lanes;
self
}
pub fn with_capacity(mut self, capacity: f64) -> Self {
self.instance.capacity = capacity;
self
}
pub fn with_free_speed(mut self, speed: f64) -> Self {
self.instance.free_speed = speed;
self
}
pub fn with_max_speed(mut self, speed: f64) -> Self {
self.instance.max_speed = speed;
self
}
pub fn with_link_type(mut self, link_type: LinkType) -> Self {
self.instance.link_type = link_type;
self
}
pub fn with_allowed_agent_types(mut self, agents: Vec<AgentType>) -> Self {
self.instance.allowed_agent_types = agents;
self
}
pub fn with_geom(mut self, geom: Vec<[f64; 2]>) -> Self {
self.instance.geom = geom;
self
}
pub fn build(self) -> Link {
self.instance
}
}
#[cfg(test)]
mod tests {
use super::*;
const EPS: f64 = 1e-10;
fn road_link(length_m: f64, speed_kmh: f64, capacity: f64, lanes: i32) -> Link {
Link::new(1, 10, 20)
.with_length_meters(length_m)
.with_free_speed(speed_kmh)
.with_capacity(capacity)
.with_lanes_num(lanes)
.build()
}
#[test]
fn free_flow_time_normal() {
let link = road_link(1000.0, 60.0, 1800.0, 2);
let t = link.get_free_flow_time_hours();
assert!((t - 1.0 / 60.0).abs() < EPS);
}
#[test]
fn free_flow_time_zero_speed_is_infinity() {
let link = road_link(1000.0, 0.0, 1800.0, 2);
assert_eq!(link.get_free_flow_time_hours(), f64::INFINITY);
}
#[test]
fn free_flow_time_zero_length_is_infinity() {
let link = road_link(0.0, 60.0, 1800.0, 2);
assert_eq!(link.get_free_flow_time_hours(), f64::INFINITY);
}
#[test]
fn free_flow_time_negative_speed_is_infinity() {
let link = road_link(1000.0, -10.0, 1800.0, 2);
assert_eq!(link.get_free_flow_time_hours(), f64::INFINITY);
}
#[test]
fn total_capacity_two_lanes() {
let link = road_link(1000.0, 60.0, 1800.0, 2);
assert!((link.get_total_capacity() - 3600.0).abs() < EPS);
}
#[test]
fn total_capacity_one_lane() {
let link = road_link(1000.0, 60.0, 1800.0, 1);
assert!((link.get_total_capacity() - 1800.0).abs() < EPS);
}
#[test]
fn total_capacity_zero_lanes_returns_per_lane() {
let link = road_link(1000.0, 60.0, 1800.0, 0);
assert!((link.get_total_capacity() - 1800.0).abs() < EPS);
}
#[test]
fn total_capacity_zero_capacity_returns_zero() {
let link = road_link(1000.0, 60.0, 0.0, 2);
assert_eq!(link.get_total_capacity(), 0.0);
}
#[test]
fn total_capacity_negative_capacity_returns_zero() {
let link = road_link(1000.0, 60.0, -100.0, 2);
assert_eq!(link.get_total_capacity(), 0.0);
}
}