violin 0.3.0

decentralized network coordinate system using the vivaldi algorithm
Documentation
//! Defines the `VecD` coordinate vector that does not use any heap allocation

use crate::{
    std::ops::{Add, AddAssign, Div, Mul},
    Vector,
};

/// A `VecD` is a coordinate vector made up of some number of `f64`s stored as
/// an array
///
/// ```rust
/// use violin::heapless::VecD;
///
/// // defines a 3D vector
/// let v3 = VecD::from([1.1, 2.2, 3.3]);
///
/// // defines a 2D vector
/// let v3 = VecD::from([1.1, 2.2]);
///
/// // defines a 8D vector
/// let v3 = VecD::from([1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8]);
/// ```
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct VecD<const N: usize> {
    inner: [f64; N],
}

impl<const N: usize> Default for VecD<N> {
    fn default() -> Self { Self { inner: [0.0f64; N] } }
}

impl<const N: usize> From<[f64; N]> for VecD<N> {
    fn from(arr: [f64; N]) -> Self { Self { inner: arr } }
}

impl_vec!(VecD<N>);

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

    #[test]
    fn distance() {
        let dist = VecD::from([1., 0., 5.]).distance(&VecD::from([0., 2., 4.]));
        #[cfg(feature = "std")]
        assert_eq!(dist, 2.449489742783178);
        #[cfg(not(feature = "std"))]
        assert_eq!(dist, 2.44948974);
    }

    #[test]
    fn magnitude() {
        assert_eq!(VecD::<3>::default().magnitude(), 0.0);
        assert_eq!(VecD::from([-2., 4., -4.]).magnitude(), 6.0f64);

        #[cfg(feature = "std")]
        assert_eq!(VecD::from([1.0, -2.0, 3.0]).magnitude(), 3.7416573867739413);
        #[cfg(not(feature = "std"))]
        assert_eq!(VecD::from([1.0, -2.0, 3.0]).magnitude(), 3.74165739);
    }

    #[cfg_attr(feature = "std", test)]
    #[cfg(feature = "std")]
    fn unit_vector() {
        let (_, uv) = VecD::from([1., 0., 5.]).unit_vector_from(&VecD::from([0., 2., 4.]));
        assert_eq!(
            uv,
            VecD::from([0.4082482904638631, -0.8164965809277261, 0.4082482904638631])
        );

        let a = VecD::from([1.0, 2.0, 3.0]);
        let b = VecD::from([0.5, 0.6, 0.7]);
        let (mag, uv) = a.unit_vector_from(&b);
        assert_eq!(
            uv,
            VecD::from([0.18257418583505536, 0.511207720338155, 0.8398412548412546])
        );
        let uv_mag = uv.magnitude();
        assert!(uv_mag > 0.9999999 && uv_mag <= 1.0);
        assert_eq!(mag, a.difference(&b).magnitude());
    }

    #[cfg_attr(not(feature = "std"), test)]
    #[cfg(not(feature = "std"))]
    fn unit_vector_no_std() {
        let (_, uv) = VecD::from([1., 0., 5.]).unit_vector_from(&VecD::from([0., 2., 4.]));
        assert_eq!(
            uv,
            VecD::from([0.408248290927726, -0.816496581855452, 0.408248290927726])
        );

        let a = VecD::from([1.0, 2.0, 3.0]);
        let b = VecD::from([0.5, 0.6, 0.7]);
        let (mag, uv) = a.unit_vector_from(&b);
        assert_eq!(
            uv,
            VecD::from([0.18257418567011074, 0.5112077198763101, 0.8398412540825093])
        );
        let uv_mag = uv.magnitude();
        assert!(uv_mag > 0.9999999 && uv_mag <= 1.0);
        assert_eq!(mag, a.difference(&b).magnitude());
    }

    #[test]
    fn equal_unit_vectors() {
        // equal coordinates should not get a divide by zero
        let a = VecD::from([1.0, 2.0, 3.0]);
        let (mag, uv) = a.unit_vector_from(&a);
        assert_eq!(uv.magnitude(), 1.0);
        assert_eq!(mag, 0.0);
    }

    #[test]
    fn add() {
        let a = VecD::from([1.0, -3.0, 3.0]);
        let b = VecD::from([-4.0, 5.0, 6.0]);
        assert_eq!(a + b, VecD::from([-3.0, 2.0, 9.0]));
        assert_eq!(a + VecD::default(), a);
    }

    #[test]
    fn difference() {
        let a = VecD::from([1.0, -3.0, 3.0]);
        let b = VecD::from([-4.0, 5.0, 6.0]);
        assert_eq!(a.difference(&b), VecD::from([5.0, -8.0, -3.0]));
        assert_eq!(a.difference(&VecD::default()), a);
    }
}