use crate::coordinate_systems::Cartesian;
pub fn vector_difference(a: Cartesian, b: Cartesian) -> f64 {
let midpoint_ab = lerp(a, b, 0.5);
let midpoint_ab = normalize(midpoint_ab);
let cross_result = cross(a, midpoint_ab);
let d = length(cross_result);
if d < 1e-8 {
let ab = subtract(a, b);
let half_distance = 0.5 * length(ab);
return half_distance;
}
d
}
pub fn triple_product(a: Cartesian, b: Cartesian, c: Cartesian) -> f64 {
let cross_bc = cross(b, c);
dot(a, cross_bc)
}
pub fn quadruple_product(a: Cartesian, b: Cartesian, c: Cartesian, d: Cartesian) -> Cartesian {
let cross_cd = cross(c, d);
let triple_product_acd = dot(a, cross_cd);
let triple_product_bcd = dot(b, cross_cd);
let scaled_a = scale(a, triple_product_bcd);
let scaled_b = scale(b, triple_product_acd);
subtract(scaled_b, scaled_a)
}
pub fn slerp(a: Cartesian, b: Cartesian, t: f64) -> Cartesian {
let gamma = angle(a, b);
if gamma < 1e-12 {
return lerp(a, b, t);
}
let weight_a = ((1.0 - t) * gamma).sin() / gamma.sin();
let weight_b = (t * gamma).sin() / gamma.sin();
let scaled_a = scale(a, weight_a);
let scaled_b = scale(b, weight_b);
add(scaled_a, scaled_b)
}
fn dot(a: Cartesian, b: Cartesian) -> f64 {
a.x() * b.x() + a.y() * b.y() + a.z() * b.z()
}
fn cross(a: Cartesian, b: Cartesian) -> Cartesian {
Cartesian::new(
a.y() * b.z() - a.z() * b.y(),
a.z() * b.x() - a.x() * b.z(),
a.x() * b.y() - a.y() * b.x(),
)
}
pub fn length(v: Cartesian) -> f64 {
(v.x() * v.x() + v.y() * v.y() + v.z() * v.z()).sqrt()
}
pub fn vec3_length(v: &Cartesian) -> f64 {
length(*v)
}
fn normalize(v: Cartesian) -> Cartesian {
let len = length(v);
if len == 0.0 {
return v;
}
Cartesian::new(v.x() / len, v.y() / len, v.z() / len)
}
fn lerp(a: Cartesian, b: Cartesian, t: f64) -> Cartesian {
Cartesian::new(
a.x() + t * (b.x() - a.x()),
a.y() + t * (b.y() - a.y()),
a.z() + t * (b.z() - a.z()),
)
}
fn subtract(a: Cartesian, b: Cartesian) -> Cartesian {
Cartesian::new(a.x() - b.x(), a.y() - b.y(), a.z() - b.z())
}
pub fn vec3_distance(a: &Cartesian, b: &Cartesian) -> f64 {
length(subtract(*a, *b))
}
fn add(a: Cartesian, b: Cartesian) -> Cartesian {
Cartesian::new(a.x() + b.x(), a.y() + b.y(), a.z() + b.z())
}
fn scale(v: Cartesian, s: f64) -> Cartesian {
Cartesian::new(v.x() * s, v.y() * s, v.z() * s)
}
fn angle(a: Cartesian, b: Cartesian) -> f64 {
let dot_product = dot(a, b);
let len_a = length(a);
let len_b = length(b);
let cos_angle = dot_product / (len_a * len_b);
cos_angle.clamp(-1.0, 1.0).acos()
}