1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! Algebraic vector types generic over a number of axes and a component type.
//!
//! All vectors types impl the [Vector] trait, and all vector components
//! impl the [Component] trait. The [Vector] trait provides a number of
//! features, including accessing components by `Index<usize>`, iterator
//! support via an [iter()] method which returns an [Iter] type,
//! and a [to_array()] method for returning the vector components as a
//! `GenericArray`.
//!
//! For vectors whose components impl `Into<f32>`, a set of vector geometry
//! extensions are provided by the [VectorExt] trait, including computing
//! the distance between vectors and the magnitude of a vector.
//!
//! [Vector]: https://docs.rs/micromath/latest/micromath/vector/trait.Vector.html
//! [Component]: https://docs.rs/micromath/latest/micromath/vector/trait.Component.html
//! [iter()]: https://docs.rs/micromath/latest/micromath/vector/trait.Vector.html#method.iter
//! [Iter]: https://docs.rs/micromath/latest/micromath/vector/struct.Iter.html
//! [to_array()]: https://docs.rs/micromath/latest/micromath/vector/trait.Vector.html#tymethod.to_array
//! [VectorExt]: https://docs.rs/micromath/latest/micromath/vector/trait.VectorExt.html

#[allow(unused_imports)]
use crate::f32ext::F32Ext;
use core::{
    fmt::Debug,
    ops::{Index, MulAssign},
};
use generic_array::{ArrayLength, GenericArray};

mod component;
mod iter;
mod xy;
mod xyz;

pub use self::{component::*, iter::*, xy::*, xyz::*};

/// Vectors with numeric components
pub trait Vector: Copy + Debug + Default + Index<usize> + PartialEq + Sized + Send + Sync {
    /// Number of axes
    type Axes: ArrayLength<Self::Component>;

    /// Type representing measured acceleration for a particular axis
    type Component: Component;

    /// Smallest value representable by a vector component
    const MIN: Self::Component;

    /// Largest value representable by a vector component
    const MAX: Self::Component;

    /// Instantiate a `Vector` from an iterator over `Self::Component` values.
    ///
    /// Panics of the iterator is not the correct length.
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = Self::Component>;

    /// Instantiate a vector from a slice of components.
    ///
    /// Panics if the slice is not the right size.
    fn from_slice(slice: &[Self::Component]) -> Self {
        Self::from_iter(slice.iter().cloned())
    }

    /// Get the component value for a particular index
    fn get(self, index: usize) -> Option<Self::Component>;

    /// Iterate over the components of a vector
    fn iter(&self) -> Iter<Self> {
        Iter::new(self)
    }

    /// Obtain an array of the acceleration components for each of the axes
    fn to_array(self) -> GenericArray<Self::Component, Self::Axes>;
}

/// Vector geometry extensions usable on vectors whose components can be
/// converted into `f32`.
pub trait VectorExt: Vector + MulAssign<f32> {
    /// Compute the distance between two vectors
    fn distance(self, other: Self) -> f32;

    /// Compute the magnitude of a vector
    fn magnitude(self) -> f32;
}

impl<V, A, C> VectorExt for V
where
    V: Vector<Axes = A, Component = C> + MulAssign<f32>,
    A: ArrayLength<C>,
    C: Component + Into<f32>,
{
    /// Compute the distance between two vectors
    fn distance(self, other: Self) -> f32 {
        let differences = self
            .iter()
            .zip(other.iter())
            .map(|(a, b)| a.into() - b.into());

        differences.map(|n| n * n).sum::<f32>().sqrt()
    }

    /// Compute the magnitude of a vector
    fn magnitude(self) -> f32 {
        self.iter()
            .map(|n| {
                let n = n.into();
                n * n
            })
            .sum::<f32>()
            .sqrt()
    }
}