use twounordered::TwoUnorderedVecs;
use super::CollisionHandler;
use super::*;
struct OtherAxisCollider<'a, A: Axis + 'a, F: 'a> {
a: &'a mut F,
axis: A,
}
impl<'a, A: Axis + 'a, T: Aabb, F: CollisionHandler<T> + 'a> CollisionHandler<T>
for OtherAxisCollider<'a, A, F>
{
#[inline(always)]
fn collide(&mut self, a: AabbPin<&mut T>, b: AabbPin<&mut T>) {
let a2 = self.axis.next();
if a.range(a2).intersects(b.range(a2)) {
self.a.collide(a, b);
}
}
}
pub fn sweep_and_prune<'a, A: Axis, T: Aabb, F: CollisionHandler<T>>(
buffer: &mut Vec<AabbPin<&'a mut T>>,
axis: A,
bots: AabbPin<&'a mut [T]>,
func: &mut F,
) {
let mut b: OtherAxisCollider<A, _> = OtherAxisCollider { a: func, axis };
self::find_iter(buffer, axis, bots, &mut b);
}
fn find_2d<'a, A: Axis, T: Aabb, F: CollisionHandler<T>>(
buffer: &mut Vec<AabbPin<&'a mut T>>,
axis: A,
bots: AabbPin<&'a mut [T]>,
func: &mut F,
check_y: bool,
) {
if check_y {
let mut b: OtherAxisCollider<A, _> = OtherAxisCollider { a: func, axis };
self::find_iter(buffer, axis, bots, &mut b);
} else {
let b = func;
self::find_iter(buffer, axis, bots, b);
}
}
struct FindParallel2DBuilder<'a, 'b, A: Axis, T: Aabb> {
pub prevec: &'b mut TwoUnorderedVecs<Vec<AabbPin<&'a mut T>>>,
pub axis: A,
pub bots1: AabbPin<&'a mut [T]>,
pub bots2: AabbPin<&'a mut [T]>,
}
impl<'a, 'b, A: Axis, T: Aabb> FindParallel2DBuilder<'a, 'b, A, T> {
#[inline(always)]
pub fn new(
prevec: &'b mut TwoUnorderedVecs<Vec<AabbPin<&'a mut T>>>,
axis: A,
bots1: AabbPin<&'a mut [T]>,
bots2: AabbPin<&'a mut [T]>,
) -> Self {
FindParallel2DBuilder {
prevec,
axis,
bots1,
bots2,
}
}
pub fn build(self, mut func: impl FnMut(AabbPin<&mut T>, AabbPin<&mut T>)) {
self::find_other_parallel4(self.prevec, self.axis, (self.bots1, self.bots2), &mut func);
}
}
fn find_perp_2d1_once<A: Axis, T: Aabb>(
axis: A, mut y: AabbPin<&mut T>,
mut r2: AabbPin<&mut [T]>,
mut func: impl CollisionHandler<T>,
) {
for y2 in r2.borrow_mut() {
if y.range(axis).end < y2.range(axis).start {
break;
}
if y.range(axis).start <= y2.range(axis).end {
func.collide(y.borrow_mut(), y2);
}
}
}
fn find_iter<'a, A: Axis, T: Aabb + 'a, F: CollisionHandler<T>>(
active: &mut Vec<AabbPin<&'a mut T>>,
axis: A,
collision_botids: AabbPin<&'a mut [T]>,
func: &mut F,
) {
use twounordered::RetainMutUnordered;
collision_botids.iter_mut().for_each(|mut curr_bot| {
active.retain_mut_unordered(|that_bot| {
let crr = curr_bot.range(axis);
if that_bot.range(axis).end >= crr.start {
debug_assert!(curr_bot.range(axis).intersects(that_bot.range(axis)));
func.collide(curr_bot.borrow_mut(), that_bot.borrow_mut());
true
} else {
false
}
});
active.push(curr_bot);
});
}
#[inline(always)]
#[allow(dead_code)]
fn find_other_parallel4<'a, A: Axis, T: Aabb, F: CollisionHandler<T>>(
active_lists: &mut TwoUnorderedVecs<Vec<AabbPin<&'a mut T>>>,
axis: A,
cols: (AabbPin<&'a mut [T]>, AabbPin<&'a mut [T]>),
func: &mut F,
) {
use twounordered::RetainMutUnordered;
let mut xiter = cols.0.into_iter();
let mut yiter = cols.1.into_iter();
const PRUNE_PERIOD: usize = 100;
let mut xcounter = 0;
let mut ycounter = 0;
enum NextP<X> {
X(X),
Y(X),
}
let mut cache: Option<NextP<AabbPin<&mut T>>> = None;
loop {
let val = match cache.take() {
Some(NextP::X(x)) => match yiter.next() {
Some(y) => {
if x.range(axis).start < y.range(axis).start {
cache = Some(NextP::Y(y));
NextP::X(x)
} else {
cache = Some(NextP::X(x));
NextP::Y(y)
}
}
None => NextP::X(x),
},
Some(NextP::Y(y)) => match xiter.next() {
Some(x) => {
if x.range(axis).start < y.range(axis).start {
cache = Some(NextP::Y(y));
NextP::X(x)
} else {
cache = Some(NextP::X(x));
NextP::Y(y)
}
}
None => NextP::Y(y),
},
None => match (xiter.next(), yiter.next()) {
(Some(x), Some(y)) => {
if x.range(axis).start < y.range(axis).start {
cache = Some(NextP::Y(y));
NextP::X(x)
} else {
cache = Some(NextP::X(x));
NextP::Y(y)
}
}
(Some(x), None) => {
if active_lists.second().is_empty() {
break;
}
NextP::X(x)
}
(None, Some(y)) => {
if active_lists.first().is_empty() {
break;
}
NextP::Y(y)
}
(None, None) => {
break;
}
},
};
match val {
NextP::X(mut x) => {
active_lists.second().retain_mut_unordered(|y| {
if y.range(axis).end >= x.range(axis).start {
func.collide(x.borrow_mut(), y.borrow_mut());
true
} else {
false
}
});
ycounter = 0;
if xcounter > PRUNE_PERIOD {
active_lists
.first()
.retain_mut_unordered(|x2| x2.range(axis).end >= x.range(axis).start);
xcounter = 0;
} else {
xcounter += 1;
}
active_lists.first().push(x);
}
NextP::Y(mut y) => {
active_lists.first().retain_mut_unordered(|x| {
if x.range(axis).end >= y.range(axis).start {
func.collide(x.borrow_mut(), y.borrow_mut());
true
} else {
false
}
});
xcounter = 0;
if ycounter > PRUNE_PERIOD {
active_lists
.second()
.retain_mut_unordered(|y2| y2.range(axis).end >= y.range(axis).start);
ycounter = 0;
} else {
ycounter += 1;
}
active_lists.second().push(y);
}
}
}
}
#[derive(Clone)]
pub struct DefaultNodeHandler<C> {
pub coll_handler: C,
prevec: PreVec,
}
impl<C> DefaultNodeHandler<C> {
pub fn new(coll_handler: C) -> Self {
DefaultNodeHandler {
coll_handler,
prevec: PreVec::new(),
}
}
}
impl<T: Aabb, C> NodeHandler<T> for DefaultNodeHandler<C>
where
C: CollisionHandler<T>,
{
#[inline(always)]
fn handle_node(&mut self, axis: AxisDyn, bots: AabbPin<&mut [T]>, is_leaf: bool) {
fn handle_node<T: Aabb, F>(
prevec: &mut PreVec,
axis: AxisDyn,
bots: AabbPin<&mut [T]>,
func: &mut F,
is_leaf: bool,
) where
F: CollisionHandler<T>,
{
let mut k = prevec.extract_vec();
match axis.next() {
AxisDyn::X => oned::find_2d(&mut k, axgeom::XAXIS, bots, func, is_leaf),
AxisDyn::Y => oned::find_2d(&mut k, axgeom::YAXIS, bots, func, is_leaf),
}
k.clear();
prevec.insert_vec(k);
}
handle_node(
&mut self.prevec,
axis,
bots,
&mut self.coll_handler,
is_leaf,
);
}
fn handle_nodes_under(&mut self, this_axis: AxisDyn, m: VistrMutPin<Node<T, T::Num>>) {
{
let (nn, rest) = m.next();
if let Some([mut left, mut right]) = rest {
if let Some(div) = nn.div {
let d = nn.into_node_ref();
let mut g = InnerRecurser {
anchor: DNode {
div,
cont: d.cont,
range: d.range,
},
anchor_axis: this_axis,
handler: self,
};
g.recurse(this_axis.next(), left.borrow_mut(), true);
g.recurse(this_axis.next(), right.borrow_mut(), false);
}
}
}
}
}
impl<'a, T: Aabb> Tree<'a, T> {
pub fn find_colliding_pairs(&mut self, func: impl FnMut(AabbPin<&mut T>, AabbPin<&mut T>)) {
CollisionVisitor::new(self.vistr_mut()).recurse_seq(&mut DefaultNodeHandler::new(func));
}
}
struct InnerRecurser<'a, T, N, C> {
anchor: DNode<'a, T, N>,
anchor_axis: AxisDyn,
handler: &'a mut DefaultNodeHandler<C>,
}
impl<'a, T: Aabb, C: CollisionHandler<T>> InnerRecurser<'a, T, T::Num, C> {
fn recurse(&mut self, this_axis: AxisDyn, m: VistrMutPin<Node<T, T::Num>>, is_left: bool) {
let anchor_axis = self.anchor_axis;
let (mut nn, rest) = m.next();
handle_children(
&mut self.handler.prevec,
&mut self.handler.coll_handler,
HandleChildrenArgs {
anchor: self.anchor.borrow(),
anchor_axis: self.anchor_axis,
current: nn.borrow_mut().into_node_ref(),
current_axis: this_axis,
},
is_left,
);
if let Some([left, right]) = rest {
if let Some(div) = nn.div {
if anchor_axis.is_equal_to(this_axis) {
match is_left {
true => {
if div < self.anchor.cont.start {
self.recurse(this_axis.next(), right, is_left);
return;
}
}
false => {
if div >= self.anchor.cont.end {
self.recurse(this_axis.next(), left, is_left);
return;
}
}
}
}
}
self.recurse(this_axis.next(), left, is_left);
self.recurse(this_axis.next(), right, is_left);
}
}
}
struct HandleChildrenArgs<'a, T, N> {
pub anchor: DNode<'a, T, N>,
pub current: NodeRef<'a, T, N>,
pub anchor_axis: AxisDyn,
pub current_axis: AxisDyn,
}
struct DNode<'a, T, N> {
pub div: N,
pub cont: &'a Range<N>,
pub range: AabbPin<&'a mut [T]>,
}
impl<'a, T, N: Copy> DNode<'a, T, N> {
fn borrow(&mut self) -> DNode<T, N> {
DNode {
div: self.div,
cont: self.cont,
range: self.range.borrow_mut(),
}
}
}
fn handle_children<T: Aabb, F>(
prevec: &mut PreVec,
func: &mut F,
f: HandleChildrenArgs<T, T::Num>,
is_left: bool,
) where
F: CollisionHandler<T>,
{
fn handle_perp<T: Aabb, A: Axis>(
axis: A,
func: &mut impl CollisionHandler<T>,
f: HandleChildrenArgs<T, T::Num>,
is_left: bool,
) {
let anchor_axis = axis;
let current_axis = axis.next();
let cc1 = f.anchor.cont;
let cc2 = f.current;
let r1 = super::tools::get_section_mut(anchor_axis, cc2.range, cc1);
let mut r2 = super::tools::get_section_mut(current_axis, f.anchor.range, cc2.cont);
if is_left {
for y in r1.iter_mut() {
let r2 = r2.borrow_mut();
oned::find_perp_2d1_once(
current_axis,
y,
r2,
|a: AabbPin<&mut T>, b: AabbPin<&mut T>| {
if a.range(axis).end >= b.range(axis).start {
func.collide(a, b);
}
},
);
}
} else {
for y in r1.iter_mut() {
let r2 = r2.borrow_mut();
oned::find_perp_2d1_once(
current_axis,
y,
r2,
|a: AabbPin<&mut T>, b: AabbPin<&mut T>| {
if a.range(axis).start <= b.range(axis).end {
func.collide(a, b);
}
},
);
}
}
}
fn handle_parallel<'a, T: Aabb, A: Axis>(
axis: A,
prevec: &mut TwoUnorderedVecs<Vec<AabbPin<&'a mut T>>>,
func: &mut impl CollisionHandler<T>,
f: HandleChildrenArgs<'a, T, T::Num>,
is_left: bool,
) {
let current2 = f.current;
let fb =
oned::FindParallel2DBuilder::new(prevec, axis.next(), f.anchor.range, current2.range);
if is_left {
if f.anchor.cont.start <= current2.cont.end {
fb.build(|a, b| {
if a.range(axis).start <= b.range(axis).end {
func.collide(a, b)
}
});
}
} else if f.anchor.cont.end >= current2.cont.start {
fb.build(|a, b| {
if a.range(axis).end >= b.range(axis).start {
func.collide(a, b)
}
});
}
}
use AxisDyn::*;
match (f.anchor_axis, f.current_axis) {
(X, X) | (Y, Y) => {
let mut k = twounordered::TwoUnorderedVecs::from(prevec.extract_vec());
match f.anchor_axis {
X => handle_parallel(XAXIS, &mut k, func, f, is_left),
Y => handle_parallel(YAXIS, &mut k, func, f, is_left),
}
let mut j: Vec<_> = k.into();
j.clear();
prevec.insert_vec(j);
}
(X, Y) => handle_perp(XAXIS, func, f, is_left),
(Y, X) => handle_perp(YAXIS, func, f, is_left),
}
}