ncollide3d/query/ray/
ray_compound.rs

1use crate::bounding_volume::AABB;
2use crate::math::Isometry;
3use crate::partitioning::{BestFirstVisitStatus, BestFirstVisitor, BVH};
4use crate::query::{Ray, RayCast, RayIntersection};
5use crate::shape::Compound;
6use na::RealField;
7
8// XXX: if solid == false, this might return internal intersection.
9impl<N: RealField + Copy> RayCast<N> for Compound<N> {
10    fn toi_with_ray(&self, m: &Isometry<N>, ray: &Ray<N>, max_toi: N, solid: bool) -> Option<N> {
11        let ls_ray = ray.inverse_transform_by(m);
12
13        let mut visitor = CompoundRayToiVisitor {
14            compound: self,
15            ray: &ls_ray,
16            max_toi,
17            solid: solid,
18        };
19
20        self.bvt().best_first_search(&mut visitor).map(|res| res.1)
21    }
22
23    fn toi_and_normal_with_ray(
24        &self,
25        m: &Isometry<N>,
26        ray: &Ray<N>,
27        max_toi: N,
28        solid: bool,
29    ) -> Option<RayIntersection<N>> {
30        let ls_ray = ray.inverse_transform_by(m);
31
32        let mut visitor = CompoundRayToiAndNormalVisitor {
33            compound: self,
34            ray: &ls_ray,
35            max_toi,
36            solid,
37        };
38
39        self.bvt()
40            .best_first_search(&mut visitor)
41            .map(|(_, mut res)| {
42                res.normal = m * res.normal;
43                res
44            })
45    }
46
47    // XXX: We have to implement toi_and_normal_and_uv_with_ray! Otherwise, no uv will be computed
48    // for any of the sub-shapes.
49}
50
51/*
52 * Costs functions.
53 */
54struct CompoundRayToiVisitor<'a, N: 'a + RealField + Copy> {
55    compound: &'a Compound<N>,
56    ray: &'a Ray<N>,
57    max_toi: N,
58    solid: bool,
59}
60
61impl<'a, N: RealField + Copy> BestFirstVisitor<N, usize, AABB<N>> for CompoundRayToiVisitor<'a, N> {
62    type Result = N;
63
64    #[inline]
65    fn visit(
66        &mut self,
67        best: N,
68        aabb: &AABB<N>,
69        data: Option<&usize>,
70    ) -> BestFirstVisitStatus<N, Self::Result> {
71        if let Some(toi) = aabb.toi_with_ray(&Isometry::identity(), self.ray, self.max_toi, true) {
72            let mut res = BestFirstVisitStatus::Continue {
73                cost: toi,
74                result: None,
75            };
76
77            if let Some(b) = data {
78                if toi < best {
79                    let elt = &self.compound.shapes()[*b];
80                    if let Some(toi) =
81                        elt.1
82                            .toi_with_ray(&elt.0, self.ray, self.max_toi, self.solid)
83                    {
84                        res = BestFirstVisitStatus::Continue {
85                            cost: toi,
86                            result: Some(toi),
87                        };
88                    }
89                }
90            }
91
92            res
93        } else {
94            BestFirstVisitStatus::Stop
95        }
96    }
97}
98
99struct CompoundRayToiAndNormalVisitor<'a, N: 'a + RealField + Copy> {
100    compound: &'a Compound<N>,
101    ray: &'a Ray<N>,
102    max_toi: N,
103    solid: bool,
104}
105
106impl<'a, N: RealField + Copy> BestFirstVisitor<N, usize, AABB<N>>
107    for CompoundRayToiAndNormalVisitor<'a, N>
108{
109    type Result = RayIntersection<N>;
110
111    #[inline]
112    fn visit(
113        &mut self,
114        best: N,
115        aabb: &AABB<N>,
116        data: Option<&usize>,
117    ) -> BestFirstVisitStatus<N, Self::Result> {
118        if let Some(toi) = aabb.toi_with_ray(&Isometry::identity(), self.ray, self.max_toi, true) {
119            let mut res = BestFirstVisitStatus::Continue {
120                cost: toi,
121                result: None,
122            };
123
124            if let Some(b) = data {
125                if toi < best {
126                    let elt = &self.compound.shapes()[*b];
127                    if let Some(toi) =
128                        elt.1
129                            .toi_and_normal_with_ray(&elt.0, self.ray, self.max_toi, self.solid)
130                    {
131                        res = BestFirstVisitStatus::Continue {
132                            cost: toi.toi,
133                            result: Some(toi),
134                        }
135                    }
136                }
137            }
138
139            res
140        } else {
141            BestFirstVisitStatus::Stop
142        }
143    }
144}