use na::Identity;
use entities::bounding_volume::AABB;
use entities::shape::Compound;
use entities::partitioning::BVTCostFn;
use ray::{Ray, RayCast, RayIntersection};
use math::{Point, Vector, Isometry};
// XXX: if solid == false, this might return internal intersection.
impl
RayCast
for Compound
where P: Point,
M: Isometry
{
fn toi_with_ray(&self, m: &M, ray: &Ray
, solid: bool) -> Option<::Scalar> {
let ls_ray = Ray::new(m.inverse_transform(&ray.origin), m.inverse_rotate(&ray.dir));
let mut cost_fn = CompoundRayToiCostFn { compound: self, ray: &ls_ray, solid: solid };
self.bvt().best_first_search(&mut cost_fn).map(|(_, res)| res)
}
fn toi_and_normal_with_ray(&self, m: &M, ray: &Ray, solid: bool) -> Option> {
let ls_ray = Ray::new(m.inverse_transform(&ray.origin), m.inverse_rotate(&ray.dir));
let mut cost_fn = CompoundRayToiAndNormalCostFn { compound: self, ray: &ls_ray, solid: solid };
self.bvt().best_first_search(&mut cost_fn).map(|(_, mut res)| {
res.normal = m.rotate(&res.normal); res
})
}
// XXX: We have to implement toi_and_normal_and_uv_with_ray! Otherwise, no uv will be computed
// for any of the sub-shapes.
}
/*
* Costs functions.
*/
struct CompoundRayToiCostFn<'a, P: 'a + Point, M: 'a> {
compound: &'a Compound,
ray: &'a Ray
,
solid: bool
}
impl<'a, P, M> BVTCostFn<::Scalar, usize, AABB> for CompoundRayToiCostFn<'a, P, M>
where P: Point,
M: Isometry
{
type UserData = ::Scalar;
#[inline]
fn compute_bv_cost(&mut self, aabb: &AABB) -> Option<::Scalar> {
aabb.toi_with_ray(&Identity::new(), self.ray, self.solid)
}
#[inline]
fn compute_b_cost(&mut self, b: &usize) -> Option<(::Scalar, ::Scalar)> {
let elt = &self.compound.shapes()[*b];
elt.1.toi_with_ray(&elt.0, self.ray, self.solid).map(|toi| (toi, toi))
}
}
struct CompoundRayToiAndNormalCostFn<'a, P: 'a + Point, M: 'a> {
compound: &'a Compound,
ray: &'a Ray
,
solid: bool
}
impl<'a, P, M> BVTCostFn<::Scalar, usize, AABB>
for CompoundRayToiAndNormalCostFn<'a, P, M>
where P: Point,
M: Isometry
{
type UserData = RayIntersection;
#[inline]
fn compute_bv_cost(&mut self, aabb: &AABB) -> Option<::Scalar> {
aabb.toi_with_ray(&Identity::new(), self.ray, self.solid)
}
#[inline]
fn compute_b_cost(&mut self, b: &usize) -> Option<(::Scalar, RayIntersection)> {
let elt = &self.compound.shapes()[*b];
elt.1.toi_and_normal_with_ray(&elt.0, self.ray, self.solid).map(|inter| (inter.toi, inter))
}
}