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 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 std::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 std::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 Eq for Vec2 {}
350
351impl Neg for Vec2 {
352    type Output = Self;
353
354    #[inline(always)]
355    fn neg(self) -> Self {
356        vec2(-self.x, -self.y)
357    }
358}
359
360impl AddAssign for Vec2 {
361    #[inline(always)]
362    fn add_assign(&mut self, rhs: Self) {
363        *self = Self {
364            x: self.x + rhs.x,
365            y: self.y + rhs.y,
366        };
367    }
368}
369
370impl SubAssign for Vec2 {
371    #[inline(always)]
372    fn sub_assign(&mut self, rhs: Self) {
373        *self = Self {
374            x: self.x - rhs.x,
375            y: self.y - rhs.y,
376        };
377    }
378}
379
380impl Add for Vec2 {
381    type Output = Self;
382
383    #[inline(always)]
384    fn add(self, rhs: Self) -> Self {
385        Self {
386            x: self.x + rhs.x,
387            y: self.y + rhs.y,
388        }
389    }
390}
391
392impl Sub for Vec2 {
393    type Output = Self;
394
395    #[inline(always)]
396    fn sub(self, rhs: Self) -> Self {
397        Self {
398            x: self.x - rhs.x,
399            y: self.y - rhs.y,
400        }
401    }
402}
403
404/// Element-wise multiplication
405impl Mul<Self> for Vec2 {
406    type Output = Self;
407
408    #[inline(always)]
409    fn mul(self, vec: Self) -> Self {
410        Self {
411            x: self.x * vec.x,
412            y: self.y * vec.y,
413        }
414    }
415}
416
417/// Element-wise division
418impl Div<Self> for Vec2 {
419    type Output = Self;
420
421    #[inline(always)]
422    fn div(self, rhs: Self) -> Self {
423        Self {
424            x: self.x / rhs.x,
425            y: self.y / rhs.y,
426        }
427    }
428}
429
430impl MulAssign<f32> for Vec2 {
431    #[inline(always)]
432    fn mul_assign(&mut self, rhs: f32) {
433        self.x *= rhs;
434        self.y *= rhs;
435    }
436}
437
438impl DivAssign<f32> for Vec2 {
439    #[inline(always)]
440    fn div_assign(&mut self, rhs: f32) {
441        self.x /= rhs;
442        self.y /= rhs;
443    }
444}
445
446impl Mul<f32> for Vec2 {
447    type Output = Self;
448
449    #[inline(always)]
450    fn mul(self, factor: f32) -> Self {
451        Self {
452            x: self.x * factor,
453            y: self.y * factor,
454        }
455    }
456}
457
458impl Mul<Vec2> for f32 {
459    type Output = Vec2;
460
461    #[inline(always)]
462    fn mul(self, vec: Vec2) -> Vec2 {
463        Vec2 {
464            x: self * vec.x,
465            y: self * vec.y,
466        }
467    }
468}
469
470impl Div<f32> for Vec2 {
471    type Output = Self;
472
473    #[inline(always)]
474    fn div(self, factor: f32) -> Self {
475        Self {
476            x: self.x / factor,
477            y: self.y / factor,
478        }
479    }
480}
481
482impl fmt::Debug for Vec2 {
483    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484        if let Some(precision) = f.precision() {
485            write!(f, "[{1:.0$} {2:.0$}]", precision, self.x, self.y)
486        } else {
487            write!(f, "[{:.1} {:.1}]", self.x, self.y)
488        }
489    }
490}
491
492impl fmt::Display for Vec2 {
493    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494        f.write_str("[")?;
495        self.x.fmt(f)?;
496        f.write_str(" ")?;
497        self.y.fmt(f)?;
498        f.write_str("]")?;
499        Ok(())
500    }
501}
502
503#[cfg(test)]
504mod test {
505    use super::*;
506
507    macro_rules! almost_eq {
508        ($left: expr, $right: expr) => {
509            let left = $left;
510            let right = $right;
511            assert!((left - right).abs() < 1e-6, "{} != {}", left, right);
512        };
513    }
514
515    #[test]
516    fn test_vec2() {
517        use std::f32::consts::TAU;
518
519        assert_eq!(Vec2::ZERO.angle(), 0.0);
520        assert_eq!(Vec2::angled(0.0).angle(), 0.0);
521        assert_eq!(Vec2::angled(1.0).angle(), 1.0);
522        assert_eq!(Vec2::X.angle(), 0.0);
523        assert_eq!(Vec2::Y.angle(), 0.25 * TAU);
524
525        assert_eq!(Vec2::RIGHT.angle(), 0.0);
526        assert_eq!(Vec2::DOWN.angle(), 0.25 * TAU);
527        almost_eq!(Vec2::LEFT.angle(), 0.50 * TAU);
528        assert_eq!(Vec2::UP.angle(), -0.25 * TAU);
529
530        let mut assignment = vec2(1.0, 2.0);
531        assignment += vec2(3.0, 4.0);
532        assert_eq!(assignment, vec2(4.0, 6.0));
533
534        let mut assignment = vec2(4.0, 6.0);
535        assignment -= vec2(1.0, 2.0);
536        assert_eq!(assignment, vec2(3.0, 4.0));
537
538        let mut assignment = vec2(1.0, 2.0);
539        assignment *= 2.0;
540        assert_eq!(assignment, vec2(2.0, 4.0));
541
542        let mut assignment = vec2(2.0, 4.0);
543        assignment /= 2.0;
544        assert_eq!(assignment, vec2(1.0, 2.0));
545    }
546
547    #[test]
548    fn test_vec2_normalized() {
549        fn generate_spiral(n: usize, start: Vec2, end: Vec2) -> impl Iterator<Item = Vec2> {
550            let angle_step = 2.0 * std::f32::consts::PI / n as f32;
551            let radius_step = (end.length() - start.length()) / n as f32;
552
553            (0..n).map(move |i| {
554                let angle = i as f32 * angle_step;
555                let radius = start.length() + i as f32 * radius_step;
556                let x = radius * angle.cos();
557                let y = radius * angle.sin();
558                vec2(x, y)
559            })
560        }
561
562        for v in generate_spiral(40, Vec2::splat(0.1), Vec2::splat(2.0)) {
563            let vn = v.normalized();
564            almost_eq!(vn.length(), 1.0);
565            assert!(vn.is_normalized());
566        }
567    }
568}