molframe_pdb/header/
mtrix.rs1use crate::PdbHeaders;
4use crate::fixed;
5
6#[derive(Clone, Debug, PartialEq)]
8pub struct Mtrix {
9 pub serial: u32,
11 pub rotation: [[f64; 3]; 3],
13 pub translation: [f64; 3],
15 pub given: bool,
17}
18
19type PartialOperator = (u32, [Option<[f64; 4]>; 3], bool);
21
22impl PdbHeaders {
23 #[must_use]
28 pub fn mtrix(&self) -> Vec<Mtrix> {
29 let mut rows: Vec<PartialOperator> = Vec::new();
30 for (row, tag) in ["MTRIX1", "MTRIX2", "MTRIX3"].into_iter().enumerate() {
31 for record in self.named(tag) {
32 let line = record.line();
33 let Some(serial) = fixed::integer(line, 8, 10).and_then(|n| u32::try_from(n).ok())
34 else {
35 continue;
36 };
37 let (Some(a), Some(b), Some(c), Some(t)) = (
38 fixed::real(line, 11, 20),
39 fixed::real(line, 21, 30),
40 fixed::real(line, 31, 40),
41 fixed::real(line, 46, 55),
42 ) else {
43 continue;
44 };
45 let given = fixed::text(line, 60, 60) == "1";
46 let position = rows.iter().position(|entry| entry.0 == serial);
47 let position = if let Some(position) = position {
48 position
49 } else {
50 rows.push((serial, [None; 3], given));
51 rows.len() - 1
52 };
53 rows[position].1[row] = Some([a, b, c, t]);
54 }
55 }
56 rows.into_iter()
57 .filter_map(|(serial, rows, given)| {
58 let [Some(x), Some(y), Some(z)] = rows else {
59 return None;
60 };
61 Some(Mtrix {
62 serial,
63 rotation: [[x[0], x[1], x[2]], [y[0], y[1], y[2]], [z[0], z[1], z[2]]],
64 translation: [x[3], y[3], z[3]],
65 given,
66 })
67 })
68 .collect()
69 }
70}
71
72#[cfg(test)]
73#[path = "mtrix_tests.rs"]
74mod tests;