use super::matching::{
backend_key, cacheable_backend, collect_selection_indices, index_cutoff_key, spatial_diagnostic,
};
use super::{CachedIndex, IndexKey, StructureSpatial};
use crate::{
NeighborPair, PairQuery, SpatialBackend, SpatialSearchOptions, for_each_pairs_within_unsorted,
};
use molframe_core::diagnostic::Diagnostic;
use molframe_core::selection::AtomSelection;
impl StructureSpatial<'_> {
pub(super) fn for_each_pair(
&self,
query: &AtomSelection,
target: &AtomSelection,
cutoff: f32,
mut emit: impl FnMut(NeighborPair),
) -> Result<(), Diagnostic> {
let backend = cacheable_backend(self.options, query.len(), target.len())
.map_err(spatial_diagnostic)?;
match backend {
SpatialBackend::CellList | SpatialBackend::KdTree => {
self.cached_for_each_pair(query, target, cutoff, backend, &mut emit)
}
_ => for_each_pairs_within_unsorted(
&PairQuery {
positions: self.positions(),
left: query,
right: target,
cutoff,
options: SpatialSearchOptions {
backend,
..self.options
},
periodic: self.periodic.as_ref(),
context: self.context,
},
emit,
)
.map_err(spatial_diagnostic),
}
}
fn cached_for_each_pair(
&self,
query: &AtomSelection,
target: &AtomSelection,
cutoff: f32,
backend: SpatialBackend,
mut emit: impl FnMut(NeighborPair),
) -> Result<(), Diagnostic> {
let target_indices = collect_selection_indices(target);
let key = IndexKey {
backend: backend_key(backend),
cutoff: index_cutoff_key(backend, cutoff),
selection: target_indices.into_boxed_slice(),
};
let index = self.cached_index(key, backend, cutoff)?;
let query_indices = collect_selection_indices(query);
match index.as_ref() {
CachedIndex::Cell(index) => index
.for_each_pair(&query_indices, cutoff, emit)
.map_err(spatial_diagnostic),
CachedIndex::Kd(index) => {
for pair in index
.pairs(&query_indices, cutoff)
.map_err(spatial_diagnostic)?
{
emit(pair);
}
Ok(())
}
}
}
}