use crate::query::inner_prelude::*;
use axgeom::Ray;
pub fn default_rect_raycast<T: Aabb>(tree: &Tree<T>) -> impl RayCast<T = T, N = T::Num>
where
T::Num: core::fmt::Debug + num_traits::Signed,
{
from_closure(
tree,
(),
|_, _, _| None,
|_, ray, a| ray.cast_to_rect(a.get()),
|_, ray, val| ray.cast_to_aaline(axgeom::XAXIS, val),
|_, ray, val| ray.cast_to_aaline(axgeom::YAXIS, val),
)
}
pub trait RayCast {
type T: Aabb<Num = Self::N>;
type N: Num;
fn cast_to_aaline<A: Axis>(
&mut self,
ray: &Ray<Self::N>,
line: A,
val: Self::N,
) -> axgeom::CastResult<Self::N>;
fn cast_broad(
&mut self,
ray: &Ray<Self::N>,
a: PMut<Self::T>,
) -> Option<axgeom::CastResult<Self::N>>;
fn cast_fine(&mut self, ray: &Ray<Self::N>, a: PMut<Self::T>) -> axgeom::CastResult<Self::N>;
}
use crate::Tree;
pub fn from_closure<A, T: Aabb>(
_tree: &Tree<T>,
acc: A,
broad: impl FnMut(&mut A, &Ray<T::Num>, PMut<T>) -> Option<CastResult<T::Num>>,
fine: impl FnMut(&mut A, &Ray<T::Num>, PMut<T>) -> CastResult<T::Num>,
xline: impl FnMut(&mut A, &Ray<T::Num>, T::Num) -> CastResult<T::Num>,
yline: impl FnMut(&mut A, &Ray<T::Num>, T::Num) -> CastResult<T::Num>,
) -> impl RayCast<T = T, N = T::Num> {
struct RayCastClosure<T, A, B, C, D, E> {
_p: PhantomData<T>,
acc: A,
broad: B,
fine: C,
xline: D,
yline: E,
}
impl<T: Aabb, A, B, C, D, E> RayCast for RayCastClosure<T, A, B, C, D, E>
where
B: FnMut(&mut A, &Ray<T::Num>, PMut<T>) -> Option<CastResult<T::Num>>,
C: FnMut(&mut A, &Ray<T::Num>, PMut<T>) -> CastResult<T::Num>,
D: FnMut(&mut A, &Ray<T::Num>, T::Num) -> CastResult<T::Num>,
E: FnMut(&mut A, &Ray<T::Num>, T::Num) -> CastResult<T::Num>,
{
type T = T;
type N = T::Num;
fn cast_to_aaline<X: Axis>(
&mut self,
ray: &Ray<Self::N>,
line: X,
val: Self::N,
) -> axgeom::CastResult<Self::N> {
if line.is_xaxis() {
(self.xline)(&mut self.acc, ray, val)
} else {
(self.yline)(&mut self.acc, ray, val)
}
}
fn cast_broad(
&mut self,
ray: &Ray<Self::N>,
a: PMut<Self::T>,
) -> Option<CastResult<Self::N>> {
(self.broad)(&mut self.acc, ray, a)
}
fn cast_fine(&mut self, ray: &Ray<Self::N>, a: PMut<Self::T>) -> CastResult<Self::N> {
(self.fine)(&mut self.acc, ray, a)
}
}
RayCastClosure {
_p: PhantomData,
acc,
broad,
fine,
xline,
yline,
}
}
struct RayCastBorrow<'a, R>(&'a mut R);
impl<'a, R: RayCast> RayCast for RayCastBorrow<'a, R> {
type T = R::T;
type N = R::N;
fn cast_to_aaline<A: Axis>(
&mut self,
ray: &Ray<Self::N>,
line: A,
val: Self::N,
) -> axgeom::CastResult<Self::N> {
self.0.cast_to_aaline(ray, line, val)
}
fn cast_broad(
&mut self,
ray: &Ray<Self::N>,
a: PMut<Self::T>,
) -> Option<axgeom::CastResult<Self::N>> {
self.0.cast_broad(ray, a)
}
fn cast_fine(&mut self, ray: &Ray<Self::N>, a: PMut<Self::T>) -> axgeom::CastResult<Self::N> {
self.0.cast_fine(ray, a)
}
}
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>,
mut b: PMut<'a, T>,
raytrait: &mut R,
) {
if let Some(broad) = raytrait.cast_broad(ray, b.borrow_mut()) {
let y = match broad {
axgeom::CastResult::Hit(val) => val,
axgeom::CastResult::NoHit => {
return;
}
};
if let Some(dis) = self.closest.as_mut() {
if y > dis.1 {
return;
} else {
}
} else {
}
}
let x = match raytrait.cast_fine(ray, b.borrow_mut()) {
axgeom::CastResult::Hit(val) => val,
axgeom::CastResult::NoHit => {
return;
}
};
match self.closest.as_mut() {
Some(mut dis) => {
if x > dis.1 {
} else if x < dis.1 {
dis.0.clear();
dis.0.push(b);
dis.1 = x;
} else {
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, R: RayCast> {
rtrait: R,
ray: Ray<R::N>,
closest: Closest<'a, R::T>,
}
impl<'a, R: RayCast> Blap<'a, R> {
fn should_recurse<A: Axis>(&mut self, line: (A, R::N)) -> bool {
match self.rtrait.cast_to_aaline(&self.ray, line.0, line.1) {
axgeom::CastResult::Hit(val) => match self.closest.get_dis() {
Some(dis) => val <= dis,
None => true,
},
axgeom::CastResult::NoHit => false,
}
}
}
fn recc<'a, 'b: 'a, A: Axis, T: Aabb, R: RayCast<N = T::Num, T = T>>(
axis: A,
stuff: LevelIter<VistrMut<'a, Node<'b, T>>>,
blap: &mut Blap<'a, R>,
) {
let ((_depth, nn), rest) = stuff.next();
let handle_curr = if let Some([left, right]) = rest {
let axis_next = axis.next();
let div = match nn.div {
Some(b) => b,
None => return,
};
let line = (axis, div);
if *blap.ray.point.get_axis(axis) < div {
recc(axis_next, left, blap);
if blap.should_recurse(line) {
recc(axis_next, right, blap);
}
} else {
recc(axis_next, right, blap);
if blap.should_recurse(line) {
recc(axis_next, left, blap);
}
}
if !nn.range.is_empty() {
match nn.cont.contains_ext(*blap.ray.point.get_axis(axis)) {
core::cmp::Ordering::Less => blap.should_recurse((axis, nn.cont.start)),
core::cmp::Ordering::Greater => blap.should_recurse((axis, nn.cont.end)),
core::cmp::Ordering::Equal => true,
}
} else {
false
}
} else {
true
};
if handle_curr {
for b in nn.into_range().iter_mut() {
blap.closest.consider(&blap.ray, b, &mut blap.rtrait);
}
}
}
pub fn assert_raycast<T: Aabb>(
tree: &mut Tree<T>,
ray: axgeom::Ray<T::Num>,
rtrait: &mut impl RayCast<T = T, N = T::Num>,
) where
T::Num: core::fmt::Debug,
{
let bots = tree.get_elements_mut();
fn into_ptr_usize<T>(a: &T) -> usize {
a as *const T as usize
}
let mut res_naive = Vec::new();
match raycast_naive_mut(bots, ray, rtrait) {
axgeom::CastResult::Hit(CastAnswer { elems, mag }) => {
for a in elems.into_iter() {
let r = *a.get();
let j = into_ptr_usize(a.into_ref());
res_naive.push((j, r, mag))
}
}
axgeom::CastResult::NoHit => {
}
}
let mut res_dino = Vec::new();
match tree.raycast_mut(ray, rtrait) {
axgeom::CastResult::Hit(CastAnswer { elems, mag }) => {
for a in elems.into_iter() {
let r = *a.get();
let j = into_ptr_usize(a.into_ref());
res_dino.push((j, r, mag))
}
}
axgeom::CastResult::NoHit => {
}
}
res_naive.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
res_dino.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
assert_eq!(
res_naive.len(),
res_dino.len(),
"len:{:?}",
(res_naive, res_dino)
);
assert!(
res_naive.iter().eq(res_dino.iter()),
"nop:\n\n naive:{:?} \n\n broc:{:?}",
res_naive,
res_dino
);
}
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>,
) -> axgeom::CastResult<CastAnswer<'a, T>> {
let mut closest = Closest { closest: None };
for b in bots.iter_mut() {
closest.consider(&ray, b, rtrait);
}
match closest.closest {
Some((a, b)) => axgeom::CastResult::Hit(CastAnswer { elems: a, mag: b }),
None => axgeom::CastResult::NoHit,
}
}
use super::Queries;
pub struct CastAnswer<'a, T: Aabb> {
pub elems: Vec<PMut<'a, T>>,
pub mag: T::Num,
}
pub trait RaycastQuery<'a>: Queries<'a> {
fn raycast_mut<'b, R: RayCast<T = Self::T, N = Self::Num>>(
&'b mut self,
ray: axgeom::Ray<Self::Num>,
rtrait: &mut R,
) -> axgeom::CastResult<CastAnswer<'b, Self::T>>
where
'a: 'b,
{
let rtrait = RayCastBorrow(rtrait);
let dt = self.vistr_mut().with_depth(Depth(0));
let closest = Closest { closest: None };
let mut blap = Blap {
rtrait,
ray,
closest,
};
recc(default_axis(), dt, &mut blap);
match blap.closest.closest {
Some((a, b)) => axgeom::CastResult::Hit(CastAnswer { elems: a, mag: b }),
None => axgeom::CastResult::NoHit,
}
}
}