1#[allow(unused_imports)]
2use crate::float::Float;
3
4#[repr(C)]
5#[derive(Clone, Copy)]
6pub struct Point {
7 pub x: f32,
8 pub y: f32,
9}
10impl Point {
11 pub const ZERO: Point = Point::zero();
12 pub const ONE: Point = Point::new(1., 1.);
13 pub const AXIS_X: Point = Point::new(1., 0.);
14 pub const AXIS_Y: Point = Point::new(0., 1.);
15 #[inline]
16 pub const fn new(x: f32, y: f32) -> Self {
17 Self { x, y }
18 }
19 #[inline]
20 pub const fn zero() -> Self {
21 Self { x: 0., y: 0. }
22 }
23 #[inline]
24 pub const fn to_array(self) -> [f32; 2] {
25 [self.x, self.y]
26 }
27 #[inline]
28 pub const fn to_tuple(self) -> (f32, f32) {
29 (self.x, self.y)
30 }
31 #[inline]
32 pub fn abs(self) -> Self {
33 Self {
34 x: self.x.abs(),
35 y: self.y.abs(),
36 }
37 }
38 #[inline]
39 pub fn floor(self) -> Self {
40 Self::new(self.x.floor(), self.y.floor())
41 }
42 #[inline]
43 pub fn round(self) -> Self {
44 Self::new(self.x.round(), self.y.round())
45 }
46 #[inline]
47 pub fn ceil(self) -> Self {
48 Self::new(self.x.ceil(), self.y.ceil())
49 }
50 #[inline]
51 pub fn normalize(self) -> Option<Self> {
52 let length = self.length();
53 if length <= f32::EPSILON {
54 return None;
55 }
56 let inverse = 1. / length;
57 Some(Self::new(self.x * inverse, self.y * inverse))
58 }
59 #[inline]
60 pub fn normalized(self) -> Self {
61 self.normalize().unwrap_or_default()
62 }
63 #[inline]
64 pub fn lerp(self, other: Self, t: f32) -> Self {
65 Point {
66 x: self.x * (1.0 - t) + other.x * t,
67 y: self.y * (1.0 - t) + other.y * t,
68 }
69 }
70 #[inline]
71 pub fn length_squared(self) -> f32 {
72 self.x * self.x + self.y * self.y
73 }
74 #[inline]
75 pub fn length(self) -> f32 {
76 self.length_squared().sqrt()
77 }
78 #[inline]
79 pub fn area(self) -> f32 {
80 self.x * self.y
81 }
82 #[inline]
83 pub fn dot(self, to: Self) -> f32 {
84 self.x * to.x + self.y * to.y
85 }
86 #[inline]
87 pub fn cross(self, to: Self) -> f32 {
88 self.x * to.y - self.y * to.x
89 }
90 #[inline]
91 pub fn distance_squared(self, to: Point) -> f32 {
92 (self - to).length_squared()
93 }
94 #[inline]
95 pub fn distance(self, to: Point) -> f32 {
96 self.distance_squared(to).sqrt()
97 }
98 #[inline]
99 pub fn normal(self) -> Point {
100 Point::new(self.y, -self.x)
101 }
102 #[inline]
103 pub fn normal_to(self, to: Point) -> Point {
104 (to - self).normal()
105 }
106 #[inline]
107 pub fn nearly(self, to: Point, epsilon: f32) -> bool {
108 (self.x - to.x).abs() < epsilon && (self.y - to.y).abs() < epsilon
109 }
110 #[inline]
112 pub fn angle(self) -> f32 {
113 self.y.atan2(self.x)
114 }
115}
116impl Default for Point {
117 #[inline]
118 fn default() -> Self {
119 Self::zero()
120 }
121}
122impl core::fmt::Debug for Point {
123 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
124 f.debug_tuple("Point").field(&self.x).field(&self.y).finish()
125 }
126}
127impl PartialEq<Point> for Point {
128 fn eq(&self, other: &Point) -> bool {
129 (self.x - other.x).abs() < f32::EPSILON && (self.y - other.y).abs() < f32::EPSILON
130 }
131}
132impl PartialOrd<Point> for Point {
133 fn partial_cmp(&self, other: &Point) -> Option<core::cmp::Ordering> {
134 if self.eq(other) {
135 Some(core::cmp::Ordering::Equal)
136 } else {
137 self.x.partial_cmp(&other.x).and_then(|x| {
138 if x != core::cmp::Ordering::Equal {
139 return Some(x);
140 }
141 self.y.partial_cmp(&other.y)
142 })
143 }
144 }
145}
146impl core::hash::Hash for Point {
147 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
148 state.write_i32((self.x * 1000.) as _);
149 state.write_i32((self.y * 1000.) as _);
150 }
151}
152
153impl core::ops::Mul<f32> for Point {
154 type Output = Point;
155 #[inline]
156 fn mul(self, scale: f32) -> Self::Output {
157 Point::new(self.x * scale, self.y * scale)
158 }
159}
160impl core::ops::Mul<Point> for Point {
161 type Output = Point;
162 fn mul(self, rhs: Point) -> Self::Output {
163 Point::new(self.x * rhs.x, self.y * rhs.y)
164 }
165}
166impl core::ops::Div<f32> for Point {
167 type Output = Point;
168 #[inline]
169 fn div(self, rhs: f32) -> Self::Output {
170 Point::new(self.x / rhs, self.y / rhs)
171 }
172}
173impl core::ops::Div for Point {
174 type Output = Self;
175 #[inline]
176 fn div(self, rhs: Self) -> Self {
177 Self::new(self.x / rhs.x, self.y / rhs.y)
178 }
179}
180impl core::ops::Add for Point {
181 type Output = Point;
182 #[inline]
183 fn add(self, other: Point) -> Self::Output {
184 Point::new(self.x + other.x, self.y + other.y)
185 }
186}
187impl core::ops::Sub for Point {
188 type Output = Point;
189 #[inline]
190 fn sub(self, other: Self) -> Self::Output {
191 Point::new(self.x - other.x, self.y - other.y)
192 }
193}
194impl core::ops::Neg for Point {
195 type Output = Point;
196 #[inline]
197 fn neg(self) -> Self::Output {
198 Point::new(-self.x, -self.y)
199 }
200}
201
202impl From<(f32, f32)> for Point {
203 #[inline]
204 fn from(value: (f32, f32)) -> Self {
205 Self::new(value.0, value.1)
206 }
207}
208impl From<[f32; 2]> for Point {
209 fn from(v: [f32; 2]) -> Self {
210 Self::new(v[0], v[1])
211 }
212}
213impl From<(i32, i32)> for Point {
214 fn from(v: (i32, i32)) -> Self {
215 Self::new(v.0 as f32, v.1 as f32)
216 }
217}
218impl From<[i32; 2]> for Point {
219 fn from(v: [i32; 2]) -> Self {
220 Self::new(v[0] as f32, v[1] as f32)
221 }
222}
223impl From<(f32, i32)> for Point {
224 fn from(v: (f32, i32)) -> Self {
225 Self::new(v.0, v.1 as f32)
226 }
227}
228impl From<(i32, f32)> for Point {
229 fn from(v: (i32, f32)) -> Self {
230 Self::new(v.0 as f32, v.1)
231 }
232}
233impl From<f32> for Point {
234 fn from(x: f32) -> Self {
235 Self::new(x, x)
236 }
237}
238impl From<i32> for Point {
239 fn from(x: i32) -> Self {
240 let x = x as f32;
241 Self::new(x, x)
242 }
243}
244impl From<Point> for [f32; 2] {
245 fn from(v: Point) -> Self {
246 [v.x, v.y]
247 }
248}
249impl From<Point> for (f32, f32) {
250 fn from(v: Point) -> Self {
251 (v.x, v.y)
252 }
253}