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
use crate::{BoundingBox, Object, RealField};
use num_traits::Float;

/// A sphere. Simple.
#[derive(Clone, Debug, PartialEq)]
pub struct Sphere<S: RealField> {
    radius: S,
    bbox: BoundingBox<S>,
}

impl<S: RealField + Float> Sphere<S> {
    /// Create a new sphere of radius r.
    pub fn new(r: S) -> Self {
        Sphere {
            radius: r,
            bbox: BoundingBox::new(&na::Point3::new(-r, -r, -r), &na::Point3::new(r, r, r)),
        }
    }
}

impl<S: ::std::fmt::Debug + RealField + Float + From<f32>> Object<S> for Sphere<S> {
    fn approx_value(&self, p: &na::Point3<S>, slack: S) -> S {
        let approx = self.bbox.distance(p);
        if approx <= slack {
            na::Vector3::new(p.x, p.y, p.z).norm() - self.radius
        } else {
            approx
        }
    }
    fn bbox(&self) -> &BoundingBox<S> {
        &self.bbox
    }
    fn normal(&self, p: &na::Point3<S>) -> na::Vector3<S> {
        na::Vector3::new(p.x, p.y, p.z).normalize()
    }
}

#[cfg(test)]
mod test {
    use crate::*;

    #[test]
    fn simple() {
        let s = Sphere::new(1.);
        assert_ulps_eq!(s.approx_value(&na::Point3::new(0., 0., 0.), 0.), -1.);
        assert_ulps_eq!(s.approx_value(&na::Point3::new(1., 0., 0.), 0.), 0.);
        assert_ulps_eq!(s.approx_value(&na::Point3::new(2., 0., 0.), 0.), 1.);
    }
}