use crate::PdbHeaders;
use crate::fixed;
#[derive(Clone, Debug, PartialEq)]
pub struct Mtrix {
pub serial: u32,
pub rotation: [[f64; 3]; 3],
pub translation: [f64; 3],
pub given: bool,
}
type PartialOperator = (u32, [Option<[f64; 4]>; 3], bool);
impl PdbHeaders {
#[must_use]
pub fn mtrix(&self) -> Vec<Mtrix> {
let mut rows: Vec<PartialOperator> = Vec::new();
for (row, tag) in ["MTRIX1", "MTRIX2", "MTRIX3"].into_iter().enumerate() {
for record in self.named(tag) {
let line = record.line();
let Some(serial) = fixed::integer(line, 8, 10).and_then(|n| u32::try_from(n).ok())
else {
continue;
};
let (Some(a), Some(b), Some(c), Some(t)) = (
fixed::real(line, 11, 20),
fixed::real(line, 21, 30),
fixed::real(line, 31, 40),
fixed::real(line, 46, 55),
) else {
continue;
};
let given = fixed::text(line, 60, 60) == "1";
let position = rows.iter().position(|entry| entry.0 == serial);
let position = if let Some(position) = position {
position
} else {
rows.push((serial, [None; 3], given));
rows.len() - 1
};
rows[position].1[row] = Some([a, b, c, t]);
}
}
rows.into_iter()
.filter_map(|(serial, rows, given)| {
let [Some(x), Some(y), Some(z)] = rows else {
return None;
};
Some(Mtrix {
serial,
rotation: [[x[0], x[1], x[2]], [y[0], y[1], y[2]], [z[0], z[1], z[2]]],
translation: [x[3], y[3], z[3]],
given,
})
})
.collect()
}
}
#[cfg(test)]
#[path = "mtrix_tests.rs"]
mod tests;