1use std::fmt;
4use std::ops::{Add, AddAssign, Sub};
5
6use crate::Vec3;
7
8#[derive(Clone, Copy, PartialEq)]
13#[repr(C)]
14pub struct Point3 {
15 pub x: f64,
17 pub y: f64,
19 pub z: f64,
21}
22
23impl Point3 {
24 pub const ORIGIN: Self = Self { x: 0.0, y: 0.0, z: 0.0 };
26
27 #[inline] pub const fn new(x: f64, y: f64, z: f64) -> Self { Self { x, y, z } }
29
30 #[inline]
32 pub fn offset_from(self, other: Self) -> Vec3 {
33 Vec3::new(self.x - other.x, self.y - other.y, self.z - other.z)
34 }
35
36 #[inline]
38 pub fn distance_to(self, other: Self) -> f64 { self.offset_from(other).length() }
39
40 #[inline]
42 pub fn lerp(self, other: Self, t: f64) -> Self {
43 Self::new(
44 self.x + t * (other.x - self.x),
45 self.y + t * (other.y - self.y),
46 self.z + t * (other.z - self.z),
47 )
48 }
49
50 #[inline]
52 pub fn to_vec(self) -> Vec3 { Vec3::new(self.x, self.y, self.z) }
53
54 #[inline]
56 pub fn from_vec(v: Vec3) -> Self { Self::new(v.x, v.y, v.z) }
57}
58
59impl Add<Vec3> for Point3 {
63 type Output = Self;
64 #[inline]
65 fn add(self, v: Vec3) -> Self {
66 Self::new(self.x + v.x, self.y + v.y, self.z + v.z)
67 }
68}
69impl AddAssign<Vec3> for Point3 {
70 #[inline] fn add_assign(&mut self, v: Vec3) { *self = *self + v; }
71}
72
73impl Sub for Point3 {
75 type Output = Vec3;
76 #[inline]
77 fn sub(self, other: Self) -> Vec3 { self.offset_from(other) }
78}
79
80impl Sub<Vec3> for Point3 {
82 type Output = Self;
83 #[inline]
84 fn sub(self, v: Vec3) -> Self { Self::new(self.x - v.x, self.y - v.y, self.z - v.z) }
85}
86
87impl fmt::Debug for Point3 {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 write!(f, "Point3({:.6}, {:.6}, {:.6})", self.x, self.y, self.z)
90 }
91}
92impl fmt::Display for Point3 {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 write!(f, "({:.4}, {:.4}, {:.4})", self.x, self.y, self.z)
95 }
96}
97
98impl From<[f64; 3]> for Point3 {
101 fn from(a: [f64; 3]) -> Self { Self::new(a[0], a[1], a[2]) }
102}
103impl From<Point3> for [f64; 3] {
104 fn from(p: Point3) -> [f64; 3] { [p.x, p.y, p.z] }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn subtraction_gives_vec() {
113 let a = Point3::new(3.0, 0.0, 0.0);
114 let b = Point3::ORIGIN;
115 let v = a - b;
116 assert_eq!(v, Vec3::new(3.0, 0.0, 0.0));
117 }
118
119 #[test]
120 fn add_vec_moves_point() {
121 let p = Point3::ORIGIN + Vec3::Z;
122 assert_eq!(p, Point3::new(0.0, 0.0, 1.0));
123 }
124}