1use std::{
26 cmp::{Eq, Ordering},
27 fmt,
28 hash::{Hash, Hasher},
29 ops::{Add, Div, Mul, Neg, Sub},
30};
31
32use crate::*;
33
34#[derive(Default, Debug, PartialEq, PartialOrd, Clone)]
37pub struct Point2D {
39 pub x: f64,
40 pub y: f64,
41}
42
43impl Point2D {
44 pub fn new(x: f64, y: f64) -> Self {
45 Point2D { x, y }
46 }
47}
48
49impl Eq for Point2D {}
50
51impl Ord for Point2D {
52 fn cmp(&self, other: &Self) -> Ordering {
53 let origin = Point2D::default();
54 sqr_dist_2d(&origin, self)
55 .partial_cmp(&sqr_dist_2d(&origin, other))
56 .unwrap_or(Ordering::Equal)
57 }
58}
59
60impl Hash for Point2D {
61 #[inline(always)]
62 fn hash<H: Hasher>(&self, state: &mut H) {
63 hash_f64(self.x, state);
64 hash_f64(self.y, state);
65 }
66}
67
68impl<P> Add<P> for Point2D
69where
70 P: Is2D,
71{
72 type Output = Point2D;
73
74 fn add(self, other: P) -> Point2D {
75 Point2D {
76 x: self.x + other.x(),
77 y: self.y + other.y(),
78 }
79 }
80}
81
82impl<P> Add<&P> for &Point2D
83where
84 P: Is2D,
85{
86 type Output = Point2D;
87
88 fn add(self, other: &P) -> Point2D {
89 Point2D {
90 x: self.x + other.x(),
91 y: self.y + other.y(),
92 }
93 }
94}
95
96impl Add<Point2D> for &Point2D {
97 type Output = Point2D;
98
99 fn add(self, other: Point2D) -> Point2D {
100 Point2D {
101 x: self.x + other.x(),
102 y: self.y + other.y(),
103 }
104 }
105}
106
107impl<P> Sub<P> for Point2D
108where
109 P: Is2D,
110{
111 type Output = Point2D;
112
113 fn sub(self, other: P) -> Point2D {
114 Point2D {
115 x: self.x - other.x(),
116 y: self.y - other.y(),
117 }
118 }
119}
120
121impl<P> Sub<&P> for &Point2D
122where
123 P: Is2D,
124{
125 type Output = Point2D;
126
127 fn sub(self, other: &P) -> Point2D {
128 Point2D {
129 x: self.x - other.x(),
130 y: self.y - other.y(),
131 }
132 }
133}
134
135impl Sub<Point2D> for &Point2D {
136 type Output = Point2D;
137
138 fn sub(self, other: Point2D) -> Point2D {
139 Point2D {
140 x: self.x - other.x(),
141 y: self.y - other.y(),
142 }
143 }
144}
145
146impl Mul<f64> for Point2D {
147 type Output = Point2D;
148
149 fn mul(self, other: f64) -> Point2D {
150 Point2D {
151 x: other * self.x,
152 y: other * self.y,
153 }
154 }
155}
156
157impl Mul<f64> for &Point2D {
158 type Output = Point2D;
159
160 fn mul(self, other: f64) -> Point2D {
161 Point2D {
162 x: other * self.x,
163 y: other * self.y,
164 }
165 }
166}
167
168impl Div<f64> for Point2D {
169 type Output = Point2D;
170
171 fn div(self, other: f64) -> Point2D {
172 Point2D {
173 x: self.x / other,
174 y: self.y / other,
175 }
176 }
177}
178
179impl Div<f64> for &Point2D {
180 type Output = Point2D;
181
182 fn div(self, other: f64) -> Point2D {
183 Point2D {
184 x: self.x / other,
185 y: self.y / other,
186 }
187 }
188}
189
190impl Neg for Point2D {
191 type Output = Point2D;
192
193 fn neg(self) -> Point2D {
194 Point2D {
195 x: -self.x,
196 y: -self.y,
197 }
198 }
199}
200
201impl Neg for &Point2D {
202 type Output = Point2D;
203
204 fn neg(self) -> Point2D {
205 Point2D {
206 x: -self.x,
207 y: -self.y,
208 }
209 }
210}
211
212impl IsMovable2D for Point2D {
213 fn move_by(&mut self, x: f64, y: f64) {
214 self.x += x;
215 self.y += y;
216 }
217}
218
219impl IsND for Point2D {
220 fn n_dimensions() -> usize {
221 2
222 }
223
224 fn position_nd(&self, dimension: usize) -> Result<f64> {
225 match dimension {
226 0 => Ok(self.x),
227 1 => Ok(self.y),
228 _ => Err(ErrorKind::IncorrectDimension),
229 }
230 }
231}
232
233impl Is2D for Point2D {
234 #[inline(always)]
235 fn x(&self) -> f64 {
236 self.x
237 }
238
239 #[inline(always)]
240 fn y(&self) -> f64 {
241 self.y
242 }
243}
244
245impl IsBuildableND for Point2D {
246 #[inline(always)]
247 fn new_nd(coords: &[f64]) -> Result<Self> {
248 if coords.len() != 2 {
249 return Err(ErrorKind::DimensionsDontMatch);
250 }
251 Ok(Point2D {
252 x: coords[0],
253 y: coords[1],
254 })
255 }
256
257 #[inline(always)]
258 fn from_nd<P>(&mut self, other: P) -> Result<()>
259 where
260 P: IsBuildableND,
261 {
262 if P::n_dimensions() != 2 {
263 return Err(ErrorKind::DimensionsDontMatch);
264 }
265
266 self.x = other.position_nd(0)?;
267 self.y = other.position_nd(1)?;
268 Ok(())
269 }
270}
271
272impl IsBuildable2D for Point2D {
273 #[inline(always)]
274 fn new(x: f64, y: f64) -> Self {
275 Point2D { x, y }
276 }
277
278 #[inline(always)]
279 fn from<P>(&mut self, other: &P)
280 where
281 P: Is2D,
282 {
283 self.x = other.x();
284 self.y = other.y();
285 }
286}
287
288impl IsEditableND for Point2D {
289 fn set_position(&mut self, dimension: usize, val: f64) -> Result<()> {
290 match dimension {
291 0 => self.x = val,
292 1 => self.y = val,
293 _ => return Err(ErrorKind::DimensionsDontMatch),
294 }
295 Ok(())
296 }
297}
298
299impl IsEditable2D for Point2D {
300 #[inline(always)]
301 fn set_x(&mut self, val: f64) {
302 self.x = val;
303 }
304
305 #[inline(always)]
306 fn set_y(&mut self, val: f64) {
307 self.y = val;
308 }
309}
310
311impl IsTransFormableTo3D for Point2D {
312 fn transform_to_3d<P>(&self, z: f64) -> P
313 where
314 P: IsBuildable3D,
315 {
316 P::new(self.x, self.y, z)
317 }
318}
319
320impl IsMatrix3Transformable for Point2D {
321 fn transformed(&self, m: &Matrix3) -> Self {
322 self.multiply_m(m)
323 }
324 fn transform(&mut self, m: &Matrix3) {
325 let new = self.multiply_m(m);
326 *self = new;
327 }
328}
329
330impl fmt::Display for Point2D {
331 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
332 write!(f, "({}, {})", self.x, self.y)
333 }
334}