fj_math/
vector.rs

1use std::{fmt, ops};
2
3use super::{
4    coordinates::{Uv, Xyz, T},
5    Scalar,
6};
7
8/// An n-dimensional vector
9///
10/// The dimensionality of the vector is defined by the const generic `D`
11/// parameter.
12#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
13#[repr(C)]
14pub struct Vector<const D: usize> {
15    /// The vector components
16    pub components: [Scalar; D],
17}
18
19impl<const D: usize> Vector<D> {
20    /// Create a vector whose components are all equal
21    pub fn from_component(scalar: impl Into<Scalar>) -> Self {
22        Self {
23            components: [scalar.into(); D],
24        }
25    }
26
27    /// Convert the vector into an nalgebra vector
28    pub fn to_na(self) -> nalgebra::SVector<f64, D> {
29        self.components.map(Scalar::into_f64).into()
30    }
31
32    /// Convert to a 1-dimensional vector
33    pub fn to_t(self) -> Vector<1> {
34        Vector {
35            components: [self.components[0]],
36        }
37    }
38
39    /// Convert the vector into a 2-dimensional vector
40    ///
41    /// If the vector is 0-, or 1-dimensional, the missing components will be
42    /// initialized to zero.
43    ///
44    /// If the vector has higher dimensionality than two, the superfluous
45    /// components will be discarded.
46    pub fn to_uv(self) -> Vector<2> {
47        let zero = Scalar::ZERO;
48
49        let components = match self.components.as_slice() {
50            [] => [zero, zero],
51            &[t] => [t, zero],
52            &[u, v, ..] => [u, v],
53        };
54
55        Vector { components }
56    }
57
58    /// Convert the vector into a 3-dimensional vector
59    ///
60    /// If the vector is 0-, 1-, or 2-dimensional, the missing components will
61    /// be initialized to zero.
62    ///
63    /// If the vector has higher dimensionality than three, the superfluous
64    /// components will be discarded.
65    pub fn to_xyz(self) -> Vector<3> {
66        let zero = Scalar::ZERO;
67
68        let components = match self.components.as_slice() {
69            [] => [zero, zero, zero],
70            &[t] => [t, zero, zero],
71            &[u, v] => [u, v, zero],
72            &[x, y, z, ..] => [x, y, z],
73        };
74
75        Vector { components }
76    }
77
78    /// Compute the magnitude of the vector
79    pub fn magnitude(&self) -> Scalar {
80        self.to_na().magnitude().into()
81    }
82
83    /// Compute a normalized version of the vector
84    pub fn normalize(&self) -> Self {
85        self.to_na().normalize().into()
86    }
87
88    /// Compute the dot product with another vector
89    pub fn dot(&self, other: &Self) -> Scalar {
90        self.to_na().dot(&other.to_na()).into()
91    }
92
93    /// Compute the scalar projection of this vector onto another
94    pub fn scalar_projection_onto(&self, other: &Self) -> Scalar {
95        if other.magnitude() == Scalar::ZERO {
96            return Scalar::ZERO;
97        }
98
99        self.dot(&other.normalize())
100    }
101}
102
103impl Vector<1> {
104    /// Construct a `Vector` that represents the t-axis
105    pub fn unit_t() -> Self {
106        Self::from([1.])
107    }
108}
109
110impl Vector<2> {
111    /// Construct a `Vector` that represents the u-axis
112    pub fn unit_u() -> Self {
113        Self::from([1., 0.])
114    }
115
116    /// Construct a `Vector` that represents the v-axis
117    pub fn unit_v() -> Self {
118        Self::from([0., 1.])
119    }
120
121    /// Compute the 2D cross product with another vector
122    pub fn cross2d(&self, other: &Self) -> Scalar {
123        (self.u * other.v) - (self.v * other.u)
124    }
125
126    /// Determine whether this vector is between two other vectors
127    pub fn is_between(&self, others: [impl Into<Self>; 2]) -> bool {
128        let [a, b] = others.map(Into::into);
129        a.cross2d(self) * b.cross2d(self) < Scalar::ZERO
130    }
131}
132
133impl Vector<3> {
134    /// Construct a `Vector` that represents the x-axis
135    pub fn unit_x() -> Self {
136        Self::from([1., 0., 0.])
137    }
138
139    /// Construct a `Vector` that represents the y-axis
140    pub fn unit_y() -> Self {
141        Self::from([0., 1., 0.])
142    }
143
144    /// Construct a `Vector` that represents the z-axis
145    pub fn unit_z() -> Self {
146        Self::from([0., 0., 1.])
147    }
148
149    /// Compute the cross product with another vector
150    pub fn cross(&self, other: &Self) -> Self {
151        self.to_na().cross(&other.to_na()).into()
152    }
153
154    /// Construct a new vector from this vector's x and y components
155    pub fn xy(&self) -> Vector<2> {
156        Vector::from([self.x, self.y])
157    }
158}
159
160impl ops::Deref for Vector<1> {
161    type Target = T;
162
163    fn deref(&self) -> &Self::Target {
164        let ptr = self.components.as_ptr() as *const Self::Target;
165
166        // This is sound. We've created this pointer from a valid instance, that
167        // has the same size and layout as the target.
168        unsafe { &*ptr }
169    }
170}
171
172impl ops::Deref for Vector<2> {
173    type Target = Uv;
174
175    fn deref(&self) -> &Self::Target {
176        let ptr = self.components.as_ptr() as *const Self::Target;
177
178        // This is sound. We've created this pointer from a valid instance, that
179        // has the same size and layout as the target.
180        unsafe { &*ptr }
181    }
182}
183
184impl ops::Deref for Vector<3> {
185    type Target = Xyz;
186
187    fn deref(&self) -> &Self::Target {
188        let ptr = self.components.as_ptr() as *const Self::Target;
189
190        // This is sound. We've created this pointer from a valid instance, that
191        // has the same size and layout as the target.
192        unsafe { &*ptr }
193    }
194}
195
196impl ops::DerefMut for Vector<1> {
197    fn deref_mut(&mut self) -> &mut Self::Target {
198        let ptr = self.components.as_mut_ptr() as *mut Self::Target;
199
200        // This is sound. We've created this pointer from a valid instance, that
201        // has the same size and layout as the target.
202        unsafe { &mut *ptr }
203    }
204}
205
206impl ops::DerefMut for Vector<2> {
207    fn deref_mut(&mut self) -> &mut Self::Target {
208        let ptr = self.components.as_mut_ptr() as *mut Self::Target;
209
210        // This is sound. We've created this pointer from a valid instance, that
211        // has the same size and layout as the target.
212        unsafe { &mut *ptr }
213    }
214}
215
216impl ops::DerefMut for Vector<3> {
217    fn deref_mut(&mut self) -> &mut Self::Target {
218        let ptr = self.components.as_mut_ptr() as *mut Self::Target;
219
220        // This is sound. We've created this pointer from a valid instance, that
221        // has the same size and layout as the target.
222        unsafe { &mut *ptr }
223    }
224}
225
226impl<const D: usize> Default for Vector<D> {
227    fn default() -> Self {
228        let components = [Scalar::default(); D];
229        Self { components }
230    }
231}
232
233impl<S: Into<Scalar>, const D: usize> From<[S; D]> for Vector<D> {
234    fn from(components: [S; D]) -> Self {
235        Self {
236            components: components.map(Into::into),
237        }
238    }
239}
240
241impl<const D: usize> From<nalgebra::SVector<f64, D>> for Vector<D> {
242    fn from(vector: nalgebra::SVector<f64, D>) -> Self {
243        let components: [f64; D] = vector.into();
244        Vector::from(components)
245    }
246}
247
248impl<const D: usize> From<Vector<D>> for [f32; D] {
249    fn from(vector: Vector<D>) -> Self {
250        vector.components.map(|scalar| scalar.into_f32())
251    }
252}
253
254impl<const D: usize> From<Vector<D>> for [f64; D] {
255    fn from(vector: Vector<D>) -> Self {
256        vector.components.map(|scalar| scalar.into_f64())
257    }
258}
259
260impl<const D: usize> From<Vector<D>> for [Scalar; D] {
261    fn from(vector: Vector<D>) -> Self {
262        vector.components
263    }
264}
265
266impl<const D: usize> From<Vector<D>> for nalgebra::SVector<f64, D> {
267    fn from(vector: Vector<D>) -> Self {
268        vector.to_na()
269    }
270}
271
272impl<const D: usize> ops::Neg for Vector<D> {
273    type Output = Self;
274
275    fn neg(self) -> Self::Output {
276        self.to_na().neg().into()
277    }
278}
279
280impl<V, const D: usize> ops::Add<V> for Vector<D>
281where
282    V: Into<Self>,
283{
284    type Output = Self;
285
286    fn add(self, rhs: V) -> Self::Output {
287        self.to_na().add(rhs.into().to_na()).into()
288    }
289}
290
291impl<V, const D: usize> ops::Sub<V> for Vector<D>
292where
293    V: Into<Self>,
294{
295    type Output = Self;
296
297    fn sub(self, rhs: V) -> Self::Output {
298        self.to_na().sub(rhs.into().to_na()).into()
299    }
300}
301
302impl<S, const D: usize> ops::Mul<S> for Vector<D>
303where
304    S: Into<Scalar>,
305{
306    type Output = Self;
307
308    fn mul(self, rhs: S) -> Self::Output {
309        self.to_na().mul(rhs.into().into_f64()).into()
310    }
311}
312
313impl<S, const D: usize> ops::MulAssign<S> for Vector<D>
314where
315    S: Into<Scalar>,
316{
317    fn mul_assign(&mut self, rhs: S) {
318        *self = *self * rhs;
319    }
320}
321
322impl<S, const D: usize> ops::Div<S> for Vector<D>
323where
324    S: Into<Scalar>,
325{
326    type Output = Self;
327
328    fn div(self, rhs: S) -> Self::Output {
329        self.to_na().div(rhs.into().into_f64()).into()
330    }
331}
332
333impl<const D: usize> fmt::Debug for Vector<D> {
334    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
335        self.components.fmt(f)
336    }
337}
338
339impl<const D: usize> approx::AbsDiffEq for Vector<D> {
340    type Epsilon = <Scalar as approx::AbsDiffEq>::Epsilon;
341
342    fn default_epsilon() -> Self::Epsilon {
343        Scalar::default_epsilon()
344    }
345
346    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
347        self.components.abs_diff_eq(&other.components, epsilon)
348    }
349}
350
351#[cfg(test)]
352mod tests {
353    use crate::{Scalar, Vector};
354
355    #[test]
356    fn to_uv() {
357        let d0: [f64; 0] = [];
358        assert_eq!(Vector::from(d0).to_uv(), Vector::from([0., 0.]));
359        assert_eq!(Vector::from([1.]).to_uv(), Vector::from([1., 0.]));
360        assert_eq!(Vector::from([1., 2.]).to_uv(), Vector::from([1., 2.]));
361        assert_eq!(Vector::from([1., 2., 3.]).to_uv(), Vector::from([1., 2.]),);
362    }
363
364    #[test]
365    fn to_xyz() {
366        let d0: [f64; 0] = [];
367        assert_eq!(Vector::from(d0).to_xyz(), Vector::from([0., 0., 0.]));
368        assert_eq!(Vector::from([1.]).to_xyz(), Vector::from([1., 0., 0.]));
369        assert_eq!(Vector::from([1., 2.]).to_xyz(), Vector::from([1., 2., 0.]));
370        assert_eq!(
371            Vector::from([1., 2., 3.]).to_xyz(),
372            Vector::from([1., 2., 3.]),
373        );
374    }
375
376    #[test]
377    fn scalar_projection_onto() {
378        let v = Vector::from([1., 2., 3.]);
379
380        let x = Vector::unit_x() * 3.;
381        let y = Vector::unit_y() * 2.;
382        let z = Vector::unit_z() * 1.;
383
384        assert_eq!(v.scalar_projection_onto(&x), Scalar::from(1.));
385        assert_eq!(v.scalar_projection_onto(&y), Scalar::from(2.));
386        assert_eq!(v.scalar_projection_onto(&z), Scalar::from(3.));
387
388        // Zero-length vectors should be handled as well.
389        assert_eq!(
390            Vector::unit_x()
391                .scalar_projection_onto(&Vector::from([0., 0., 0.])),
392            Scalar::ZERO
393        );
394    }
395
396    #[test]
397    fn is_between() {
398        let v = Vector::from([1., 1.]);
399
400        assert!(v.is_between([[1., 0.], [0., 1.]]));
401        assert!(!v.is_between([[1., 0.], [0., -1.]]));
402        assert!(!v.is_between([[-1., 0.], [0., 1.]]));
403    }
404}