#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DiatomicRotationFrame {
pub r: f64,
pub l: f64,
pub m: f64,
pub n: f64,
pub d1: [[f64; 3]; 3],
}
impl DiatomicRotationFrame {
pub fn compute(ra: &[f64; 3], rb: &[f64; 3]) -> Self {
let dx = rb[0] - ra[0];
let dy = rb[1] - ra[1];
let dz = rb[2] - ra[2];
let r2 = dx * dx + dy * dy + dz * dz;
let r = r2.sqrt();
if r < 1e-12 {
return Self {
r: 0.0,
l: 0.0,
m: 0.0,
n: 1.0,
d1: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
};
}
let l = dx / r;
let m = dy / r;
let n = dz / r;
let xy = (dx * dx + dy * dy).sqrt();
let (d1_row0, d1_row1, d1_row2) = if xy > 1e-10 {
let x_prime = [-dy / xy, dx / xy, 0.0];
let z_prime = [l, m, n];
let y_prime = [
z_prime[1] * x_prime[2] - z_prime[2] * x_prime[1],
z_prime[2] * x_prime[0] - z_prime[0] * x_prime[2],
z_prime[0] * x_prime[1] - z_prime[1] * x_prime[0],
];
(x_prime, y_prime, z_prime)
} else {
let sign = if dz >= 0.0 { 1.0 } else { -1.0 };
([1.0, 0.0, 0.0], [0.0, sign, 0.0], [0.0, 0.0, sign])
};
Self {
r,
l,
m,
n,
d1: [d1_row0, d1_row1, d1_row2],
}
}
pub fn is_orthonormal(&self, tol: f64) -> bool {
for i in 0..3 {
for j in 0..3 {
let dot = self.d1[i][0] * self.d1[j][0]
+ self.d1[i][1] * self.d1[j][1]
+ self.d1[i][2] * self.d1[j][2];
let expected = if i == j { 1.0 } else { 0.0 };
if (dot - expected).abs() > tol {
return false;
}
}
}
true
}
pub fn determinant(&self) -> f64 {
let m = &self.d1;
m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
- m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
+ m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0])
}
}