use crate::{AdjacencyList, Atom, Bond};
use glam::DVec2;
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum SmilesParseError {
#[error("SMILES parser is not implemented yet")]
NotImplemented,
#[error("{0}")]
ParseError(String),
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Molecule {
pub atoms: Vec<Atom>,
pub bonds: Vec<Bond>,
pub coords_2d: Option<Vec<DVec2>>,
pub adjacency: Option<AdjacencyList>,
}
impl Molecule {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn add_atom(&mut self, atom: Atom) -> usize {
let index = self.atoms.len();
let mut atom = atom;
atom.index = index;
self.atoms.push(atom);
self.coords_2d = None;
self.adjacency = None;
index
}
pub fn add_bond(&mut self, bond: Bond) -> usize {
let index = self.bonds.len();
let mut bond = bond;
bond.index = index;
self.bonds.push(bond);
self.adjacency = None;
index
}
pub fn rebuild_adjacency(&mut self) {
self.adjacency = Some(AdjacencyList::from_topology(self.atoms.len(), &self.bonds));
}
pub fn from_smiles(smiles: &str) -> Result<Self, SmilesParseError> {
crate::smiles::parse_smiles(smiles)
}
pub fn compute_2d_coords(&mut self) -> Result<&mut Self, crate::io::molblock::MolWriteError> {
let coords = crate::io::molblock::compute_2d_coords_minimal(self)?;
self.coords_2d = Some(coords.into_iter().map(|(x, y)| DVec2::new(x, y)).collect());
Ok(self)
}
#[must_use]
pub fn coords_2d(&self) -> Option<&[DVec2]> {
self.coords_2d.as_deref()
}
#[must_use]
pub fn atomic_numbers(&self) -> Vec<u8> {
self.atoms.iter().map(|atom| atom.atomic_num).collect()
}
}