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