use super::{Converter, Equivalency};
use crate::dimension::{Dimension, Rational16};
use crate::unit::Unit;
pub fn dimensionless_angles() -> Equivalency {
Equivalency::new("dimensionless_angles", |from, to| {
let from_dim = from.dimension();
let to_dim = to.dimension();
let from_no_angles = remove_angle_dimensions(&from_dim);
let to_no_angles = remove_angle_dimensions(&to_dim);
if from_no_angles != to_no_angles {
return None;
}
let from_scale = from.scale();
let to_scale = to.scale();
let factor = from_scale / to_scale;
Some(Converter::new_infallible(
move |x| x * factor,
move |x| x / factor,
))
})
}
fn remove_angle_dimensions(dim: &Dimension) -> Dimension {
Dimension {
length: dim.length,
time: dim.time,
mass: dim.mass,
current: dim.current,
temperature: dim.temperature,
angle: Rational16::ZERO, solid_angle: Rational16::ZERO, luminous_intensity: dim.luminous_intensity,
magnitude: dim.magnitude,
amount: dim.amount,
photon: dim.photon,
}
}
pub fn has_angle_dimension(unit: &Unit) -> bool {
let dim = unit.dimension();
!dim.angle.is_zero() || !dim.solid_angle.is_zero()
}
pub fn angle_power(unit: &Unit) -> i32 {
let dim = unit.dimension();
let angle_exp = dim.angle.to_f64() as i32;
let solid_angle_exp = dim.solid_angle.to_f64() as i32;
angle_exp + solid_angle_exp
}
#[cfg(test)]
mod tests {
use super::*;
use crate::systems::si::{HZ, J, KG, M, RAD, S, SR, W};
use std::f64::consts::PI;
#[test]
fn test_angular_frequency_to_frequency() {
let omega = 2.0 * PI * RAD / S;
let f = omega.to_equiv(&HZ, dimensionless_angles()).unwrap();
assert!((f.value() - 2.0 * PI).abs() < 1e-10);
}
#[test]
fn test_frequency_to_angular_frequency() {
let f = 1.0 * HZ;
let rad_per_s = RAD / S;
let omega = f.to_equiv(&rad_per_s, dimensionless_angles()).unwrap();
assert!((omega.value() - 1.0).abs() < 1e-10);
}
#[test]
fn test_rotational_energy() {
let I = 2.0 * KG * M * M;
let omega = 3.0 * RAD / S;
let omega_squared = &omega * ω
let E_raw = 0.5 * &I * omega_squared;
assert!(has_angle_dimension(E_raw.unit()));
let E = E_raw.to_equiv(&J, dimensionless_angles()).unwrap();
assert!((E.value() - 9.0).abs() < 1e-10);
}
#[test]
fn test_torque_times_angle() {
let tau = 10.0 * KG * M * M / (S * S); let theta = 2.0 * RAD;
let work_raw = &tau * θ
assert!(has_angle_dimension(work_raw.unit()));
let work = work_raw.to_equiv(&J, dimensionless_angles()).unwrap();
assert!((work.value() - 20.0).abs() < 1e-10);
}
#[test]
fn test_solid_angle_intensity() {
let intensity = 100.0 * W / SR;
let solid_angle = 0.5 * SR;
let power_raw = &intensity * &solid_angle;
let power = power_raw.to_equiv(&W, dimensionless_angles()).unwrap();
assert!((power.value() - 50.0).abs() < 1e-10);
}
#[test]
fn test_has_angle_dimension() {
assert!(has_angle_dimension(&(RAD / S)));
assert!(has_angle_dimension(&Unit::from(SR)));
assert!(!has_angle_dimension(&Unit::from(HZ)));
assert!(!has_angle_dimension(&Unit::from(J)));
}
#[test]
fn test_angle_power() {
let omega = RAD / S;
assert_eq!(angle_power(&omega), 1);
let omega_sq = omega.pow(2);
assert_eq!(angle_power(&omega_sq), 2);
assert_eq!(angle_power(&Unit::from(HZ)), 0);
}
#[test]
fn test_incompatible_dimensions_fail() {
let mass = 1.0 * KG;
let result = mass.to_equiv(&HZ, dimensionless_angles());
assert!(result.is_err());
}
#[test]
fn test_pure_angle_to_dimensionless() {
let angle = 1.0 * RAD;
let dimless = angle
.to_equiv(&Unit::dimensionless(), dimensionless_angles())
.unwrap();
assert!((dimless.value() - 1.0).abs() < 1e-10);
}
#[test]
fn test_pi_radians() {
let angle = PI * RAD;
let dimless = angle
.to_equiv(&Unit::dimensionless(), dimensionless_angles())
.unwrap();
assert!((dimless.value() - PI).abs() < 1e-10);
}
}