1//! Traits and structure needed to cast rays.
23use crate::math::{Isometry, Point, Vector};
4use crate::shape::FeatureId;
5#[cfg(feature = "dim3")]
6use na::Point2;
7use na::RealField;
89/// A Ray.
10#[derive(Debug, Clone, Copy)]
11pub struct Ray<N: RealField + Copy> {
12/// Starting point of the ray.
13pub origin: Point<N>,
14/// Direction of the ray.
15pub dir: Vector<N>,
16}
1718impl<N: RealField + Copy> Ray<N> {
19/// Creates a new ray starting from `origin` and with the direction `dir`. `dir` must be
20 /// normalized.
21pub fn new(origin: Point<N>, dir: Vector<N>) -> Ray<N> {
22 Ray {
23 origin: origin,
24 dir: dir,
25 }
26 }
2728/// Transforms this ray by the given isometry.
29#[inline]
30pub fn transform_by(&self, m: &Isometry<N>) -> Self {
31Self::new(m * self.origin, m * self.dir)
32 }
3334/// Transforms this ray by the inverse of the given isometry.
35#[inline]
36pub fn inverse_transform_by(&self, m: &Isometry<N>) -> Self {
37Self::new(
38 m.inverse_transform_point(&self.origin),
39 m.inverse_transform_vector(&self.dir),
40 )
41 }
4243/// Translates this ray by the given vector. Its direction is left unchanged.
44#[inline]
45pub fn translate_by(&self, v: Vector<N>) -> Self {
46Self::new(self.origin + v, self.dir)
47 }
4849/// Computes the point at the given parameter on this line.
50 ///
51 /// This computes `self.origin + self.dir * t`.
52#[inline]
53pub fn point_at(&self, t: N) -> Point<N> {
54self.origin + self.dir * t
55 }
56}
5758/// 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.
65pub toi: N,
6667/// 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.
71pub normal: Vector<N>,
7273/// Feature at the intersection point.
74pub feature: FeatureId,
7576/// The textures coordinates at the intersection point. This is an `Option` because some shape
77 /// do not support texture coordinates.
78#[cfg(feature = "dim3")]
79pub uvs: Option<Point2<N>>,
80}
8182impl<N: RealField + Copy> RayIntersection<N> {
83#[inline]
84/// Creates a new `RayIntersection`.
85#[cfg(feature = "dim3")]
86pub 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 }
99100#[inline]
101/// Creates a new `RayIntersection`.
102#[cfg(feature = "dim3")]
103pub fn new(toi: N, normal: Vector<N>, feature: FeatureId) -> RayIntersection<N> {
104 RayIntersection {
105 toi,
106 normal,
107 feature,
108 uvs: None,
109 }
110 }
111112#[inline]
113/// Creates a new `RayIntersection`.
114#[cfg(feature = "dim2")]
115pub fn new(toi: N, normal: Vector<N>, feature: FeatureId) -> RayIntersection<N> {
116 RayIntersection {
117 toi,
118 normal,
119 feature,
120 }
121 }
122}
123124/// 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.
127fn toi_with_ray(&self, m: &Isometry<N>, ray: &Ray<N>, max_toi: N, solid: bool) -> Option<N> {
128self.toi_and_normal_with_ray(m, ray, max_toi, solid)
129 .map(|inter| inter.toi)
130 }
131132/// Computes the time of impact, and normal between this transformed shape and a ray.
133fn 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>>;
140141/// Computes time of impact, normal, and texture coordinates (uv) between this transformed
142 /// shape and a ray.
143#[cfg(feature = "dim3")]
144 #[inline]
145fn 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>> {
152self.toi_and_normal_with_ray(m, ray, max_toi, solid)
153 }
154155/// Tests whether a ray intersects this transformed shape.
156#[inline]
157fn intersects_ray(&self, m: &Isometry<N>, ray: &Ray<N>, max_toi: N) -> bool {
158self.toi_with_ray(m, ray, max_toi, true).is_some()
159 }
160}