use crate::query::inner_prelude::*;
use axgeom::Ray;
use core::cmp::Ordering;
pub trait RayCast {
type T: Aabb<Num = Self::N>;
type N: Num;
fn compute_distance_to_rect(
&mut self,
ray: &Ray<Self::N>,
a: &Rect<Self::N>,
) -> axgeom::CastResult<Self::N>;
fn compute_distance_to_bot(
&mut self,
ray: &Ray<Self::N>,
a: &Self::T,
) -> axgeom::CastResult<Self::N> {
self.compute_distance_to_rect(ray, a.get())
}
}
pub struct RayCastClosure<'a, A, B, C, T> {
pub a: &'a mut A,
pub broad: B,
pub fine: C,
pub _p: PhantomData<T>,
}
impl<'a,
A,
B: FnMut(&mut A, &Ray<T::Num>, &Rect<T::Num>) -> CastResult<T::Num>,
C: FnMut(&mut A, &Ray<T::Num>, &T) -> CastResult<T::Num>,
T: Aabb,
> RayCastClosure<'a, A, B, C, T>
{
pub fn new(acc:&'a mut A,broad:B,fine:C)->Self{
RayCastClosure{
a:acc,
broad,
fine,
_p:PhantomData
}
}
}
impl<
A,
B: FnMut(&mut A, &Ray<T::Num>, &Rect<T::Num>) -> CastResult<T::Num>,
C: FnMut(&mut A, &Ray<T::Num>, &T) -> CastResult<T::Num>,
T: Aabb,
> RayCast for RayCastClosure<'_, A, B, C, T>
{
type T = T;
type N = T::Num;
fn compute_distance_to_rect(
&mut self,
ray: &Ray<Self::N>,
a: &Rect<Self::N>,
) -> CastResult<Self::N> {
(self.broad)(&mut self.a, ray, a)
}
fn compute_distance_to_bot(&mut self, ray: &Ray<Self::N>, a: &Self::T) -> CastResult<Self::N> {
(self.fine)(&mut self.a, ray, a)
}
}
fn make_rect_from_range<A: Axis, N: Num>(axis: A, range: &Range<N>, rect: &Rect<N>) -> Rect<N> {
if axis.is_xaxis() {
Rect {
x: *range,
y: rect.y,
}
} else {
Rect {
x: rect.x,
y: *range,
}
}
}
struct Closest<'a, T: Aabb> {
closest: Option<(Vec<PMut<'a, T>>, T::Num)>,
}
impl<'a, T: Aabb> Closest<'a, T> {
fn consider<R: RayCast<N = T::Num, T = T>>(
&mut self,
ray: &Ray<T::Num>,
b: PMut<'a, T>,
raytrait: &mut R,
) {
let y = match raytrait.compute_distance_to_rect(ray, b.get()) {
axgeom::CastResult::Hit(val) => val,
axgeom::CastResult::NoHit => {
return;
}
};
match self.closest.as_mut() {
Some(dis) => {
match y.cmp(&dis.1) {
Ordering::Greater => {
return;
}
Ordering::Less => {
}
Ordering::Equal => {
}
}
}
None => {
}
}
let x = match raytrait.compute_distance_to_bot(ray, &b) {
axgeom::CastResult::Hit(val) => val,
axgeom::CastResult::NoHit => {
return;
}
};
match self.closest.as_mut() {
Some(mut dis) => {
match x.cmp(&dis.1) {
Ordering::Greater => {
}
Ordering::Less => {
dis.0.clear();
dis.0.push(b);
dis.1 = x;
}
Ordering::Equal => {
dis.0.push(b);
}
}
}
None => self.closest = Some((vec![b], x)),
};
}
fn get_dis(&self) -> Option<T::Num> {
match &self.closest {
Some(x) => Some(x.1),
None => None,
}
}
}
struct Blap<'a: 'b, 'b, R: RayCast> {
rtrait: &'b mut R,
ray: Ray<R::N>,
closest: Closest<'a, R::T>,
}
impl<'a: 'b, 'b, R: RayCast> Blap<'a, 'b, R> {
fn should_handle_rect(&mut self, rect: &Rect<R::N>) -> bool {
match self.rtrait.compute_distance_to_rect(&self.ray, rect) {
axgeom::CastResult::Hit(val) => match self.closest.get_dis() {
Some(dis) => {
if val <= dis {
return true;
}
}
None => {
return true;
}
},
axgeom::CastResult::NoHit => {}
}
false
}
}
fn recc<'a: 'b, 'b, A: Axis, N: Node, R: RayCast<N = N::Num, T = N::T>>(
axis: A,
stuff: LevelIter<VistrMut<'a, N>>,
rect: Rect<N::Num>,
blap: &mut Blap<'a, 'b, R>,
) {
let ((_depth, nn), rest) = stuff.next();
let nn = nn.get_mut();
match rest {
Some([left, right]) => {
let axis_next = axis.next();
let div = match nn.div {
Some(b) => b,
None => return,
};
let (rleft, rright) = rect.subdivide(axis, *div);
let range = &match nn.cont {
Some(range) => *range,
None => Range {
start: *div,
end: *div,
},
};
let rmiddle = make_rect_from_range(axis, range, &rect);
match blap.ray.range_side(axis, range) {
Ordering::Less => {
if blap.should_handle_rect(&rleft) {
recc(axis_next, left, rleft, blap);
}
if blap.should_handle_rect(&rmiddle) {
for b in nn.bots.iter_mut() {
blap.closest.consider(&blap.ray, b, blap.rtrait);
}
}
if blap.should_handle_rect(&rright) {
recc(axis_next, right, rright, blap);
}
}
Ordering::Greater => {
if blap.should_handle_rect(&rright) {
recc(axis_next, right, rright, blap);
}
if blap.should_handle_rect(&rmiddle) {
for b in nn.bots.iter_mut() {
blap.closest.consider(&blap.ray, b, blap.rtrait);
}
}
if blap.should_handle_rect(&rleft) {
recc(axis_next, left, rleft, blap);
}
}
Ordering::Equal => {
if blap.should_handle_rect(&rleft) {
recc(axis_next, left, rleft, blap);
}
if blap.should_handle_rect(&rright) {
recc(axis_next, right, rright, blap);
}
if blap.should_handle_rect(&rmiddle) {
for b in nn.bots.iter_mut() {
blap.closest.consider(&blap.ray, b, blap.rtrait);
}
}
}
}
}
None => {
for b in nn.bots.iter_mut() {
blap.closest.consider(&blap.ray, b, blap.rtrait);
}
}
}
}
pub use self::mutable::raycast_mut;
pub use self::mutable::raycast_naive_mut;
mod mutable {
use super::*;
pub fn raycast_naive_mut<'a, T: Aabb>(
bots: PMut<'a, [T]>,
ray: Ray<T::Num>,
rtrait: &mut impl RayCast<N = T::Num, T = T>,
border: Rect<T::Num>,
) -> axgeom::CastResult<(Vec<PMut<'a, T>>, T::Num)> {
let mut closest = Closest { closest: None };
for b in bots.iter_mut() {
if border.intersects_rect(b.get()) {
closest.consider(&ray, b, rtrait);
}
}
match closest.closest {
Some((a, b)) => axgeom::CastResult::Hit((a, b)),
None => axgeom::CastResult::NoHit,
}
}
pub fn raycast_mut<'a, A: Axis, N: Node>(
axis: A,
vistr: VistrMut<'a, N>,
rect: Rect<N::Num>,
ray: Ray<N::Num>,
rtrait: &mut impl RayCast<N = N::Num, T = N::T>,
) -> axgeom::CastResult<(Vec<PMut<'a, N::T>>, N::Num)> {
let dt = vistr.with_depth(Depth(0));
let closest = Closest { closest: None };
let mut blap = Blap {
rtrait,
ray,
closest,
};
recc(axis, dt, rect, &mut blap);
match blap.closest.closest {
Some((a, b)) => axgeom::CastResult::Hit((a, b)),
None => axgeom::CastResult::NoHit,
}
}
}