robomath/
vec2.rs

1use core::ops::{Add, Div, Mul, Neg, Sub};
2
3/// A 2D vector with generic components, suitable for mathematical operations in 2D space.
4///
5/// `Vec2<T>` represents a 2D vector with components `x` and `y`, where `T` is a numeric type.
6/// It supports various arithmetic operations such as addition, subtraction, multiplication,
7/// division, and negation. For `T = f32`, additional methods like `clamp` are available.
8///
9/// The generic type `T` must implement certain traits depending on the operations used:
10/// - For basic instantiation: `T: Default`.
11/// - For arithmetic operations: `T: Add`, `T: Sub`, `T: Mul`, `T: Div`.
12/// - For negation: `T: Neg`.
13///
14/// # Examples
15///
16/// ```
17/// use robomath::{Vec2, vec2};
18///
19/// // Create a Vec2 with f32 components
20/// let v1 = vec2(1.0, 2.0);
21/// let v2 = vec2(3.0, 4.0);
22///
23/// // Perform arithmetic operations
24/// let sum = v1 + v2;
25/// assert_eq!(sum, vec2(4.0, 6.0));
26///
27/// // Scalar multiplication
28/// let scaled = 2.0 * v1;
29/// assert_eq!(scaled, vec2(2.0, 4.0));
30///
31/// // Clamp components (only available for f32)
32/// let clamped = v1.clamp(0.0, 1.5);
33/// assert_eq!(clamped, vec2(1.0, 1.5));
34/// ```
35#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
36pub struct Vec2<T: Default> {
37    pub x: T,
38    pub y: T,
39}
40
41impl Vec2<f32> {
42    /// Clamps the components of the vector to be within the specified range.
43    ///
44    /// Each component (`x`, `y`) is clamped to the interval `[min, max]`. If a component
45    /// is less than `min`, it is set to `min`. If it is greater than `max`, it is set to `max`.
46    ///
47    /// # Arguments
48    ///
49    /// * `min` - The minimum value for each component.
50    /// * `max` - The maximum value for each component.
51    ///
52    /// # Returns
53    ///
54    /// A new `Vec2<f32>` with components clamped to the specified range.
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use robomath::vec2;
60    ///
61    /// let v = vec2(-1.0, 5.0);
62    /// let clamped = v.clamp(0.0, 2.0);
63    /// assert_eq!(clamped, vec2(0.0, 2.0));
64    /// ```    
65    pub fn clamp(&self, min: f32, max: f32) -> Vec2<f32> {
66        Vec2 {
67            x: self.x.clamp(min, max),
68            y: self.y.clamp(min, max),
69        }
70    }
71}
72
73/// Creates a new `Vec2` with the given components.
74///
75/// This helper function provides a concise way to instantiate a `Vec2`.
76///
77/// # Arguments
78///
79/// * `x` - The x-coordinate of the vector.
80/// * `y` - The y-coordinate of the vector.
81///
82/// # Returns
83///
84/// A new `Vec2<T>` with the specified components.
85///
86/// # Examples
87///
88/// ```
89/// use robomath::vec2;
90///
91/// let v = vec2(1.0, 2.0);
92/// assert_eq!(v.x, 1.0);
93/// assert_eq!(v.y, 2.0);
94/// ```
95pub fn vec2<T: Default>(x: T, y: T) -> Vec2<T> {
96    Vec2 { x, y }
97}
98
99impl<T: Sub<Output = T> + Default> Sub for Vec2<T> {
100    type Output = Vec2<T>;
101
102    /// Subtracts two `Vec2`s component-wise.
103    ///
104    /// # Arguments
105    ///
106    /// * `rhs` - The vector to subtract from `self`.
107    ///
108    /// # Returns
109    ///
110    /// A new `Vec2<T>` where each component is the difference of the corresponding components.
111    ///
112    /// # Examples
113    ///
114    /// ```
115    /// use robomath::vec2;
116    ///
117    /// let v1 = vec2(5.0, 7.0);
118    /// let v2 = vec2(1.0, 2.0);
119    /// let result = v1 - v2;
120    /// assert_eq!(result, vec2(4.0, 5.0));
121    /// ```    
122    fn sub(self, rhs: Vec2<T>) -> Vec2<T> {
123        Vec2 {
124            x: self.x - rhs.x,
125            y: self.y - rhs.y,
126        }
127    }
128}
129
130impl<T: Add<Output = T> + Default> Add for Vec2<T> {
131    type Output = Vec2<T>;
132
133    /// Adds two `Vec2`s component-wise.
134    ///
135    /// # Arguments
136    ///
137    /// * `rhs` - The vector to add to `self`.
138    ///
139    /// # Returns
140    ///
141    /// A new `Vec2<T>` where each component is the sum of the corresponding components.
142    ///
143    /// # Examples
144    ///
145    /// ```
146    /// use robomath::vec2;
147    ///
148    /// let v1 = vec2(1.0, 2.0);
149    /// let v2 = vec2(3.0, 4.0);
150    /// let result = v1 + v2;
151    /// assert_eq!(result, vec2(4.0, 6.0));
152    /// ```    
153    fn add(self, rhs: Vec2<T>) -> Vec2<T> {
154        Vec2 {
155            x: self.x + rhs.x,
156            y: self.y + rhs.y,
157        }
158    }
159}
160
161impl<T: Mul<Output = T> + Default> Mul for Vec2<T> {
162    type Output = Vec2<T>;
163
164    /// Multiplies two `Vec2`s component-wise (element-wise multiplication).
165    ///
166    /// # Arguments
167    ///
168    /// * `rhs` - The vector to multiply with `self`.
169    ///
170    /// # Returns
171    ///
172    /// A new `Vec2<T>` where each component is the product of the corresponding components.
173    ///
174    /// # Examples
175    ///
176    /// ```
177    /// use robomath::vec2;
178    ///
179    /// let v1 = vec2(2.0, 3.0);
180    /// let v2 = vec2(5.0, 6.0);
181    /// let result = v1 * v2;
182    /// assert_eq!(result, vec2(10.0, 18.0));
183    /// ```    
184    fn mul(self, rhs: Vec2<T>) -> Vec2<T> {
185        Vec2 {
186            x: self.x * rhs.x,
187            y: self.y * rhs.y,
188        }
189    }
190}
191
192impl Mul<Vec2<f32>> for f32 {
193    type Output = Vec2<f32>;
194
195    /// Scales a `Vec2<f32>` by a scalar value.
196    ///
197    /// Each component of the vector is multiplied by the scalar.
198    ///
199    /// # Arguments
200    ///
201    /// * `rhs` - The vector to scale.
202    ///
203    /// # Returns
204    ///
205    /// A new `Vec2<f32>` with each component scaled by the scalar.
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// use robomath::vec2;
211    ///
212    /// let v = vec2(1.0, 2.0);
213    /// let scaled = 2.0 * v;
214    /// assert_eq!(scaled, vec2(2.0, 4.0));
215    /// ```    
216    fn mul(self, rhs: Vec2<f32>) -> Vec2<f32> {
217        Vec2 {
218            x: self * rhs.x,
219            y: self * rhs.y,
220        }
221    }
222}
223
224impl<T: Div<Output = T> + Copy + Default> Div<T> for Vec2<T> {
225    type Output = Vec2<T>;
226
227    /// Divides each component of the `Vec2` by a scalar.
228    ///
229    /// # Arguments
230    ///
231    /// * `rhs` - The scalar to divide by.
232    ///
233    /// # Returns
234    ///
235    /// A new `Vec2<T>` with each component divided by the scalar.
236    ///
237    /// # Panics
238    ///
239    /// Panics if `rhs` is zero and `T` does not handle division by zero gracefully (e.g., for integers).
240    /// For `T = f32`, division by zero results in infinity or NaN as per IEEE 754.
241    ///
242    /// # Examples
243    ///
244    /// ```
245    /// use robomath::vec2;
246    ///
247    /// let v = vec2(4.0, 6.0);
248    /// let result = v / 2.0;
249    /// assert_eq!(result, vec2(2.0, 3.0));
250    /// ```    
251    fn div(self, rhs: T) -> Vec2<T> {
252        Vec2 {
253            x: self.x / rhs,
254            y: self.y / rhs,
255        }
256    }
257}
258
259impl<T: Default> Default for Vec2<T> {
260    /// Provides a default `Vec2` where each component is `T::default()`.
261    ///
262    /// For numeric types, this typically means zero.
263    ///
264    /// # Examples
265    ///
266    /// ```
267    /// use robomath::Vec2;
268    ///
269    /// let v: Vec2<f32> = Vec2::default();
270    /// assert_eq!(v, Vec2 { x: 0.0, y: 0.0 });
271    ///
272    /// let v_int: Vec2<i32> = Vec2::default();
273    /// assert_eq!(v_int, Vec2 { x: 0, y: 0 });
274    /// ```    
275    fn default() -> Self {
276        Vec2 {
277            x: T::default(),
278            y: T::default(),
279        }
280    }
281}
282
283impl<T: Neg<Output = T> + Default> Neg for Vec2<T> {
284    type Output = Vec2<T>;
285
286    /// Negates each component of the `Vec2`.
287    ///
288    /// # Returns
289    ///
290    /// A new `Vec2<T>` with each component negated.
291    ///
292    /// # Examples
293    ///
294    /// ```
295    /// use robomath::vec2;
296    ///
297    /// let v = vec2(1.0, -2.0);
298    /// let neg = -v;
299    /// assert_eq!(neg, vec2(-1.0, 2.0));
300    /// ```    
301    fn neg(self) -> Self::Output {
302        Vec2 {
303            x: -self.x,
304            y: -self.y,
305        }
306    }
307}