emath/
pos2.rs

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