implicit3d/
sphere.rs

1use crate::{BoundingBox, Object, RealField};
2use num_traits::Float;
3
4/// A sphere. Simple.
5#[derive(Clone, Debug, PartialEq)]
6pub struct Sphere<S: RealField> {
7    radius: S,
8    bbox: BoundingBox<S>,
9}
10
11impl<S: RealField + Float> Sphere<S> {
12    /// Create a new sphere of radius r.
13    pub fn new(r: S) -> Self {
14        Sphere {
15            radius: r,
16            bbox: BoundingBox::new(&na::Point3::new(-r, -r, -r), &na::Point3::new(r, r, r)),
17        }
18    }
19}
20
21impl<S: ::std::fmt::Debug + RealField + Float + From<f32>> Object<S> for Sphere<S> {
22    fn approx_value(&self, p: &na::Point3<S>, slack: S) -> S {
23        let approx = self.bbox.distance(p);
24        if approx <= slack {
25            na::Vector3::new(p.x, p.y, p.z).norm() - self.radius
26        } else {
27            approx
28        }
29    }
30    fn bbox(&self) -> &BoundingBox<S> {
31        &self.bbox
32    }
33    fn normal(&self, p: &na::Point3<S>) -> na::Vector3<S> {
34        na::Vector3::new(p.x, p.y, p.z).normalize()
35    }
36}
37
38#[cfg(test)]
39mod test {
40    use crate::*;
41
42    #[test]
43    fn simple() {
44        let s = Sphere::new(1.);
45        assert_ulps_eq!(s.approx_value(&na::Point3::new(0., 0., 0.), 0.), -1.);
46        assert_ulps_eq!(s.approx_value(&na::Point3::new(1., 0., 0.), 0.), 0.);
47        assert_ulps_eq!(s.approx_value(&na::Point3::new(2., 0., 0.), 0.), 1.);
48    }
49}