melvin_ob/util/math/
vec2d.rs

1use fixed::prelude::{FromFixed, ToFixed};
2use fixed::types::{I32F32, I64F64, I96F32};
3use fixed::{
4    traits::{Fixed, FixedSigned},
5    types::I32F0,
6};
7use num::traits::{Num, NumAssignOps};
8use std::{
9    cmp::Ordering,
10    fmt::Display,
11    ops::{Add, Deref, Div, Mul, Rem, Sub},
12};
13use strum_macros::Display;
14
15/// A 2D vector generic over any numeric type.
16///
17/// This struct represents a 2D point or vector in space and provides common
18/// mathematical operations such as addition, normalization, rotation, and distance calculations.
19///
20/// # Type Parameters
21/// * `T` - The functionality for the vector depends on traits implemented by `T`.
22#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, serde::Serialize, serde::Deserialize)]
23pub struct Vec2D<T> {
24    /// The x-component of the vector.
25    x: T,
26    /// The y-component of the vector.
27    y: T,
28}
29
30#[derive(Debug, Copy, Clone, Display)]
31pub enum VecAxis {
32    X,
33    Y,
34}
35
36/// A 2D vector wrapper with fixed-size wrapping capabilities.
37///
38/// This struct is generic over a numeric type `T` and two constants `X` and `Y`,
39/// which represent the fixed size of the 2D wrapping area.
40///
41/// # Type Parameters
42/// * `T` - Any numeric type that implements the `Fixed` trait.
43/// * `X` - The maximum bound for the x-axis.
44/// * `Y` - The maximum bound for the y-axis.
45pub struct Wrapped2D<T, const X: u32, const Y: u32>(Vec2D<T>);
46
47impl<T, const X: u32, const Y: u32> Wrapped2D<T, X, Y>
48where T: Fixed
49{
50    /// Wraps the coordinates of the vector around the bounds defined by `X` and `Y`.
51    ///
52    /// # Returns
53    /// A new `Wrapped2D` instance with its coordinates wrapped within the bounds.
54    pub fn wrap_around_map(&self) -> Self {
55        Wrapped2D(Vec2D::new(
56            Self::wrap_coordinate(self.0.x, T::from_num(X)),
57            Self::wrap_coordinate(self.0.y, T::from_num(Y)),
58        ))
59    }
60
61    /// Wraps a single coordinate value around a maximum value.
62    ///
63    /// # Arguments
64    /// * `value` - The coordinate value to be wrapped.
65    /// * `max_value` - The maximum bound for the coordinate.
66    ///
67    /// # Returns
68    /// The wrapped coordinate value.
69    pub fn wrap_coordinate(value: T, max_value: T) -> T {
70        ((value % max_value) + max_value) % max_value
71    }
72}
73
74impl<T, const X: u32, const Y: u32> Deref for Wrapped2D<T, X, Y> {
75    type Target = Vec2D<T>;
76
77    /// Dereferences the `Wrapped2D` wrapper to access its inner `Vec2D` value.
78    ///
79    /// # Returns
80    /// A reference to the inner `Vec2D`.
81    fn deref(&self) -> &Self::Target { &self.0 }
82}
83
84impl<T> Display for Vec2D<T>
85where T: Display
86{
87    /// Formats the `Vec2D` as a string in the format `[x, y]`.
88    ///
89    /// # Arguments
90    /// * `f` - A mutable reference to the formatter.
91    ///
92    /// # Returns
93    /// A `Result` indicating the success of the formatting operation.
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        match f.precision() {
96            Some(p) => write!(f, "[{:.prec$}, {:.prec$}]", self.x, self.y, prec=p),
97            None => write!(f, "[{}, {}]", self.x, self.y),
98        }
99    }
100}
101
102/// A trait providing a method to define the size of a 2D map.
103///
104/// This is used to determine the dimensions of the map for wrapping operations.
105pub trait MapSize {
106    /// The output type of the map dimensions.
107    type Output;
108
109    /// Returns the size of the map as a `Vec2D` object.
110    ///
111    /// # Returns
112    /// A `Vec2D` representing the width (`x`) and height (`y`) of the map.
113    fn map_size() -> Vec2D<Self::Output>;
114}
115
116/// Implementation of the `MapSize` trait for the `I32F32` fixed-point number type.
117impl MapSize for I32F32 {
118    type Output = I32F32;
119
120    /// Defines the size of the map as a `Vec2D` with dimensions 21600.0 x 10800.0.
121    ///
122    /// # Returns
123    /// A `Vec2D` with fixed-point components representing the map dimensions.
124    fn map_size() -> Vec2D<I32F32> {
125        Vec2D { x: I32F32::from_num(21600.0), y: I32F32::from_num(10800.0) }
126    }
127}
128
129/// Implementation of the `MapSize` trait for the `I96F32` fixed-point number type.
130impl MapSize for I96F32 {
131    type Output = I96F32;
132
133    /// Defines the size of the map as a `Vec2D` with dimensions 21600.0 x 10800.0.
134    ///
135    /// # Returns
136    /// A `Vec2D` with fixed-point components representing the map dimensions.
137    fn map_size() -> Vec2D<I96F32> {
138        Vec2D { x: I96F32::from_num(21600.0), y: I96F32::from_num(10800.0) }
139    }
140}
141
142impl MapSize for f64 {
143    type Output = f64;
144    /// Defines the size of the map as a `Vec2D` with dimensions 21600.0 x 10800.0.
145    ///
146    /// # Returns
147    /// A `Vec2D` with floating-point components representing the map dimensions.
148    fn map_size() -> Vec2D<f64> { Vec2D { x: 21600.0, y: 10800.0 } }
149}
150
151/// Implementation of the `MapSize` trait for the `I32F0` fixed-point number type.
152impl MapSize for I32F0 {
153    type Output = I32F0;
154
155    /// Defines the size of the map as a `Vec2D` with dimensions 21600 x 10800.
156    ///
157    /// # Returns
158    /// A `Vec2D` with fixed-point integer components representing the map dimensions.
159    fn map_size() -> Vec2D<I32F0> { Vec2D { x: I32F0::from_num(21600), y: I32F0::from_num(10800) } }
160}
161
162/// Implementation of the `MapSize` trait for the `u32` type.
163impl MapSize for u32 {
164    type Output = u32;
165
166    /// Defines the size of the map as a `Vec2D` with dimensions 21600 x 10800.
167    ///
168    /// # Returns
169    /// A `Vec2D` with unsigned 32-bit integer components representing the map dimensions.
170    fn map_size() -> Vec2D<u32> { Vec2D { x: 21600, y: 10800 } }
171}
172
173/// Implementation of the `MapSize` trait for the `i32` type.
174impl MapSize for i32 {
175    type Output = i32;
176
177    /// Defines the size of the map as a `Vec2D` with dimensions 21600 x 10800.
178    ///
179    /// # Returns
180    /// A `Vec2D` with signed 32-bit integer components representing the map dimensions.
181    fn map_size() -> Vec2D<i32> { Vec2D { x: 21600, y: 10800 } }
182}
183
184/// Implementation of the `MapSize` trait for a `Vec2D` type with components
185/// that also implement the `MapSize` trait.
186impl<T> MapSize for Vec2D<T>
187where T: MapSize<Output = T>
188{
189    type Output = T;
190
191    /// Defines the size of the map by delegating to the `map_size` implementation of `T`.
192    ///
193    /// # Returns
194    /// A `Vec2D` with components of type `T` representing the map dimensions.
195    fn map_size() -> Vec2D<Self::Output> { T::map_size() }
196}
197
198impl<T> Vec2D<T>
199where T: FixedSigned + NumAssignOps
200{
201    /// Computes the magnitude (absolute value) of the vector.
202    ///
203    /// # Returns
204    /// The magnitude of the vector as a scalar of type `T`.
205    pub fn abs(&self) -> T { (self.x * self.x + self.y * self.y).sqrt() }
206
207    pub fn abs_sq(&self) -> T { self.x * self.x + self.y * self.y }
208
209    pub fn round(&self) -> Self { Self { x: self.x.round(), y: self.y.round() } }
210
211    pub fn round_to_2(&self) -> Self {
212        let factor = T::from_num(100);
213        let new_x = (self.x * factor).round() / factor;
214        let new_y = (self.y * factor).round() / factor;
215        Self { x: new_x, y: new_y }
216    }
217
218    pub fn floor(&self) -> Self { Vec2D::new(self.x.floor(), self.y.floor()) }
219
220    pub fn from_real<R>(&other: &Vec2D<R>) -> Self
221    where R: Copy + ToFixed {
222        Self { x: T::from_num(other.x()), y: T::from_num(other.y()) }
223    }
224
225    /// Creates a vector pointing from the current vector (`self`) to another vector (`other`).
226    ///
227    /// # Arguments
228    /// * `other` - The target vector.
229    ///
230    /// # Returns
231    /// A new vector representing the direction from `self` to `other`.
232    pub fn to(&self, other: &Self) -> Self { Vec2D::new(other.x - self.x, other.y - self.y) }
233
234    pub fn to_num<R: FromFixed + Copy>(self) -> Vec2D<R> {
235        Vec2D::new(self.x.to_num::<R>(), self.y.to_num::<R>())
236    }
237
238    pub fn project_overboundary_fw(&self, dir: &Self) -> Self {
239        let map_size = I32F32::map_size().to_num::<T>();
240        let t_x = if dir.x().is_positive() {
241            (map_size.x() - self.x()) / dir.x()
242        } else if dir.x().is_negative() {
243            (T::ZERO - self.x()) / dir.x()
244        } else {
245            T::MAX
246        };
247
248        // intersection times with horizontal boundaries
249        let t_y = if dir.y().is_positive() {
250            (map_size.y() - self.y()) / dir.y()
251        } else if dir.y().is_negative() {
252            (T::ZERO - self.y()) / dir.y()
253        } else {
254            T::MAX // no intersection vertically, moving horizontally
255        };
256        let t_adjust = t_x.min(t_y).ceil();
257        *self + *dir * t_adjust
258    }
259
260    pub fn project_overboundary_bw(&self, dir: &Self) -> Self {
261        let map_size = I32F32::map_size().to_num::<T>();
262        let t_x = if dir.x().is_positive() {
263            self.x() / dir.x()
264        } else if dir.x().is_negative() {
265            (self.x() - map_size.x()) / dir.x()
266        } else {
267            T::MAX
268        };
269
270        let t_y = if dir.y().is_positive() {
271            self.y() / dir.y()
272        } else if dir.y().is_negative() {
273            (self.y() - map_size.y()) / dir.y()
274        } else {
275            T::MAX
276        };
277
278        let t_adjust = t_x.min(t_y).ceil();
279        *self + *dir * (t_adjust * T::from_num(-1.0))
280    }
281
282    /// Computes an "unwrapped" vector pointing from the current vector (`self`) to another vector (`other`).
283    ///
284    /// This method considers potential wrapping around a 2D map (based on the map size) and calculates
285    /// the smallest vector that connects `self` to `other`. The wrapping allows for efficient navigation
286    /// across boundaries.
287    ///
288    /// # Arguments
289    /// * `other` - The target vector to which the direction is computed.
290    ///
291    /// # Returns
292    /// A `Vec2D` representing the shortest unwrapped direction from `self` to `other`.
293    pub fn unwrapped_to(&self, other: &Self) -> Self {
294        let options = self.get_projected_in_range(other, (&[1, 0, -1], &[1, 0, -1]));
295        options.into_iter().min_by(|a, b| a.1.cmp(&b.1)).unwrap().0
296    }
297
298    pub fn unwrap_all(&self) -> [Self; 9] {
299        let options = self.get_projected_in_range(self, (&[1, 0, -1], &[1, 0, -1]));
300        options.into_iter().take(9).map(|x| x.0 + *self).collect::<Vec<_>>().try_into().unwrap()
301    }
302
303    pub fn unwrapped_to_top_right(&self, other: &Self) -> Self {
304        let options = self.get_projected_in_range(other, (&[1, 0], &[1, 0]));
305        options.into_iter().min_by(|a, b| a.1.cmp(&b.1)).unwrap().0
306    }
307
308    pub fn unwrapped_to_bottom_right(&self, other: &Self) -> Self {
309        let options = self.get_projected_in_range(other, (&[1, 0], &[-1, 0]));
310        options.into_iter().min_by(|a, b| a.1.cmp(&b.1)).unwrap().0
311    }
312
313    fn get_projected_in_range(&self, to: &Self, range: (&[i8], &[i8])) -> Vec<(Self, I64F64)> {
314        let mut options = Vec::new();
315        for x_sign in range.0 {
316            for y_sign in range.1 {
317                let target: Vec2D<T> = Vec2D::new(
318                    to.x + T::from_num(u32::map_size().x()) * T::from_num(*x_sign),
319                    to.y + T::from_num(u32::map_size().y()) * T::from_num(*y_sign),
320                );
321                let to_target = self.to(&target);
322                let tt_scale =
323                    Vec2D::new(I64F64::from_num(to_target.x), I64F64::from_num(to_target.y));
324                let to_target_abs_sq = tt_scale.abs_sq();
325                options.push((to_target, to_target_abs_sq));
326            }
327        }
328        options
329    }
330
331    /// Computes a perpendicular unit vector pointing to another vector (`other`).
332    ///
333    /// The direction of the perpendicular vector depends on whether `self` is clockwise
334    /// or counterclockwise to `other`.
335    ///
336    /// # Arguments
337    /// * `other` - The target vector to compare directions with.
338    ///
339    /// # Returns
340    /// A unit `Vec2D` perpendicular to `self` pointing towards `other`.
341    /// Returns a zero vector if `self` and `other` are collinear.
342    pub fn perp_unit_to(&self, other: &Self) -> Self {
343        match self.is_clockwise_to(other) {
344            Some(dir) => self.perp_unit(dir),
345            None => Self::zero(),
346        }
347    }
348
349    /// Computes a perpendicular unit vector to the current vector.
350    ///
351    /// The direction of the perpendicular vector depends on the `clockwise` parameter.
352    ///
353    /// # Arguments
354    /// * `clockwise` - A boolean indicating the direction. `true` for clockwise, `false` for counterclockwise.
355    ///
356    /// # Returns
357    /// A normalized perpendicular `Vec2D`.
358    pub fn perp_unit(&self, clockwise: bool) -> Self {
359        let perp = if clockwise { Self::new(self.y, -self.x) } else { Self::new(-self.y, self.x) };
360        perp.normalize()
361    }
362
363    /// Computes a flipped collinear unit vector to the current vector.
364    ///
365    /// This is equivalent to rotating the vector 180 degrees.
366    ///
367    /// # Returns
368    /// A normalized flipped collinear `Vec2D`.
369    pub fn flip_unit(&self) -> Self {
370        let flip = Self::new(-self.y, -self.x);
371        flip.normalize()
372    }
373
374    /// Determines whether the current vector is clockwise relative to another vector (`other`).
375    ///
376    /// This is determined using the cross product:
377    /// * `Some(true)` if `self` is clockwise to `other`.
378    /// * `Some(false)` if `self` is counterclockwise to `other`.
379    /// * `None` if `self` and `other` are collinear.
380    ///
381    /// # Arguments
382    /// * `other` - The vector to compare relative direction with.
383    ///
384    /// # Returns
385    /// An `Option<bool>` indicating the relative direction.
386    pub fn is_clockwise_to(&self, other: &Self) -> Option<bool> {
387        let cross = self.cross(other);
388        match cross.partial_cmp(&T::zero()) {
389            Some(Ordering::Less) => Some(true),
390            Some(Ordering::Greater) => Some(false),
391            _ => None,
392        }
393    }
394
395    /// Computes the angle (in degrees) between the current vector and another vector (`other`).
396    ///
397    /// The method calculates the cosine of the angle using the dot product, clamps it to
398    /// the valid range of `[-1, 1]`, and then computes the angle in degrees.
399    ///
400    /// # Arguments
401    /// * `other` - The target vector to compute the angle to.
402    ///
403    /// # Returns
404    /// The angle in degrees as a scalar of type `T`.
405    pub fn angle_to(&self, other: &Self) -> T {
406        let dot = self.dot(other);
407
408        let a_abs = self.abs();
409        let b_abs = other.abs();
410
411        if a_abs == 0.0 || b_abs == 0.0 {
412            return T::zero();
413        }
414        let cos_theta = dot / (a_abs * b_abs);
415        let clamped_cos_theta = cos_theta.clamp(T::from_num(-1.0), T::from_num(1.0));
416        let angle_radians = T::from_num(clamped_cos_theta.to_num::<f64>().acos());
417        angle_radians * T::from_num(180.0) / T::PI()
418    }
419
420    /// Normalizes the vector to have a magnitude of 1.
421    /// If the magnitude is zero, the original vector is returned unmodified.
422    ///
423    /// # Returns
424    /// A normalized vector.
425    pub fn normalize(self) -> Self {
426        let magnitude = self.abs();
427        if magnitude.is_zero() { self } else { Self::new(self.x / magnitude, self.y / magnitude) }
428    }
429
430    /// Rotates the vector by a given angle in degrees.
431    ///
432    /// # Arguments
433    /// * `angle_degrees` - The angle to rotate by, in degrees.
434    pub fn rotate_by(&mut self, angle_degrees: T) {
435        let angle_radians = angle_degrees.to_num::<f64>().to_radians();
436        let sin = T::from_num(angle_radians.sin());
437        let cos = T::from_num(angle_radians.cos());
438        let new_x = self.x * cos - self.y * sin;
439        self.y = self.x * sin + self.y * cos;
440        self.x = new_x;
441    }
442    
443    pub fn is_eq_signum(&self, other: &Self) -> bool {
444        self.x().signum() == other.x().signum() && self.y().signum() == other.y().signum()
445    }
446
447    /// Computes the Euclidean distance between the current vector and another vector.
448    ///
449    /// # Arguments
450    /// * `other` - The other vector to compute the distance to.
451    ///
452    /// # Returns
453    /// The Euclidean distance as a scalar of type `T`.
454    pub fn euclid_distance(&self, other: &Self) -> T { self.euclid_distance_sq(other).sqrt() }
455
456    /// Computes the Euclidean distance squared.
457    ///
458    /// # Arguments
459    /// * `other` - The other vector to compute the distance to.
460    ///
461    /// # Returns
462    /// The Euclidean distance squared as a scalar of type `T`.
463    pub fn euclid_distance_sq(&self, other: &Self) -> T {
464        (self.x - other.x) * (self.x - other.x) + (self.y - other.y) * (self.y - other.y)
465    }
466
467    pub fn from_axis_and_val(axis: VecAxis, val: T) -> Self {
468        match axis {
469            VecAxis::X => Self { x: val, y: T::zero() },
470            VecAxis::Y => Self { x: T::zero(), y: val },
471        }
472    }
473}
474
475impl<T: Copy> Vec2D<T> {
476    /// Creates a new vector with the given x and y components.
477    ///
478    /// # Arguments
479    /// * `x` - The x-component of the vector.
480    /// * `y` - The y-component of the vector.
481    ///
482    /// # Returns
483    /// A new `Vec2D` object.
484    pub const fn new(x: T, y: T) -> Self { Self { x, y } }
485
486    /// Returns the x-component of the vector.
487    ///
488    /// # Returns
489    /// The `x` value of type `T`.
490    pub const fn x(&self) -> T { self.x }
491
492    /// Returns the y-component of the vector.
493    ///
494    /// # Returns
495    /// The `y` value of type `T`.
496    pub const fn y(&self) -> T { self.y }
497
498    pub const fn get(&self, axis: VecAxis) -> T {
499        match axis {
500            VecAxis::X => self.x,
501            VecAxis::Y => self.y,
502        }
503    }
504}
505
506impl<T: Fixed + Copy> Vec2D<T> {
507    /// Computes the dot product of the current vector with another vector.
508    /// The dot product is defined as:
509    ///
510    /// ```text
511    /// dot_product = (x1 * x2) + (y1 * y2)
512    /// ```
513    ///
514    /// # Arguments
515    /// * `other` - Another `Vec2D` vector to compute the dot product with.
516    ///
517    /// # Returns
518    /// A scalar value of type `T` that represents the dot product of the two vectors.
519    pub fn dot(self, other: &Self) -> T { self.x * other.x + self.y * other.y }
520
521    /// Computes the cross product of the current vector with another vector.
522    ///
523    /// The cross product is defined as:
524    ///
525    /// ```text
526    /// cross_product = (x1 * y2) - (y1 * x2)
527    /// ```
528    ///
529    /// # Arguments
530    /// * `other` - Another `Vec2D` vector to compute the cross product with.
531    ///
532    /// # Returns
533    /// A scalar value of type `T` that represents the cross product of the two vectors.
534    pub fn cross(self, other: &Self) -> T { self.x * other.y - self.y * other.x }
535
536    /// Computes the magnitude (absolute value) of the vector as an `f64`.
537    /// This enables magnitude calculation for integer types `T`.
538    ///
539    /// # Returns
540    /// The magnitude of the vector as an `f64`.
541    pub fn abs_f64(self) -> f64 { (self.x * self.x + self.y * self.y).to_f64().unwrap().sqrt() }
542
543    /// Creates a zero vector (x = 0, y = 0).
544    ///
545    /// # Returns
546    /// A zero-initialized `Vec2D` with member type `T`.
547    pub fn zero() -> Self { Self::new(T::zero(), T::zero()) }
548
549    pub fn is_zero(&self) -> bool { self.x.is_zero() && self.y.is_zero() }
550}
551
552impl Vec2D<i32> {
553    /// Converts the vector to an unsigned equivalent.
554    ///
555    /// This method casts both the x and y components of the vector from `i32` to `u32`.
556    ///
557    /// # Returns
558    /// A `Vec2D<u32>` with the unsigned components of the original vector.
559    ///
560    /// # Note
561    /// The conversion may cause loss of sign. Negative values will wrap around.
562    #[allow(clippy::cast_sign_loss)]
563    pub fn to_unsigned(self) -> Vec2D<u32> { Vec2D { x: self.x as u32, y: self.y as u32 } }
564}
565
566pub enum WrapDirection {
567    None,
568    WrapX,
569    WrapY,
570    Both,
571}
572
573impl<T> Vec2D<T>
574where T: Add<Output = T> + Rem<Output = T> + Copy + MapSize<Output = T> + PartialEq
575{
576    /// Wraps the vector around a predefined 2D map.
577    ///
578    /// This method ensures the vector’s coordinates do not exceed the boundaries
579    /// of the map defined by `map_size()`. If coordinates go beyond these boundaries,
580    /// they are wrapped to remain within valid values.
581    pub fn wrap_around_map(&self) -> Self {
582        let map_size_x = T::map_size().x;
583        let map_size_y = T::map_size().y;
584
585        Vec2D::new(
586            Self::wrap_coordinate(self.x, map_size_x),
587            Self::wrap_coordinate(self.y, map_size_y),
588        )
589    }
590
591    pub fn wraps(&self) -> WrapDirection {
592        let map_size_x = T::map_size().x;
593        let map_size_y = T::map_size().y;
594        let wrapped_y = Self::wrap_coordinate(self.y, map_size_y);
595        let wrapped_x = Self::wrap_coordinate(self.x, map_size_x);
596        if wrapped_x == self.x && wrapped_y == self.y {
597            WrapDirection::None
598        } else if wrapped_x == self.x {
599            WrapDirection::WrapY
600        } else if wrapped_y == self.y {
601            WrapDirection::WrapX
602        } else {
603            WrapDirection::Both
604        }
605    }
606
607    pub fn wrap_by(&self, dir: &WrapDirection) -> Self {
608        match dir {
609            WrapDirection::None => *self,
610            WrapDirection::WrapX => {
611                let map_size_x = T::map_size().x;
612                let wrapped_x = Self::wrap_coordinate(self.x, map_size_x);
613                Vec2D::new(wrapped_x, self.y)
614            }
615            WrapDirection::WrapY => {
616                let map_size_y = T::map_size().y;
617                let wrapped_y = Self::wrap_coordinate(self.y, map_size_y);
618                Vec2D::new(self.x, wrapped_y)
619            }
620            WrapDirection::Both => self.wrap_around_map(),
621        }
622    }
623
624    /// Wraps a single coordinate around a specific maximum value.
625    ///
626    /// # Arguments
627    /// * `value` - The value to wrap.
628    /// * `max_value` - The maximum value to wrap around.
629    ///
630    /// # Returns
631    /// The wrapped coordinate as type `T`.
632    pub fn wrap_coordinate(value: T, max_value: T) -> T {
633        ((value % max_value) + max_value) % max_value
634    }
635}
636
637impl<T> Add for Vec2D<T>
638where T: Add<Output = T>
639{
640    type Output = Vec2D<T>;
641
642    /// Implements the `+` operator for two `Vec2D` objects.
643    ///
644    /// # Arguments
645    /// * `rhs` - The vector to add.
646    ///
647    /// # Returns
648    /// A new `Vec2D` representing the sum of the vectors.
649    fn add(self, rhs: Vec2D<T>) -> Self::Output {
650        Self::Output { x: self.x + rhs.x, y: self.y + rhs.y }
651    }
652}
653
654impl<T, TMul> Mul<TMul> for Vec2D<T>
655where
656    T: Fixed,
657    TMul: Fixed + Copy,
658{
659    type Output = Vec2D<T>;
660
661    /// Implements the `*` operator for a [`Vec2D`] and a scalar.
662    ///
663    /// # Arguments
664    /// * `rhs` - The scalar value to multiply by.
665    ///
666    /// # Returns
667    /// A new scaled vector.
668    fn mul(self, rhs: TMul) -> Self::Output {
669        Self::Output { x: self.x * T::from_num(rhs), y: self.y * T::from_num(rhs) }
670    }
671}
672
673impl<T> Div<T> for Vec2D<T>
674where T: Div<T, Output = T> + Copy
675{
676    type Output = Vec2D<T>;
677
678    /// Implements the `/` operator for a `Vec2D` and a scalar.
679    ///
680    /// # Arguments
681    /// * `rhs` - The scalar value to divide by.
682    ///
683    /// # Returns
684    /// A new scaled vector.
685    fn div(self, rhs: T) -> Self::Output { Self::Output { x: self.x / rhs, y: self.y / rhs } }
686}
687
688impl<T, TSub> Sub<Vec2D<TSub>> for Vec2D<T>
689where
690    T: FixedSigned,
691    TSub: Fixed,
692{
693    type Output = Vec2D<T>;
694
695    /// Implements the `-` operator for two `Vec2D`.
696    ///
697    /// # Arguments
698    /// * `rhs` - The `Vec2D` to subtract.
699    ///
700    /// # Returns
701    /// A new vector.
702    fn sub(self, rhs: Vec2D<TSub>) -> Self::Output {
703        Self::Output { x: self.x - T::from_num(rhs.x), y: self.y - T::from_num(rhs.y) }
704    }
705}
706
707impl<T: Num> From<(T, T)> for Vec2D<T> {
708    /// Creates a `Vec2D` from a tuple of (x, y) values.
709    ///
710    /// # Arguments
711    /// * `tuple` - A tuple representing the x and y values.
712    ///
713    /// # Returns
714    /// A new `Vec2D` created from the tuple.
715    fn from(tuple: (T, T)) -> Self { Vec2D { x: tuple.0, y: tuple.1 } }
716}
717
718impl<T: Num> From<Vec2D<T>> for (T, T) {
719    /// Creates a tuple from a `Vec2D` of (x, y) values.
720    ///
721    /// # Arguments
722    /// * `tuple` - A tuple representing the x and y values.
723    ///
724    /// # Returns
725    /// A new `Vec2D` created from the tuple.
726    fn from(value: Vec2D<T>) -> Self { (value.x, value.y) }
727}
728
729impl<T> From<&[T; 2]> for Vec2D<T>
730where T: Copy
731{
732    /// Creates a `Vec2D` from a slice of (x, y) values.
733    ///
734    /// # Arguments
735    /// * `slice` - A slice representing the x and y values.
736    ///
737    /// # Returns
738    /// A new `Vec2D` created from the slice.
739    fn from(slice: &[T; 2]) -> Self { Self { x: slice[0], y: slice[1] } }
740}
741
742impl<T> From<Vec2D<T>> for [T; 2]
743where T: Copy
744{
745    /// Creates a slice [x, y] from a `Vec2D`.
746    ///
747    /// # Arguments
748    /// * `vec` - A `Vec2D` representing the x and y values.
749    ///
750    /// # Returns
751    /// A new slice created from the `Vec2D`.
752    fn from(vec: Vec2D<T>) -> Self { [vec.x(), vec.y()] }
753}