use crate::dual_quaternion::DualQuaternion;
use crate::matrix3x3::M33;
use crate::matrix4x4::M44;
use crate::traits::LinearAlgebra;
use num::Float;
pub fn nearly_equal<T: Float>(a: T, b: T, epsilon: T) -> bool {
let abs_a = a.abs();
let abs_b = b.abs();
let abs_diff = (a - b).abs();
let zero = T::zero();
if a == b {
true
} else if a == zero || b == zero || (abs_a + abs_b < T::min_value()) {
abs_diff < epsilon
} else {
abs_diff / T::min(abs_a + abs_b, T::max_value()) < epsilon
}
}
#[inline(always)]
pub fn nearly_zero<T: Float>(a: T) -> bool {
nearly_equal(a, T::zero(), T::epsilon())
}
pub fn compare_vecs<T: Float>(v1: &[T], v2: &[T], epsilon: T) -> bool {
v1.iter()
.zip(v2)
.map(|(a, b)| nearly_equal(*a, *b, epsilon))
.all(|x| x)
}
pub fn compare_floats<T: Float>(num1: T, num2: T, tol: T) -> bool {
Float::abs(num1 - num2) < tol
}
pub fn is_rotation<T: Float + core::iter::Sum>(r: M33<T>) -> bool {
let r2 = r * r;
nearly_equal(r.det(), T::one(), T::epsilon()) && nearly_equal(r2.det(), T::one(), T::epsilon())
}
pub fn is_rotation_h<T: Float + core::iter::Sum>(r: M44<T>) -> bool {
let r2 = r * r;
let eps = T::from(1e-6).unwrap();
nearly_equal(r.det(), T::one(), eps) && nearly_equal(r2.det(), T::one(), eps)
}
pub fn compare_dual_quaternions<T: Float>(
a: DualQuaternion<T>,
b: DualQuaternion<T>,
epsilon: T,
) -> bool {
nearly_equal(a.real().real(), b.real().real(), epsilon)
&& nearly_equal(a.real().imag()[0], b.real().imag()[0], epsilon)
&& nearly_equal(a.real().imag()[1], b.real().imag()[1], epsilon)
&& nearly_equal(a.real().imag()[2], b.real().imag()[2], epsilon)
&& nearly_equal(a.dual().real(), b.dual().real(), epsilon)
&& nearly_equal(a.dual().imag()[0], b.dual().imag()[0], epsilon)
&& nearly_equal(a.dual().imag()[1], b.dual().imag()[1], epsilon)
&& nearly_equal(a.dual().imag()[2], b.dual().imag()[2], epsilon)
}
#[cfg(test)]
mod test_utils {
use super::*;
#[test]
fn test_nearly_equal() {
let a = 0.15 + 0.15;
let b = 0.1 + 0.2;
assert_eq!(nearly_equal(a, b, 1e-10), true);
}
#[test]
fn test_zero_signs() {
let a = 0.0;
let b = -0.0;
assert_eq!(nearly_equal(a, b, 1e-10), true);
}
#[test]
fn test_one_zero() {
let b = -0.0000000005561918225744;
let a = 0.0;
assert_eq!(nearly_equal(a, b, 1e-8), true);
}
}