ncollide3d/query/ray/
ray_plane.rs
1use na::{self, RealField};
2
3use crate::math::{Isometry, Point, Vector};
4use crate::query::{Ray, RayCast, RayIntersection};
5use crate::shape::{FeatureId, Plane};
6
7#[inline]
9pub fn line_toi_with_plane<N: RealField + Copy>(
10 plane_center: &Point<N>,
11 plane_normal: &Vector<N>,
12 line_origin: &Point<N>,
13 line_dir: &Vector<N>,
14) -> Option<N> {
15 let dpos = *plane_center - *line_origin;
16 let denom = plane_normal.dot(line_dir);
17
18 if relative_eq!(denom, N::zero()) {
19 None
20 } else {
21 Some(plane_normal.dot(&dpos) / denom)
22 }
23}
24
25#[inline]
27pub fn ray_toi_with_plane<N: RealField + Copy>(
28 center: &Point<N>,
29 normal: &Vector<N>,
30 ray: &Ray<N>,
31) -> Option<N> {
32 if let Some(t) = line_toi_with_plane(center, normal, &ray.origin, &ray.dir) {
33 if t >= na::zero() {
34 return Some(t);
35 }
36 }
37
38 None
39}
40
41impl<N: RealField + Copy> RayCast<N> for Plane<N> {
42 #[inline]
43 fn toi_and_normal_with_ray(
44 &self,
45 m: &Isometry<N>,
46 ray: &Ray<N>,
47 max_toi: N,
48 solid: bool,
49 ) -> Option<RayIntersection<N>> {
50 let ls_ray = ray.inverse_transform_by(m);
51
52 let dpos = -ls_ray.origin;
53
54 let dot_normal_dpos = self.normal.dot(&dpos.coords);
55
56 if solid && dot_normal_dpos > na::zero() {
57 return Some(RayIntersection::new(
59 na::zero(),
60 na::zero(),
61 FeatureId::Face(0),
62 ));
63 }
64
65 let t = dot_normal_dpos / self.normal.dot(&ls_ray.dir);
66
67 if t >= na::zero() && t <= max_toi {
68 let n = if dot_normal_dpos > na::zero() {
69 -self.normal
70 } else {
71 self.normal
72 };
73
74 Some(RayIntersection::new(t, m * *n, FeatureId::Face(0)))
75 } else {
76 None
77 }
78 }
79}