ncollide3d/query/ray/
ray.rs

1//! Traits and structure needed to cast rays.
2
3use crate::math::{Isometry, Point, Vector};
4use crate::shape::FeatureId;
5#[cfg(feature = "dim3")]
6use na::Point2;
7use na::RealField;
8
9/// A Ray.
10#[derive(Debug, Clone, Copy)]
11pub struct Ray<N: RealField + Copy> {
12    /// Starting point of the ray.
13    pub origin: Point<N>,
14    /// Direction of the ray.
15    pub dir: Vector<N>,
16}
17
18impl<N: RealField + Copy> Ray<N> {
19    /// Creates a new ray starting from `origin` and with the direction `dir`. `dir` must be
20    /// normalized.
21    pub fn new(origin: Point<N>, dir: Vector<N>) -> Ray<N> {
22        Ray {
23            origin: origin,
24            dir: dir,
25        }
26    }
27
28    /// Transforms this ray by the given isometry.
29    #[inline]
30    pub fn transform_by(&self, m: &Isometry<N>) -> Self {
31        Self::new(m * self.origin, m * self.dir)
32    }
33
34    /// Transforms this ray by the inverse of the given isometry.
35    #[inline]
36    pub fn inverse_transform_by(&self, m: &Isometry<N>) -> Self {
37        Self::new(
38            m.inverse_transform_point(&self.origin),
39            m.inverse_transform_vector(&self.dir),
40        )
41    }
42
43    /// Translates this ray by the given vector. Its direction is left unchanged.
44    #[inline]
45    pub fn translate_by(&self, v: Vector<N>) -> Self {
46        Self::new(self.origin + v, self.dir)
47    }
48
49    /// Computes the point at the given parameter on this line.
50    ///
51    /// This computes `self.origin + self.dir * t`.
52    #[inline]
53    pub fn point_at(&self, t: N) -> Point<N> {
54        self.origin + self.dir * t
55    }
56}
57
58/// Structure containing the result of a successful ray cast.
59#[derive(Copy, Clone, Debug)]
60#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
61pub struct RayIntersection<N: RealField + Copy> {
62    /// The time of impact of the ray with the object.  The exact contact point can be computed
63    /// with: `ray.point_at(toi)` or equivalently `origin + dir * toi` where `origin` is the origin of the ray;
64    /// `dir` is its direction and `toi` is the value of this field.
65    pub toi: N,
66
67    /// The normal at the intersection point.
68    ///
69    /// If the `toi` is exactly zero, the normal might not be reliable.
70    // XXX: use a Unit<Vetor<N>> instead.
71    pub normal: Vector<N>,
72
73    /// Feature at the intersection point.
74    pub feature: FeatureId,
75
76    /// The textures coordinates at the intersection point.  This is an `Option` because some shape
77    /// do not support texture coordinates.
78    #[cfg(feature = "dim3")]
79    pub uvs: Option<Point2<N>>,
80}
81
82impl<N: RealField + Copy> RayIntersection<N> {
83    #[inline]
84    /// Creates a new `RayIntersection`.
85    #[cfg(feature = "dim3")]
86    pub fn new_with_uvs(
87        toi: N,
88        normal: Vector<N>,
89        feature: FeatureId,
90        uvs: Option<Point2<N>>,
91    ) -> RayIntersection<N> {
92        RayIntersection {
93            toi,
94            normal,
95            feature,
96            uvs,
97        }
98    }
99
100    #[inline]
101    /// Creates a new `RayIntersection`.
102    #[cfg(feature = "dim3")]
103    pub fn new(toi: N, normal: Vector<N>, feature: FeatureId) -> RayIntersection<N> {
104        RayIntersection {
105            toi,
106            normal,
107            feature,
108            uvs: None,
109        }
110    }
111
112    #[inline]
113    /// Creates a new `RayIntersection`.
114    #[cfg(feature = "dim2")]
115    pub fn new(toi: N, normal: Vector<N>, feature: FeatureId) -> RayIntersection<N> {
116        RayIntersection {
117            toi,
118            normal,
119            feature,
120        }
121    }
122}
123
124/// Traits of objects which can be transformed and tested for intersection with a ray.
125pub trait RayCast<N: RealField + Copy> {
126    /// Computes the time of impact between this transform shape and a ray.
127    fn toi_with_ray(&self, m: &Isometry<N>, ray: &Ray<N>, max_toi: N, solid: bool) -> Option<N> {
128        self.toi_and_normal_with_ray(m, ray, max_toi, solid)
129            .map(|inter| inter.toi)
130    }
131
132    /// Computes the time of impact, and normal between this transformed shape and a ray.
133    fn toi_and_normal_with_ray(
134        &self,
135        m: &Isometry<N>,
136        ray: &Ray<N>,
137        max_toi: N,
138        solid: bool,
139    ) -> Option<RayIntersection<N>>;
140
141    /// Computes time of impact, normal, and texture coordinates (uv) between this transformed
142    /// shape and a ray.
143    #[cfg(feature = "dim3")]
144    #[inline]
145    fn toi_and_normal_and_uv_with_ray(
146        &self,
147        m: &Isometry<N>,
148        ray: &Ray<N>,
149        max_toi: N,
150        solid: bool,
151    ) -> Option<RayIntersection<N>> {
152        self.toi_and_normal_with_ray(m, ray, max_toi, solid)
153    }
154
155    /// Tests whether a ray intersects this transformed shape.
156    #[inline]
157    fn intersects_ray(&self, m: &Isometry<N>, ray: &Ray<N>, max_toi: N) -> bool {
158        self.toi_with_ray(m, ray, max_toi, true).is_some()
159    }
160}