emath/
pos2.rs

1use std::{
2    fmt,
3    ops::{Add, AddAssign, MulAssign, Sub, SubAssign},
4};
5
6use crate::{Div, Mul, Vec2, lerp};
7
8/// A position on screen.
9///
10/// Normally given in points (logical pixels).
11///
12/// Mathematically this is known as a "point", but the term position was chosen so not to
13/// conflict with the unit (one point = X physical pixels).
14#[repr(C)]
15#[derive(Clone, Copy, Default, PartialEq)]
16#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
17#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
18pub struct Pos2 {
19    /// How far to the right.
20    pub x: f32,
21
22    /// How far down.
23    pub y: f32,
24    // implicit w = 1
25}
26
27/// `pos2(x, y) == Pos2::new(x, y)`
28#[inline(always)]
29pub const fn pos2(x: f32, y: f32) -> Pos2 {
30    Pos2 { x, y }
31}
32
33// ----------------------------------------------------------------------------
34// Compatibility and convenience conversions to and from [f32; 2]:
35
36impl From<[f32; 2]> for Pos2 {
37    #[inline(always)]
38    fn from(v: [f32; 2]) -> Self {
39        Self { x: v[0], y: v[1] }
40    }
41}
42
43impl From<&[f32; 2]> for Pos2 {
44    #[inline(always)]
45    fn from(v: &[f32; 2]) -> Self {
46        Self { x: v[0], y: v[1] }
47    }
48}
49
50impl From<Pos2> for [f32; 2] {
51    #[inline(always)]
52    fn from(v: Pos2) -> Self {
53        [v.x, v.y]
54    }
55}
56
57impl From<&Pos2> for [f32; 2] {
58    #[inline(always)]
59    fn from(v: &Pos2) -> Self {
60        [v.x, v.y]
61    }
62}
63
64// ----------------------------------------------------------------------------
65// Compatibility and convenience conversions to and from (f32, f32):
66
67impl From<(f32, f32)> for Pos2 {
68    #[inline(always)]
69    fn from(v: (f32, f32)) -> Self {
70        Self { x: v.0, y: v.1 }
71    }
72}
73
74impl From<&(f32, f32)> for Pos2 {
75    #[inline(always)]
76    fn from(v: &(f32, f32)) -> Self {
77        Self { x: v.0, y: v.1 }
78    }
79}
80
81impl From<Pos2> for (f32, f32) {
82    #[inline(always)]
83    fn from(v: Pos2) -> Self {
84        (v.x, v.y)
85    }
86}
87
88impl From<&Pos2> for (f32, f32) {
89    #[inline(always)]
90    fn from(v: &Pos2) -> Self {
91        (v.x, v.y)
92    }
93}
94
95// ----------------------------------------------------------------------------
96// Mint compatibility and convenience conversions
97
98#[cfg(feature = "mint")]
99impl From<mint::Point2<f32>> for Pos2 {
100    #[inline(always)]
101    fn from(v: mint::Point2<f32>) -> Self {
102        Self::new(v.x, v.y)
103    }
104}
105
106#[cfg(feature = "mint")]
107impl From<Pos2> for mint::Point2<f32> {
108    #[inline(always)]
109    fn from(v: Pos2) -> Self {
110        Self { x: v.x, y: v.y }
111    }
112}
113
114// ----------------------------------------------------------------------------
115
116impl Pos2 {
117    /// The zero position, the origin.
118    /// The top left corner in a GUI.
119    /// Same as `Pos2::default()`.
120    pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
121
122    pub const NAN: Self = Self {
123        x: f32::NAN,
124        y: f32::NAN,
125    };
126
127    #[inline(always)]
128    pub const fn new(x: f32, y: f32) -> Self {
129        Self { x, y }
130    }
131
132    /// The vector from origin to this position.
133    /// `p.to_vec2()` is equivalent to `p - Pos2::default()`.
134    #[inline(always)]
135    pub fn to_vec2(self) -> Vec2 {
136        Vec2 {
137            x: self.x,
138            y: self.y,
139        }
140    }
141
142    #[inline]
143    pub fn distance(self, other: Self) -> f32 {
144        (self - other).length()
145    }
146
147    #[inline]
148    pub fn distance_sq(self, other: Self) -> f32 {
149        (self - other).length_sq()
150    }
151
152    #[inline(always)]
153    pub fn floor(self) -> Self {
154        pos2(self.x.floor(), self.y.floor())
155    }
156
157    #[inline(always)]
158    pub fn round(self) -> Self {
159        pos2(self.x.round(), self.y.round())
160    }
161
162    #[inline(always)]
163    pub fn ceil(self) -> Self {
164        pos2(self.x.ceil(), self.y.ceil())
165    }
166
167    /// True if all members are also finite.
168    #[inline(always)]
169    pub fn is_finite(self) -> bool {
170        self.x.is_finite() && self.y.is_finite()
171    }
172
173    /// True if any member is NaN.
174    #[inline(always)]
175    pub fn any_nan(self) -> bool {
176        self.x.is_nan() || self.y.is_nan()
177    }
178
179    #[must_use]
180    #[inline]
181    pub fn min(self, other: Self) -> Self {
182        pos2(self.x.min(other.x), self.y.min(other.y))
183    }
184
185    #[must_use]
186    #[inline]
187    pub fn max(self, other: Self) -> Self {
188        pos2(self.x.max(other.x), self.y.max(other.y))
189    }
190
191    #[must_use]
192    #[inline]
193    pub fn clamp(self, min: Self, max: Self) -> Self {
194        Self {
195            x: self.x.clamp(min.x, max.x),
196            y: self.y.clamp(min.y, max.y),
197        }
198    }
199
200    /// Linearly interpolate towards another point, so that `0.0 => self, 1.0 => other`.
201    pub fn lerp(&self, other: Self, t: f32) -> Self {
202        Self {
203            x: lerp(self.x..=other.x, t),
204            y: lerp(self.y..=other.y, t),
205        }
206    }
207}
208
209impl std::ops::Index<usize> for Pos2 {
210    type Output = f32;
211
212    #[inline(always)]
213    fn index(&self, index: usize) -> &f32 {
214        match index {
215            0 => &self.x,
216            1 => &self.y,
217            _ => panic!("Pos2 index out of bounds: {index}"),
218        }
219    }
220}
221
222impl std::ops::IndexMut<usize> for Pos2 {
223    #[inline(always)]
224    fn index_mut(&mut self, index: usize) -> &mut f32 {
225        match index {
226            0 => &mut self.x,
227            1 => &mut self.y,
228            _ => panic!("Pos2 index out of bounds: {index}"),
229        }
230    }
231}
232
233impl Eq for Pos2 {}
234
235impl AddAssign<Vec2> for Pos2 {
236    #[inline(always)]
237    fn add_assign(&mut self, rhs: Vec2) {
238        *self = Self {
239            x: self.x + rhs.x,
240            y: self.y + rhs.y,
241        };
242    }
243}
244
245impl SubAssign<Vec2> for Pos2 {
246    #[inline(always)]
247    fn sub_assign(&mut self, rhs: Vec2) {
248        *self = Self {
249            x: self.x - rhs.x,
250            y: self.y - rhs.y,
251        };
252    }
253}
254
255impl Add<Vec2> for Pos2 {
256    type Output = Self;
257
258    #[inline(always)]
259    fn add(self, rhs: Vec2) -> Self {
260        Self {
261            x: self.x + rhs.x,
262            y: self.y + rhs.y,
263        }
264    }
265}
266
267impl Sub for Pos2 {
268    type Output = Vec2;
269
270    #[inline(always)]
271    fn sub(self, rhs: Self) -> Vec2 {
272        Vec2 {
273            x: self.x - rhs.x,
274            y: self.y - rhs.y,
275        }
276    }
277}
278
279impl Sub<Vec2> for Pos2 {
280    type Output = Self;
281
282    #[inline(always)]
283    fn sub(self, rhs: Vec2) -> Self {
284        Self {
285            x: self.x - rhs.x,
286            y: self.y - rhs.y,
287        }
288    }
289}
290
291impl Mul<f32> for Pos2 {
292    type Output = Self;
293
294    #[inline(always)]
295    fn mul(self, factor: f32) -> Self {
296        Self {
297            x: self.x * factor,
298            y: self.y * factor,
299        }
300    }
301}
302
303impl Mul<Pos2> for f32 {
304    type Output = Pos2;
305
306    #[inline(always)]
307    fn mul(self, vec: Pos2) -> Pos2 {
308        Pos2 {
309            x: self * vec.x,
310            y: self * vec.y,
311        }
312    }
313}
314
315impl MulAssign<f32> for Pos2 {
316    #[inline(always)]
317    fn mul_assign(&mut self, rhs: f32) {
318        self.x *= rhs;
319        self.y *= rhs;
320    }
321}
322
323impl Div<f32> for Pos2 {
324    type Output = Self;
325
326    #[inline(always)]
327    fn div(self, factor: f32) -> Self {
328        Self {
329            x: self.x / factor,
330            y: self.y / factor,
331        }
332    }
333}
334
335impl fmt::Debug for Pos2 {
336    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337        if let Some(precision) = f.precision() {
338            write!(f, "[{1:.0$} {2:.0$}]", precision, self.x, self.y)
339        } else {
340            write!(f, "[{:.1} {:.1}]", self.x, self.y)
341        }
342    }
343}
344
345impl fmt::Display for Pos2 {
346    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347        f.write_str("[")?;
348        self.x.fmt(f)?;
349        f.write_str(" ")?;
350        self.y.fmt(f)?;
351        f.write_str("]")?;
352        Ok(())
353    }
354}