use std::f64::consts::TAU;
use super::uvw::UVW;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[allow(clippy::upper_case_acronyms)]
pub struct LMN {
pub l: f64,
pub m: f64,
pub n: f64,
}
impl LMN {
pub fn dot(self, uvw: UVW) -> f64 {
TAU * (uvw.u * self.l + uvw.v * self.m + uvw.w * (self.n - 1.0))
}
pub fn prepare_for_rime(self) -> LmnRime {
LmnRime {
l: TAU * self.l,
m: TAU * self.m,
n: TAU * (self.n - 1.0),
}
}
}
#[cfg(any(test, feature = "approx"))]
impl approx::AbsDiffEq for LMN {
type Epsilon = f64;
fn default_epsilon() -> f64 {
f64::EPSILON
}
fn abs_diff_eq(&self, other: &Self, epsilon: f64) -> bool {
f64::abs_diff_eq(&self.l, &other.l, epsilon)
&& f64::abs_diff_eq(&self.m, &other.m, epsilon)
&& f64::abs_diff_eq(&self.n, &other.n, epsilon)
}
}
#[cfg(any(test, feature = "approx"))]
impl approx::RelativeEq for LMN {
#[inline]
fn default_max_relative() -> f64 {
f64::EPSILON
}
#[inline]
fn relative_eq(&self, other: &Self, epsilon: f64, max_relative: f64) -> bool {
f64::relative_eq(&self.l, &other.l, epsilon, max_relative)
&& f64::relative_eq(&self.m, &other.m, epsilon, max_relative)
&& f64::relative_eq(&self.n, &other.n, epsilon, max_relative)
}
#[inline]
fn relative_ne(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
!Self::relative_eq(self, other, epsilon, max_relative)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct LmnRime {
pub l: f64,
pub m: f64,
pub n: f64,
}
impl LmnRime {
pub fn dot(self, uvw: UVW) -> f64 {
uvw.u * self.l + uvw.v * self.m + uvw.w * self.n
}
pub fn to_lmn(self) -> LMN {
LMN {
l: self.l / TAU,
m: self.m / TAU,
n: self.n / TAU + 1.0,
}
}
}
#[cfg(any(test, feature = "approx"))]
impl approx::AbsDiffEq for LmnRime {
type Epsilon = f64;
fn default_epsilon() -> f64 {
f64::EPSILON
}
fn abs_diff_eq(&self, other: &Self, epsilon: f64) -> bool {
f64::abs_diff_eq(&self.l, &other.l, epsilon)
&& f64::abs_diff_eq(&self.m, &other.m, epsilon)
&& f64::abs_diff_eq(&self.n, &other.n, epsilon)
}
}
#[cfg(any(test, feature = "approx"))]
impl approx::RelativeEq for LmnRime {
#[inline]
fn default_max_relative() -> f64 {
f64::EPSILON
}
#[inline]
fn relative_eq(&self, other: &Self, epsilon: f64, max_relative: f64) -> bool {
f64::relative_eq(&self.l, &other.l, epsilon, max_relative)
&& f64::relative_eq(&self.m, &other.m, epsilon, max_relative)
&& f64::relative_eq(&self.n, &other.n, epsilon, max_relative)
}
#[inline]
fn relative_ne(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
!Self::relative_eq(self, other, epsilon, max_relative)
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_abs_diff_eq;
use std::f64::consts::PI;
#[test]
fn test_lmn_dot() {
let lmn = LMN {
l: 0.5,
m: 0.5,
n: 0.707,
};
let uvw = UVW {
u: 1.0,
v: 2.0,
w: 3.0,
};
assert_abs_diff_eq!(lmn.dot(uvw), 3.9018580757585224);
}
#[test]
fn test_lmn_prepare_for_rime() {
let lmn = LMN {
l: 0.5,
m: 0.5,
n: 0.707,
};
let lmn_rime = lmn.prepare_for_rime();
assert_abs_diff_eq!(
lmn_rime,
LmnRime {
l: PI,
m: PI,
n: -1.840973295003619
}
);
}
#[test]
fn test_lmn_rime_dot() {
let lmn = LmnRime {
l: 0.5,
m: 0.5,
n: 0.707,
};
let uvw = UVW {
u: 1.0,
v: 2.0,
w: 3.0,
};
assert_abs_diff_eq!(lmn.dot(uvw), 3.621);
}
#[test]
fn test_lmn_rime_to_lmn() {
let lmn = LMN {
l: 0.5,
m: 0.5,
n: 0.707,
};
let lmn_rime = lmn.prepare_for_rime();
let lmn2 = lmn_rime.to_lmn();
assert_abs_diff_eq!(lmn, lmn2);
}
}