Skip to main content

sciforge_lib/maths/vector/
ops.rs

1use super::types::Vec3;
2
3pub fn lerp(a: &Vec3, b: &Vec3, t: f64) -> Vec3 {
4    &a.scale(1.0 - t) + &b.scale(t)
5}
6
7pub fn angle_between(a: &Vec3, b: &Vec3) -> f64 {
8    let d = a.dot(b) / (a.magnitude() * b.magnitude());
9    d.clamp(-1.0, 1.0).acos()
10}
11
12pub fn project(v: &Vec3, onto: &Vec3) -> Vec3 {
13    onto.scale(v.dot(onto) / onto.dot(onto))
14}
15
16pub fn reject(v: &Vec3, from: &Vec3) -> Vec3 {
17    v - &project(v, from)
18}
19
20pub fn reflect(v: &Vec3, normal: &Vec3) -> Vec3 {
21    v - &normal.scale(2.0 * v.dot(normal))
22}
23
24pub fn triple_scalar(a: &Vec3, b: &Vec3, c: &Vec3) -> f64 {
25    a.dot(&b.cross(c))
26}
27
28pub fn triple_vector(a: &Vec3, b: &Vec3, c: &Vec3) -> Vec3 {
29    &b.scale(a.dot(c)) - &c.scale(a.dot(b))
30}
31
32pub fn slerp(a: &Vec3, b: &Vec3, t: f64) -> Vec3 {
33    let dot = a.dot(b) / (a.magnitude() * b.magnitude());
34    let dot = dot.clamp(-1.0, 1.0);
35    let theta = dot.acos();
36    if theta.abs() < 1e-10 {
37        return lerp(a, b, t);
38    }
39    let sin_theta = theta.sin();
40    let wa = ((1.0 - t) * theta).sin() / sin_theta;
41    let wb = (t * theta).sin() / sin_theta;
42    &a.scale(wa) + &b.scale(wb)
43}
44
45pub fn distance(a: &Vec3, b: &Vec3) -> f64 {
46    (b - a).magnitude()
47}
48
49pub fn midpoint(a: &Vec3, b: &Vec3) -> Vec3 {
50    lerp(a, b, 0.5)
51}
52
53pub fn centroid(points: &[Vec3]) -> Vec3 {
54    let n = points.len() as f64;
55    let mut sum = Vec3::zero();
56    for p in points {
57        sum = &sum + p;
58    }
59    sum.scale(1.0 / n)
60}
61
62pub fn area_triangle(a: &Vec3, b: &Vec3, c: &Vec3) -> f64 {
63    let ab = b - a;
64    let ac = c - a;
65    0.5 * ab.cross(&ac).magnitude()
66}
67
68pub fn normal_triangle(a: &Vec3, b: &Vec3, c: &Vec3) -> Vec3 {
69    let ab = b - a;
70    let ac = c - a;
71    ab.cross(&ac).normalize()
72}
73
74pub fn decompose_parallel_perpendicular(v: &Vec3, direction: &Vec3) -> (Vec3, Vec3) {
75    let parallel = project(v, direction);
76    let perpendicular = v - &parallel;
77    (parallel, perpendicular)
78}
79
80pub fn rotate_around_axis(v: &Vec3, axis: &Vec3, angle: f64) -> Vec3 {
81    let k = axis.normalize();
82    let cos_a = angle.cos();
83    let sin_a = angle.sin();
84    let term1 = v.scale(cos_a);
85    let term2 = k.cross(v).scale(sin_a);
86    let term3 = k.scale(k.dot(v) * (1.0 - cos_a));
87    &(&term1 + &term2) + &term3
88}
89
90pub fn spherical_to_cartesian(r: f64, theta: f64, phi: f64) -> Vec3 {
91    Vec3::new(
92        r * theta.sin() * phi.cos(),
93        r * theta.sin() * phi.sin(),
94        r * theta.cos(),
95    )
96}
97
98pub fn cartesian_to_spherical(v: &Vec3) -> (f64, f64, f64) {
99    let r = v.magnitude();
100    let theta = if r.abs() < 1e-30 {
101        0.0
102    } else {
103        (v.z / r).acos()
104    };
105    let phi = v.y.atan2(v.x);
106    (r, theta, phi)
107}
108
109pub fn cylindrical_to_cartesian(rho: f64, phi: f64, z: f64) -> Vec3 {
110    Vec3::new(rho * phi.cos(), rho * phi.sin(), z)
111}
112
113pub fn cartesian_to_cylindrical(v: &Vec3) -> (f64, f64, f64) {
114    let rho = (v.x * v.x + v.y * v.y).sqrt();
115    let phi = v.y.atan2(v.x);
116    (rho, phi, v.z)
117}