parry3d_f64/query/ray/
ray.rs1use crate::math::{Isometry, Point, Real, Vector};
4use crate::shape::FeatureId;
5
6#[cfg(feature = "rkyv")]
7use rkyv::{bytecheck, CheckBytes};
8
9#[derive(Debug, Clone, Copy)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12#[cfg_attr(
13 feature = "rkyv",
14 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
15 archive(as = "Self")
16)]
17#[repr(C)]
18pub struct Ray {
19 pub origin: Point<Real>,
21 pub dir: Vector<Real>,
23}
24
25impl Ray {
26 pub fn new(origin: Point<Real>, dir: Vector<Real>) -> Ray {
28 Ray { origin, dir }
29 }
30
31 #[inline]
33 pub fn transform_by(&self, m: &Isometry<Real>) -> Self {
34 Self::new(m * self.origin, m * self.dir)
35 }
36
37 #[inline]
39 pub fn inverse_transform_by(&self, m: &Isometry<Real>) -> Self {
40 Self::new(
41 m.inverse_transform_point(&self.origin),
42 m.inverse_transform_vector(&self.dir),
43 )
44 }
45
46 #[inline]
48 pub fn translate_by(&self, v: Vector<Real>) -> Self {
49 Self::new(self.origin + v, self.dir)
50 }
51
52 #[inline]
56 pub fn point_at(&self, t: Real) -> Point<Real> {
57 self.origin + self.dir * t
58 }
59}
60
61#[derive(Copy, Clone, Debug)]
63#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
64#[cfg_attr(
65 feature = "rkyv",
66 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
67 archive(as = "Self")
68)]
69pub struct RayIntersection {
70 pub time_of_impact: Real,
74
75 pub normal: Vector<Real>,
84
85 pub feature: FeatureId,
87}
88
89impl RayIntersection {
90 #[inline]
91 #[cfg(feature = "dim3")]
93 pub fn new(time_of_impact: Real, normal: Vector<Real>, feature: FeatureId) -> RayIntersection {
94 RayIntersection {
95 time_of_impact,
96 normal,
97 feature,
98 }
99 }
100
101 #[inline]
102 #[cfg(feature = "dim2")]
104 pub fn new(time_of_impact: Real, normal: Vector<Real>, feature: FeatureId) -> RayIntersection {
105 RayIntersection {
106 time_of_impact,
107 normal,
108 feature,
109 }
110 }
111
112 #[inline]
113 pub fn transform_by(&self, transform: &Isometry<Real>) -> Self {
114 RayIntersection {
115 time_of_impact: self.time_of_impact,
116 normal: transform * self.normal,
117 feature: self.feature,
118 }
119 }
120}
121
122pub trait RayCast {
124 fn cast_local_ray(&self, ray: &Ray, max_time_of_impact: Real, solid: bool) -> Option<Real> {
126 self.cast_local_ray_and_get_normal(ray, max_time_of_impact, solid)
127 .map(|inter| inter.time_of_impact)
128 }
129
130 fn cast_local_ray_and_get_normal(
132 &self,
133 ray: &Ray,
134 max_time_of_impact: Real,
135 solid: bool,
136 ) -> Option<RayIntersection>;
137
138 #[inline]
140 fn intersects_local_ray(&self, ray: &Ray, max_time_of_impact: Real) -> bool {
141 self.cast_local_ray(ray, max_time_of_impact, true).is_some()
142 }
143
144 fn cast_ray(
146 &self,
147 m: &Isometry<Real>,
148 ray: &Ray,
149 max_time_of_impact: Real,
150 solid: bool,
151 ) -> Option<Real> {
152 let ls_ray = ray.inverse_transform_by(m);
153 self.cast_local_ray(&ls_ray, max_time_of_impact, solid)
154 }
155
156 fn cast_ray_and_get_normal(
158 &self,
159 m: &Isometry<Real>,
160 ray: &Ray,
161 max_time_of_impact: Real,
162 solid: bool,
163 ) -> Option<RayIntersection> {
164 let ls_ray = ray.inverse_transform_by(m);
165 self.cast_local_ray_and_get_normal(&ls_ray, max_time_of_impact, solid)
166 .map(|inter| inter.transform_by(m))
167 }
168
169 #[inline]
171 fn intersects_ray(&self, m: &Isometry<Real>, ray: &Ray, max_time_of_impact: Real) -> bool {
172 let ls_ray = ray.inverse_transform_by(m);
173 self.intersects_local_ray(&ls_ray, max_time_of_impact)
174 }
175}