pub type V3 = [f64; 3];
pub fn add(a: V3, b: V3) -> V3 {
[a[0] + b[0], a[1] + b[1], a[2] + b[2]]
}
pub fn sub(a: V3, b: V3) -> V3 {
[a[0] - b[0], a[1] - b[1], a[2] - b[2]]
}
pub fn scale(a: V3, s: f64) -> V3 {
a.map(|x| x * s)
}
pub fn dot(a: V3, b: V3) -> f64 {
a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
pub fn cross(a: V3, b: V3) -> V3 {
[
a[1] * b[2] - a[2] * b[1],
a[2] * b[0] - a[0] * b[2],
a[0] * b[1] - a[1] * b[0],
]
}
pub fn length(a: V3) -> f64 {
dot(a, a).sqrt()
}
pub fn unit(a: V3) -> Option<V3> {
let l = length(a);
(l > 0.0 && l.is_finite()).then(|| a.map(|x| x / l))
}
pub fn unit_beyond(a: V3, shortest: f64) -> Option<V3> {
let l = length(a);
(l > shortest && l.is_finite()).then(|| a.map(|x| x / l))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn arithmetic_and_directions() {
let (a, b) = ([1.0, 2.0, 3.0], [4.0, 5.0, 6.0]);
assert_eq!(add(a, b), [5.0, 7.0, 9.0]);
assert_eq!(sub(b, a), [3.0, 3.0, 3.0]);
assert_eq!(scale(a, 2.0), [2.0, 4.0, 6.0]);
assert_eq!(dot(a, b), 32.0);
assert_eq!(cross([1.0, 0.0, 0.0], [0.0, 1.0, 0.0]), [0.0, 0.0, 1.0]);
assert_eq!(length([3.0, 4.0, 0.0]), 5.0);
assert_eq!(unit([3.0, 4.0, 0.0]), Some([0.6, 0.8, 0.0]));
assert_eq!(unit([0.0; 3]), None);
assert_eq!(unit([f64::INFINITY, 0.0, 0.0]), None);
assert_eq!(unit_beyond([1e-10, 0.0, 0.0], 1e-9), None);
assert_eq!(unit_beyond([2e-9, 0.0, 0.0], 1e-9), Some([1.0, 0.0, 0.0]));
}
}