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
//! Generic rays

use std::marker::PhantomData;

use cgmath::{BaseFloat, BaseNum};
use cgmath::{Point2, Point3};
use cgmath::{Vector2, Vector3};
use cgmath::prelude::*;

use traits::{Continuous, ContinuousTransformed, Discrete, DiscreteTransformed};

/// A generic ray starting at `origin` and extending infinitely in
/// `direction`.
#[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Ray<S, P, V> {
    /// Ray origin
    pub origin: P,
    /// Normalized ray direction
    pub direction: V,
    phantom_s: PhantomData<S>,
}

impl<S, V, P> Ray<S, P, V>
where
    S: BaseNum,
    V: VectorSpace<Scalar = S>,
    P: EuclideanSpace<Scalar = S, Diff = V>,
{
    /// Create a generic ray starting at `origin` and extending infinitely in
    /// `direction`.
    pub fn new(origin: P, direction: V) -> Ray<S, P, V> {
        Ray {
            origin,
            direction,
            phantom_s: PhantomData,
        }
    }

    /// Create a new ray by applying a transform.
    pub fn transform<T>(&self, transform: T) -> Self
    where
        T: Transform<P>,
    {
        Self::new(
            transform.transform_point(self.origin),
            transform.transform_vector(self.direction),
        )
    }
}

/// 2D ray
pub type Ray2<S> = Ray<S, Point2<S>, Vector2<S>>;

/// 3D ray
pub type Ray3<S> = Ray<S, Point3<S>, Vector3<S>>;

impl<S, P> Continuous<Ray<S, P, P::Diff>> for P
where
    S: BaseFloat,
    P: EuclideanSpace<Scalar = S>,
    P::Diff: InnerSpace<Scalar = S>,
{
    type Result = P;
    fn intersection(&self, ray: &Ray<S, P, P::Diff>) -> Option<P> {
        if self.intersects(ray) {
            Some(*self)
        } else {
            None
        }
    }
}

impl<S, P> Discrete<Ray<S, P, P::Diff>> for P
where
    S: BaseFloat,
    P: EuclideanSpace<Scalar = S>,
    P::Diff: InnerSpace<Scalar = S>,
{
    fn intersects(&self, ray: &Ray<S, P, P::Diff>) -> bool {
        let p = *self;
        let l = p - ray.origin;
        let tca = l.dot(ray.direction);
        tca > S::zero()
            && (tca * tca).relative_eq(
                &l.magnitude2(),
                S::default_epsilon(),
                S::default_max_relative(),
            )
    }
}

impl<P, C> DiscreteTransformed<Ray<P::Scalar, P, P::Diff>> for C
where
    C: Discrete<Ray<P::Scalar, P, P::Diff>>,
    P: EuclideanSpace,
    P::Scalar: BaseFloat,
{
    type Point = P;

    fn intersects_transformed<T>(&self, ray: &Ray<P::Scalar, P, P::Diff>, transform: &T) -> bool
    where
        T: Transform<P>,
    {
        self.intersects(&ray.transform(transform.inverse_transform().unwrap()))
    }
}

impl<P, C> ContinuousTransformed<Ray<P::Scalar, P, P::Diff>> for C
where
    C: Continuous<Ray<P::Scalar, P, P::Diff>, Result = P>,
    P: EuclideanSpace,
    P::Scalar: BaseFloat,
{
    type Point = P;
    type Result = P;

    fn intersection_transformed<T>(
        &self,
        ray: &Ray<P::Scalar, P, P::Diff>,
        transform: &T,
    ) -> Option<P>
    where
        T: Transform<P>,
    {
        self.intersection(&ray.transform(transform.inverse_transform().unwrap()))
            .map(|p| transform.transform_point(p))
    }
}