use std::fmt;
use approx;
use log;
use nalgebra as na;
use serde::{Deserialize, Serialize};
#[cfg(test)]
#[path = "rotsym_tests.rs"]
mod rotsym_tests;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum RotationalSymmetry {
Spherical,
OblatePlanar,
OblateNonPlanar,
ProlateLinear,
ProlateNonLinear,
AsymmetricPlanar,
AsymmetricNonPlanar,
}
impl fmt::Display for RotationalSymmetry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RotationalSymmetry::Spherical => write!(f, "Spherical"),
RotationalSymmetry::OblatePlanar => write!(f, "Oblate, planar"),
RotationalSymmetry::OblateNonPlanar => write!(f, "Oblate, non-planar"),
RotationalSymmetry::ProlateLinear => write!(f, "Prolate, linear"),
RotationalSymmetry::ProlateNonLinear => write!(f, "Prolate, non-linear"),
RotationalSymmetry::AsymmetricPlanar => write!(f, "Asymmetric, planar"),
RotationalSymmetry::AsymmetricNonPlanar => write!(f, "Asymmetric, non-planar"),
}
}
}
#[must_use]
pub fn calc_rotational_symmetry(
inertia_tensor: &na::Matrix3<f64>,
thresh: f64,
) -> RotationalSymmetry {
let moi_mat = inertia_tensor.symmetric_eigenvalues();
let mut moi: Vec<&f64> = moi_mat.iter().collect();
moi.sort_by(|a, b| {
a.partial_cmp(b)
.unwrap_or_else(|| panic!("`{a}` and `{b}` cannot be compared."))
});
log::debug!("Moments of inertia:");
for component in &moi {
log::debug!(" {component:+.14}");
}
if approx::relative_eq!(*moi[0], *moi[1], epsilon = thresh, max_relative = thresh) {
if approx::relative_eq!(*moi[1], *moi[2], epsilon = thresh, max_relative = thresh) {
return RotationalSymmetry::Spherical;
}
if approx::relative_eq!(
*moi[2],
*moi[0] + *moi[1],
epsilon = thresh,
max_relative = thresh
) {
return RotationalSymmetry::OblatePlanar;
}
return RotationalSymmetry::OblateNonPlanar;
}
if approx::relative_eq!(*moi[1], *moi[2], epsilon = thresh, max_relative = thresh) {
if moi[0].abs() < thresh {
return RotationalSymmetry::ProlateLinear;
}
return RotationalSymmetry::ProlateNonLinear;
}
if approx::relative_eq!(
*moi[2],
*moi[0] + *moi[1],
epsilon = thresh,
max_relative = thresh
) {
return RotationalSymmetry::AsymmetricPlanar;
}
RotationalSymmetry::AsymmetricNonPlanar
}