vg_algebra/vectors/
vector3d.rs

1use std::ops::{Add, AddAssign, Mul, Sub};
2
3use super::{BivectorTrait, VectorTrait};
4
5/// 3d vector in R3
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Vector {
8    pub x: f64,
9    pub y: f64,
10    pub z: f64,
11}
12
13impl Vector {
14    pub fn new(x: f64, y: f64, z: f64) -> Vector {
15        return Vector { x, y, z };
16    }
17}
18
19impl super::VectorTrait for Vector {
20    fn scale(&self, scale: f64) -> Vector {
21        return Vector {
22            x: scale * self.x,
23            y: scale * self.y,
24            z: scale * self.z,
25        };
26    }
27
28    fn length(&self) -> f64 {
29        f64::sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
30    }
31
32    fn normalize(&self) -> Vector {
33        let length = self.length();
34        Vector::new(self.x / length, self.y / length, self.z / length)
35    }
36
37    fn is_colinear_to(&self, rhs: Self) -> bool {
38        let factor_x = self.x / rhs.x;
39        let factor_y = self.y / rhs.y;
40        let factor_z = self.z / rhs.z;
41
42        let differences = vec![
43            factor_x - factor_y,
44            factor_x - factor_z,
45            factor_z - factor_y,
46        ];
47
48        for difference in differences {
49            if difference >= f64::EPSILON {
50                return false;
51            }
52        }
53        return true;
54    }
55
56    type WedgeProductOutput = Bivector;
57    fn wedge_product(&self, rhs: Self) -> Self::WedgeProductOutput {
58        Bivector {
59            yz: self.y * rhs.z - self.z * rhs.y,
60            zx: self.z * rhs.x - self.x * rhs.z,
61            xy: self.x * rhs.y - self.y * rhs.x,
62        }
63    }
64
65    type CrossProductOutput = Vector;
66    fn cross_product(&self, rhs: Self) -> Self::CrossProductOutput {
67        self.wedge_product(rhs).as_vector()
68    }
69
70    fn dot_product(&self, rhs: Self) -> f64 {
71        (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z)
72    }
73}
74
75impl Add for Vector {
76    type Output = Vector;
77
78    fn add(self, rhs: Self) -> Vector {
79        Self {
80            x: self.x + rhs.x,
81            y: self.y + rhs.y,
82            z: self.z + rhs.z,
83        }
84    }
85}
86
87impl AddAssign for Vector {
88    fn add_assign(&mut self, rhs: Self) {
89        *self = *self + rhs
90    }
91}
92
93impl Sub for Vector {
94    type Output = Self;
95
96    fn sub(self, other: Self) -> Self::Output {
97        Self {
98            x: self.x - other.x,
99            y: self.y - other.y,
100            z: self.z - other.z,
101        }
102    }
103}
104
105impl Mul for Vector {
106    type Output = Rotor;
107
108    fn mul(self, rhs: Self) -> Self::Output {
109        let scalar = self.dot_product(rhs);
110        let bivector = self.wedge_product(rhs);
111
112        Rotor { scalar, bivector }
113    }
114}
115
116/// Struct for 3d bivector: an oriented area (gives axis for rotations)
117#[derive(Debug, PartialEq)]
118pub struct Bivector {
119    pub yz: f64,
120    pub zx: f64,
121    pub xy: f64,
122}
123
124impl Bivector {
125    /// create a new bivector
126    pub fn new(yz: f64, zx: f64, xy: f64) -> Self {
127        Bivector { yz, zx, xy }
128    }
129
130    /// Returns the bivector's pseudovector as if it was a vector
131    fn as_vector(&self) -> Vector {
132        Vector::new(self.yz, self.zx, self.xy)
133    }
134}
135
136impl BivectorTrait for Bivector {
137    fn scale(&self, p: f64) -> Self {
138        Bivector::new(self.yz * p, self.zx * p, self.xy * p)
139    }
140
141    fn magnitude(&self) -> f64 {
142        self.as_vector().length()
143    }
144}
145
146/// Defines a rotation in 3d space
147#[derive(Debug, PartialEq)]
148pub struct Rotor {
149    scalar: f64,
150    bivector: Bivector,
151}
152
153impl Rotor {
154    /// returns the equivalent quaternion to rotor
155    pub fn as_quaternion(self) -> Quaternion {
156        Quaternion {
157            real: self.scalar,
158            i: self.bivector.yz,
159            j: self.bivector.zx,
160            k: self.bivector.xy,
161        }
162    }
163}
164
165/// defines a quaternion
166#[derive(Debug, PartialEq)]
167pub struct Quaternion {
168    real: f64,
169    i: f64,
170    j: f64,
171    k: f64,
172}
173
174impl Quaternion {
175    /// Returns the equivalent 3d rotor
176    pub fn as_rotor(&self) -> Rotor {
177        let bivector = Bivector {
178            yz: self.i,
179            zx: self.j,
180            xy: self.k,
181        };
182        Rotor {
183            scalar: self.real,
184            bivector: bivector,
185        }
186    }
187}
188
189#[cfg(test)]
190mod test_vectors {
191    use super::{Bivector, Quaternion, Rotor, Vector};
192    use crate::vectors::VectorTrait;
193
194    #[test]
195    fn test_new_vector() {
196        let vector = Vector::new(0.1, 0.3, 0.6);
197        let expected_result = Vector {
198            x: 0.1,
199            y: 0.3,
200            z: 0.6,
201        };
202
203        assert_eq!(vector, expected_result);
204    }
205
206    #[test]
207
208    fn test_scale_vector() {
209        let vector = Vector::new(0.1, 0.3, 0.6);
210        let result = vector.scale(2.0);
211        let expected_result = Vector {
212            x: 0.2,
213            y: 0.6,
214            z: 1.2,
215        };
216
217        assert_eq!(result, expected_result);
218    }
219
220    #[test]
221    fn test_vector_length() {
222        let a = Vector::new(0.0, 3.0, 0.0);
223        let b = Vector::new(1.0, 1.0, -1.0);
224
225        assert_eq!(a.length(), 3.0);
226        assert_eq!(b.length(), f64::sqrt(3.0));
227    }
228
229    #[test]
230    fn test_vector_normalize() {
231        let a = Vector::new(0.0, 3.0, 0.0).normalize();
232        let b = Vector::new(1.0, 1.0, -1.0).normalize();
233
234        assert_eq!(a, Vector::new(0.0, 1.0, 0.0));
235        assert!(b.length() - 1.0 <= f64::EPSILON);
236    }
237
238    #[test]
239    fn test_vector_addition() {
240        let a = Vector::new(0.1, 0.3, 0.6);
241        let b = Vector::new(0.1, 0.3, 0.4);
242
243        let expected_result = Vector::new(0.2, 0.6, 1.0);
244
245        assert_eq!(a + b, expected_result);
246    }
247
248    #[test]
249    fn test_is_colinear_to() {
250        let a = Vector::new(0.1, 0.3, 0.6);
251        let b = Vector::new(2.0, 0.3, 0.0);
252        let c = Vector::new(0.2, 0.6, 1.2);
253
254        assert_eq!(a.is_colinear_to(b), b.is_colinear_to(c));
255        assert!(a.is_colinear_to(c));
256        assert!(a.is_colinear_to(a))
257    }
258
259    #[test]
260    fn test_vector_subtraction() {
261        let a = Vector::new(0.1, 0.3, 0.6);
262        let b = Vector::new(0.1, 0.3, 0.4);
263
264        let expected_result = Vector::new(0.0, 0.0, 0.2);
265        let result = a - b;
266
267        let difference = result - expected_result;
268        assert!(difference.x <= f64::EPSILON);
269        assert!(difference.y <= f64::EPSILON);
270        assert!(difference.z <= f64::EPSILON);
271    }
272
273    #[test]
274    fn test_vector_multiplication() {
275        let a = Vector::new(1.0, 0.5, 0.5);
276        let b = Vector::new(2.0, 0.0, 1.0);
277
278        let expected_with_help = Rotor {
279            scalar: a.dot_product(b),
280            bivector: a.wedge_product(b),
281        };
282        let expected_without_help = Rotor {
283            scalar: 2.5,
284            bivector: Bivector {
285                yz: 0.5,
286                zx: 0.0,
287                xy: -1.0,
288            },
289        };
290
291        let result = a * b;
292        assert_eq!(expected_with_help, expected_without_help);
293        assert_eq!(expected_with_help, result);
294        assert_eq!(expected_without_help, result);
295    }
296
297    #[test]
298    fn test_rotor_as_quaternion() {
299        let bivector = Bivector {
300            yz: 1.0,
301            zx: 0.2,
302            xy: -0.3,
303        };
304        let rotor = Rotor {
305            scalar: 0.3,
306            bivector,
307        };
308
309        let expected = Quaternion {
310            real: 0.3,
311            i: 1.0,
312            j: 0.2,
313            k: -0.3,
314        };
315        let result = rotor.as_quaternion();
316
317        assert_eq!(expected, result)
318    }
319
320    #[test]
321    fn test_quaternion_as_rotor() {
322        let quaternion = Quaternion {
323            real: 0.3,
324            i: 1.0,
325            j: 0.2,
326            k: -0.3,
327        };
328
329        let bivector = Bivector {
330            yz: 1.0,
331            zx: 0.2,
332            xy: -0.3,
333        };
334        let expected = Rotor {
335            scalar: 0.3,
336            bivector,
337        };
338        let result = quaternion.as_rotor();
339
340        assert_eq!(expected, result)
341    }
342}