ncollide3d/query/ray/
ray_polyline.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::{FeatureId, Polyline};
6use na::RealField;
7
8impl<N: RealField + Copy> RayCast<N> for Polyline<N> {
9 #[inline]
10 fn toi_with_ray(&self, m: &Isometry<N>, ray: &Ray<N>, max_toi: N, _: bool) -> Option<N> {
11 let ls_ray = ray.inverse_transform_by(m);
12
13 let mut visitor = PolylineRayToiVisitor {
14 polyline: self,
15 ray: &ls_ray,
16 max_toi,
17 };
18
19 self.bvt().best_first_search(&mut visitor).map(|res| res.1)
20 }
21
22 #[inline]
23 fn toi_and_normal_with_ray(
24 &self,
25 m: &Isometry<N>,
26 ray: &Ray<N>,
27 max_toi: N,
28 _: bool,
29 ) -> Option<RayIntersection<N>> {
30 let ls_ray = ray.inverse_transform_by(m);
31
32 let mut visitor = PolylineRayToiAndNormalVisitor {
33 polyline: self,
34 ray: &ls_ray,
35 max_toi,
36 };
37
38 self.bvt()
39 .best_first_search(&mut visitor)
40 .map(|(_, (best, mut res))| {
41 if let FeatureId::Face(1) = res.feature {
42 res.feature = FeatureId::Face(best + self.edges().len());
43 } else {
44 res.feature = FeatureId::Face(best);
45 }
46
47 res.normal = m * res.normal;
48 res
49 })
50 }
51}
52
53struct PolylineRayToiVisitor<'a, N: 'a + RealField + Copy> {
57 polyline: &'a Polyline<N>,
58 ray: &'a Ray<N>,
59 max_toi: N,
60}
61
62impl<'a, N: RealField + Copy> BestFirstVisitor<N, usize, AABB<N>> for PolylineRayToiVisitor<'a, N> {
63 type Result = N;
64
65 #[inline]
66 fn visit(
67 &mut self,
68 best: N,
69 aabb: &AABB<N>,
70 data: Option<&usize>,
71 ) -> BestFirstVisitStatus<N, Self::Result> {
72 if let Some(toi) = aabb.toi_with_ray(&Isometry::identity(), self.ray, self.max_toi, true) {
73 let mut res = BestFirstVisitStatus::Continue {
74 cost: toi,
75 result: None,
76 };
77
78 if let Some(b) = data {
79 if toi < best {
80 let segment = self.polyline.segment_at(*b);
82 if let Some(toi) =
83 segment.toi_with_ray(&Isometry::identity(), self.ray, self.max_toi, true)
84 {
85 res = BestFirstVisitStatus::Continue {
86 cost: toi,
87 result: Some(toi),
88 }
89 }
90 }
91 }
92
93 res
94 } else {
95 BestFirstVisitStatus::Stop
96 }
97 }
98}
99
100struct PolylineRayToiAndNormalVisitor<'a, N: 'a + RealField + Copy> {
101 polyline: &'a Polyline<N>,
102 ray: &'a Ray<N>,
103 max_toi: N,
104}
105
106impl<'a, N: RealField + Copy> BestFirstVisitor<N, usize, AABB<N>>
107 for PolylineRayToiAndNormalVisitor<'a, N>
108{
109 type Result = (usize, 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 segment = self.polyline.segment_at(*b);
128 if let Some(toi) = segment.toi_and_normal_with_ray(
129 &Isometry::identity(),
130 self.ray,
131 self.max_toi,
132 true,
133 ) {
134 res = BestFirstVisitStatus::Continue {
135 cost: toi.toi,
136 result: Some((*b, toi)),
137 };
138 }
139 }
140 }
141
142 res
143 } else {
144 BestFirstVisitStatus::Stop
145 }
146 }
147}