use std::ops::Mul;
use crate::physics::basic::{Acceleration, AccelerationType, Coef, Vector3, Velocity};
use crate::utils::float;
impl Mul<chrono::TimeDelta> for Vector3<Acceleration> {
type Output = Vector3<Velocity>;
fn mul(self, rhs: chrono::TimeDelta) -> Self::Output {
let x = self.x * rhs;
let y = self.y * rhs;
let z = self.z * rhs;
Vector3::<Velocity>::new(x, y, z)
}
}
impl Vector3<Acceleration> {
pub fn limit_float(&self, threshold: f64, acceleration_type: AccelerationType) -> Self {
let (x, y, z) = match acceleration_type {
AccelerationType::MPerSecond2 => (
float::limit_float(self.x.as_m_per_s2(), threshold),
float::limit_float(self.y.as_m_per_s2(), threshold),
float::limit_float(self.z.as_m_per_s2(), threshold),
),
AccelerationType::KmPerHour2 => (
float::limit_float(self.x.as_km_per_h_2(), threshold),
float::limit_float(self.y.as_km_per_h_2(), threshold),
float::limit_float(self.z.as_km_per_h_2(), threshold),
),
AccelerationType::G => (
float::limit_float(self.x.as_g(), threshold),
float::limit_float(self.y.as_g(), threshold),
float::limit_float(self.z.as_g(), threshold),
),
};
Self {
x: Acceleration { v: x, default_type: acceleration_type },
y: Acceleration { v: y, default_type: acceleration_type },
z: Acceleration { v: z, default_type: acceleration_type },
}
}
pub fn to_vector3_coef(&self, acceleration_type: AccelerationType) -> Vector3<Coef> {
match acceleration_type {
AccelerationType::MPerSecond2 => {
let (x, y, z) = (self.x.as_m_per_s2(), self.y.as_m_per_s2(), self.z.as_m_per_s2());
Vector3::<Coef>::from_array([x, y, z])
}
AccelerationType::KmPerHour2 => {
let (x, y, z) = (self.x.as_km_per_h_2(), self.y.as_km_per_h_2(), self.z.as_km_per_h_2());
Vector3::<Coef>::from_array([x, y, z])
}
AccelerationType::G => {
let (x, y, z) = (self.x.as_g(), self.y.as_g(), self.z.as_g());
Vector3::<Coef>::from_array([x, y, z])
}
}
}
pub fn from_vector_coef(coef: Vector3<Coef>, acceleration_type: AccelerationType) -> Vector3<Acceleration> {
let x = Acceleration {
v: coef.x.v,
default_type: acceleration_type,
};
let y = Acceleration {
v: coef.y.v,
default_type: acceleration_type,
};
let z = Acceleration {
v: coef.z.v,
default_type: acceleration_type,
};
Vector3::new(x, y, z)
}
pub fn from_array_with_unit(array: [f64; 3], acceleration_type: AccelerationType) -> Vector3<Acceleration> {
let [x, y, z] = array;
let x = Acceleration {
v: x,
default_type: acceleration_type,
};
let y = Acceleration {
v: y,
default_type: acceleration_type,
};
let z = Acceleration {
v: z,
default_type: acceleration_type,
};
Vector3::new(x, y, z)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mul_timedelta() {
let a = Vector3::new(
Acceleration::from_m_per_s2(2.0),
Acceleration::from_m_per_s2(3.0),
Acceleration::from_m_per_s2(-1.0),
);
let v = a * chrono::TimeDelta::seconds(2);
assert_relative_eq!(v.x.as_m_per_sec(), 4.0);
assert_relative_eq!(v.y.as_m_per_sec(), 6.0);
assert_relative_eq!(v.z.as_m_per_sec(), -2.0);
let v_neg = a * chrono::TimeDelta::seconds(-1);
assert_relative_eq!(v_neg.x.as_m_per_sec(), -2.0);
let v_zero = a * chrono::TimeDelta::zero();
assert_relative_eq!(v_zero.x.as_m_per_sec(), 0.0);
assert_relative_eq!(v_zero.z.as_m_per_sec(), 0.0);
}
use approx::assert_relative_eq;
#[test]
fn test_limit_float() {
let v = Vector3::new(
Acceleration::from_m_per_s2(1.0),
Acceleration::from_m_per_s2(-5.0),
Acceleration::from_m_per_s2(3.0),
);
let result = v.limit_float(3.0, AccelerationType::MPerSecond2);
assert_relative_eq!(result.x.as_m_per_s2(), 1.0);
assert_relative_eq!(result.y.as_m_per_s2(), -3.0);
assert_relative_eq!(result.z.as_m_per_s2(), 3.0);
let result = v.limit_float(1e10, AccelerationType::KmPerHour2);
assert_relative_eq!(result.x.as_km_per_h_2(), 12960.0);
assert_relative_eq!(result.y.as_km_per_h_2(), -64800.0);
assert_relative_eq!(result.z.as_km_per_h_2(), 38880.0);
let result = v.limit_float(1e10, AccelerationType::G);
assert_relative_eq!(result.x.as_g(), 1.0 / 9.80665);
assert_relative_eq!(result.y.as_g(), -5.0 / 9.80665);
assert_relative_eq!(result.z.as_g(), 3.0 / 9.80665);
}
#[test]
fn test_to_vector3_coef_m_per_s2() {
let acceleration_vec = Vector3::new(
Acceleration::from_m_per_s2(9.8),
Acceleration::from_m_per_s2(19.6),
Acceleration::from_m_per_s2(29.4),
);
let coef_vec = acceleration_vec.to_vector3_coef(AccelerationType::MPerSecond2);
assert_relative_eq!(coef_vec.x, 9.8);
assert_relative_eq!(coef_vec.y, 19.6);
assert_relative_eq!(coef_vec.z, 29.4);
}
#[test]
fn test_to_vector3_coef_g() {
let acceleration_vec = Vector3::new(
Acceleration::from_g(1.0),
Acceleration::from_g(2.0),
Acceleration::from_g(3.0),
);
let coef_vec = acceleration_vec.to_vector3_coef(AccelerationType::G);
assert_relative_eq!(coef_vec.x, 1.0);
assert_relative_eq!(coef_vec.y, 2.0);
assert_relative_eq!(coef_vec.z, 3.0);
}
#[test]
fn test_from_vector_coef_m_per_s2() {
let coef_vec = Vector3::new(
Coef::new(9.8),
Coef::new(19.6),
Coef::new(29.4),
);
let acceleration_vec = Vector3::<Acceleration>::from_vector_coef(coef_vec, AccelerationType::MPerSecond2);
assert_relative_eq!(acceleration_vec.x.as_m_per_s2(), 9.8);
assert_relative_eq!(acceleration_vec.y.as_m_per_s2(), 19.6);
assert_relative_eq!(acceleration_vec.z.as_m_per_s2(), 29.4);
}
#[test]
fn test_from_vector_coef_g() {
let coef_vec = Vector3::new(
Coef::new(1.0),
Coef::new(2.0),
Coef::new(3.0),
);
let acceleration_vec = Vector3::<Acceleration>::from_vector_coef(coef_vec, AccelerationType::G);
assert_relative_eq!(acceleration_vec.x.as_g(), 1.0);
assert_relative_eq!(acceleration_vec.y.as_g(), 2.0);
assert_relative_eq!(acceleration_vec.z.as_g(), 3.0);
}
#[test]
fn test_from_vector_coef_roundtrip() {
let original_acceleration_vec = Vector3::new(
Acceleration::from_m_per_s2(9.8),
Acceleration::from_m_per_s2(19.6),
Acceleration::from_m_per_s2(29.4),
);
let coef_vec = original_acceleration_vec.to_vector3_coef(AccelerationType::MPerSecond2);
let reconstructed_acceleration_vec = Vector3::<Acceleration>::from_vector_coef(coef_vec, AccelerationType::MPerSecond2);
assert_relative_eq!(original_acceleration_vec.x.as_m_per_s2(), reconstructed_acceleration_vec.x.as_m_per_s2());
assert_relative_eq!(original_acceleration_vec.y.as_m_per_s2(), reconstructed_acceleration_vec.y.as_m_per_s2());
assert_relative_eq!(original_acceleration_vec.z.as_m_per_s2(), reconstructed_acceleration_vec.z.as_m_per_s2());
}
#[test]
fn test_to_vector3_coef_km_per_h2() {
let acceleration_vec = Vector3::new(
Acceleration::from_m_per_s2(1.0), Acceleration::from_m_per_s2(2.0), Acceleration::from_m_per_s2(0.5), );
let coef_vec = acceleration_vec.to_vector3_coef(AccelerationType::KmPerHour2);
assert_relative_eq!(coef_vec.x.get_value(), 12960.0);
assert_relative_eq!(coef_vec.y.get_value(), 25920.0);
assert_relative_eq!(coef_vec.z.get_value(), 6480.0);
}
#[test]
fn test_from_vector_coef_km_per_h2() {
let coef_vec = Vector3::new(
Coef::new(12960.0),
Coef::new(25920.0),
Coef::new(6480.0),
);
let acceleration_vec = Vector3::<Acceleration>::from_vector_coef(coef_vec, AccelerationType::KmPerHour2);
assert_relative_eq!(acceleration_vec.x.as_km_per_h_2(), 12960.0);
assert_relative_eq!(acceleration_vec.y.as_km_per_h_2(), 25920.0);
assert_relative_eq!(acceleration_vec.z.as_km_per_h_2(), 6480.0);
}
#[test]
fn test_roundtrip_all_types() {
let types = vec![
AccelerationType::MPerSecond2,
AccelerationType::KmPerHour2,
AccelerationType::G,
];
let original_acceleration_vec = Vector3::new(
Acceleration::from_m_per_s2(9.8),
Acceleration::from_m_per_s2(19.6),
Acceleration::from_m_per_s2(29.4),
);
for acceleration_type in types {
let coef_vec = original_acceleration_vec.to_vector3_coef(acceleration_type);
let reconstructed_acceleration_vec = Vector3::<Acceleration>::from_vector_coef(coef_vec, acceleration_type);
match acceleration_type {
AccelerationType::MPerSecond2 => {
assert_relative_eq!(reconstructed_acceleration_vec.x.as_m_per_s2(), 9.8);
assert_relative_eq!(reconstructed_acceleration_vec.y.as_m_per_s2(), 19.6);
assert_relative_eq!(reconstructed_acceleration_vec.z.as_m_per_s2(), 29.4);
}
AccelerationType::KmPerHour2 => {
assert_relative_eq!(reconstructed_acceleration_vec.x.as_km_per_h_2(), 127008.0);
assert_relative_eq!(reconstructed_acceleration_vec.y.as_km_per_h_2(), 254016.0);
assert_relative_eq!(reconstructed_acceleration_vec.z.as_km_per_h_2(), 381024.0);
}
AccelerationType::G => {
assert_relative_eq!(reconstructed_acceleration_vec.x.as_g(), 9.8 / 9.80665);
assert_relative_eq!(reconstructed_acceleration_vec.y.as_g(), 19.6 / 9.80665);
assert_relative_eq!(reconstructed_acceleration_vec.z.as_g(), 29.4 / 9.80665);
}
}
}
}
#[test]
fn test_edge_cases() {
let zero_acceleration_vec = Vector3::new(
Acceleration::from_m_per_s2(0.0),
Acceleration::from_m_per_s2(0.0),
Acceleration::from_m_per_s2(0.0),
);
let coef_vec = zero_acceleration_vec.to_vector3_coef(AccelerationType::MPerSecond2);
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_acceleration_vec = Vector3::new(
Acceleration::from_m_per_s2(-9.8),
Acceleration::from_m_per_s2(-19.6),
Acceleration::from_m_per_s2(-29.4),
);
let coef_vec = negative_acceleration_vec.to_vector3_coef(AccelerationType::MPerSecond2);
assert_relative_eq!(coef_vec.x.get_value(), -9.8);
assert_relative_eq!(coef_vec.y.get_value(), -19.6);
assert_relative_eq!(coef_vec.z.get_value(), -29.4);
let small_acceleration_vec = Vector3::new(
Acceleration::from_m_per_s2(1e-10),
Acceleration::from_m_per_s2(1e-15),
Acceleration::from_m_per_s2(1e-20),
);
let coef_vec = small_acceleration_vec.to_vector3_coef(AccelerationType::MPerSecond2);
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 = [9.8, 19.6, 29.4];
let acceleration_vec = Vector3::<Acceleration>::from_array_with_unit(array, AccelerationType::MPerSecond2);
assert_relative_eq!(acceleration_vec.x.as_m_per_s2(), 9.8);
assert_relative_eq!(acceleration_vec.y.as_m_per_s2(), 19.6);
assert_relative_eq!(acceleration_vec.z.as_m_per_s2(), 29.4);
let acceleration_vec_kmh2 = Vector3::<Acceleration>::from_array_with_unit(array, AccelerationType::KmPerHour2);
assert_relative_eq!(acceleration_vec_kmh2.x.as_km_per_h_2(), 9.8);
assert_relative_eq!(acceleration_vec_kmh2.y.as_km_per_h_2(), 19.6);
assert_relative_eq!(acceleration_vec_kmh2.z.as_km_per_h_2(), 29.4);
let acceleration_vec_g = Vector3::<Acceleration>::from_array_with_unit(array, AccelerationType::G);
assert_relative_eq!(acceleration_vec_g.x.as_g(), 9.8);
assert_relative_eq!(acceleration_vec_g.y.as_g(), 19.6);
assert_relative_eq!(acceleration_vec_g.z.as_g(), 29.4);
}
}