1use core::{
2 fmt,
3 ops::{Add, AddAssign, MulAssign, Sub, SubAssign},
4};
5
6use crate::{Div, Mul, Vec2, lerp};
7
8#[repr(C)]
15#[derive(Clone, Copy, Default)]
16#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
17#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
18pub struct Pos2 {
19 pub x: f32,
21
22 pub y: f32,
24 }
26
27#[inline(always)]
29pub const fn pos2(x: f32, y: f32) -> Pos2 {
30 Pos2 { x, y }
31}
32
33impl 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
64impl 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#[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
114impl Pos2 {
117 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 #[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 #[inline(always)]
169 pub fn is_finite(self) -> bool {
170 self.x.is_finite() && self.y.is_finite()
171 }
172
173 #[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 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 core::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 core::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 PartialEq for Pos2 {
234 #[track_caller]
235 #[inline]
236 fn eq(&self, other: &Self) -> bool {
237 debug_assert!(
238 !self.any_nan() && !other.any_nan(),
239 "Comparing NaN positions ({self:?} and {other:?}). \
240 A NaN is not even equal to itself, which leads to very confusing bugs."
241 );
242 self.x == other.x && self.y == other.y
243 }
244}
245
246impl Eq for Pos2 {}
249
250impl AddAssign<Vec2> for Pos2 {
251 #[inline(always)]
252 fn add_assign(&mut self, rhs: Vec2) {
253 *self = Self {
254 x: self.x + rhs.x,
255 y: self.y + rhs.y,
256 };
257 }
258}
259
260impl SubAssign<Vec2> for Pos2 {
261 #[inline(always)]
262 fn sub_assign(&mut self, rhs: Vec2) {
263 *self = Self {
264 x: self.x - rhs.x,
265 y: self.y - rhs.y,
266 };
267 }
268}
269
270impl Add<Vec2> for Pos2 {
271 type Output = Self;
272
273 #[inline(always)]
274 fn add(self, rhs: Vec2) -> Self {
275 Self {
276 x: self.x + rhs.x,
277 y: self.y + rhs.y,
278 }
279 }
280}
281
282impl Sub for Pos2 {
283 type Output = Vec2;
284
285 #[inline(always)]
286 fn sub(self, rhs: Self) -> Vec2 {
287 Vec2 {
288 x: self.x - rhs.x,
289 y: self.y - rhs.y,
290 }
291 }
292}
293
294impl Sub<Vec2> for Pos2 {
295 type Output = Self;
296
297 #[inline(always)]
298 fn sub(self, rhs: Vec2) -> Self {
299 Self {
300 x: self.x - rhs.x,
301 y: self.y - rhs.y,
302 }
303 }
304}
305
306impl Mul<f32> for Pos2 {
307 type Output = Self;
308
309 #[inline(always)]
310 fn mul(self, factor: f32) -> Self {
311 Self {
312 x: self.x * factor,
313 y: self.y * factor,
314 }
315 }
316}
317
318impl Mul<Pos2> for f32 {
319 type Output = Pos2;
320
321 #[inline(always)]
322 fn mul(self, vec: Pos2) -> Pos2 {
323 Pos2 {
324 x: self * vec.x,
325 y: self * vec.y,
326 }
327 }
328}
329
330impl MulAssign<f32> for Pos2 {
331 #[inline(always)]
332 fn mul_assign(&mut self, rhs: f32) {
333 self.x *= rhs;
334 self.y *= rhs;
335 }
336}
337
338impl Div<f32> for Pos2 {
339 type Output = Self;
340
341 #[inline(always)]
342 fn div(self, factor: f32) -> Self {
343 Self {
344 x: self.x / factor,
345 y: self.y / factor,
346 }
347 }
348}
349
350impl fmt::Debug for Pos2 {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 if let Some(precision) = f.precision() {
353 write!(f, "[{1:.0$} {2:.0$}]", precision, self.x, self.y)
354 } else {
355 write!(f, "[{:.1} {:.1}]", self.x, self.y)
356 }
357 }
358}
359
360impl fmt::Display for Pos2 {
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 f.write_str("[")?;
363 self.x.fmt(f)?;
364 f.write_str(" ")?;
365 self.y.fmt(f)?;
366 f.write_str("]")?;
367 Ok(())
368 }
369}