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