dualquat 0.1.0

Quaternion and Dual Quaternion math library for high-precision physics simulation
Documentation
use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub};
#[cfg(feature = "nanoserde")]
use nanoserde::{DeBin, SerBin};

#[derive(Default, Debug, Copy, Clone, PartialOrd)]
#[cfg_attr(feature = "nanoserde", derive(nanoserde::DeBin, nanoserde::SerBin))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "speedy", derive(speedy::Readable, speedy::Writable))]
pub struct Vec3 {
    pub i: f64,
    pub j: f64,
    pub k: f64,
}

impl Neg for Vec3 {
    type Output = Vec3;

    fn neg(self) -> Self::Output {
        Vec3 {
            i: -self.i,
            j: -self.j,
            k: -self.k,
        }
    }
}

impl Add for Vec3 {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        Self {
            i: self.i + other.i,
            j: self.j + other.j,
            k: self.k + other.k,
        }
    }
}

impl AddAssign for Vec3 {
    fn add_assign(&mut self, rhs: Self) {
        self.i += rhs.i;
        self.j += rhs.j;
        self.k += rhs.k;
    }
}

impl Sub for Vec3 {
    type Output = Self;
    fn sub(self, other: Self) -> Self {
        Self {
            i: self.i - other.i,
            j: self.j - other.j,
            k: self.k - other.k,
        }
    }
}

impl Mul<f64> for Vec3 {
    type Output = Self;
    fn mul(self, other: f64) -> Self {
        Self {
            i: self.i * other,
            j: self.j * other,
            k: self.k * other,
        }
    }
}

impl Div<f64> for Vec3 {
    type Output = Self;
    fn div(self, other: f64) -> Self {
        Self {
            i: self.i / other,
            j: self.j / other,
            k: self.k / other,
        }
    }
}

impl IntoIterator for Vec3 {
    type Item = f64;
    type IntoIter = std::array::IntoIter<f64, 3>;

    fn into_iter(self) -> Self::IntoIter {
        IntoIterator::into_iter([self.i, self.j, self.k])
    }
}

impl PartialEq for Vec3 {
    fn eq(&self, other: &Self) -> bool {
        (self.i - other.i).abs() < 10.0 * f64::EPSILON
            && (self.j - other.j).abs() < 10.0 * f64::EPSILON
            && (self.k - other.k).abs() < 10.0 * f64::EPSILON
    }
}

impl Vec3 {
    #[inline(always)]
    pub const fn new(x: f64, y: f64, z: f64) -> Vec3 {
        Vec3 { i: x, j: y, k: z }
    }

    pub fn invert(self) -> Vec3 {
        Vec3 {
            i: -(self.i),
            j: -(self.j),
            k: -(self.k),
        }
    }

    pub fn sum(&self) -> f64 {
        self.i + self.j + self.k
    }

    pub fn distance(&self, second_location: Vec3) -> f64 {
        ((self.i - second_location.i).powi(2)
            + (self.k - second_location.k).powi(2)
            + (self.j - second_location.j).powi(2))
        .sqrt()
    }

    pub fn unit(&self) -> Vec3 {
        let norm = self.norm();
        *self * (1.0 / norm)
    }

    pub fn norm(&self) -> f64 {
        ((self.i).powi(2) + (self.k).powi(2) + (self.j).powi(2)).sqrt()
    }

    pub fn norm_squared(&self) -> f64 {
        (self.i).powi(2) + (self.k).powi(2) + (self.j).powi(2)
    }

    pub fn cross(self, other: Self) -> Self {
        Vec3 {
            i: (self.j * other.k) - (self.k * other.j),
            j: (self.k * other.i) - (self.i * other.k),
            k: (self.i * other.j) - (self.j * other.i),
        }
    }

    pub fn dot(self, other: Self) -> f64 {
        (self.i * other.i) + (self.j * other.j) + (self.k * other.k)
    }

    pub fn between(self, start: Self, end: Self) -> bool {
        (self.distance(start) + self.distance(end) - start.distance(end)).abs() < f64::EPSILON
    }

    #[cfg(test)]
    fn exact_eq(self, other: Self) -> bool {
        (self.i == other.i) && (self.j == other.j) && (self.k == other.k)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_cross_product_self() {
        let l = Vec3::new(2.0, 3.0, 4.0);
        assert!(l.cross(l).exact_eq(Vec3::default()));
    }

    #[test]
    fn test_cross_product_other() {
        let l = Vec3::new(1.0, 2.0, 3.0);
        let r = Vec3::new(4.0, 5.0, 6.0);
        assert!(l.cross(r).exact_eq(Vec3::new(-3.0, 6.0, -3.0)));
    }

    #[test]
    fn test_dot_product() {
        let l = Vec3::new(3.0, 5.0, 8.0);
        let r = Vec3::new(2.0, 7.0, 1.0);
        assert!(l.dot(r) == 49.0)
    }

    #[test]
    fn test_invert() {
        let l = Vec3::new(3.0, 5.0, 8.0);
        let r = l.invert();
        assert_ne!(l, r);
        let r = r.invert();
        assert_eq!(l, r);
    }
}