use super::{Aabb, Scalar};
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum HierarchicalError {
KernelError0 = 0,
KernelError1 = 1,
Ok = 2,
EmptyInput = 3,
LengthMismatch = 4,
ScratchTooSmall = 5,
InvalidTheta = 6,
CapacityExceeded = 7,
Unknown = 8,
}
impl HierarchicalError {
#[inline]
pub fn from_u32(value: u32) -> Self {
match value {
0 => Self::KernelError0,
1 => Self::KernelError1,
2 => Self::Ok,
3 => Self::EmptyInput,
4 => Self::LengthMismatch,
5 => Self::ScratchTooSmall,
6 => Self::InvalidTheta,
7 => Self::CapacityExceeded,
_ => Self::Unknown,
}
}
}
pub trait BoundedGeometry {
type Scalar: Scalar;
fn aabb(&self) -> Aabb<Self::Scalar>;
fn representative_point(&self) -> [Self::Scalar; 3];
}
pub trait BoundedGeometryCollection<T: Scalar>: Copy + Sync {
fn len(self) -> usize;
fn valid_lengths(self) -> bool;
fn aabb(self, index: usize) -> Aabb<T>;
fn representative_point(self, index: usize) -> [T; 3];
#[inline]
fn is_empty(self) -> bool {
self.len() == 0
}
}
impl<T, G> BoundedGeometryCollection<T> for &[G]
where
T: Scalar,
G: BoundedGeometry<Scalar = T> + Sync,
{
#[inline]
fn len(self) -> usize {
<[G]>::len(self)
}
#[inline]
fn valid_lengths(self) -> bool {
true
}
#[inline]
fn aabb(self, index: usize) -> Aabb<T> {
self[index].aabb()
}
#[inline]
fn representative_point(self, index: usize) -> [T; 3] {
self[index].representative_point()
}
}
impl<T, G, const N: usize> BoundedGeometryCollection<T> for &[G; N]
where
T: Scalar,
G: BoundedGeometry<Scalar = T> + Sync,
{
#[inline]
fn len(self) -> usize {
N
}
#[inline]
fn valid_lengths(self) -> bool {
true
}
#[inline]
fn aabb(self, index: usize) -> Aabb<T> {
self[index].aabb()
}
#[inline]
fn representative_point(self, index: usize) -> [T; 3] {
self[index].representative_point()
}
}
pub trait SourceCollection<K: HierarchicalKernel>: BoundedGeometryCollection<K::Scalar> {
fn source(self, index: usize) -> K::SourceGeometry;
}
impl<K> SourceCollection<K> for &[K::SourceGeometry]
where
K: HierarchicalKernel,
K::SourceGeometry: Copy,
{
#[inline]
fn source(self, index: usize) -> K::SourceGeometry {
self[index]
}
}
impl<K, const N: usize> SourceCollection<K> for &[K::SourceGeometry; N]
where
K: HierarchicalKernel,
K::SourceGeometry: Copy,
{
#[inline]
fn source(self, index: usize) -> K::SourceGeometry {
self[index]
}
}
pub trait SourceMomentCollection<K: HierarchicalKernel>: Copy + Sync {
fn len(self) -> usize;
fn valid_lengths(self) -> bool;
fn moment(self, index: usize) -> K::SourceMoment;
#[inline]
fn is_empty(self) -> bool {
self.len() == 0
}
}
impl<K> SourceMomentCollection<K> for &[K::SourceMoment]
where
K: HierarchicalKernel,
K::SourceMoment: Copy,
{
#[inline]
fn len(self) -> usize {
<[K::SourceMoment]>::len(self)
}
#[inline]
fn valid_lengths(self) -> bool {
true
}
#[inline]
fn moment(self, index: usize) -> K::SourceMoment {
self[index]
}
}
impl<K, const N: usize> SourceMomentCollection<K> for &[K::SourceMoment; N]
where
K: HierarchicalKernel,
K::SourceMoment: Copy,
{
#[inline]
fn len(self) -> usize {
N
}
#[inline]
fn valid_lengths(self) -> bool {
true
}
#[inline]
fn moment(self, index: usize) -> K::SourceMoment {
self[index]
}
}
pub trait TargetCollection<K: HierarchicalKernel>: Copy + Sync {
fn len(self) -> usize;
fn valid_lengths(self) -> bool;
fn target(self, index: usize) -> K::TargetGeometry;
fn slice(self, start: usize, end: usize) -> Self;
#[inline]
fn is_empty(self) -> bool {
self.len() == 0
}
}
impl<K> TargetCollection<K> for &[K::TargetGeometry]
where
K: HierarchicalKernel,
K::TargetGeometry: Copy,
{
#[inline]
fn len(self) -> usize {
<[K::TargetGeometry]>::len(self)
}
#[inline]
fn valid_lengths(self) -> bool {
true
}
#[inline]
fn target(self, index: usize) -> K::TargetGeometry {
self[index]
}
#[inline]
fn slice(self, start: usize, end: usize) -> Self {
&self[start..end]
}
}
pub trait HierarchicalKernel: Sized {
type Scalar: Scalar;
type SourceGeometry: BoundedGeometry<Scalar = Self::Scalar> + Sync;
type TargetGeometry: BoundedGeometry<Scalar = Self::Scalar> + Sync;
type SourceMoment: Clone + Send + Sync;
type SourceSummary: Copy + Default + Send + Sync;
type TargetSummary: Copy + Default + Send + Sync;
type Output: Copy + Default + Send + Sync;
fn summarize_leaf_sources<S, M>(
&self,
source_ids: &[u32],
sources: S,
moments: M,
out: &mut Self::SourceSummary,
) -> HierarchicalError
where
S: SourceCollection<Self>,
M: SourceMomentCollection<Self>;
fn combine_source_summaries(
&self,
children: &[Self::SourceSummary],
out: &mut Self::SourceSummary,
) -> HierarchicalError;
fn summarize_leaf_targets(
&self,
target_ids: &[u32],
targets: &[Self::TargetGeometry],
out: &mut Self::TargetSummary,
) -> HierarchicalError;
fn eval_near(
&self,
target: &Self::TargetGeometry,
source: &Self::SourceGeometry,
moment: &Self::SourceMoment,
out: &mut Self::Output,
);
fn eval_far(
&self,
target: &Self::TargetSummary,
source: &Self::SourceSummary,
out: &mut Self::Output,
);
#[inline]
fn accept_far(
&self,
target_aabb: Aabb<Self::Scalar>,
source_aabb: Aabb<Self::Scalar>,
_source: &Self::SourceSummary,
theta: Self::Scalar,
) -> bool {
geometric_accept_far(target_aabb, source_aabb, theta)
}
fn zero_output(&self, out: &mut Self::Output);
fn accumulate(&self, out: &mut Self::Output, contribution: &Self::Output);
}
#[inline]
pub(crate) fn geometric_accept_far<T: Scalar>(
target_aabb: Aabb<T>,
source_aabb: Aabb<T>,
theta: T,
) -> bool {
if theta <= T::ZERO {
return false;
}
let gap_sq = target_aabb.gap_distance_sq(&source_aabb);
if gap_sq <= T::ZERO {
return false;
}
let target_diam = target_aabb.diameter_sq().sqrt();
let source_diam = source_aabb.diameter_sq().sqrt();
let combined = target_diam + source_diam;
gap_sq * theta * theta > combined * combined
}