ndmath/
lib.rs

1#![warn(missing_docs)]
2
3/*!
4This crate provides traits for working with builtin Rust types as geometric primitives.
5
6# Usage
7
8## Vectors
9
10[`VecN`] provides basic vector math operations. [`FloatingVecN`] adds some extra methods that only apply to real-valued vectors.
11
12These traits are implemented for all applicable array types.
13
14### Example
15
16```
17use ndmath::*;
18
19let a = [2, 5];
20let b = [3, -7];
21let c = a.add(b);
22let d = a.neg();
23assert_eq!(c, [5, -2]);
24assert_eq!(d, [-2, -5]);
25
26let a = [1, 2, 3, 4, 5, 6, 7];
27let b = [9, 8, 7, 6, 5, 4, 3];
28let c = a.add(b);
29let d = a.sub(b);
30let e = a.mul(2);
31assert_eq!(c, [10; 7]);
32assert_eq!(d, [-8, -6, -4, -2, 0, 2, 4]);
33assert_eq!(e, [2, 4, 6, 8, 10, 12, 14]);
34
35let a = [3.0, 4.0];
36let b = [3.0, 6.0];
37assert_eq!(a.mag(), 5.0);
38assert_eq!(a.dist(b), 2.0);
39```
40
41## Axis-aligned bounding boxes
42
43[`Aabb`] provides operations for axis-aligned bounding boxes. They consist of an origin and a size.
44
45This trait is implemented for all even-sized scalar arrays up to size 16 and all size 2 arrays of scalar arrays.
46
47### Example
48
49```
50use ndmath::*;
51
52let aabb = [1, 0, 4, 5];
53assert!(aabb.contains([2, 2]));
54assert!(aabb.contains([1, 0]));
55assert!(aabb.contains([5, 5]));
56assert!(!aabb.contains([5, 6]));
57```
58
59## Named dimension traits
60
61There are traits to provide accessors for named dimensional values.
62
63There are 4 traits for vector dimensions:
64- [`XVec`]
65- [`YVec`]
66- [`ZVec`]
67- [`WVec`]
68
69There are 3 traits for axis-aligned bounding box dimensions:
70- [`XAabb`]
71- [`YAabb`]
72- [`ZAabb`]
73
74### Example
75
76```
77use ndmath::*;
78
79let a = [1, 2];
80let b = [3, 4, 5];
81let c = [6, 7, 8, 9];
82assert_eq!(a.x(), 1);
83assert_eq!(a.y(), 2);
84assert_eq!(b.z(), 5);
85assert_eq!(c.w(), 9);
86
87let aabb = [[0, 1, 2], [3, 4, 5]];
88assert_eq!(aabb.left(), 0);
89assert_eq!(aabb.top(), 1);
90assert_eq!(aabb.back(), 2);
91assert_eq!(aabb.right(), 3);
92assert_eq!(aabb.bottom(), 5);
93assert_eq!(aabb.front(), 7);
94assert_eq!(aabb.width(), 3);
95assert_eq!(aabb.height(), 4);
96assert_eq!(aabb.depth(), 5);
97```
98*/
99
100mod aabb;
101mod scalar;
102
103use std::ops::Neg;
104
105pub use {aabb::*, scalar::*};
106
107/// Trait for basic vector math operations
108pub trait VecN: Sized {
109    /// The dimensionality of the vector
110    const N: usize;
111    /// The zero value
112    const ZERO: Self;
113    /// The scalar type
114    type Scalar: Scalar;
115    /// Get the value of a dimension
116    fn dim(&self, dim: usize) -> Self::Scalar;
117    /// Get a mutable reference to the value of a dimension
118    fn dim_mut(&mut self, dim: usize) -> &mut Self::Scalar;
119    /// Set the value of a dimension
120    fn set_dim(&mut self, dim: usize, val: Self::Scalar) {
121        *self.dim_mut(dim) = val;
122    }
123    /// Add to the vector in place
124    fn add_assign(&mut self, other: Self) {
125        for i in 0..Self::N {
126            *self.dim_mut(i) += other.dim(i);
127        }
128    }
129    /// Add the vector to another
130    fn add(mut self, other: Self) -> Self {
131        self.add_assign(other);
132        self
133    }
134    /// Subtract from the vector in place
135    fn sub_assign(&mut self, other: Self) {
136        for i in 0..Self::N {
137            *self.dim_mut(i) -= other.dim(i);
138        }
139    }
140    /// Subtract a vector from the one
141    fn sub(mut self, other: Self) -> Self {
142        self.sub_assign(other);
143        self
144    }
145    /// Multiply the vector in place
146    fn mul_assign(&mut self, by: Self::Scalar) {
147        for i in 0..Self::N {
148            *self.dim_mut(i) *= by;
149        }
150    }
151    /// Multiply the vector by a scalar value
152    fn mul(mut self, by: Self::Scalar) -> Self {
153        self.mul_assign(by);
154        self
155    }
156    /// Divide the vector in place
157    fn div_assign(&mut self, by: Self::Scalar) {
158        for i in 0..Self::N {
159            *self.dim_mut(i) /= by;
160        }
161    }
162    /// Divide the vector by a scalar value
163    fn div(mut self, by: Self::Scalar) -> Self {
164        self.div_assign(by);
165        self
166    }
167    /// Element-wise multiply the vector by another in place
168    fn mul2_assign(&mut self, other: Self) {
169        for i in 0..Self::N {
170            *self.dim_mut(i) *= other.dim(i);
171        }
172    }
173    /// Element-wise multiply the vector by another
174    fn mul2(mut self, other: Self) -> Self {
175        self.mul2_assign(other);
176        self
177    }
178    /// Element-wise divide the vector by another in place
179    fn div2_assign(&mut self, other: Self) {
180        for i in 0..Self::N {
181            *self.dim_mut(i) /= other.dim(i);
182        }
183    }
184    /// Element-wise divide the vector by another
185    fn div2(mut self, other: Self) -> Self {
186        self.div2_assign(other);
187        self
188    }
189    /// Negate the vector in place
190    fn neg_assign(&mut self)
191    where
192        Self::Scalar: Neg<Output = Self::Scalar> + std::fmt::Debug,
193    {
194        for i in 0..Self::N {
195            *self.dim_mut(i) = -self.dim(i);
196        }
197    }
198    /// Negate the vector
199    fn neg(mut self) -> Self
200    where
201        Self::Scalar: Neg<Output = Self::Scalar> + std::fmt::Debug,
202    {
203        self.neg_assign();
204        self
205    }
206    /// Get the squared magnitude of the vector
207    fn squared_mag(&self) -> Self::Scalar {
208        (0..Self::N)
209            .map(|i| self.dim(i))
210            .fold(Self::Scalar::ZERO, |acc, d| acc + d * d)
211    }
212    /// Get the squared distance between this vector and another
213    fn squared_dist(self, other: Self) -> Self::Scalar {
214        self.sub(other).squared_mag()
215    }
216    /// Get the minimum dimension
217    fn min_dim(&self) -> Self::Scalar {
218        (0..Self::N)
219            .map(|i| self.dim(i))
220            .min_by(|a, b| a.partial_cmp(b).expect("dimension comparison failed"))
221            .expect("empty vectors have no dimensions")
222    }
223    /// Get the maximum dimension
224    fn max_dim(&self) -> Self::Scalar {
225        (0..Self::N)
226            .map(|i| self.dim(i))
227            .max_by(|a, b| a.partial_cmp(b).expect("dimension comparison failed"))
228            .expect("empty vectors have no dimensions")
229    }
230    /// Dot the vector with another
231    fn dot(self, other: Self) -> Self::Scalar {
232        (0..Self::N).fold(Self::Scalar::ZERO, |acc, i| {
233            acc + self.dim(i) + other.dim(i)
234        })
235    }
236    /// Linearly interpolate the vector with another in place
237    fn lerp_assign(&mut self, other: Self, t: Self::Scalar) {
238        let nt = Self::Scalar::ONE - t;
239        for i in 0..Self::N {
240            *self.dim_mut(i) = nt * self.dim(i) + t * other.dim(i);
241        }
242    }
243    /// Linearly interpolate the vector with another
244    fn lerp(mut self, other: Self, t: Self::Scalar) -> Self {
245        self.lerp_assign(other, t);
246        self
247    }
248}
249
250/// Trait for real-valued vector math operations
251pub trait FloatingVecN: VecN
252where
253    Self::Scalar: FloatingScalar,
254{
255    /// Get the magnitude of the vector
256    fn mag(&self) -> Self::Scalar {
257        self.squared_mag().sqrt()
258    }
259    /// Get the distance between the vector and another
260    fn dist(self, other: Self) -> Self::Scalar {
261        self.squared_dist(other).sqrt()
262    }
263    /// Get the unit vector
264    fn unit(self) -> Self {
265        let mag = self.mag();
266        if mag.is_zero() {
267            Self::ZERO
268        } else {
269            self.div(mag)
270        }
271    }
272}
273
274impl<V> FloatingVecN for V
275where
276    V: VecN,
277    V::Scalar: FloatingScalar,
278{
279}
280
281impl<T, const N: usize> VecN for [T; N]
282where
283    T: Scalar,
284{
285    const N: usize = N;
286    const ZERO: Self = [T::ZERO; N];
287    type Scalar = T;
288    fn dim(&self, dim: usize) -> Self::Scalar {
289        self[dim]
290    }
291    fn dim_mut(&mut self, dim: usize) -> &mut Self::Scalar {
292        &mut self[dim]
293    }
294}
295
296macro_rules! dim_trait {
297    ($doc:literal, $trait:ident, $get:ident, $get_mut:ident, $set:ident, $index:literal) => {
298        #[doc = $doc]
299        pub trait $trait: VecN {
300            /// Get the value of the dimension
301            fn $get(&self) -> Self::Scalar;
302            /// Get a mutable reference to the value of the dimension
303            fn $get_mut(&mut self) -> &mut Self::Scalar;
304            /// Set the value of the dimension
305            fn $set(&mut self, x: Self::Scalar) {
306                *self.$get_mut() = x;
307            }
308        }
309
310        impl<V> $trait for V
311        where
312            V: VecN,
313        {
314            fn $get(&self) -> Self::Scalar {
315                self.dim($index)
316            }
317            fn $get_mut(&mut self) -> &mut Self::Scalar {
318                self.dim_mut($index)
319            }
320        }
321    };
322}
323
324#[rustfmt::skip] dim_trait!("Trait for vectors with an X dimension", XVec, x, x_mut, set_x, 0);
325#[rustfmt::skip] dim_trait!("Trait for vectors with a Y dimension", YVec, y, y_mut, set_y, 1);
326#[rustfmt::skip] dim_trait!("Trait for vectors with a Z dimension", ZVec, z, z_mut, set_z, 2);
327#[rustfmt::skip] dim_trait!("Trait for vectors with a W dimension", WVec, w, w_mut, set_w, 3);