use crate::{Per, Quantity, Unit};
pub use crate::dimension::VelocityDim;
pub trait VelocityUnit: Unit<Dim = VelocityDim> {}
impl<T: Unit<Dim = VelocityDim>> VelocityUnit for T {}
pub type Velocity<N, D> = Quantity<Per<N, D>>;
#[cfg(test)]
mod tests {
use super::*;
use crate::units::length::{Au, Kilometer, Kilometers, Meter};
use crate::units::time::{Day, Hour, Second, Seconds};
use crate::Per;
use approx::{assert_abs_diff_eq, assert_relative_eq};
use proptest::prelude::*;
#[test]
fn km_per_s_to_m_per_s() {
let v: Velocity<Kilometer, Second> = Velocity::new(1.0);
let v_mps: Velocity<Meter, Second> = v.to();
assert_abs_diff_eq!(v_mps.value(), 1000.0, epsilon = 1e-9);
}
#[test]
fn m_per_s_to_km_per_s() {
let v: Velocity<Meter, Second> = Velocity::new(1000.0);
let v_kps: Velocity<Kilometer, Second> = v.to();
assert_abs_diff_eq!(v_kps.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn km_per_h_to_m_per_s() {
let v: Velocity<Kilometer, Hour> = Velocity::new(3.6);
let v_mps: Velocity<Meter, Second> = v.to();
assert_abs_diff_eq!(v_mps.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn km_per_h_to_km_per_s() {
let v: Velocity<Kilometer, Hour> = Velocity::new(3600.0);
let v_kps: Velocity<Kilometer, Second> = v.to();
assert_abs_diff_eq!(v_kps.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn au_per_day_to_km_per_s() {
let v: Velocity<Au, Day> = Velocity::new(1.0);
let v_kps: Velocity<Kilometer, Second> = v.to();
assert_relative_eq!(v_kps.value(), 1731.5, max_relative = 1e-3);
}
#[test]
fn per_ratio_km_s() {
let ratio = <Per<Kilometer, Second>>::RATIO;
assert_relative_eq!(ratio, 1000.0, max_relative = 1e-12);
}
#[test]
fn per_ratio_m_s() {
let ratio = <Per<Meter, Second>>::RATIO;
assert_relative_eq!(ratio, 1.0, max_relative = 1e-12);
}
#[test]
fn velocity_times_time() {
let v: Velocity<Kilometer, Second> = Velocity::new(10.0);
let t: Seconds = Seconds::new(5.0);
let d: Kilometers = (v * t).to();
assert_abs_diff_eq!(d.value(), 50.0, epsilon = 1e-9);
}
#[test]
fn time_times_velocity() {
let v: Velocity<Kilometer, Second> = Velocity::new(10.0);
let t: Seconds = Seconds::new(5.0);
let d: Kilometers = (t * v).to();
assert_abs_diff_eq!(d.value(), 50.0, epsilon = 1e-9);
}
#[test]
fn length_div_time() {
let d: Kilometers = Kilometers::new(100.0);
let t: Seconds = Seconds::new(10.0);
let v: Velocity<Kilometer, Second> = d / t;
assert_abs_diff_eq!(v.value(), 10.0, epsilon = 1e-9);
}
#[test]
fn roundtrip_mps_kps() {
let original: Velocity<Meter, Second> = Velocity::new(500.0);
let converted: Velocity<Kilometer, Second> = original.to();
let back: Velocity<Meter, Second> = converted.to();
assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-9);
}
proptest! {
#[test]
fn prop_roundtrip_mps_kps(v in 1e-6..1e6f64) {
let original: Velocity<Meter, Second> = Velocity::new(v);
let converted: Velocity<Kilometer, Second> = original.to();
let back: Velocity<Meter, Second> = converted.to();
prop_assert!((back.value() - original.value()).abs() < 1e-9 * v.abs().max(1.0));
}
#[test]
fn prop_mps_kps_ratio(v in 1e-6..1e6f64) {
let mps: Velocity<Meter, Second> = Velocity::new(v);
let kps: Velocity<Kilometer, Second> = mps.to();
prop_assert!((mps.value() / kps.value() - 1000.0).abs() < 1e-9);
}
#[test]
fn prop_velocity_time_roundtrip(
v_val in 1e-3..1e3f64,
t_val in 1e-3..1e3f64
) {
let v: Velocity<Kilometer, Second> = Velocity::new(v_val);
let t: Seconds = Seconds::new(t_val);
let d: Kilometers = (v * t).to();
let v_back: Velocity<Kilometer, Second> = d / t;
prop_assert!((v_back.value() - v.value()).abs() / v.value() < 1e-12);
}
}
}