1use crate::point::Point;
5use crate::shape::Shape;
6use nalgebra::SVector;
7
8#[derive(Clone, Copy, Debug)]
10pub struct Sphere<const D: usize> {
11 pub center: Point<D>,
12 pub radius: f64,
13}
14
15impl<const D: usize> Sphere<D> {
16 pub fn unit() -> Self {
17 Self {
18 center: Point::origin(),
19 radius: 1.0,
20 }
21 }
22
23 pub fn new(center: Point<D>, radius: f64) -> Self {
24 Self { center, radius }
25 }
26
27 #[inline]
28 pub fn contains(&self, point: &Point<D>) -> bool {
29 self.center.distance_squared(point) <= self.radius * self.radius
30 }
31
32 #[inline]
33 pub fn intersects(&self, other: &Self) -> bool {
34 self.center.distance(&other.center) <= self.radius + other.radius
35 }
36}
37
38impl<const D: usize> Shape<D> for Sphere<D> {
39 fn support(&self, direction: &SVector<f64, D>) -> SVector<f64, D> {
40 let norm = direction.norm();
41 if norm < 1e-15 {
42 return self.center.0;
43 }
44 self.center.0 + direction * (self.radius / norm)
45 }
46
47 fn bounding_sphere(&self) -> (Point<D>, f64) {
48 (self.center, self.radius)
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn contains_origin() {
58 let s = Sphere::<3>::unit();
59 assert!(s.contains(&Point::origin()));
60 }
61
62 #[test]
63 fn not_contains_far() {
64 let s = Sphere::<3>::unit();
65 assert!(!s.contains(&Point::new([2.0, 0.0, 0.0])));
66 }
67
68 #[test]
69 fn support_x() {
70 let s = Sphere::<3>::unit();
71 let dir = SVector::from([1.0, 0.0, 0.0]);
72 let sp = s.support(&dir);
73 assert!((sp[0] - 1.0).abs() < 1e-12);
74 }
75
76 #[test]
77 fn intersection() {
78 let a = Sphere::new(Point::new([0.0, 0.0]), 1.0);
79 let b = Sphere::new(Point::new([1.5, 0.0]), 1.0);
80 assert!(a.intersects(&b));
81 let c = Sphere::new(Point::new([3.0, 0.0]), 1.0);
82 assert!(!a.intersects(&c));
83 }
84
85 #[test]
86 fn support_4d() {
87 let s = Sphere::new(Point::new([1.0, 2.0, 3.0, 4.0]), 2.0);
88 let dir = SVector::from([0.0, 0.0, 0.0, 1.0]);
89 let sp = s.support(&dir);
90 assert!((sp[3] - 6.0).abs() < 1e-12);
91 }
92}