use crate::physics::basic;
use std::any::Any;
use std::ops::Div;
mod acceleration;
mod angular;
mod angular_acceleration;
mod angular_momentum;
mod angular_velocity;
mod area;
mod coef;
mod distance;
mod energy;
mod force;
mod magnetic_angular_velocity;
mod magnetic_induction;
mod magnetic_moment;
pub mod mass;
mod momentum;
mod power;
mod torque;
pub mod vector;
mod velocity;
mod volume;
pub trait VectorQuantity: PhysicalQuantity {}
pub trait PhysicalQuantity: Any {
fn as_any(&self) -> &dyn Any;
fn is_zero(&self) -> bool;
fn default_unit_value(&self) -> f64;
fn set_value(&mut self, value: f64);
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DistanceType {
M,
KM,
LightYear,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum VelocityType {
MPerSecond,
KmPerHour,
KmPerSecond,
LightSpeed,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub struct Distance {
default_type: DistanceType,
v: f64,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub struct Velocity {
default_type: VelocityType,
v: f64,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub struct Acceleration {
default_type: AccelerationType,
v: f64,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum AccelerationType {
MPerSecond2,
KmPerHour2,
G,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum AngularType {
Rad,
Deg,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub struct Angular {
default_type: AngularType,
v: f64,
}
#[derive(Clone, Debug, PartialEq, Copy, Default)]
pub enum AngularVelocityType {
#[default]
RadperSecond,
DegPerSecond,
RadperHour,
DegperHour,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub struct AngularVelocity {
default_type: AngularVelocityType,
v: f64,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum AngularAccelerationType {
RadperSecond2,
DegPerSecond2,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub struct AngularAcceleration {
default_type: AngularAccelerationType,
v: f64,
}
#[derive(Clone, Debug, PartialEq, PartialOrd, Copy)]
pub struct Coef {
v: f64,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum MassType {
Kg,
g,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub struct Mass {
default_type: MassType,
pub v: f64,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum AngularMomentumType {
KgM2perSecond, KgKm2perSecond, Nms, MillNms, MicroNms, NanoNms, }
#[derive(Clone, Debug, PartialEq, Copy)]
pub struct AngularMomentum {
default_type: AngularMomentumType,
pub v: f64,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum MomentumType {
KgMperSecond, KgKmperSecond, }
#[derive(Clone, Debug, PartialEq, Copy)]
pub struct Momentum {
default_type: MomentumType,
pub v: f64,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub struct Vector3<T: VectorQuantity + Default> {
pub x: T,
pub y: T,
pub z: T,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AreaType {
M2,
KM2,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Area {
default_type: AreaType,
pub v: f64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub enum MagneticInductionType {
Gauss,
#[default]
Tesla,
MillTesla, MicroTesla, NanoTesla, MillGauss, KiloGauss, }
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MagneticInduction {
default_type: MagneticInductionType,
pub v: f64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum MagneticMomentType {
AM2, MillAM2, MicroAM2, NanoAM2, JPerTesla, MillJPerTesla, MicroJPerTesla, NanoJPerTesla, }
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MagneticMoment {
default_type: MagneticMomentType,
pub v: f64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum TorqueType {
NM, MillNM, MicroNM, NanoNM, KNM, MNM, }
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Torque {
default_type: TorqueType,
pub v: f64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum EnergyType {
Joule, MillJoule, MicroJoule, NanoJoule, KiloJoule, MegaJoule, ElectronVolt, KiloElectronVolt, MegaElectronVolt, }
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Energy {
default_type: EnergyType,
pub v: f64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ForceType {
Newton, MillNewton, MicroNewton, NanoNewton, KiloNewton, MegaNewton, }
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Force {
default_type: ForceType,
pub v: f64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum PowerType {
Watt, MillWatt, MicroWatt, NanoWatt, KiloWatt, MegaWatt, HorsePower, }
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Power {
default_type: PowerType,
pub v: f64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum MagneticAngularVelocityType {
TeslaRadPerSecond, MillTeslaRadPerSecond, MicroTeslaRadPerSecond, NanoTeslaRadPerSecond, GaussRadPerSecond, MillGaussRadPerSecond, KiloGaussRadPerSecond, }
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct MagneticAngularVelocity {
default_type: MagneticAngularVelocityType,
pub v: f64,
}
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum VolumeType {
M3,
KM3,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Volume {
default_type: VolumeType,
pub v: f64,
}
impl Default for Distance {
fn default() -> Self {
Distance::from_m(0.0)
}
}
impl PhysicalQuantity for Distance {
fn as_any(&self) -> &dyn Any {
self
}
fn is_zero(&self) -> bool {
self.v == 0.0
}
fn default_unit_value(&self) -> f64 {
self.as_m()
}
fn set_value(&mut self, value: f64) {
self.v = value;
}
}
impl Default for Angular {
fn default() -> Self {
Angular::from_rad(0.0)
}
}
impl PhysicalQuantity for Angular {
fn as_any(&self) -> &dyn Any {
self
}
fn is_zero(&self) -> bool {
self.v == 0.0
}
fn default_unit_value(&self) -> f64 {
self.as_rad()
}
fn set_value(&mut self, value: f64) {
self.v = value;
}
}
impl Default for AngularVelocity {
fn default() -> Self {
AngularVelocity::from_rad_per_second(0.0)
}
}
impl Div for AngularMomentum {
type Output = Coef;
fn div(self, rhs: Self) -> Self::Output {
let v = self.default_unit_value() / rhs.default_unit_value();
Coef::new(v)
}
}
impl Default for Coef {
fn default() -> Self {
Coef::new(1.0)
}
}
impl Default for AngularAcceleration {
fn default() -> Self {
AngularAcceleration::from_rad_per_second2(0.0)
}
}
impl<T: VectorQuantity + Default> Default for Vector3<T> {
fn default() -> Self {
Vector3 {
x: T::default(),
y: T::default(),
z: T::default(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_as_any() {
let g: &dyn PhysicalQuantity = &Acceleration::from_g(1.23);
let d = g.as_any().downcast_ref::<Acceleration>().unwrap();
let g: &dyn PhysicalQuantity = &Area::from_m2(10.0);
let d = g.as_any().downcast_ref::<Area>().unwrap();
let g: &dyn PhysicalQuantity = &Distance::from_m(10.0);
let d = g.as_any().downcast_ref::<Distance>().unwrap();
assert_eq!(d.default_type, DistanceType::M);
let g: &dyn PhysicalQuantity = &Velocity::from_m_per_sec(10.0);
let d = g.as_any().downcast_ref::<Velocity>().unwrap();
assert_eq!(d.default_type, VelocityType::MPerSecond);
let g: &dyn PhysicalQuantity = &Acceleration::from_g(1.23);
let d = g.as_any().downcast_ref::<Acceleration>().unwrap();
assert_eq!(d.default_type, AccelerationType::G);
let g: &dyn PhysicalQuantity = &Angular::from_rad(1.23);
let d = g.as_any().downcast_ref::<Angular>().unwrap();
assert_eq!(d.default_type, AngularType::Rad);
let g: &dyn PhysicalQuantity = &AngularVelocity::from_rad_per_hour(1.23);
let d = g.as_any().downcast_ref::<AngularVelocity>().unwrap();
assert_eq!(d.default_type, AngularVelocityType::RadperHour);
let g: &dyn PhysicalQuantity = &Coef::new(1.23);
let d = g.as_any().downcast_ref::<Coef>().unwrap();
assert_eq!(d.v, 1.23);
let g: &dyn PhysicalQuantity = &AngularAcceleration::from_rad_per_second2(1.23);
let d = g.as_any().downcast_ref::<AngularAcceleration>().unwrap();
assert_eq!(d.default_type, AngularAccelerationType::RadperSecond2);
}
#[test]
fn test_acceleration_default() {
let a = Acceleration::default();
assert_eq!(0.0, a.as_m_per_s2());
}
#[test]
fn test_angular_velocity_default() {
let a = AngularVelocity::default();
assert_eq!(0.0, a.as_rad_per_hour());
let a = AngularAcceleration::default();
assert_eq!(0.0, a.as_rad_per_second2());
}
#[test]
fn test_angular_is_zero() {
let a = Angular::from_rad(0.0);
assert_eq!(true, a.is_zero());
let a = Angular::from_rad(1.0);
assert_eq!(false, a.is_zero());
}
#[test]
fn test_volume_clone() {
let a = Volume::from_m3(3.8);
let b = a.clone();
assert_relative_eq!(a.as_km3(), b.as_km3(), epsilon = 1e-8);
}
#[test]
fn test_magnetic_moment_as_any() {
let g: &dyn PhysicalQuantity = &MagneticMoment::from_am2(1.23);
let d = g.as_any().downcast_ref::<MagneticMoment>().unwrap();
assert_eq!(d.default_type, MagneticMomentType::AM2);
}
#[test]
fn test_magnetic_moment_default() {
let mm = MagneticMoment::default();
assert_eq!(0.0, mm.as_am2());
}
#[test]
fn test_magnetic_moment_is_zero() {
let mm = MagneticMoment::from_am2(0.0);
assert_eq!(true, mm.is_zero());
let mm = MagneticMoment::from_am2(1.0);
assert_eq!(false, mm.is_zero());
}
#[test]
fn test_torque_as_any() {
let g: &dyn PhysicalQuantity = &Torque::from_nm(1.23);
let d = g.as_any().downcast_ref::<Torque>().unwrap();
assert_eq!(d.default_type, TorqueType::NM);
}
#[test]
fn test_torque_default() {
let t = Torque::default();
assert_eq!(0.0, t.as_nm());
}
#[test]
fn test_torque_is_zero() {
let t = Torque::from_nm(0.0);
assert_eq!(true, t.is_zero());
let t = Torque::from_nm(1.0);
assert_eq!(false, t.is_zero());
}
#[test]
fn test_energy_as_any() {
let g: &dyn PhysicalQuantity = &Energy::from_joule(1.23);
let d = g.as_any().downcast_ref::<Energy>().unwrap();
assert_eq!(d.default_type, EnergyType::Joule);
}
#[test]
fn test_energy_default() {
let e = Energy::default();
assert_eq!(0.0, e.as_joule());
}
#[test]
fn test_energy_is_zero() {
let e = Energy::from_joule(0.0);
assert_eq!(true, e.is_zero());
let e = Energy::from_joule(1.0);
assert_eq!(false, e.is_zero());
}
#[test]
fn test_angular_default_unit_value_is_rad() {
let a_rad = Angular::from_rad(std::f64::consts::PI);
assert_relative_eq!(a_rad.default_unit_value(), a_rad.as_rad(), epsilon = 1e-12);
let a_deg = Angular::from_deg(180.0);
assert_relative_eq!(a_deg.default_unit_value(), a_deg.as_rad(), epsilon = 1e-12);
let cases = vec![
-720.0, -360.0, -45.5, 0.0, 12.34, 90.0, 123.456, 360.0, 720.0,
];
for deg in cases {
let a = Angular::from_deg(deg);
assert_relative_eq!(a.default_unit_value(), a.as_rad(), epsilon = 1e-12);
}
}
}
impl VectorQuantity for Distance {}
impl VectorQuantity for Velocity {}
impl VectorQuantity for Acceleration {}
impl VectorQuantity for Angular {}
impl VectorQuantity for AngularVelocity {}
impl VectorQuantity for AngularAcceleration {}
impl VectorQuantity for Coef {}
impl VectorQuantity for AngularMomentum {}
impl VectorQuantity for Momentum {}
impl VectorQuantity for MagneticInduction {}
impl VectorQuantity for MagneticMoment {}
impl VectorQuantity for Torque {}
impl VectorQuantity for Force {}
impl VectorQuantity for MagneticAngularVelocity {}