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
use na::Real;

use math::Isometry;
use partitioning::{BVTCostFn, BVTVisitor};
use query::{Ray, RayCast, RayIntersection};

/// A search thet selects the objects that has the smallest time of impact with a given ray.
pub struct RayIntersectionCostFn<'a, N: 'a + Real> {
    ray: &'a Ray<N>,
    solid: bool,

    #[cfg(feature = "dim3")]
    uvs: bool,
}

impl<'a, N: Real> RayIntersectionCostFn<'a, N> {
    /// Creates a new `BestRayInterferenceSearch`.
    #[cfg(feature = "dim3")]
    pub fn new(ray: &'a Ray<N>, solid: bool, uvs: bool) -> RayIntersectionCostFn<'a, N> {
        RayIntersectionCostFn {
            ray,
            solid,
            uvs,
        }
    }

        /// Creates a new `BestRayInterferenceSearch`.
    #[cfg(feature = "dim2")]
    pub fn new(ray: &'a Ray<N>, solid: bool) -> RayIntersectionCostFn<'a, N> {
        RayIntersectionCostFn {
            ray,
            solid,
        }
    }
}

impl<'a, N, B, BV> BVTCostFn<N, B, BV> for RayIntersectionCostFn<'a, N>
where
    N: Real,
    B: RayCast<N>,
    BV: RayCast<N>,
{
    type UserData = RayIntersection<N>;

    #[inline]
    fn compute_bv_cost(&mut self, bv: &BV) -> Option<N> {
        bv.toi_with_ray(&Isometry::identity(), self.ray, true)
    }

    #[cfg(feature = "dim3")]
    #[inline]
    fn compute_b_cost(&mut self, b: &B) -> Option<(N, RayIntersection<N>)> {
        if self.uvs {
            b.toi_and_normal_and_uv_with_ray(&Isometry::identity(), self.ray, self.solid)
                .map(|i| (i.toi, i))
        } else {
            b.toi_and_normal_with_ray(&Isometry::identity(), self.ray, self.solid)
                .map(|i| (i.toi, i))
        }
    }
    
    #[cfg(feature = "dim2")]
    #[inline]
    fn compute_b_cost(&mut self, b: &B) -> Option<(N, RayIntersection<N>)> {
        b.toi_and_normal_with_ray(&Isometry::identity(), self.ray, self.solid)
            .map(|i| (i.toi, i))
    }
}

/// Bounding Volume Tree visitor collecting interferences with a given ray.
pub struct RayInterferencesCollector<'a, N: 'a + Real, B: 'a> {
    ray: &'a Ray<N>,
    collector: &'a mut Vec<B>,
}

impl<'a, N: Real, B> RayInterferencesCollector<'a, N, B> {
    /// Creates a new `RayInterferencesCollector`.
    #[inline]
    pub fn new(ray: &'a Ray<N>, buffer: &'a mut Vec<B>) -> RayInterferencesCollector<'a, N, B> {
        RayInterferencesCollector {
            ray: ray,
            collector: buffer,
        }
    }
}

impl<'a, N, B, BV> BVTVisitor<B, BV> for RayInterferencesCollector<'a, N, B>
where
    N: Real,
    B: Clone,
    BV: RayCast<N>,
{
    #[inline]
    fn visit_internal(&mut self, bv: &BV) -> bool {
        bv.intersects_ray(&Isometry::identity(), self.ray)
    }

    #[inline]
    fn visit_leaf(&mut self, b: &B, bv: &BV) {
        if bv.intersects_ray(&Isometry::identity(), self.ray) {
            self.collector.push(b.clone())
        }
    }
}