pix_engine/
vector.rs

1//! A [Euclidean] `Vector` in N-dimensional space.
2//!
3//! Each [Vector] represents a N-dimensional [Euclidean] (or geometric) vector with a magnitude
4//! and a direction. The [Vector] `struct`, however, contains N values for each dimensional
5//! coordinate. The magnitude and direction are retrieved with the [`Vector::mag`] and
6//! [`Vector::heading`] methods.
7//!
8//! Some example uses of a [Vector] include modeling a position, velocity, or acceleration of an
9//! object or particle in 2D or 3D space.
10//!
11//! # Examples
12//!
13//! You can create a [Vector] using [`Vector::new`]:
14//!
15//! ```
16//! # use pix_engine::prelude::*;
17//! let v = Vector::new([10.0, 20.0, 15.0]);
18//! ```
19//! ...or by using the [vector!] macro:
20//!
21//! ```
22//! # use pix_engine::prelude::*;
23//! let v: Vector<f64, 3> = vector!(); // vector at the origin (0, 0, 0) with no direction or magnitude
24//! assert_eq!(v.coords(), [0.0, 0.0, 0.0]);
25//!
26//! let v = vector!(5.0); // 1D vector on the x-axis with magnitude 5
27//! assert_eq!(v.coords(), [5.0]);
28//!
29//! let v = vector!(5.0, 10.0); // 2D vector in the x/y-plane
30//! assert_eq!(v.coords(), [5.0, 10.0]);
31//!
32//! let v = vector!(-1.5, 3.0, 2.2); // 3D vector
33//! assert_eq!(v.coords(), [-1.5, 3.0, 2.2]);
34//! ```
35//!
36//! You can also create random `Vector`s using [`Vector::random`] which create unit vectors with
37//! magnitudes in the range `-1.0..=1.0`.
38//!
39//! ```
40//! use pix_engine::prelude::*;
41//!
42//! let v: Vector<f64, 1> = Vector::random();
43//! // `v.coords()` will return something like:
44//! // [-0.9993116191591512, 0.03709835324533284, 0.0]
45//! assert!(v.x() >= -1.0 && v.x() <= 1.0);
46//!
47//! let v: Vector<f64, 2> = Vector::random();
48//! // `v.coords()` will return something like:
49//! // [-0.9993116191591512, 0.03709835324533284, 0.0]
50//! assert!(v.x() >= -1.0 && v.x() <= 1.0);
51//! assert!(v.y() >= -1.0 && v.y() <= 1.0);
52//!
53//! let v: Vector<f64, 3> = Vector::random();
54//! // `v.coords()` will return something like:
55//! // [-0.40038099206441835, 0.8985763512414204, 0.17959844705110184]
56//! assert!(v.x() >= -1.0 && v.x() <= 1.0);
57//! assert!(v.y() >= -1.0 && v.y() <= 1.0);
58//! assert!(v.z() >= -1.0 && v.z() <= 1.0);
59//! ```
60//!
61//! [Euclidean]: https://en.wikipedia.org/wiki/Euclidean_vector
62
63use crate::prelude::*;
64#[cfg(feature = "serde")]
65use crate::serialize::arrays;
66use num_traits::Signed;
67use rand::distributions::uniform::SampleUniform;
68#[cfg(feature = "serde")]
69use serde::{de::DeserializeOwned, Deserialize, Serialize};
70use std::{fmt, ops::MulAssign};
71
72/// A [Euclidean] `Vector` in N-dimensional space.
73///
74/// Also known as a geometric vector. A `Vector` has both a magnitude and a direction. The [Vector]
75/// struct, however, contains N values for each dimensional coordinate.
76///
77/// The magnitude and direction are retrieved with the [mag] and [heading] methods.
78///
79/// Some example uses of a [Vector] include modeling a position, velocity, or acceleration of an
80/// object or particle.
81///
82/// [Vector]s can be combined using [vector math][vecmath], so for example two [Vector]s can be added together
83/// to form a new [Vector] using `let v3 = v1 + v2` or you can add one [Vector] to another by calling
84/// `v1 += v2`.
85///
86/// Please see the [module-level documentation] for examples.
87///
88/// [Euclidean]: https://en.wikipedia.org/wiki/Euclidean_vector
89/// [mag]: Vector::mag
90/// [heading]: Vector::heading
91/// [vecmath]: https://en.wikipedia.org/wiki/Vector_(mathematics_and_p.y()sics)
92/// [module-level documentation]: mod@crate::vector
93#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
94#[repr(transparent)]
95#[must_use]
96#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
97#[cfg_attr(feature = "serde", serde(bound = "T: Serialize + DeserializeOwned"))]
98pub struct Vector<T = f64, const N: usize = 2>(
99    #[cfg_attr(feature = "serde", serde(with = "arrays"))] pub(crate) [T; N],
100);
101
102/// Constructs a [Vector].
103///
104/// # Examples
105///
106/// ```
107/// # use pix_engine::prelude::*;
108/// let v: Vector<f64, 3> = vector!();
109/// assert_eq!(v.coords(), [0.0, 0.0, 0.0]);
110///
111/// let v = vector!(1.0);
112/// assert_eq!(v.coords(), [1.0]);
113///
114/// let v = vector!(1.0, 2.0);
115/// assert_eq!(v.coords(), [1.0, 2.0]);
116///
117/// let v = vector!(1.0, -2.0, 1.0);
118/// assert_eq!(v.coords(), [1.0, -2.0, 1.0]);
119/// ```
120#[macro_export]
121macro_rules! vector {
122    () => {
123        $crate::prelude::Vector::origin()
124    };
125    ($x:expr) => {
126        $crate::prelude::Vector::from_x($x)
127    };
128    ($x:expr, $y:expr$(,)?) => {
129        $crate::prelude::Vector::from_xy($x, $y)
130    };
131    ($x:expr, $y:expr, $z:expr$(,)?) => {
132        $crate::prelude::Vector::from_xyz($x, $y, $z)
133    };
134}
135
136impl<T, const N: usize> Vector<T, N> {
137    /// Constructs a `Vector` from `[T; N]` coordinates.
138    ///
139    /// # Examples
140    ///
141    /// ```
142    /// # use pix_engine::prelude::*;
143    /// let v = Vector::new([2.1]);
144    /// assert_eq!(v.coords(), [2.1]);
145    ///
146    /// let v = Vector::new([2.1, 3.5]);
147    /// assert_eq!(v.coords(), [2.1, 3.5]);
148    ///
149    /// let v = Vector::new([2.1, 3.5, 1.0]);
150    /// assert_eq!(v.coords(), [2.1, 3.5, 1.0]);
151    /// ```
152    #[inline]
153    pub const fn new(coords: [T; N]) -> Self {
154        Self(coords)
155    }
156
157    /// Constructs a `Vector` at the origin.
158    ///
159    /// # Example
160    ///
161    /// ```
162    /// # use pix_engine::prelude::*;
163    /// let v: Vector<f64, 3> = Vector::origin();
164    /// assert_eq!(v.coords(), [0.0, 0.0, 0.0]);
165    /// ```
166    #[inline]
167    pub fn origin() -> Self
168    where
169        T: Default,
170    {
171        Self::new([(); N].map(|_| T::default()))
172    }
173}
174
175impl<T> Vector<T, 1> {
176    /// Constructs a `Vector` from an individual x coordinate.
177    #[inline]
178    pub const fn from_x(x: T) -> Self {
179        Self([x])
180    }
181}
182
183impl<T> Vector<T> {
184    /// Constructs a `Vector` from individual x/y coordinates.
185    #[inline]
186    pub const fn from_xy(x: T, y: T) -> Self {
187        Self([x, y])
188    }
189}
190
191impl<T> Vector<T, 3> {
192    /// Constructs a `Vector` from individual x/y/z coordinates.
193    #[inline]
194    pub const fn from_xyz(x: T, y: T, z: T) -> Self {
195        Self([x, y, z])
196    }
197}
198
199impl<T: Num + Float> Vector<T> {
200    /// Constructs a `Vector` from another `Vector`, rotated by an `angle`.
201    ///
202    /// # Example
203    ///
204    /// ```
205    /// # use pix_engine::prelude::*;
206    /// use pix_engine::math::FRAC_PI_2;
207    /// let v1 = Vector::new([10.0, 20.0]);
208    /// let v2 = Vector::rotated(v1, FRAC_PI_2);
209    /// assert!(v2.approx_eq(vector![-20.0, 10.0], 1e-4));
210    /// ```
211    pub fn rotated<V>(v: V, angle: T) -> Self
212    where
213        V: Into<Vector<T>>,
214    {
215        let mut v = v.into();
216        v.rotate(angle);
217        v
218    }
219
220    /// Constructs a 2D unit `Vector` in the XY plane from a given angle. Angle is given as
221    /// radians and is unaffected by [`AngleMode`].
222    ///
223    /// # Example
224    ///
225    /// ```
226    /// # use pix_engine::prelude::*;
227    /// use pix_engine::math::FRAC_PI_4;
228    /// let v = Vector::from_angle(FRAC_PI_4, 15.0);
229    /// assert!(v.approx_eq(vector!(10.6066, 10.6066), 1e-4));
230    /// ```
231    pub fn from_angle(angle: T, length: T) -> Self {
232        let (sin, cos) = angle.sin_cos();
233        Self::new([length * cos, length * sin])
234    }
235
236    /// Returns the 2D angular direction of the `Vector`.
237    ///
238    /// # Example
239    ///
240    /// ```
241    /// # use pix_engine::prelude::*;
242    /// let v = vector!(10.0, 10.0);
243    /// let heading: f64 = v.heading();
244    /// assert_eq!(heading.to_degrees(), 45.0);
245    /// ```
246    pub fn heading(&self) -> T {
247        self.y().atan2(self.x())
248    }
249
250    /// Rotate a 2D `Vector` by an angle in radians, magnitude remains the same. Unaffected by
251    /// [`AngleMode`].
252    ///
253    /// # Example
254    ///
255    /// ```
256    /// # use pix_engine::prelude::*;
257    /// use pix_engine::math::FRAC_PI_2;
258    /// let mut v = vector!(10.0, 20.0);
259    /// v.rotate(FRAC_PI_2);
260    /// assert!(v.approx_eq(vector![-20.0, 10.0], 1e-4));
261    /// ```
262    pub fn rotate(&mut self, angle: T) {
263        let new_heading = self.heading() + angle;
264        let mag = self.mag();
265        let (sin, cos) = new_heading.sin_cos();
266        self.set_x(cos * mag);
267        self.set_y(sin * mag);
268    }
269}
270
271impl<T: Num + Float> Vector<T, 3> {
272    /// Returns the [cross product](https://en.wikipedia.org/wiki/Cross_product) between two
273    /// `Vector`s. Only defined for 3D `Vector`s.
274    ///
275    /// # Example
276    ///
277    /// ```
278    /// # use pix_engine::prelude::*;
279    /// let v1 = vector!(1.0, 2.0, 3.0);
280    /// let v2 = vector!(1.0, 2.0, 3.0);
281    /// let cross = v1.cross(v2);
282    /// assert_eq!(cross.coords(), [0.0, 0.0, 0.0]);
283    /// ```
284    pub fn cross<V>(&self, v: V) -> Self
285    where
286        V: Into<Vector<T, 3>>,
287    {
288        let v = v.into();
289        Self::new([
290            self.y() * v.z() - self.z() * v.y(),
291            self.z() * v.x() - self.x() * v.z(),
292            self.x() * v.y() - self.y() * v.x(),
293        ])
294    }
295
296    /// Returns the angle between two 3D `Vector`s in radians.
297    ///
298    /// # Example
299    ///
300    /// ```
301    /// # use pix_engine::prelude::*;
302    /// let v1 = vector!(1.0, 0.0, 0.0);
303    /// let v2 = vector!(0.0, 1.0, 0.0);
304    /// let angle = v1.angle_between(v2);
305    /// assert_eq!(angle, std::f64::consts::FRAC_PI_2);
306    /// ```
307    pub fn angle_between<V>(&self, v: V) -> T
308    where
309        V: Into<Vector<T, 3>>,
310    {
311        let v = v.into();
312        // This should range from -1.0 to 1.0, inclusive but could possibly land outside this range
313        // due to floating-point rounding, so we'll need to clamp it to the correct range.
314        let dot_mag_product =
315            num_traits::clamp(self.dot(v) / (self.mag() * v.mag()), -T::one(), T::one());
316        dot_mag_product.acos() * self.cross(v).z().signum()
317    }
318}
319
320impl<T: Copy, const N: usize> Vector<T, N> {
321    /// Constructs a `Vector` from a [Point].
322    ///
323    /// # Example
324    ///
325    /// ```
326    /// # use pix_engine::prelude::*;
327    /// let p = point!(1.0, 2.0);
328    /// let v = Vector::from_point(p);
329    /// assert_eq!(v.coords(), [1.0, 2.0]);
330    /// ```
331    #[inline]
332    pub fn from_point(p: Point<T, N>) -> Self {
333        Self::new(p.coords())
334    }
335
336    /// Returns the `x-coordinate`.
337    ///
338    /// # Panics
339    ///
340    /// If `Vector` has zero dimensions.
341    ///
342    /// # Example
343    ///
344    /// ```
345    /// # use pix_engine::prelude::*;
346    /// let v = vector!(1.0, 2.0);
347    /// assert_eq!(v.x(), 1.0);
348    /// ```
349    #[inline]
350    pub fn x(&self) -> T {
351        self.0[0]
352    }
353
354    /// Sets the `x-magnitude`.
355    ///
356    /// # Panics
357    ///
358    /// If `Vector` has zero dimensions.
359    ///
360    /// # Example
361    ///
362    /// ```
363    /// # use pix_engine::prelude::*;
364    /// let mut v = vector!(1.0, 2.0);
365    /// v.set_x(3.0);
366    /// assert_eq!(v.coords(), [3.0, 2.0]);
367    /// ```
368    #[inline]
369    pub fn set_x(&mut self, x: T) {
370        self.0[0] = x;
371    }
372
373    /// Returns the `y-magnitude`.
374    ///
375    /// # Panics
376    ///
377    /// If `Vector` has less than 2 dimensions.
378    ///
379    /// # Example
380    ///
381    /// ```
382    /// # use pix_engine::prelude::*;
383    /// let v = vector!(1.0, 2.0);
384    /// assert_eq!(v.y(), 2.0);
385    /// ```
386    #[inline]
387    pub fn y(&self) -> T {
388        self.0[1]
389    }
390
391    /// Sets the `y-magnitude`.
392    ///
393    /// # Panics
394    ///
395    /// If `Vector` has less than 2 dimensions.
396    ///
397    /// # Example
398    ///
399    /// ```
400    /// # use pix_engine::prelude::*;
401    /// let mut v = vector!(1.0, 2.0);
402    /// v.set_y(3.0);
403    /// assert_eq!(v.coords(), [1.0, 3.0]);
404    /// ```
405    #[inline]
406    pub fn set_y(&mut self, y: T) {
407        self.0[1] = y;
408    }
409
410    /// Returns the `z-magnitude`.
411    ///
412    /// # Panics
413    ///
414    /// If `Vector` has less than 3 dimensions.
415    ///
416    /// # Example
417    ///
418    /// ```
419    /// # use pix_engine::prelude::*;
420    /// let v = vector!(1.0, 2.0, 2.5);
421    /// assert_eq!(v.z(), 2.5);
422    /// ```
423    #[inline]
424    pub fn z(&self) -> T {
425        self.0[2]
426    }
427
428    /// Sets the `z-magnitude`.
429    ///
430    /// # Panics
431    ///
432    /// If `Vector` has less than 3 dimensions.
433    ///
434    /// # Example
435    ///
436    /// ```
437    /// # use pix_engine::prelude::*;
438    /// let mut v = vector!(1.0, 2.0, 1.0);
439    /// v.set_z(3.0);
440    /// assert_eq!(v.coords(), [1.0, 2.0, 3.0]);
441    /// ```
442    #[inline]
443    pub fn set_z(&mut self, z: T) {
444        self.0[2] = z;
445    }
446
447    /// Get `Vector` coordinates as `[T; N]`.
448    ///
449    /// # Example
450    ///
451    /// ```
452    /// # use pix_engine::prelude::*;
453    /// let v = vector!(2.0, 1.0, 3.0);
454    /// assert_eq!(v.coords(), [2.0, 1.0, 3.0]);
455    /// ```
456    #[inline]
457    pub fn coords(&self) -> [T; N] {
458        self.0
459    }
460
461    /// Get `Vector` coordinates as a mutable slice `&[T; N]`.
462    ///
463    /// # Example
464    ///
465    /// ```
466    /// # use pix_engine::prelude::*;
467    /// let mut vector = vector!(2.0, 1.0, 3.0);
468    /// for v in vector.coords_mut() {
469    ///     *v *= 2.0;
470    /// }
471    /// assert_eq!(vector.coords(), [4.0, 2.0, 6.0]);
472    /// ```
473    #[inline]
474    pub fn coords_mut(&mut self) -> &mut [T; N] {
475        &mut self.0
476    }
477
478    /// Returns `Vector` as a [Vec].
479    ///
480    /// # Example
481    ///
482    /// ```
483    /// # use pix_engine::prelude::*;
484    /// let v = vector!(1.0, 1.0, 0.0);
485    /// assert_eq!(v.to_vec(), vec![1.0, 1.0, 0.0]);
486    /// ```
487    #[inline]
488    pub fn to_vec(self) -> Vec<T> {
489        self.0.to_vec()
490    }
491}
492
493impl<T: Num, const N: usize> Vector<T, N> {
494    /// Constructs a `Vector` by shifting coordinates by given amount.
495    ///
496    /// # Examples
497    ///
498    /// ```
499    /// # use pix_engine::prelude::*;
500    /// let mut v = vector!(2.0, 3.0, 1.5);
501    /// v.offset([2.0, -4.0]);
502    /// assert_eq!(v.coords(), [4.0, -1.0, 1.5]);
503    /// ```
504    #[inline]
505    pub fn offset<V, const M: usize>(&mut self, offsets: V)
506    where
507        V: Into<Vector<T, M>>,
508    {
509        let offsets = offsets.into();
510        for (v, o) in self.iter_mut().zip(offsets) {
511            *v += o;
512        }
513    }
514
515    /// Offsets the `x-coordinate` of the point by a given amount.
516    ///
517    /// # Panics
518    ///
519    /// If `Point` has zero dimensions.
520    #[inline]
521    pub fn offset_x(&mut self, offset: T) {
522        self.0[0] += offset;
523    }
524
525    /// Offsets the `y-coordinate` of the point by a given amount.
526    ///
527    /// # Panics
528    ///
529    /// If `Vector` has less than 2 dimensions.
530    #[inline]
531    pub fn offset_y(&mut self, offset: T) {
532        self.0[1] += offset;
533    }
534
535    /// Offsets the `z-coordinate` of the point by a given amount.
536    ///
537    /// # Panics
538    ///
539    /// If `Vector` has less than 3 dimensions.
540    #[inline]
541    pub fn offset_z(&mut self, offset: T) {
542        self.0[2] += offset;
543    }
544
545    /// Constructs a `Vector` by multiplying it by the given scale factor.
546    ///
547    /// # Examples
548    ///
549    /// ```
550    /// # use pix_engine::prelude::*;
551    /// let mut v = vector!(2.0, 3.0, 1.5);
552    /// v.scale(2.0);
553    /// assert_eq!(v.coords(), [4.0, 6.0, 3.0]);
554    /// ```
555    pub fn scale<U>(&mut self, s: U)
556    where
557        T: MulAssign<U>,
558        U: Num,
559    {
560        *self *= s;
561    }
562
563    /// Wraps `Vector` around the given `[T; N]`, and size (radius).
564    ///
565    /// # Examples
566    ///
567    /// ```
568    /// # use pix_engine::prelude::*;
569    /// let mut v = vector!(200.0, 300.0);
570    /// v.wrap([150.0, 400.0], 10.0);
571    /// assert_eq!(v.coords(), [-10.0, 300.0]);
572    ///
573    /// let mut v = vector!(-100.0, 300.0);
574    /// v.wrap([150.0, 400.0], 10.0);
575    /// assert_eq!(v.coords(), [160.0, 300.0]);
576    /// ```
577    pub fn wrap(&mut self, wrap: [T; N], size: T)
578    where
579        T: Signed,
580    {
581        for (v, w) in self.iter_mut().zip(wrap) {
582            let w = w + size;
583            if *v > w {
584                *v = -size;
585            } else if *v < -size {
586                *v = w;
587            }
588        }
589    }
590
591    /// Constructs a random unit `Vector` in 1D space.
592    ///
593    /// # Example
594    ///
595    /// ```
596    /// # use pix_engine::prelude::*;
597    /// let v: Vector<f64, 3> = Vector::random();
598    /// assert!(v.x() > -1.0 && v.x() < 1.0);
599    /// assert!(v.y() > -1.0 && v.y() < 1.0);
600    /// assert!(v.z() > -1.0 && v.z() < 1.0);
601    ///
602    /// // May make v's (x, y, z) values something like:
603    /// // (0.61554617, 0.0, 0.0) or
604    /// // (-0.4695841, 0.0, 0.0) or
605    /// // (0.6091097, 0.0, 0.0)
606    /// ```
607    pub fn random() -> Self
608    where
609        T: SampleUniform,
610    {
611        let mut coords = [T::zero(); N];
612        for coord in &mut coords {
613            *coord = random!(T::one());
614        }
615        Self::new(coords)
616    }
617}
618
619impl<T: Num + Float, const N: usize> Vector<T, N> {
620    /// Constructs a `Vector` from a reflection about a normal to a line in 2D space or a plane in 3D
621    /// space.
622    ///
623    /// # Example
624    ///
625    /// ```
626    /// # use pix_engine::prelude::*;
627    /// let v1 = Vector::new([1.0, 1.0, 0.0]);
628    /// let normal = Vector::new([0.0, 1.0, 0.0]);
629    /// let v2 = Vector::reflection(v1, normal);
630    /// assert_eq!(v2.coords(), [-1.0, 1.0, 0.0]);
631    /// ```
632    pub fn reflection<V>(v: V, normal: V) -> Self
633    where
634        V: Into<Vector<T, N>>,
635    {
636        let mut v = v.into();
637        v.reflect(normal);
638        v
639    }
640
641    /// Constructs a unit `Vector` of length `1` from another `Vector`.
642    ///
643    /// # Example
644    ///
645    /// ```
646    /// # use pix_engine::prelude::*;
647    /// let v1 = Vector::new([0.0, 5.0, 0.0]);
648    /// let v2 = Vector::normalized(v1);
649    /// assert_eq!(v2.coords(), [0.0, 1.0, 0.0]);
650    /// ```
651    pub fn normalized<V>(v: V) -> Self
652    where
653        V: Into<Vector<T, N>>,
654    {
655        let mut v = v.into();
656        v.normalize();
657        v
658    }
659
660    /// Returns the magnitude (length) of the `Vector`.
661    ///
662    /// The formula used for 2D is `sqrt(x*x + y*y)`.
663    /// The formula used for 3D is `sqrt(x*x + y*y + z*z)`.
664    ///
665    /// # Example
666    ///
667    /// ```
668    /// # use pix_engine::prelude::*;
669    /// let v = vector!(1.0, 2.0, 3.0);
670    /// let abs_difference = (v.mag() as f64 - 3.7416).abs();
671    /// assert!(abs_difference <= 1e-4);
672    /// ```
673    pub fn mag(&self) -> T {
674        self.mag_sq().sqrt()
675    }
676
677    /// Returns the squared magnitude (length) of the `Vector`. This is faster if the real length
678    /// is not required in the case of comparing vectors.
679    ///
680    /// The formula used for 2D is `x*x + y*y`.
681    /// The formula used for 3D is `x*x + y*y + z*z`.
682    ///
683    /// # Example
684    ///
685    /// ```
686    /// # use pix_engine::prelude::*;
687    /// let v = vector!(1.0, 2.0, 3.0);
688    /// assert_eq!(v.mag_sq(), 14.0);
689    /// ```
690    pub fn mag_sq(&self) -> T {
691        let mut sum = T::zero();
692        for &v in self.iter() {
693            sum += v * v;
694        }
695        sum
696    }
697
698    /// Returns the [dot product](https://en.wikipedia.org/wiki/Dot_product) betwen two `Vector`s.
699    ///
700    /// # Example
701    ///
702    /// ```
703    /// # use pix_engine::prelude::*;
704    /// let v1 = vector!(1.0, 2.0, 3.0);
705    /// let v2 = vector!(2.0, 3.0, 4.0);
706    /// let dot_product = v1.dot(v2);
707    /// assert_eq!(dot_product, 20.0);
708    /// ```
709    pub fn dot<V>(&self, o: V) -> T
710    where
711        V: Into<Vector<T, N>>,
712    {
713        let o = o.into();
714        let mut sum = T::zero();
715        for (&v, o) in self.iter().zip(o) {
716            sum += v * o;
717        }
718        sum
719    }
720
721    /// Reflect `Vector` about a normal to a line in 2D space or a plane in 3D space.
722    ///
723    /// # Example
724    ///
725    /// ```
726    /// # use pix_engine::prelude::*;
727    /// let mut v = vector!(4.0, 6.0); // Vector heading right and down
728    /// let n = vector!(0.0, 1.0); // Surface normal facing up
729    /// v.reflect(n); // Reflect about the surface normal (e.g. the x-axis)
730    /// assert_eq!(v.x(), -4.0);
731    /// assert_eq!(v.y(), 6.0);
732    /// ```
733    pub fn reflect<V>(&mut self, normal: V)
734    where
735        V: Into<Vector<T, N>>,
736    {
737        let normal = Self::normalized(normal);
738        *self = normal * ((T::one() + T::one()) * self.dot(normal)) - *self;
739    }
740
741    /// Set the magnitude (length) of the `Vector`.
742    ///
743    /// # Examples
744    ///
745    /// ```
746    /// # use pix_engine::prelude::*;
747    /// let mut v = vector!(10.0, 20.0, 2.0);
748    /// v.set_mag(10.0);
749    /// assert!(v.approx_eq(vector![4.4543, 8.9087, 0.8908], 1e-4));
750    /// ```
751    pub fn set_mag(&mut self, mag: T) {
752        self.normalize();
753        *self *= mag;
754    }
755
756    /// Returns the Euclidean distance between two `Vector`s.
757    ///
758    /// # Example
759    ///
760    /// ```
761    /// # use pix_engine::prelude::*;
762    /// let v1 = vector!(1.0, 0.0, 0.0);
763    /// let v2 = vector!(0.0, 1.0, 0.0);
764    /// let dist = v1.dist(v2);
765    /// let abs_difference: f64 = (dist - std::f64::consts::SQRT_2).abs();
766    /// assert!(abs_difference <= 1e-4);
767    /// ```
768    pub fn dist<V>(&self, v: V) -> T
769    where
770        V: Into<Vector<T, N>>,
771    {
772        (*self - v.into()).mag()
773    }
774
775    /// Normalize the `Vector` to length `1` making it a unit vector.
776    ///
777    /// # Example
778    ///
779    /// ```
780    /// # use pix_engine::prelude::*;
781    /// let mut v = vector!(10.0, 20.0, 2.0);
782    /// v.normalize();
783    /// assert!(v.approx_eq(vector!(0.4454, 0.8908, 0.0890), 1e-4));
784    /// ```
785    pub fn normalize(&mut self) {
786        let len = self.mag();
787        if len != T::zero() {
788            // Multiply by the reciprocol so we don't duplicate a div by zero check
789            *self *= len.recip();
790        }
791    }
792
793    /// Clamp the magnitude (length) of `Vector` to the value given by `max`.
794    ///
795    /// # Example
796    ///
797    /// ```
798    /// # use pix_engine::prelude::*;
799    /// let mut v = vector!(10.0, 20.0, 2.0);
800    /// v.limit(5.0);
801    /// assert!(v.approx_eq(vector!(2.2271, 4.4543,  0.4454), 1e-4));
802    /// ```
803    pub fn limit(&mut self, max: T) {
804        let mag_sq = self.mag_sq();
805        if mag_sq > max * max {
806            *self /= mag_sq.sqrt();
807            *self *= max;
808        }
809    }
810
811    /// Constructs a `Vector` by linear interpolating between two `Vector`s by a given amount
812    /// between `0.0` and `1.0`.
813    ///
814    /// # Example
815    ///
816    /// ```
817    /// # use pix_engine::prelude::*;
818    /// let v1 = vector!(1.0, 1.0, 0.0);
819    /// let v2 = vector!(3.0, 3.0, 0.0);
820    /// let v3 = v1.lerp(v2, 0.5);
821    /// assert_eq!(v3.coords(), [2.0, 2.0, 0.0]);
822    /// ```
823    pub fn lerp<V>(&self, o: V, amt: T) -> Self
824    where
825        V: Into<Vector<T, N>>,
826    {
827        let o = o.into();
828        let lerp = |start, stop, amt| amt * (stop - start) + start;
829        let amt = num_traits::clamp(amt, T::zero(), T::one());
830        let mut coords = [T::zero(); N];
831        for ((c, &v), o) in coords.iter_mut().zip(self.iter()).zip(o) {
832            *c = lerp(v, o, amt);
833        }
834        Self::new(coords)
835    }
836
837    /// Returns whether two `Vector`s are approximately equal.
838    ///
839    /// # Example
840    ///
841    /// ```
842    /// # use pix_engine::prelude::*;
843    /// let v1 = vector!(10.0, 20.0, 2.0);
844    /// let v2 = vector!(10.0001, 20.0, 2.0);
845    /// assert!(v1.approx_eq(v2, 1e-3));
846    /// ```
847    pub fn approx_eq<V>(&self, other: V, epsilon: T) -> bool
848    where
849        V: Into<Vector<T, N>>,
850    {
851        let other = other.into();
852        let mut approx_eq = true;
853        for (&v, o) in self.iter().zip(other) {
854            approx_eq &= (v - o).abs() < epsilon;
855        }
856        approx_eq
857    }
858}
859
860impl<T: Default, const N: usize> Default for Vector<T, N> {
861    /// Return default `Vector` as origin.
862    fn default() -> Self {
863        Self::origin()
864    }
865}
866
867impl<T, const N: usize> fmt::Display for Vector<T, N>
868where
869    [T; N]: fmt::Debug,
870{
871    /// Display [Vector] as a string of coordinates.
872    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
873        write!(f, "{:?}", self.0)
874    }
875}
876
877impl<T: Copy, const N: usize> From<Point<T, N>> for Vector<T, N> {
878    fn from(p: Point<T, N>) -> Self {
879        Self::from_point(p)
880    }
881}
882
883impl<T: Copy, const N: usize> From<&Point<T, N>> for Vector<T, N> {
884    fn from(p: &Point<T, N>) -> Self {
885        Self::from_point(*p)
886    }
887}
888
889impl<T: Copy, const N: usize> From<Vector<T, N>> for Point<T, N> {
890    fn from(v: Vector<T, N>) -> Self {
891        Self::from_vector(v)
892    }
893}
894
895impl<T: Copy, const N: usize> From<&Vector<T, N>> for Point<T, N> {
896    fn from(v: &Vector<T, N>) -> Self {
897        Self::from_vector(*v)
898    }
899}