rust_3d/
point_2d.rs

1/*
2Copyright 2016 Martin Buck
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation the
7rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the Software
9is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall
12be included all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21*/
22
23//! Point2D, a point / position within 2D space
24
25use std::{
26    cmp::{Eq, Ordering},
27    fmt,
28    hash::{Hash, Hasher},
29    ops::{Add, Div, Mul, Neg, Sub},
30};
31
32use crate::*;
33
34//------------------------------------------------------------------------------
35
36#[derive(Default, Debug, PartialEq, PartialOrd, Clone)]
37/// Point2D, a point / position within 2D space
38pub 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}