rust_tracer/
math.rs

1use std::ops;
2
3#[derive(Debug, Copy, Clone, PartialEq)]
4pub struct Vector3(pub f64, pub f64, pub f64);
5
6impl Vector3 {
7    pub fn new(x: f64, y: f64, z: f64) -> Vector3 {
8        Vector3(x, y, z)
9    }
10
11    pub fn x(&self) -> f64 {
12        self.0
13    }
14    pub fn y(&self) -> f64 {
15        self.1
16    }
17    pub fn z(&self) -> f64 {
18        self.2
19    }
20
21    pub fn length_squared(&self) -> f64 {
22        self.0 * self.0 + self.1 * self.1 + self.2 * self.2
23    }
24
25    pub fn length(&self) -> f64 {
26        self.length_squared().sqrt()
27    }
28
29    pub fn dot(&self, other: &Self) -> f64 {
30        self.0 * other.0 + self.1 * other.1 + self.2 * other.2
31    }
32
33    pub fn cross(&self, other: &Self) -> Self {
34        Vector3(
35            self.1 * other.2 - self.2 * other.1,
36            self.2 * other.0 - self.0 * other.2,
37            self.0 * other.1 - self.1 * other.0,
38        )
39    }
40
41    pub fn unit_vector(&self) -> Self {
42        *self / self.length()
43    }
44
45    pub fn near_zero(&self) -> bool {
46        let small = 1e-8;
47
48        (self.0.abs() < small) && (self.1.abs() < small) && (self.2.abs() < small)
49    }
50}
51
52impl ops::Add for Vector3 {
53    type Output = Vector3;
54
55    fn add(self, rhs: Self) -> Self::Output {
56        Vector3(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
57    }
58}
59
60impl ops::AddAssign for Vector3 {
61    fn add_assign(&mut self, rhs: Self) {
62        self.0 += rhs.0;
63        self.1 += rhs.1;
64        self.2 += rhs.2;
65    }
66}
67
68impl ops::Sub for Vector3 {
69    type Output = Vector3;
70
71    fn sub(self, rhs: Self) -> Self::Output {
72        Vector3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
73    }
74}
75
76impl ops::SubAssign for Vector3 {
77    fn sub_assign(&mut self, rhs: Self) {
78        self.0 -= rhs.0;
79        self.1 -= rhs.1;
80        self.2 -= rhs.2;
81    }
82}
83
84impl ops::Div<f64> for Vector3 {
85    type Output = Vector3;
86
87    fn div(self, rhs: f64) -> Self::Output {
88        Vector3(self.0 / rhs, self.1 / rhs, self.2 / rhs)
89    }
90}
91
92impl ops::DivAssign<f64> for Vector3 {
93    fn div_assign(&mut self, rhs: f64) {
94        self.0 /= rhs;
95        self.1 /= rhs;
96        self.2 /= rhs;
97    }
98}
99
100impl ops::Mul<f64> for Vector3 {
101    type Output = Vector3;
102
103    fn mul(self, rhs: f64) -> Self::Output {
104        Vector3(self.0 * rhs, self.1 * rhs, self.2 * rhs)
105    }
106}
107
108impl ops::Mul<Vector3> for f64 {
109    type Output = Vector3;
110
111    fn mul(self, rhs: Vector3) -> Self::Output {
112        Vector3(self * rhs.0, self * rhs.1, self * rhs.2)
113    }
114}
115
116impl ops::MulAssign<f64> for Vector3 {
117    fn mul_assign(&mut self, rhs: f64) {
118        self.0 *= rhs;
119        self.1 *= rhs;
120        self.2 *= rhs;
121    }
122}
123
124impl ops::Neg for Vector3 {
125    type Output = Vector3;
126
127    fn neg(self) -> Self::Output {
128        Vector3(-self.0, -self.1, -self.2)
129    }
130}
131
132impl ops::Mul<Vector3> for Vector3 {
133    type Output = Vector3;
134
135    fn mul(self, rhs: Vector3) -> Self::Output {
136        Vector3(self.0 * rhs.0, self.1 * rhs.1, self.2 * rhs.2)
137    }
138}
139
140pub type Point3 = Vector3;
141pub type Color = Vector3;
142
143#[cfg(test)]
144mod tests {
145    use crate::math::*;
146
147    #[test]
148    fn vector_eq() {
149        assert_eq!(Vector3(1.0, 2.0, 3.0), Vector3(1.0, 2.0, 3.0));
150    }
151
152    #[test]
153    fn vector_add() {
154        assert_eq!(
155            Vector3(1.0, 2.0, 3.0) + Vector3(4.0, 5.0, 6.0),
156            Vector3(5.0, 7.0, 9.0)
157        );
158    }
159
160    #[test]
161    fn vector_add_assign() {
162        let mut v = Vector3(1.0, 2.0, 3.0);
163        v += Vector3(4.0, 5.0, 6.0);
164
165        assert_eq!(v, Vector3(5.0, 7.0, 9.0));
166    }
167
168    #[test]
169    fn vector_sub() {
170        assert_eq!(
171            Vector3(1.0, 2.0, 3.0) - Vector3(4.0, 5.0, 6.0),
172            Vector3(-3.0, -3.0, -3.0)
173        );
174    }
175
176    #[test]
177    fn vector_sub_assign() {
178        let mut v = Vector3(1.0, 2.0, 3.0);
179        v -= Vector3(4.0, 5.0, 6.0);
180
181        assert_eq!(v, Vector3(-3.0, -3.0, -3.0));
182    }
183
184    #[test]
185    fn vector_div() {
186        assert_eq!(Vector3(1.0, 2.0, 3.0) / 2.0, Vector3(0.5, 1.0, 1.5));
187    }
188
189    #[test]
190    fn vector_div_assign() {
191        let mut v = Vector3(1.0, 2.0, 3.0);
192        v /= 2.0;
193
194        assert_eq!(v, Vector3(0.5, 1.0, 1.5));
195    }
196
197    #[test]
198    fn vector_mul() {
199        assert_eq!(Vector3(1.0, 2.0, 3.0) * 2.0, Vector3(2.0, 4.0, 6.0));
200    }
201
202    #[test]
203    fn vector_mul_assign() {
204        let mut v = Vector3(1.0, 2.0, 3.0);
205        v *= 2.0;
206
207        assert_eq!(v, Vector3(2.0, 4.0, 6.0));
208    }
209
210    #[test]
211    fn vector_neg() {
212        assert_eq!(-Vector3(1.0, 2.0, 3.0), Vector3(-1.0, -2.0, -3.0));
213    }
214}
215
216#[derive(Debug, Copy, Clone, PartialEq)]
217pub struct Ray {
218    pub origin: Point3,
219    pub direction: Vector3,
220}
221
222impl Ray {
223    pub fn new(origin: Point3, direction: Vector3) -> Self {
224        Ray { origin, direction }
225    }
226
227    pub fn at(&self, t: f64) -> Point3 {
228        self.origin + self.direction * t
229    }
230}