Skip to main content

emath/
vec2.rs

1use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
2use std::fmt;
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)]
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 ONE: Self = Self { x: 1.0, y: 1.0 };
144    pub const INFINITY: Self = Self::splat(f32::INFINITY);
145    pub const NAN: Self = Self::splat(f32::NAN);
146
147    #[inline(always)]
148    pub const fn new(x: f32, y: f32) -> Self {
149        Self { x, y }
150    }
151
152    /// Set both `x` and `y` to the same value.
153    #[inline(always)]
154    pub const fn splat(v: f32) -> Self {
155        Self { x: v, y: v }
156    }
157
158    /// Treat this vector as a position.
159    /// `v.to_pos2()` is equivalent to `Pos2::default() + v`.
160    #[inline(always)]
161    pub fn to_pos2(self) -> crate::Pos2 {
162        crate::Pos2 {
163            x: self.x,
164            y: self.y,
165        }
166    }
167
168    /// Safe normalize: returns zero if input is zero.
169    #[must_use]
170    #[inline(always)]
171    pub fn normalized(self) -> Self {
172        let len = self.length();
173        if len <= 0.0 { self } else { self / len }
174    }
175
176    /// Checks if `self` has length `1.0` up to a precision of `1e-6`.
177    #[inline(always)]
178    pub fn is_normalized(self) -> bool {
179        (self.length_sq() - 1.0).abs() < 2e-6
180    }
181
182    /// Rotates the vector by 90°, i.e positive X to positive Y
183    /// (clockwise in egui coordinates).
184    #[inline(always)]
185    pub fn rot90(self) -> Self {
186        vec2(self.y, -self.x)
187    }
188
189    #[inline(always)]
190    pub fn length(self) -> f32 {
191        self.x.hypot(self.y)
192    }
193
194    #[inline(always)]
195    pub fn length_sq(self) -> f32 {
196        self.x * self.x + self.y * self.y
197    }
198
199    /// Measures the angle of the vector.
200    ///
201    /// ```
202    /// # use emath::Vec2;
203    /// use std::f32::consts::TAU;
204    ///
205    /// assert_eq!(Vec2::ZERO.angle(), 0.0);
206    /// assert_eq!(Vec2::angled(0.0).angle(), 0.0);
207    /// assert_eq!(Vec2::angled(1.0).angle(), 1.0);
208    /// assert_eq!(Vec2::X.angle(), 0.0);
209    /// assert_eq!(Vec2::Y.angle(), 0.25 * TAU);
210    ///
211    /// assert_eq!(Vec2::RIGHT.angle(), 0.0);
212    /// assert_eq!(Vec2::DOWN.angle(), 0.25 * TAU);
213    /// assert_eq!(Vec2::UP.angle(), -0.25 * TAU);
214    /// ```
215    #[inline(always)]
216    pub fn angle(self) -> f32 {
217        self.y.atan2(self.x)
218    }
219
220    /// Create a unit vector with the given CW angle (in radians).
221    /// * An angle of zero gives the unit X axis.
222    /// * An angle of 𝞃/4 = 90° gives the unit Y axis.
223    ///
224    /// ```
225    /// # use emath::Vec2;
226    /// use std::f32::consts::TAU;
227    ///
228    /// assert_eq!(Vec2::angled(0.0), Vec2::X);
229    /// assert!((Vec2::angled(0.25 * TAU) - Vec2::Y).length() < 1e-5);
230    /// ```
231    #[inline(always)]
232    pub fn angled(angle: f32) -> Self {
233        let (sin, cos) = angle.sin_cos();
234        vec2(cos, sin)
235    }
236
237    #[must_use]
238    #[inline(always)]
239    pub fn floor(self) -> Self {
240        vec2(self.x.floor(), self.y.floor())
241    }
242
243    #[must_use]
244    #[inline(always)]
245    pub fn round(self) -> Self {
246        vec2(self.x.round(), self.y.round())
247    }
248
249    #[must_use]
250    #[inline(always)]
251    pub fn ceil(self) -> Self {
252        vec2(self.x.ceil(), self.y.ceil())
253    }
254
255    #[must_use]
256    #[inline]
257    pub fn abs(self) -> Self {
258        vec2(self.x.abs(), self.y.abs())
259    }
260
261    /// True if all members are also finite.
262    #[inline(always)]
263    pub fn is_finite(self) -> bool {
264        self.x.is_finite() && self.y.is_finite()
265    }
266
267    /// True if any member is NaN.
268    #[inline(always)]
269    pub fn any_nan(self) -> bool {
270        self.x.is_nan() || self.y.is_nan()
271    }
272
273    #[must_use]
274    #[inline]
275    pub fn min(self, other: Self) -> Self {
276        vec2(self.x.min(other.x), self.y.min(other.y))
277    }
278
279    #[must_use]
280    #[inline]
281    pub fn max(self, other: Self) -> Self {
282        vec2(self.x.max(other.x), self.y.max(other.y))
283    }
284
285    /// The dot-product of two vectors.
286    #[inline]
287    pub fn dot(self, other: Self) -> f32 {
288        self.x * other.x + self.y * other.y
289    }
290
291    /// Returns the minimum of `self.x` and `self.y`.
292    #[must_use]
293    #[inline(always)]
294    pub fn min_elem(self) -> f32 {
295        self.x.min(self.y)
296    }
297
298    /// Returns the maximum of `self.x` and `self.y`.
299    #[inline(always)]
300    #[must_use]
301    pub fn max_elem(self) -> f32 {
302        self.x.max(self.y)
303    }
304
305    /// Swizzle the axes.
306    #[inline]
307    #[must_use]
308    pub fn yx(self) -> Self {
309        Self {
310            x: self.y,
311            y: self.x,
312        }
313    }
314
315    #[must_use]
316    #[inline]
317    pub fn clamp(self, min: Self, max: Self) -> Self {
318        Self {
319            x: self.x.clamp(min.x, max.x),
320            y: self.y.clamp(min.y, max.y),
321        }
322    }
323}
324
325impl core::ops::Index<usize> for Vec2 {
326    type Output = f32;
327
328    #[inline(always)]
329    fn index(&self, index: usize) -> &f32 {
330        match index {
331            0 => &self.x,
332            1 => &self.y,
333            _ => panic!("Vec2 index out of bounds: {index}"),
334        }
335    }
336}
337
338impl core::ops::IndexMut<usize> for Vec2 {
339    #[inline(always)]
340    fn index_mut(&mut self, index: usize) -> &mut f32 {
341        match index {
342            0 => &mut self.x,
343            1 => &mut self.y,
344            _ => panic!("Vec2 index out of bounds: {index}"),
345        }
346    }
347}
348
349impl PartialEq for Vec2 {
350    #[track_caller]
351    #[inline]
352    fn eq(&self, other: &Self) -> bool {
353        debug_assert!(
354            !self.any_nan() && !other.any_nan(),
355            "Comparing NaN vectors ({self:?} and {other:?}). \
356             A NaN is not even equal to itself, which leads to very confusing bugs."
357        );
358        self.x == other.x && self.y == other.y
359    }
360}
361
362/// This is a lie for NaN vectors, which are not equal to themselves.
363/// [`PartialEq`] catches those in debug builds.
364impl Eq for Vec2 {}
365
366impl Neg for Vec2 {
367    type Output = Self;
368
369    #[inline(always)]
370    fn neg(self) -> Self {
371        vec2(-self.x, -self.y)
372    }
373}
374
375impl AddAssign for Vec2 {
376    #[inline(always)]
377    fn add_assign(&mut self, rhs: Self) {
378        *self = Self {
379            x: self.x + rhs.x,
380            y: self.y + rhs.y,
381        };
382    }
383}
384
385impl SubAssign for Vec2 {
386    #[inline(always)]
387    fn sub_assign(&mut self, rhs: Self) {
388        *self = Self {
389            x: self.x - rhs.x,
390            y: self.y - rhs.y,
391        };
392    }
393}
394
395impl Add for Vec2 {
396    type Output = Self;
397
398    #[inline(always)]
399    fn add(self, rhs: Self) -> Self {
400        Self {
401            x: self.x + rhs.x,
402            y: self.y + rhs.y,
403        }
404    }
405}
406
407impl Sub for Vec2 {
408    type Output = Self;
409
410    #[inline(always)]
411    fn sub(self, rhs: Self) -> Self {
412        Self {
413            x: self.x - rhs.x,
414            y: self.y - rhs.y,
415        }
416    }
417}
418
419/// Element-wise multiplication
420impl Mul<Self> for Vec2 {
421    type Output = Self;
422
423    #[inline(always)]
424    fn mul(self, vec: Self) -> Self {
425        Self {
426            x: self.x * vec.x,
427            y: self.y * vec.y,
428        }
429    }
430}
431
432/// Element-wise division
433impl Div<Self> for Vec2 {
434    type Output = Self;
435
436    #[inline(always)]
437    fn div(self, rhs: Self) -> Self {
438        Self {
439            x: self.x / rhs.x,
440            y: self.y / rhs.y,
441        }
442    }
443}
444
445impl MulAssign<f32> for Vec2 {
446    #[inline(always)]
447    fn mul_assign(&mut self, rhs: f32) {
448        self.x *= rhs;
449        self.y *= rhs;
450    }
451}
452
453impl DivAssign<f32> for Vec2 {
454    #[inline(always)]
455    fn div_assign(&mut self, rhs: f32) {
456        self.x /= rhs;
457        self.y /= rhs;
458    }
459}
460
461impl Mul<f32> for Vec2 {
462    type Output = Self;
463
464    #[inline(always)]
465    fn mul(self, factor: f32) -> Self {
466        Self {
467            x: self.x * factor,
468            y: self.y * factor,
469        }
470    }
471}
472
473impl Mul<Vec2> for f32 {
474    type Output = Vec2;
475
476    #[inline(always)]
477    fn mul(self, vec: Vec2) -> Vec2 {
478        Vec2 {
479            x: self * vec.x,
480            y: self * vec.y,
481        }
482    }
483}
484
485impl Div<f32> for Vec2 {
486    type Output = Self;
487
488    #[inline(always)]
489    fn div(self, factor: f32) -> Self {
490        Self {
491            x: self.x / factor,
492            y: self.y / factor,
493        }
494    }
495}
496
497impl fmt::Debug for Vec2 {
498    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499        if let Some(precision) = f.precision() {
500            write!(f, "[{1:.0$} {2:.0$}]", precision, self.x, self.y)
501        } else {
502            write!(f, "[{:.1} {:.1}]", self.x, self.y)
503        }
504    }
505}
506
507impl fmt::Display for Vec2 {
508    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
509        f.write_str("[")?;
510        self.x.fmt(f)?;
511        f.write_str(" ")?;
512        self.y.fmt(f)?;
513        f.write_str("]")?;
514        Ok(())
515    }
516}
517
518#[cfg(test)]
519mod test {
520    use super::*;
521
522    macro_rules! almost_eq {
523        ($left: expr, $right: expr) => {
524            let left = $left;
525            let right = $right;
526            assert!((left - right).abs() < 1e-6, "{} != {}", left, right);
527        };
528    }
529
530    #[test]
531    fn test_vec2() {
532        use core::f32::consts::TAU;
533
534        assert_eq!(Vec2::ZERO.angle(), 0.0);
535        assert_eq!(Vec2::angled(0.0).angle(), 0.0);
536        assert_eq!(Vec2::angled(1.0).angle(), 1.0);
537        assert_eq!(Vec2::X.angle(), 0.0);
538        assert_eq!(Vec2::Y.angle(), 0.25 * TAU);
539
540        assert_eq!(Vec2::RIGHT.angle(), 0.0);
541        assert_eq!(Vec2::DOWN.angle(), 0.25 * TAU);
542        almost_eq!(Vec2::LEFT.angle(), 0.50 * TAU);
543        assert_eq!(Vec2::UP.angle(), -0.25 * TAU);
544
545        let mut assignment = vec2(1.0, 2.0);
546        assignment += vec2(3.0, 4.0);
547        assert_eq!(assignment, vec2(4.0, 6.0));
548
549        let mut assignment = vec2(4.0, 6.0);
550        assignment -= vec2(1.0, 2.0);
551        assert_eq!(assignment, vec2(3.0, 4.0));
552
553        let mut assignment = vec2(1.0, 2.0);
554        assignment *= 2.0;
555        assert_eq!(assignment, vec2(2.0, 4.0));
556
557        let mut assignment = vec2(2.0, 4.0);
558        assignment /= 2.0;
559        assert_eq!(assignment, vec2(1.0, 2.0));
560    }
561
562    #[test]
563    fn test_vec2_normalized() {
564        fn generate_spiral(n: usize, start: Vec2, end: Vec2) -> impl Iterator<Item = Vec2> {
565            let angle_step = 2.0 * core::f32::consts::PI / n as f32;
566            let radius_step = (end.length() - start.length()) / n as f32;
567
568            (0..n).map(move |i| {
569                let angle = i as f32 * angle_step;
570                let radius = start.length() + i as f32 * radius_step;
571                let x = radius * angle.cos();
572                let y = radius * angle.sin();
573                vec2(x, y)
574            })
575        }
576
577        for v in generate_spiral(40, Vec2::splat(0.1), Vec2::splat(2.0)) {
578            let vn = v.normalized();
579            almost_eq!(vn.length(), 1.0);
580            assert!(vn.is_normalized());
581        }
582    }
583}