mod atom;
mod assembly;
mod bond;
mod secondary;
pub use atom::{Atom, Element};
pub use assembly::{Assembly, AssemblyInstance, Transform};
pub use bond::Bond;
pub use secondary::{HelixType, SecondaryStructure, SecondaryStructureAssignment};
use nalgebra::Vector3;
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Molecule {
pub atoms: Vec<Atom>,
pub bonds: Vec<Bond>,
pub chains: Vec<char>,
pub secondary_structure: Vec<SecondaryStructureAssignment>,
pub assemblies: Vec<Assembly>,
pub model: u32,
}
impl Molecule {
pub fn new() -> Self {
Self {
atoms: Vec::new(),
bonds: Vec::new(),
chains: Vec::new(),
secondary_structure: Vec::new(),
assemblies: Vec::new(),
model: 1,
}
}
pub fn center(&self) -> Vector3<f32> {
if self.atoms.is_empty() {
return Vector3::zeros();
}
let sum: Vector3<f32> = self.atoms.iter().map(|a| a.coord).sum();
sum / self.atoms.len() as f32
}
#[allow(dead_code)]
pub fn bounding_box(&self) -> (Vector3<f32>, Vector3<f32>) {
if self.atoms.is_empty() {
return (Vector3::zeros(), Vector3::zeros());
}
let mut min = self.atoms[0].coord;
let mut max = self.atoms[0].coord;
for atom in &self.atoms {
min.x = min.x.min(atom.coord.x);
min.y = min.y.min(atom.coord.y);
min.z = min.z.min(atom.coord.z);
max.x = max.x.max(atom.coord.x);
max.y = max.y.max(atom.coord.y);
max.z = max.z.max(atom.coord.z);
}
(min, max)
}
#[allow(dead_code)]
pub fn atoms_in_chain(&self, chain_id: char) -> impl Iterator<Item = &Atom> {
self.atoms.iter().filter(move |a| a.chain_id == chain_id)
}
#[allow(dead_code)]
pub fn backbone_atoms(&self) -> Vec<&Atom> {
self.atoms
.iter()
.filter(|a| a.name == "CA" || a.name == "P")
.collect()
}
pub fn chain_count(&self) -> usize {
self.chains.len()
}
pub fn atom_count(&self) -> usize {
self.atoms.len()
}
pub fn assembly_count(&self) -> usize {
if self.assemblies.is_empty() {
1
} else {
self.assemblies.len()
}
}
}
impl Default for Molecule {
fn default() -> Self {
Self::new()
}
}