use std::ops::{Div, Mul};
use crate::physics::basic::{Acceleration, Coef, Mass, Momentum, Vector3, Velocity, VelocityType};
use crate::utils::float;
impl Div<chrono::TimeDelta> for Vector3<Velocity> {
type Output = Vector3<Acceleration>;
fn div(self, rhs: chrono::TimeDelta) -> Self::Output {
let x = self.x / rhs;
let y = self.y / rhs;
let z = self.z / rhs;
Vector3::<Acceleration>::new(x, y, z)
}
}
impl Mul<Mass> for Vector3<Velocity> {
type Output = Vector3<Momentum>;
fn mul(self, rhs: Mass) -> Self::Output {
Vector3::new(self.x * rhs, self.y * rhs, self.z * rhs)
}
}
impl Vector3<Velocity> {
pub fn limit_float(&self, threshold: f64, velocity_type: VelocityType) -> Self {
let (x, y, z) = match velocity_type {
VelocityType::MPerSecond => (
float::limit_float(self.x.as_m_per_sec(), threshold),
float::limit_float(self.y.as_m_per_sec(), threshold),
float::limit_float(self.z.as_m_per_sec(), threshold),
),
VelocityType::KmPerHour => (
float::limit_float(self.x.as_km_per_h(), threshold),
float::limit_float(self.y.as_km_per_h(), threshold),
float::limit_float(self.z.as_km_per_h(), threshold),
),
VelocityType::KmPerSecond => (
float::limit_float(self.x.as_km_per_sec(), threshold),
float::limit_float(self.y.as_km_per_sec(), threshold),
float::limit_float(self.z.as_km_per_sec(), threshold),
),
VelocityType::LightSpeed => (
float::limit_float(self.x.as_light_speed(), threshold),
float::limit_float(self.y.as_light_speed(), threshold),
float::limit_float(self.z.as_light_speed(), threshold),
),
};
Self {
x: Velocity { v: x, default_type: velocity_type },
y: Velocity { v: y, default_type: velocity_type },
z: Velocity { v: z, default_type: velocity_type },
}
}
pub fn to_vector3_coef(&self, velocity_type: VelocityType) -> Vector3<Coef> {
match velocity_type {
VelocityType::MPerSecond => {
let (x, y, z) = (self.x.as_m_per_sec(), self.y.as_m_per_sec(), self.z.as_m_per_sec());
Vector3::<Coef>::from_array([x, y, z])
}
VelocityType::KmPerHour => {
let (x, y, z) = (self.x.as_km_per_h(), self.y.as_km_per_h(), self.z.as_km_per_h());
Vector3::<Coef>::from_array([x, y, z])
}
VelocityType::KmPerSecond => {
let (x, y, z) = (self.x.as_km_per_sec(), self.y.as_km_per_sec(), self.z.as_km_per_sec());
Vector3::<Coef>::from_array([x, y, z])
}
VelocityType::LightSpeed => {
let (x, y, z) = (self.x.as_light_speed(), self.y.as_light_speed(), self.z.as_light_speed());
Vector3::<Coef>::from_array([x, y, z])
}
}
}
pub fn from_vector_coef(coef: Vector3<Coef>, velocity_type: VelocityType) -> Vector3<Velocity> {
let x = Velocity {
v: coef.x.v,
default_type: velocity_type,
};
let y = Velocity {
v: coef.y.v,
default_type: velocity_type,
};
let z = Velocity {
v: coef.z.v,
default_type: velocity_type,
};
Vector3::new(x, y, z)
}
pub fn from_array_with_unit(array: [f64; 3], velocity_type: VelocityType) -> Vector3<Velocity> {
let [x, y, z] = array;
let x = Velocity {
v: x,
default_type: velocity_type,
};
let y = Velocity {
v: y,
default_type: velocity_type,
};
let z = Velocity {
v: z,
default_type: velocity_type,
};
Vector3::new(x, y, z)
}
}
#[cfg(test)]
mod tests {
use approx::assert_relative_eq;
use super::*;
#[test]
fn test_div_timedelta() {
let v = Vector3::new(
Velocity::from_m_per_sec(10.0),
Velocity::from_m_per_sec(-4.0),
Velocity::from_m_per_sec(0.0),
);
let a = v / chrono::TimeDelta::seconds(2);
assert_relative_eq!(a.x.as_m_per_s2(), 5.0);
assert_relative_eq!(a.y.as_m_per_s2(), -2.0);
assert_relative_eq!(a.z.as_m_per_s2(), 0.0);
let a_neg = v / chrono::TimeDelta::seconds(-2);
assert_relative_eq!(a_neg.x.as_m_per_s2(), -5.0);
assert_relative_eq!(a_neg.y.as_m_per_s2(), 2.0);
let a_zero = v / chrono::TimeDelta::zero();
assert!(a_zero.x.as_m_per_s2().is_infinite());
}
#[test]
fn test_limit_float() {
let v = Vector3::new(
Velocity::from_m_per_sec(1.0),
Velocity::from_m_per_sec(-5.0),
Velocity::from_m_per_sec(3.0),
);
let result = v.limit_float(3.0, VelocityType::MPerSecond);
assert_relative_eq!(result.x.as_m_per_sec(), 1.0);
assert_relative_eq!(result.y.as_m_per_sec(), -3.0);
assert_relative_eq!(result.z.as_m_per_sec(), 3.0);
let result = v.limit_float(1e10, VelocityType::KmPerHour);
assert_relative_eq!(result.x.as_km_per_h(), 3.6);
assert_relative_eq!(result.y.as_km_per_h(), -18.0);
assert_relative_eq!(result.z.as_km_per_h(), 10.8);
let result = v.limit_float(1e10, VelocityType::KmPerSecond);
assert_relative_eq!(result.x.as_km_per_sec(), 0.001);
assert_relative_eq!(result.y.as_km_per_sec(), -0.005);
assert_relative_eq!(result.z.as_km_per_sec(), 0.003);
let result = v.limit_float(1e10, VelocityType::LightSpeed);
assert_relative_eq!(result.x.as_light_speed(), 1.0 / 299792458.0);
assert_relative_eq!(result.y.as_light_speed(), -5.0 / 299792458.0);
assert_relative_eq!(result.z.as_light_speed(), 3.0 / 299792458.0);
}
#[test]
fn test_to_momentum() {
let vec = Vector3::new(Velocity::from_m_per_sec(1.0), Velocity::from_m_per_sec(2.0), Velocity::from_m_per_sec(3.0));
let mass = Mass::from_kg(4.0);
let momentum = vec * mass;
assert_relative_eq!(4.0, momentum.x.as_kg_m_s());
assert_relative_eq!(8.0, momentum.y.as_kg_m_s());
assert_relative_eq!(12.0, momentum.z.as_kg_m_s());
}
#[test]
fn test_to_vector3_coef_m_per_sec() {
let velocity_vec = Vector3::new(
Velocity::from_m_per_sec(10.0),
Velocity::from_m_per_sec(20.0),
Velocity::from_m_per_sec(30.0),
);
let coef_vec = velocity_vec.to_vector3_coef(VelocityType::MPerSecond);
assert_relative_eq!(coef_vec.x, 10.0);
assert_relative_eq!(coef_vec.y, 20.0);
assert_relative_eq!(coef_vec.z, 30.0);
}
#[test]
fn test_to_vector3_coef_km_per_h() {
let velocity_vec = Vector3::new(
Velocity::from_m_per_sec(10.0), Velocity::from_m_per_sec(20.0), Velocity::from_m_per_sec(30.0), );
let coef_vec = velocity_vec.to_vector3_coef(VelocityType::KmPerHour);
assert_relative_eq!(coef_vec.x, 36.0);
assert_relative_eq!(coef_vec.y, 72.0);
assert_relative_eq!(coef_vec.z, 108.0);
}
#[test]
fn test_from_vector_coef_m_per_sec() {
let coef_vec = Vector3::new(
Coef::new(10.0),
Coef::new(20.0),
Coef::new(30.0),
);
let velocity_vec = Vector3::<Velocity>::from_vector_coef(coef_vec, VelocityType::MPerSecond);
assert_relative_eq!(velocity_vec.x.as_m_per_sec(), 10.0);
assert_relative_eq!(velocity_vec.y.as_m_per_sec(), 20.0);
assert_relative_eq!(velocity_vec.z.as_m_per_sec(), 30.0);
}
#[test]
fn test_from_vector_coef_km_per_h() {
let coef_vec = Vector3::new(
Coef::new(36.0),
Coef::new(72.0),
Coef::new(108.0),
);
let velocity_vec = Vector3::<Velocity>::from_vector_coef(coef_vec, VelocityType::KmPerHour);
assert_relative_eq!(velocity_vec.x.as_km_per_h(), 36.0);
assert_relative_eq!(velocity_vec.y.as_km_per_h(), 72.0);
assert_relative_eq!(velocity_vec.z.as_km_per_h(), 108.0);
}
#[test]
fn test_from_vector_coef_roundtrip() {
let original_velocity_vec = Vector3::new(
Velocity::from_m_per_sec(15.0),
Velocity::from_m_per_sec(25.0),
Velocity::from_m_per_sec(35.0),
);
let coef_vec = original_velocity_vec.to_vector3_coef(VelocityType::MPerSecond);
let reconstructed_velocity_vec = Vector3::<Velocity>::from_vector_coef(coef_vec, VelocityType::MPerSecond);
assert_relative_eq!(original_velocity_vec.x.as_m_per_sec(), reconstructed_velocity_vec.x.as_m_per_sec());
assert_relative_eq!(original_velocity_vec.y.as_m_per_sec(), reconstructed_velocity_vec.y.as_m_per_sec());
assert_relative_eq!(original_velocity_vec.z.as_m_per_sec(), reconstructed_velocity_vec.z.as_m_per_sec());
}
#[test]
fn test_to_vector3_coef_km_per_sec() {
let velocity_vec = Vector3::new(
Velocity::from_m_per_sec(1000.0), Velocity::from_m_per_sec(2000.0), Velocity::from_m_per_sec(3000.0), );
let coef_vec = velocity_vec.to_vector3_coef(VelocityType::KmPerSecond);
assert_relative_eq!(coef_vec.x.get_value(), 1.0);
assert_relative_eq!(coef_vec.y.get_value(), 2.0);
assert_relative_eq!(coef_vec.z.get_value(), 3.0);
}
#[test]
fn test_to_vector3_coef_light_speed() {
let velocity_vec = Vector3::new(
Velocity::from_m_per_sec(299792458.0), Velocity::from_m_per_sec(149896229.0), Velocity::from_m_per_sec(59958491.6), );
let coef_vec = velocity_vec.to_vector3_coef(VelocityType::LightSpeed);
assert_relative_eq!(coef_vec.x.get_value(), 1.0);
assert_relative_eq!(coef_vec.y.get_value(), 0.5);
assert_relative_eq!(coef_vec.z.get_value(), 0.2);
}
#[test]
fn test_from_vector_coef_km_per_sec() {
let coef_vec = Vector3::new(
Coef::new(1.0),
Coef::new(2.0),
Coef::new(3.0),
);
let velocity_vec = Vector3::<Velocity>::from_vector_coef(coef_vec, VelocityType::KmPerSecond);
assert_relative_eq!(velocity_vec.x.as_km_per_sec(), 1.0);
assert_relative_eq!(velocity_vec.y.as_km_per_sec(), 2.0);
assert_relative_eq!(velocity_vec.z.as_km_per_sec(), 3.0);
}
#[test]
fn test_from_vector_coef_light_speed() {
let coef_vec = Vector3::new(
Coef::new(1.0),
Coef::new(0.5),
Coef::new(0.2),
);
let velocity_vec = Vector3::<Velocity>::from_vector_coef(coef_vec, VelocityType::LightSpeed);
assert_relative_eq!(velocity_vec.x.as_light_speed(), 1.0);
assert_relative_eq!(velocity_vec.y.as_light_speed(), 0.5);
assert_relative_eq!(velocity_vec.z.as_light_speed(), 0.2);
}
#[test]
fn test_roundtrip_all_types() {
let types = vec![
VelocityType::MPerSecond,
VelocityType::KmPerHour,
VelocityType::KmPerSecond,
VelocityType::LightSpeed,
];
let original_velocity_vec = Vector3::new(
Velocity::from_m_per_sec(100.0),
Velocity::from_m_per_sec(200.0),
Velocity::from_m_per_sec(300.0),
);
for velocity_type in types {
let coef_vec = original_velocity_vec.to_vector3_coef(velocity_type);
let reconstructed_velocity_vec = Vector3::<Velocity>::from_vector_coef(coef_vec, velocity_type);
match velocity_type {
VelocityType::MPerSecond => {
assert_relative_eq!(reconstructed_velocity_vec.x.as_m_per_sec(), 100.0);
assert_relative_eq!(reconstructed_velocity_vec.y.as_m_per_sec(), 200.0);
assert_relative_eq!(reconstructed_velocity_vec.z.as_m_per_sec(), 300.0);
}
VelocityType::KmPerHour => {
assert_relative_eq!(reconstructed_velocity_vec.x.as_km_per_h(), 360.0);
assert_relative_eq!(reconstructed_velocity_vec.y.as_km_per_h(), 720.0);
assert_relative_eq!(reconstructed_velocity_vec.z.as_km_per_h(), 1080.0);
}
VelocityType::KmPerSecond => {
assert_relative_eq!(reconstructed_velocity_vec.x.as_km_per_sec(), 0.1);
assert_relative_eq!(reconstructed_velocity_vec.y.as_km_per_sec(), 0.2);
assert_relative_eq!(reconstructed_velocity_vec.z.as_km_per_sec(), 0.3);
}
VelocityType::LightSpeed => {
assert_relative_eq!(reconstructed_velocity_vec.x.as_light_speed(), 100.0 / 299792458.0);
assert_relative_eq!(reconstructed_velocity_vec.y.as_light_speed(), 200.0 / 299792458.0);
assert_relative_eq!(reconstructed_velocity_vec.z.as_light_speed(), 300.0 / 299792458.0);
}
}
}
}
#[test]
fn test_edge_cases() {
let zero_velocity_vec = Vector3::new(
Velocity::from_m_per_sec(0.0),
Velocity::from_m_per_sec(0.0),
Velocity::from_m_per_sec(0.0),
);
let coef_vec = zero_velocity_vec.to_vector3_coef(VelocityType::MPerSecond);
assert_relative_eq!(coef_vec.x.get_value(), 0.0);
assert_relative_eq!(coef_vec.y.get_value(), 0.0);
assert_relative_eq!(coef_vec.z.get_value(), 0.0);
let negative_velocity_vec = Vector3::new(
Velocity::from_m_per_sec(-10.0),
Velocity::from_m_per_sec(-20.0),
Velocity::from_m_per_sec(-30.0),
);
let coef_vec = negative_velocity_vec.to_vector3_coef(VelocityType::MPerSecond);
assert_relative_eq!(coef_vec.x.get_value(), -10.0);
assert_relative_eq!(coef_vec.y.get_value(), -20.0);
assert_relative_eq!(coef_vec.z.get_value(), -30.0);
let small_velocity_vec = Vector3::new(
Velocity::from_m_per_sec(1e-10),
Velocity::from_m_per_sec(1e-15),
Velocity::from_m_per_sec(1e-20),
);
let coef_vec = small_velocity_vec.to_vector3_coef(VelocityType::MPerSecond);
assert_relative_eq!(coef_vec.x.get_value(), 1e-10);
assert_relative_eq!(coef_vec.y.get_value(), 1e-15);
assert_relative_eq!(coef_vec.z.get_value(), 1e-20);
}
#[test]
fn test_from_array_with_unit() {
let array = [10.0, 20.0, 30.0];
let velocity_vec = Vector3::<Velocity>::from_array_with_unit(array, VelocityType::MPerSecond);
assert_relative_eq!(velocity_vec.x.as_m_per_sec(), 10.0);
assert_relative_eq!(velocity_vec.y.as_m_per_sec(), 20.0);
assert_relative_eq!(velocity_vec.z.as_m_per_sec(), 30.0);
let velocity_vec_kmh = Vector3::<Velocity>::from_array_with_unit(array, VelocityType::KmPerHour);
assert_relative_eq!(velocity_vec_kmh.x.as_km_per_h(), 10.0);
assert_relative_eq!(velocity_vec_kmh.y.as_km_per_h(), 20.0);
assert_relative_eq!(velocity_vec_kmh.z.as_km_per_h(), 30.0);
let velocity_vec_kms = Vector3::<Velocity>::from_array_with_unit(array, VelocityType::KmPerSecond);
assert_relative_eq!(velocity_vec_kms.x.as_km_per_sec(), 10.0);
assert_relative_eq!(velocity_vec_kms.y.as_km_per_sec(), 20.0);
assert_relative_eq!(velocity_vec_kms.z.as_km_per_sec(), 30.0);
let velocity_vec_light = Vector3::<Velocity>::from_array_with_unit(array, VelocityType::LightSpeed);
assert_relative_eq!(velocity_vec_light.x.as_light_speed(), 10.0);
assert_relative_eq!(velocity_vec_light.y.as_light_speed(), 20.0);
assert_relative_eq!(velocity_vec_light.z.as_light_speed(), 30.0);
}
}