1pub type V3 = [f64; 3];
7
8pub fn add(a: V3, b: V3) -> V3 {
9 [a[0] + b[0], a[1] + b[1], a[2] + b[2]]
10}
11
12pub fn sub(a: V3, b: V3) -> V3 {
13 [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
14}
15
16pub fn scale(a: V3, s: f64) -> V3 {
18 a.map(|x| x * s)
19}
20
21pub fn dot(a: V3, b: V3) -> f64 {
23 a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
24}
25
26pub fn cross(a: V3, b: V3) -> V3 {
27 [
28 a[1] * b[2] - a[2] * b[1],
29 a[2] * b[0] - a[0] * b[2],
30 a[0] * b[1] - a[1] * b[0],
31 ]
32}
33
34pub fn length(a: V3) -> f64 {
36 dot(a, a).sqrt()
37}
38
39pub fn unit(a: V3) -> Option<V3> {
42 let l = length(a);
43 (l > 0.0 && l.is_finite()).then(|| a.map(|x| x / l))
44}
45
46pub fn unit_beyond(a: V3, shortest: f64) -> Option<V3> {
48 let l = length(a);
49 (l > shortest && l.is_finite()).then(|| a.map(|x| x / l))
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
59 fn arithmetic_and_directions() {
60 let (a, b) = ([1.0, 2.0, 3.0], [4.0, 5.0, 6.0]);
61 assert_eq!(add(a, b), [5.0, 7.0, 9.0]);
62 assert_eq!(sub(b, a), [3.0, 3.0, 3.0]);
63 assert_eq!(scale(a, 2.0), [2.0, 4.0, 6.0]);
64 assert_eq!(dot(a, b), 32.0);
65 assert_eq!(cross([1.0, 0.0, 0.0], [0.0, 1.0, 0.0]), [0.0, 0.0, 1.0]);
66 assert_eq!(length([3.0, 4.0, 0.0]), 5.0);
67 assert_eq!(unit([3.0, 4.0, 0.0]), Some([0.6, 0.8, 0.0]));
68 assert_eq!(unit([0.0; 3]), None);
69 assert_eq!(unit([f64::INFINITY, 0.0, 0.0]), None);
70 assert_eq!(unit_beyond([1e-10, 0.0, 0.0], 1e-9), None);
71 assert_eq!(unit_beyond([2e-9, 0.0, 0.0], 1e-9), Some([1.0, 0.0, 0.0]));
72 }
73}