use super::data::{Structure, StructureData};
use crate::coords::{Aabb, CoordinateGeneration};
use crate::index::ModelIndex;
use crate::selection::AtomSelection;
use std::sync::Arc;
#[derive(Clone, Debug)]
pub struct StructureView {
structure: Arc<StructureData>,
atoms: AtomSelection,
generation: CoordinateGeneration,
}
impl StructureView {
#[must_use]
pub fn new(structure: &Structure, atoms: AtomSelection) -> Self {
Self {
structure: structure.shared(),
atoms,
generation: structure.generation(),
}
}
#[must_use]
pub const fn selection(&self) -> &AtomSelection {
&self.atoms
}
#[must_use]
pub fn data(&self) -> &StructureData {
&self.structure
}
#[must_use]
pub fn len(&self) -> u64 {
self.atoms.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.atoms.is_empty()
}
#[must_use]
pub const fn generation(&self) -> CoordinateGeneration {
self.generation
}
#[must_use]
pub fn is_stale_for(&self, structure: &Structure) -> bool {
self.generation != structure.generation()
}
#[must_use]
pub fn narrow(&self, other: &AtomSelection) -> Self {
self.with_selection(self.atoms.intersect(other))
}
#[must_use]
pub fn union(&self, other: &Self) -> Self {
self.with_selection(self.atoms.union(&other.atoms))
}
#[must_use]
pub fn intersect(&self, other: &Self) -> Self {
self.with_selection(self.atoms.intersect(&other.atoms))
}
#[must_use]
pub fn difference(&self, other: &Self) -> Self {
self.with_selection(self.atoms.difference(&other.atoms))
}
fn with_selection(&self, atoms: AtomSelection) -> Self {
Self {
structure: Arc::clone(&self.structure),
atoms,
generation: self.generation,
}
}
pub fn positions(&self, model: ModelIndex) -> impl Iterator<Item = [f32; 3]> + '_ {
let block = self.structure.coords.block(model);
self.atoms
.iter()
.filter_map(move |atom| block?.as_slice().get(atom as usize).copied())
}
#[must_use]
pub fn bounds(&self, model: ModelIndex) -> Aabb {
let mut bounds = Aabb::EMPTY;
for position in self.positions(model) {
bounds.extend(position);
}
bounds
}
}
impl Structure {
#[must_use]
pub fn view(&self) -> StructureView {
StructureView::new(self, AtomSelection::All(self.atom_count()))
}
#[must_use]
pub fn view_of(&self, selection: AtomSelection) -> StructureView {
StructureView::new(self, selection)
}
}
#[cfg(test)]
#[path = "view_tests.rs"]
mod tests;