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    #[inline(always)]
123    pub const fn new(x: f32, y: f32) -> Self {
124        Self { x, y }
125    }
126
127    /// The vector from origin to this position.
128    /// `p.to_vec2()` is equivalent to `p - Pos2::default()`.
129    #[inline(always)]
130    pub fn to_vec2(self) -> Vec2 {
131        Vec2 {
132            x: self.x,
133            y: self.y,
134        }
135    }
136
137    #[inline]
138    pub fn distance(self, other: Self) -> f32 {
139        (self - other).length()
140    }
141
142    #[inline]
143    pub fn distance_sq(self, other: Self) -> f32 {
144        (self - other).length_sq()
145    }
146
147    #[inline(always)]
148    pub fn floor(self) -> Self {
149        pos2(self.x.floor(), self.y.floor())
150    }
151
152    #[inline(always)]
153    pub fn round(self) -> Self {
154        pos2(self.x.round(), self.y.round())
155    }
156
157    #[inline(always)]
158    pub fn ceil(self) -> Self {
159        pos2(self.x.ceil(), self.y.ceil())
160    }
161
162    /// True if all members are also finite.
163    #[inline(always)]
164    pub fn is_finite(self) -> bool {
165        self.x.is_finite() && self.y.is_finite()
166    }
167
168    /// True if any member is NaN.
169    #[inline(always)]
170    pub fn any_nan(self) -> bool {
171        self.x.is_nan() || self.y.is_nan()
172    }
173
174    #[must_use]
175    #[inline]
176    pub fn min(self, other: Self) -> Self {
177        pos2(self.x.min(other.x), self.y.min(other.y))
178    }
179
180    #[must_use]
181    #[inline]
182    pub fn max(self, other: Self) -> Self {
183        pos2(self.x.max(other.x), self.y.max(other.y))
184    }
185
186    #[must_use]
187    #[inline]
188    pub fn clamp(self, min: Self, max: Self) -> Self {
189        Self {
190            x: self.x.clamp(min.x, max.x),
191            y: self.y.clamp(min.y, max.y),
192        }
193    }
194
195    /// Linearly interpolate towards another point, so that `0.0 => self, 1.0 => other`.
196    pub fn lerp(&self, other: Self, t: f32) -> Self {
197        Self {
198            x: lerp(self.x..=other.x, t),
199            y: lerp(self.y..=other.y, t),
200        }
201    }
202}
203
204impl std::ops::Index<usize> for Pos2 {
205    type Output = f32;
206
207    #[inline(always)]
208    fn index(&self, index: usize) -> &f32 {
209        match index {
210            0 => &self.x,
211            1 => &self.y,
212            _ => panic!("Pos2 index out of bounds: {index}"),
213        }
214    }
215}
216
217impl std::ops::IndexMut<usize> for Pos2 {
218    #[inline(always)]
219    fn index_mut(&mut self, index: usize) -> &mut f32 {
220        match index {
221            0 => &mut self.x,
222            1 => &mut self.y,
223            _ => panic!("Pos2 index out of bounds: {index}"),
224        }
225    }
226}
227
228impl Eq for Pos2 {}
229
230impl AddAssign<Vec2> for Pos2 {
231    #[inline(always)]
232    fn add_assign(&mut self, rhs: Vec2) {
233        *self = Self {
234            x: self.x + rhs.x,
235            y: self.y + rhs.y,
236        };
237    }
238}
239
240impl SubAssign<Vec2> for Pos2 {
241    #[inline(always)]
242    fn sub_assign(&mut self, rhs: Vec2) {
243        *self = Self {
244            x: self.x - rhs.x,
245            y: self.y - rhs.y,
246        };
247    }
248}
249
250impl Add<Vec2> for Pos2 {
251    type Output = Self;
252
253    #[inline(always)]
254    fn add(self, rhs: Vec2) -> Self {
255        Self {
256            x: self.x + rhs.x,
257            y: self.y + rhs.y,
258        }
259    }
260}
261
262impl Sub for Pos2 {
263    type Output = Vec2;
264
265    #[inline(always)]
266    fn sub(self, rhs: Self) -> Vec2 {
267        Vec2 {
268            x: self.x - rhs.x,
269            y: self.y - rhs.y,
270        }
271    }
272}
273
274impl Sub<Vec2> for Pos2 {
275    type Output = Self;
276
277    #[inline(always)]
278    fn sub(self, rhs: Vec2) -> Self {
279        Self {
280            x: self.x - rhs.x,
281            y: self.y - rhs.y,
282        }
283    }
284}
285
286impl Mul<f32> for Pos2 {
287    type Output = Self;
288
289    #[inline(always)]
290    fn mul(self, factor: f32) -> Self {
291        Self {
292            x: self.x * factor,
293            y: self.y * factor,
294        }
295    }
296}
297
298impl Mul<Pos2> for f32 {
299    type Output = Pos2;
300
301    #[inline(always)]
302    fn mul(self, vec: Pos2) -> Pos2 {
303        Pos2 {
304            x: self * vec.x,
305            y: self * vec.y,
306        }
307    }
308}
309
310impl MulAssign<f32> for Pos2 {
311    #[inline(always)]
312    fn mul_assign(&mut self, rhs: f32) {
313        self.x *= rhs;
314        self.y *= rhs;
315    }
316}
317
318impl Div<f32> for Pos2 {
319    type Output = Self;
320
321    #[inline(always)]
322    fn div(self, factor: f32) -> Self {
323        Self {
324            x: self.x / factor,
325            y: self.y / factor,
326        }
327    }
328}
329
330impl fmt::Debug for Pos2 {
331    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
332        if let Some(precision) = f.precision() {
333            write!(f, "[{1:.0$} {2:.0$}]", precision, self.x, self.y)
334        } else {
335            write!(f, "[{:.1} {:.1}]", self.x, self.y)
336        }
337    }
338}
339
340impl fmt::Display for Pos2 {
341    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342        f.write_str("[")?;
343        self.x.fmt(f)?;
344        f.write_str(" ")?;
345        self.y.fmt(f)?;
346        f.write_str("]")?;
347        Ok(())
348    }
349}