sciforge_lib/maths/vector/
ops.rs1use 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 - ∥
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}