emath/
vec2.rs

1use std::fmt;
2use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
3
4use crate::Vec2b;
5
6/// A vector has a direction and length.
7/// A [`Vec2`] is often used to represent a size.
8///
9/// emath represents positions using [`crate::Pos2`].
10///
11/// Normally the units are points (logical pixels).
12#[repr(C)]
13#[derive(Clone, Copy, Default, PartialEq)]
14#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
15#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
16pub struct Vec2 {
17    /// Rightwards. Width.
18    pub x: f32,
19
20    /// Downwards. Height.
21    pub y: f32,
22}
23
24/// `vec2(x, y) == Vec2::new(x, y)`
25#[inline(always)]
26pub const fn vec2(x: f32, y: f32) -> Vec2 {
27    Vec2 { x, y }
28}
29
30// ----------------------------------------------------------------------------
31// Compatibility and convenience conversions to and from [f32; 2]:
32
33impl From<[f32; 2]> for Vec2 {
34    #[inline(always)]
35    fn from(v: [f32; 2]) -> Self {
36        Self { x: v[0], y: v[1] }
37    }
38}
39
40impl From<&[f32; 2]> for Vec2 {
41    #[inline(always)]
42    fn from(v: &[f32; 2]) -> Self {
43        Self { x: v[0], y: v[1] }
44    }
45}
46
47impl From<Vec2> for [f32; 2] {
48    #[inline(always)]
49    fn from(v: Vec2) -> Self {
50        [v.x, v.y]
51    }
52}
53
54impl From<&Vec2> for [f32; 2] {
55    #[inline(always)]
56    fn from(v: &Vec2) -> Self {
57        [v.x, v.y]
58    }
59}
60
61// ----------------------------------------------------------------------------
62// Compatibility and convenience conversions to and from (f32, f32):
63
64impl From<(f32, f32)> for Vec2 {
65    #[inline(always)]
66    fn from(v: (f32, f32)) -> Self {
67        Self { x: v.0, y: v.1 }
68    }
69}
70
71impl From<&(f32, f32)> for Vec2 {
72    #[inline(always)]
73    fn from(v: &(f32, f32)) -> Self {
74        Self { x: v.0, y: v.1 }
75    }
76}
77
78impl From<Vec2> for (f32, f32) {
79    #[inline(always)]
80    fn from(v: Vec2) -> Self {
81        (v.x, v.y)
82    }
83}
84
85impl From<&Vec2> for (f32, f32) {
86    #[inline(always)]
87    fn from(v: &Vec2) -> Self {
88        (v.x, v.y)
89    }
90}
91
92impl From<Vec2b> for Vec2 {
93    #[inline(always)]
94    fn from(v: Vec2b) -> Self {
95        Self {
96            x: v.x as i32 as f32,
97            y: v.y as i32 as f32,
98        }
99    }
100}
101
102// ----------------------------------------------------------------------------
103// Mint compatibility and convenience conversions
104
105#[cfg(feature = "mint")]
106impl From<mint::Vector2<f32>> for Vec2 {
107    #[inline]
108    fn from(v: mint::Vector2<f32>) -> Self {
109        Self::new(v.x, v.y)
110    }
111}
112
113#[cfg(feature = "mint")]
114impl From<Vec2> for mint::Vector2<f32> {
115    #[inline]
116    fn from(v: Vec2) -> Self {
117        Self { x: v.x, y: v.y }
118    }
119}
120
121// ----------------------------------------------------------------------------
122
123impl Vec2 {
124    /// Right
125    pub const X: Self = Self { x: 1.0, y: 0.0 };
126
127    /// Down
128    pub const Y: Self = Self { x: 0.0, y: 1.0 };
129
130    /// +X
131    pub const RIGHT: Self = Self { x: 1.0, y: 0.0 };
132
133    /// -X
134    pub const LEFT: Self = Self { x: -1.0, y: 0.0 };
135
136    /// -Y
137    pub const UP: Self = Self { x: 0.0, y: -1.0 };
138
139    /// +Y
140    pub const DOWN: Self = Self { x: 0.0, y: 1.0 };
141
142    pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
143    pub const INFINITY: Self = Self::splat(f32::INFINITY);
144    pub const NAN: Self = Self::splat(f32::NAN);
145
146    #[inline(always)]
147    pub const fn new(x: f32, y: f32) -> Self {
148        Self { x, y }
149    }
150
151    /// Set both `x` and `y` to the same value.
152    #[inline(always)]
153    pub const fn splat(v: f32) -> Self {
154        Self { x: v, y: v }
155    }
156
157    /// Treat this vector as a position.
158    /// `v.to_pos2()` is equivalent to `Pos2::default() + v`.
159    #[inline(always)]
160    pub fn to_pos2(self) -> crate::Pos2 {
161        crate::Pos2 {
162            x: self.x,
163            y: self.y,
164        }
165    }
166
167    /// Safe normalize: returns zero if input is zero.
168    #[must_use]
169    #[inline(always)]
170    pub fn normalized(self) -> Self {
171        let len = self.length();
172        if len <= 0.0 {
173            self
174        } else {
175            self / len
176        }
177    }
178
179    /// Checks if `self` has length `1.0` up to a precision of `1e-6`.
180    #[inline(always)]
181    pub fn is_normalized(self) -> bool {
182        (self.length_sq() - 1.0).abs() < 2e-6
183    }
184
185    /// Rotates the vector by 90°, i.e positive X to positive Y
186    /// (clockwise in egui coordinates).
187    #[inline(always)]
188    pub fn rot90(self) -> Self {
189        vec2(self.y, -self.x)
190    }
191
192    #[inline(always)]
193    pub fn length(self) -> f32 {
194        self.x.hypot(self.y)
195    }
196
197    #[inline(always)]
198    pub fn length_sq(self) -> f32 {
199        self.x * self.x + self.y * self.y
200    }
201
202    /// Measures the angle of the vector.
203    ///
204    /// ```
205    /// # use emath::Vec2;
206    /// use std::f32::consts::TAU;
207    ///
208    /// assert_eq!(Vec2::ZERO.angle(), 0.0);
209    /// assert_eq!(Vec2::angled(0.0).angle(), 0.0);
210    /// assert_eq!(Vec2::angled(1.0).angle(), 1.0);
211    /// assert_eq!(Vec2::X.angle(), 0.0);
212    /// assert_eq!(Vec2::Y.angle(), 0.25 * TAU);
213    ///
214    /// assert_eq!(Vec2::RIGHT.angle(), 0.0);
215    /// assert_eq!(Vec2::DOWN.angle(), 0.25 * TAU);
216    /// assert_eq!(Vec2::UP.angle(), -0.25 * TAU);
217    /// ```
218    #[inline(always)]
219    pub fn angle(self) -> f32 {
220        self.y.atan2(self.x)
221    }
222
223    /// Create a unit vector with the given CW angle (in radians).
224    /// * An angle of zero gives the unit X axis.
225    /// * An angle of 𝞃/4 = 90° gives the unit Y axis.
226    ///
227    /// ```
228    /// # use emath::Vec2;
229    /// use std::f32::consts::TAU;
230    ///
231    /// assert_eq!(Vec2::angled(0.0), Vec2::X);
232    /// assert!((Vec2::angled(0.25 * TAU) - Vec2::Y).length() < 1e-5);
233    /// ```
234    #[inline(always)]
235    pub fn angled(angle: f32) -> Self {
236        let (sin, cos) = angle.sin_cos();
237        vec2(cos, sin)
238    }
239
240    #[must_use]
241    #[inline(always)]
242    pub fn floor(self) -> Self {
243        vec2(self.x.floor(), self.y.floor())
244    }
245
246    #[must_use]
247    #[inline(always)]
248    pub fn round(self) -> Self {
249        vec2(self.x.round(), self.y.round())
250    }
251
252    #[must_use]
253    #[inline(always)]
254    pub fn ceil(self) -> Self {
255        vec2(self.x.ceil(), self.y.ceil())
256    }
257
258    #[must_use]
259    #[inline]
260    pub fn abs(self) -> Self {
261        vec2(self.x.abs(), self.y.abs())
262    }
263
264    /// True if all members are also finite.
265    #[inline(always)]
266    pub fn is_finite(self) -> bool {
267        self.x.is_finite() && self.y.is_finite()
268    }
269
270    /// True if any member is NaN.
271    #[inline(always)]
272    pub fn any_nan(self) -> bool {
273        self.x.is_nan() || self.y.is_nan()
274    }
275
276    #[must_use]
277    #[inline]
278    pub fn min(self, other: Self) -> Self {
279        vec2(self.x.min(other.x), self.y.min(other.y))
280    }
281
282    #[must_use]
283    #[inline]
284    pub fn max(self, other: Self) -> Self {
285        vec2(self.x.max(other.x), self.y.max(other.y))
286    }
287
288    /// The dot-product of two vectors.
289    #[inline]
290    pub fn dot(self, other: Self) -> f32 {
291        self.x * other.x + self.y * other.y
292    }
293
294    /// Returns the minimum of `self.x` and `self.y`.
295    #[must_use]
296    #[inline(always)]
297    pub fn min_elem(self) -> f32 {
298        self.x.min(self.y)
299    }
300
301    /// Returns the maximum of `self.x` and `self.y`.
302    #[inline(always)]
303    #[must_use]
304    pub fn max_elem(self) -> f32 {
305        self.x.max(self.y)
306    }
307
308    /// Swizzle the axes.
309    #[inline]
310    #[must_use]
311    pub fn yx(self) -> Self {
312        Self {
313            x: self.y,
314            y: self.x,
315        }
316    }
317
318    #[must_use]
319    #[inline]
320    pub fn clamp(self, min: Self, max: Self) -> Self {
321        Self {
322            x: self.x.clamp(min.x, max.x),
323            y: self.y.clamp(min.y, max.y),
324        }
325    }
326}
327
328impl std::ops::Index<usize> for Vec2 {
329    type Output = f32;
330
331    #[inline(always)]
332    fn index(&self, index: usize) -> &f32 {
333        match index {
334            0 => &self.x,
335            1 => &self.y,
336            _ => panic!("Vec2 index out of bounds: {index}"),
337        }
338    }
339}
340
341impl std::ops::IndexMut<usize> for Vec2 {
342    #[inline(always)]
343    fn index_mut(&mut self, index: usize) -> &mut f32 {
344        match index {
345            0 => &mut self.x,
346            1 => &mut self.y,
347            _ => panic!("Vec2 index out of bounds: {index}"),
348        }
349    }
350}
351
352impl Eq for Vec2 {}
353
354impl Neg for Vec2 {
355    type Output = Self;
356
357    #[inline(always)]
358    fn neg(self) -> Self {
359        vec2(-self.x, -self.y)
360    }
361}
362
363impl AddAssign for Vec2 {
364    #[inline(always)]
365    fn add_assign(&mut self, rhs: Self) {
366        *self = Self {
367            x: self.x + rhs.x,
368            y: self.y + rhs.y,
369        };
370    }
371}
372
373impl SubAssign for Vec2 {
374    #[inline(always)]
375    fn sub_assign(&mut self, rhs: Self) {
376        *self = Self {
377            x: self.x - rhs.x,
378            y: self.y - rhs.y,
379        };
380    }
381}
382
383impl Add for Vec2 {
384    type Output = Self;
385
386    #[inline(always)]
387    fn add(self, rhs: Self) -> Self {
388        Self {
389            x: self.x + rhs.x,
390            y: self.y + rhs.y,
391        }
392    }
393}
394
395impl Sub for Vec2 {
396    type Output = Self;
397
398    #[inline(always)]
399    fn sub(self, rhs: Self) -> Self {
400        Self {
401            x: self.x - rhs.x,
402            y: self.y - rhs.y,
403        }
404    }
405}
406
407/// Element-wise multiplication
408impl Mul<Self> for Vec2 {
409    type Output = Self;
410
411    #[inline(always)]
412    fn mul(self, vec: Self) -> Self {
413        Self {
414            x: self.x * vec.x,
415            y: self.y * vec.y,
416        }
417    }
418}
419
420/// Element-wise division
421impl Div<Self> for Vec2 {
422    type Output = Self;
423
424    #[inline(always)]
425    fn div(self, rhs: Self) -> Self {
426        Self {
427            x: self.x / rhs.x,
428            y: self.y / rhs.y,
429        }
430    }
431}
432
433impl MulAssign<f32> for Vec2 {
434    #[inline(always)]
435    fn mul_assign(&mut self, rhs: f32) {
436        self.x *= rhs;
437        self.y *= rhs;
438    }
439}
440
441impl DivAssign<f32> for Vec2 {
442    #[inline(always)]
443    fn div_assign(&mut self, rhs: f32) {
444        self.x /= rhs;
445        self.y /= rhs;
446    }
447}
448
449impl Mul<f32> for Vec2 {
450    type Output = Self;
451
452    #[inline(always)]
453    fn mul(self, factor: f32) -> Self {
454        Self {
455            x: self.x * factor,
456            y: self.y * factor,
457        }
458    }
459}
460
461impl Mul<Vec2> for f32 {
462    type Output = Vec2;
463
464    #[inline(always)]
465    fn mul(self, vec: Vec2) -> Vec2 {
466        Vec2 {
467            x: self * vec.x,
468            y: self * vec.y,
469        }
470    }
471}
472
473impl Div<f32> for Vec2 {
474    type Output = Self;
475
476    #[inline(always)]
477    fn div(self, factor: f32) -> Self {
478        Self {
479            x: self.x / factor,
480            y: self.y / factor,
481        }
482    }
483}
484
485impl fmt::Debug for Vec2 {
486    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
487        if let Some(precision) = f.precision() {
488            write!(f, "[{1:.0$} {2:.0$}]", precision, self.x, self.y)
489        } else {
490            write!(f, "[{:.1} {:.1}]", self.x, self.y)
491        }
492    }
493}
494
495impl fmt::Display for Vec2 {
496    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
497        f.write_str("[")?;
498        self.x.fmt(f)?;
499        f.write_str(" ")?;
500        self.y.fmt(f)?;
501        f.write_str("]")?;
502        Ok(())
503    }
504}
505
506#[cfg(test)]
507mod test {
508    use super::*;
509
510    macro_rules! almost_eq {
511        ($left: expr, $right: expr) => {
512            let left = $left;
513            let right = $right;
514            assert!((left - right).abs() < 1e-6, "{} != {}", left, right);
515        };
516    }
517
518    #[test]
519    fn test_vec2() {
520        use std::f32::consts::TAU;
521
522        assert_eq!(Vec2::ZERO.angle(), 0.0);
523        assert_eq!(Vec2::angled(0.0).angle(), 0.0);
524        assert_eq!(Vec2::angled(1.0).angle(), 1.0);
525        assert_eq!(Vec2::X.angle(), 0.0);
526        assert_eq!(Vec2::Y.angle(), 0.25 * TAU);
527
528        assert_eq!(Vec2::RIGHT.angle(), 0.0);
529        assert_eq!(Vec2::DOWN.angle(), 0.25 * TAU);
530        almost_eq!(Vec2::LEFT.angle(), 0.50 * TAU);
531        assert_eq!(Vec2::UP.angle(), -0.25 * TAU);
532
533        let mut assignment = vec2(1.0, 2.0);
534        assignment += vec2(3.0, 4.0);
535        assert_eq!(assignment, vec2(4.0, 6.0));
536
537        let mut assignment = vec2(4.0, 6.0);
538        assignment -= vec2(1.0, 2.0);
539        assert_eq!(assignment, vec2(3.0, 4.0));
540
541        let mut assignment = vec2(1.0, 2.0);
542        assignment *= 2.0;
543        assert_eq!(assignment, vec2(2.0, 4.0));
544
545        let mut assignment = vec2(2.0, 4.0);
546        assignment /= 2.0;
547        assert_eq!(assignment, vec2(1.0, 2.0));
548    }
549
550    #[test]
551    fn test_vec2_normalized() {
552        fn generate_spiral(n: usize, start: Vec2, end: Vec2) -> impl Iterator<Item = Vec2> {
553            let angle_step = 2.0 * std::f32::consts::PI / n as f32;
554            let radius_step = (end.length() - start.length()) / n as f32;
555
556            (0..n).map(move |i| {
557                let angle = i as f32 * angle_step;
558                let radius = start.length() + i as f32 * radius_step;
559                let x = radius * angle.cos();
560                let y = radius * angle.sin();
561                vec2(x, y)
562            })
563        }
564
565        for v in generate_spiral(40, Vec2::splat(0.1), Vec2::splat(2.0)) {
566            let vn = v.normalized();
567            almost_eq!(vn.length(), 1.0);
568            assert!(vn.is_normalized());
569        }
570    }
571}