1use 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#[derive(Default, Debug, PartialEq, PartialOrd, Clone)]
38pub 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}