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}