use broccoli::{
aabb::pin::AabbPin,
aabb::Aabb,
queries::colfind::{
build::{CollisionHandler, CollisionVisitor, NodeHandler},
oned::DefaultNodeHandler,
},
Tree,
};
pub trait CollisionHandlerExt<T: Aabb>: CollisionHandler<T> + Sized {
fn div(&mut self) -> Self;
fn add(&mut self, b: Self);
}
pub trait NodeHandlerExt<T: Aabb>: NodeHandler<T> + Sized {
fn div(&mut self) -> Self;
fn add(&mut self, b: Self);
}
pub const SEQ_FALLBACK_DEFAULT: usize = 256;
pub trait RayonQueryPar<'a, T: Aabb> {
fn par_find_colliding_pairs<F>(&mut self, func: F)
where
F: FnMut(AabbPin<&mut T>, AabbPin<&mut T>),
F: Send + Clone,
T: Send,
T::Num: Send;
fn par_find_colliding_pairs_acc_closure<Acc, A, B, F>(
&mut self,
acc: Acc,
div: A,
add: B,
func: F,
) -> Acc
where
A: FnMut(&mut Acc) -> Acc + Clone + Send,
B: FnMut(&mut Acc, Acc) + Clone + Send,
F: FnMut(&mut Acc, AabbPin<&mut T>, AabbPin<&mut T>) + Clone + Send,
Acc: Send,
T: Send,
T::Num: Send;
}
impl<'a, T: Aabb> RayonQueryPar<'a, T> for Tree<'a, T> {
fn par_find_colliding_pairs_acc_closure<Acc, A, B, F>(
&mut self,
acc: Acc,
div: A,
add: B,
func: F,
) -> Acc
where
A: FnMut(&mut Acc) -> Acc + Clone + Send,
B: FnMut(&mut Acc, Acc) + Clone + Send,
F: FnMut(&mut Acc, AabbPin<&mut T>, AabbPin<&mut T>) + Clone + Send,
Acc: Send,
T: Send,
T::Num: Send,
{
let mut f = DefaultNodeHandler::new(ClosureExt {
acc,
div,
add,
func,
});
let vv = CollisionVisitor::new(self.vistr_mut());
recurse_par(vv, &mut f, SEQ_FALLBACK_DEFAULT);
f.coll_handler.acc
}
fn par_find_colliding_pairs<F>(&mut self, func: F)
where
F: FnMut(AabbPin<&mut T>, AabbPin<&mut T>) + Clone,
F: Send,
T: Send,
T::Num: Send,
{
let mut f = DefaultNodeHandler::new(func);
let vv = CollisionVisitor::new(self.vistr_mut());
recurse_par(vv, &mut f, SEQ_FALLBACK_DEFAULT);
}
}
impl<F, T: Aabb> CollisionHandlerExt<T> for F
where
F: Clone + FnMut(AabbPin<&mut T>, AabbPin<&mut T>),
{
fn div(&mut self) -> Self {
self.clone()
}
fn add(&mut self, _: Self) {}
}
pub struct ClosureExt<K, A, B, F> {
pub acc: K,
pub div: A,
pub add: B,
pub func: F,
}
impl<T: Aabb, K, A, B, F> CollisionHandler<T> for ClosureExt<K, A, B, F>
where
F: FnMut(&mut K, AabbPin<&mut T>, AabbPin<&mut T>),
{
fn collide(&mut self, a: AabbPin<&mut T>, b: AabbPin<&mut T>) {
(self.func)(&mut self.acc, a, b)
}
}
impl<T: Aabb, K, A: FnMut(&mut K) -> K + Clone, B: FnMut(&mut K, K) + Clone, F: Clone>
CollisionHandlerExt<T> for ClosureExt<K, A, B, F>
where
F: FnMut(&mut K, AabbPin<&mut T>, AabbPin<&mut T>),
{
fn div(&mut self) -> Self {
ClosureExt {
acc: (self.div)(&mut self.acc),
div: self.div.clone(),
add: self.add.clone(),
func: self.func.clone(),
}
}
fn add(&mut self, b: Self) {
(self.add)(&mut self.acc, b.acc)
}
}
impl<Acc: CollisionHandlerExt<T>, T: Aabb> NodeHandlerExt<T> for DefaultNodeHandler<Acc> {
fn div(&mut self) -> Self {
DefaultNodeHandler::new(self.coll_handler.div())
}
fn add(&mut self, b: Self) {
self.coll_handler.add(b.coll_handler);
}
}
pub fn recurse_par<T: Aabb, SO: NodeHandlerExt<T>>(
vistr: CollisionVisitor<T>,
handler: &mut SO,
num_seq_fallback: usize,
) where
T: Send,
T::Num: Send,
SO: Send,
{
if vistr.num_elem() <= num_seq_fallback {
vistr.recurse_seq(handler);
} else {
let (n, rest) = vistr.collide_and_next(handler);
if let Some([left, right]) = rest {
let mut h2 = handler.div();
rayon::join(
|| {
n.finish(handler);
recurse_par(left, handler, num_seq_fallback)
},
|| recurse_par(right, &mut h2, num_seq_fallback),
);
handler.add(h2);
} else {
n.finish(handler);
}
}
}