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 fn as_any(&self) -> &dyn std::any::Any { self }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn contains_origin() {
60 let s = Sphere::<3>::unit();
61 assert!(s.contains(&Point::origin()));
62 }
63
64 #[test]
65 fn not_contains_far() {
66 let s = Sphere::<3>::unit();
67 assert!(!s.contains(&Point::new([2.0, 0.0, 0.0])));
68 }
69
70 #[test]
71 fn support_x() {
72 let s = Sphere::<3>::unit();
73 let dir = SVector::from([1.0, 0.0, 0.0]);
74 let sp = s.support(&dir);
75 assert!((sp[0] - 1.0).abs() < 1e-12);
76 }
77
78 #[test]
79 fn intersection() {
80 let a = Sphere::new(Point::new([0.0, 0.0]), 1.0);
81 let b = Sphere::new(Point::new([1.5, 0.0]), 1.0);
82 assert!(a.intersects(&b));
83 let c = Sphere::new(Point::new([3.0, 0.0]), 1.0);
84 assert!(!a.intersects(&c));
85 }
86
87 #[test]
88 fn support_4d() {
89 let s = Sphere::new(Point::new([1.0, 2.0, 3.0, 4.0]), 2.0);
90 let dir = SVector::from([0.0, 0.0, 0.0, 1.0]);
91 let sp = s.support(&dir);
92 assert!((sp[3] - 6.0).abs() < 1e-12);
93 }
94}