1use crate::math::{Isometry, Point, Real, Vector};
4use crate::shape::FeatureId;
5
6#[cfg(feature = "alloc")]
7use crate::partitioning::BvhLeafCost;
8#[cfg(feature = "rkyv")]
9use rkyv::{bytecheck, CheckBytes};
10
11#[derive(Debug, Clone, Copy)]
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14#[cfg_attr(
15 feature = "rkyv",
16 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
17 archive(as = "Self")
18)]
19#[repr(C)]
20pub struct Ray {
21 pub origin: Point<Real>,
23 pub dir: Vector<Real>,
25}
26
27impl Ray {
28 pub fn new(origin: Point<Real>, dir: Vector<Real>) -> Ray {
30 Ray { origin, dir }
31 }
32
33 #[inline]
35 pub fn transform_by(&self, m: &Isometry<Real>) -> Self {
36 Self::new(m * self.origin, m * self.dir)
37 }
38
39 #[inline]
41 pub fn inverse_transform_by(&self, m: &Isometry<Real>) -> Self {
42 Self::new(
43 m.inverse_transform_point(&self.origin),
44 m.inverse_transform_vector(&self.dir),
45 )
46 }
47
48 #[inline]
50 pub fn translate_by(&self, v: Vector<Real>) -> Self {
51 Self::new(self.origin + v, self.dir)
52 }
53
54 #[inline]
58 pub fn point_at(&self, t: Real) -> Point<Real> {
59 self.origin + self.dir * t
60 }
61}
62
63#[derive(Copy, Clone, Debug)]
65#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
66#[cfg_attr(
67 feature = "rkyv",
68 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
69 archive(as = "Self")
70)]
71pub struct RayIntersection {
72 pub time_of_impact: Real,
76
77 pub normal: Vector<Real>,
86
87 pub feature: FeatureId,
89}
90
91impl RayIntersection {
92 #[inline]
93 #[cfg(feature = "dim3")]
95 pub fn new(time_of_impact: Real, normal: Vector<Real>, feature: FeatureId) -> RayIntersection {
96 RayIntersection {
97 time_of_impact,
98 normal,
99 feature,
100 }
101 }
102
103 #[inline]
104 #[cfg(feature = "dim2")]
106 pub fn new(time_of_impact: Real, normal: Vector<Real>, feature: FeatureId) -> RayIntersection {
107 RayIntersection {
108 time_of_impact,
109 normal,
110 feature,
111 }
112 }
113
114 #[inline]
115 pub fn transform_by(&self, transform: &Isometry<Real>) -> Self {
116 RayIntersection {
117 time_of_impact: self.time_of_impact,
118 normal: transform * self.normal,
119 feature: self.feature,
120 }
121 }
122}
123
124#[cfg(feature = "alloc")]
125impl BvhLeafCost for RayIntersection {
126 #[inline]
127 fn cost(&self) -> Real {
128 self.time_of_impact
129 }
130}
131
132pub trait RayCast {
134 fn cast_local_ray(&self, ray: &Ray, max_time_of_impact: Real, solid: bool) -> Option<Real> {
136 self.cast_local_ray_and_get_normal(ray, max_time_of_impact, solid)
137 .map(|inter| inter.time_of_impact)
138 }
139
140 fn cast_local_ray_and_get_normal(
142 &self,
143 ray: &Ray,
144 max_time_of_impact: Real,
145 solid: bool,
146 ) -> Option<RayIntersection>;
147
148 #[inline]
150 fn intersects_local_ray(&self, ray: &Ray, max_time_of_impact: Real) -> bool {
151 self.cast_local_ray(ray, max_time_of_impact, true).is_some()
152 }
153
154 fn cast_ray(
156 &self,
157 m: &Isometry<Real>,
158 ray: &Ray,
159 max_time_of_impact: Real,
160 solid: bool,
161 ) -> Option<Real> {
162 let ls_ray = ray.inverse_transform_by(m);
163 self.cast_local_ray(&ls_ray, max_time_of_impact, solid)
164 }
165
166 fn cast_ray_and_get_normal(
168 &self,
169 m: &Isometry<Real>,
170 ray: &Ray,
171 max_time_of_impact: Real,
172 solid: bool,
173 ) -> Option<RayIntersection> {
174 let ls_ray = ray.inverse_transform_by(m);
175 self.cast_local_ray_and_get_normal(&ls_ray, max_time_of_impact, solid)
176 .map(|inter| inter.transform_by(m))
177 }
178
179 #[inline]
181 fn intersects_ray(&self, m: &Isometry<Real>, ray: &Ray, max_time_of_impact: Real) -> bool {
182 let ls_ray = ray.inverse_transform_by(m);
183 self.intersects_local_ray(&ls_ray, max_time_of_impact)
184 }
185}