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
8impl<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 }
50
51struct 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}