use crate::spatial::region::simbox::SimBox;
use crate::types::{F, FNx3View};
use ndarray::ArrayView2;
pub mod aabb;
pub mod bruteforce;
pub mod filter;
mod linkcell;
pub mod periodic_buffer;
mod query;
pub use aabb::AabbQuery;
pub use bruteforce::BruteForce;
pub use filter::{filter_rad, filter_sann};
pub use linkcell::LinkCell;
pub use periodic_buffer::{PeriodicBufferResult, periodic_buffer};
pub use query::NeighborQuery;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QueryMode {
SelfQuery,
CrossQuery,
}
pub trait PairVisitor {
fn visit_pair(&mut self, i: u32, j: u32, dist_sq: F, diff: [F; 3]);
}
impl<T: FnMut(u32, u32, F, [F; 3])> PairVisitor for T {
#[inline(always)]
fn visit_pair(&mut self, i: u32, j: u32, dist_sq: F, diff: [F; 3]) {
self(i, j, dist_sq, diff)
}
}
pub trait NbListAlgo {
fn build(&mut self, points: FNx3View<'_>, bx: &SimBox);
fn update(&mut self, points: FNx3View<'_>, bx: &SimBox);
fn query(&self) -> &NeighborList;
fn box_ref(&self) -> &SimBox;
fn build_index(&mut self, points: FNx3View<'_>, bx: &SimBox) {
self.build(points, bx);
}
fn update_index(&mut self, points: FNx3View<'_>, bx: &SimBox) {
self.update(points, bx);
}
fn visit_pairs(&self, visitor: &mut dyn PairVisitor) {
let result = self.query();
let diff = result.vectors();
for k in 0..result.n_pairs() {
visitor.visit_pair(
result.query_point_indices()[k],
result.point_indices()[k],
result.dist_sq()[k],
[diff[[k, 0]], diff[[k, 1]], diff[[k, 2]]],
);
}
}
}
#[derive(Debug, Clone)]
pub struct NbList<A: NbListAlgo>(pub A);
impl<A: NbListAlgo> NbList<A> {
pub fn build(&mut self, points: FNx3View<'_>, bx: &SimBox) {
self.0.build(points, bx)
}
pub fn update(&mut self, points: FNx3View<'_>, bx: &SimBox) {
self.0.update(points, bx)
}
pub fn query(&self) -> &NeighborList {
self.0.query()
}
pub fn box_ref(&self) -> &SimBox {
self.0.box_ref()
}
pub fn build_index(&mut self, points: FNx3View<'_>, bx: &SimBox) {
self.0.build_index(points, bx)
}
pub fn update_index(&mut self, points: FNx3View<'_>, bx: &SimBox) {
self.0.update_index(points, bx)
}
pub fn visit_pairs(&self, visitor: &mut dyn PairVisitor) {
self.0.visit_pairs(visitor)
}
}
#[derive(Debug, Clone)]
pub struct NeighborList {
pub(crate) idx_i: Vec<u32>,
pub(crate) idx_j: Vec<u32>,
pub(crate) dist_sq: Vec<F>,
pub(crate) diff_flat: Vec<F>,
pub(crate) mode: QueryMode,
pub(crate) num_points: usize,
pub(crate) num_query_points: usize,
}
impl NeighborList {
pub(crate) fn empty() -> Self {
Self {
idx_i: Vec::new(),
idx_j: Vec::new(),
dist_sq: Vec::new(),
diff_flat: Vec::new(),
mode: QueryMode::SelfQuery,
num_points: 0,
num_query_points: 0,
}
}
pub(crate) fn with_mode(mode: QueryMode, num_points: usize, num_query_points: usize) -> Self {
Self {
idx_i: Vec::new(),
idx_j: Vec::new(),
dist_sq: Vec::new(),
diff_flat: Vec::new(),
mode,
num_points,
num_query_points,
}
}
pub(crate) fn clear(&mut self) {
self.idx_i.clear();
self.idx_j.clear();
self.dist_sq.clear();
self.diff_flat.clear();
}
#[inline(always)]
pub(crate) fn push(&mut self, i: u32, j: u32, d2: F, dr: [F; 3]) {
self.idx_i.push(i);
self.idx_j.push(j);
self.dist_sq.push(d2);
self.diff_flat.extend(dr);
}
#[inline]
pub fn n_pairs(&self) -> usize {
self.idx_i.len()
}
#[inline]
pub fn mode(&self) -> QueryMode {
self.mode
}
#[inline]
pub fn num_points(&self) -> usize {
self.num_points
}
#[inline]
pub fn num_query_points(&self) -> usize {
self.num_query_points
}
#[inline]
pub fn query_point_indices(&self) -> &[u32] {
&self.idx_i
}
#[inline]
pub fn point_indices(&self) -> &[u32] {
&self.idx_j
}
pub fn distances(&self) -> Vec<F> {
self.dist_sq.iter().map(|&d2| d2.sqrt()).collect()
}
#[inline]
pub fn dist_sq(&self) -> &[F] {
&self.dist_sq
}
#[inline]
pub fn vectors(&self) -> FNx3View<'_> {
ArrayView2::from_shape((self.n_pairs(), 3), &self.diff_flat)
.expect("diff_flat shape mismatch")
}
}