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