1use std::cmp::{Eq, Ordering};
26
27use crate::*;
28
29#[derive(Debug, PartialEq, PartialOrd, Clone, Hash, Default)]
32pub struct Sphere {
34 pub center: Point3D,
35 pub radius: Positive,
36}
37
38impl Eq for Sphere {}
39
40impl Ord for Sphere {
41 fn cmp(&self, other: &Self) -> Ordering {
42 let origin = Point3D::default();
43 match sqr_dist_3d(&origin, &self.center).partial_cmp(&sqr_dist_3d(&origin, &other.center)) {
44 Some(x) => x,
45 None => self
46 .radius
47 .partial_cmp(&other.radius)
48 .unwrap_or(Ordering::Equal),
49 }
50 }
51}
52
53impl IsND for Sphere {
54 fn n_dimensions() -> usize {
55 Point3D::n_dimensions()
56 }
57
58 fn position_nd(&self, dimension: usize) -> Result<f64> {
59 self.center.position_nd(dimension)
60 }
61}
62
63impl Is3D for Sphere {
64 #[inline(always)]
65 fn x(&self) -> f64 {
66 self.center.x()
67 }
68
69 #[inline(always)]
70 fn y(&self) -> f64 {
71 self.center.y()
72 }
73
74 #[inline(always)]
75 fn z(&self) -> f64 {
76 self.center.y()
77 }
78}
79
80impl IsBuildableND for Sphere {
81 #[inline(always)]
82 fn new_nd(coords: &[f64]) -> Result<Self> {
83 Ok(Sphere {
84 center: Point3D::new_nd(coords)?,
85 radius: Positive::one(),
86 })
87 }
88
89 #[inline(always)]
90 fn from_nd<P>(&mut self, other: P) -> Result<()>
91 where
92 P: IsBuildableND,
93 {
94 self.center.from_nd(other)
95 }
96}
97
98impl IsBuildable3D for Sphere {
99 #[inline(always)]
100 fn new(x: f64, y: f64, z: f64) -> Self {
101 Sphere {
102 center: Point3D { x, y, z },
103 radius: Positive::one(),
104 }
105 }
106
107 #[inline(always)]
108 fn from<P>(&mut self, other: &P)
109 where
110 P: Is3D,
111 {
112 self.center.from(other)
113 }
114}
115
116impl IsEditableND for Sphere {
117 fn set_position(&mut self, dimension: usize, val: f64) -> Result<()> {
118 self.center.set_position(dimension, val)
119 }
120}
121
122impl IsEditable3D for Sphere {
123 #[inline(always)]
124 fn set_x(&mut self, val: f64) {
125 self.center.set_x(val);
126 }
127
128 #[inline(always)]
129 fn set_y(&mut self, val: f64) {
130 self.center.set_y(val);
131 }
132
133 #[inline(always)]
134 fn set_z(&mut self, val: f64) {
135 self.center.set_z(val);
136 }
137}
138
139impl HasBoundingBox3D for Sphere {
140 fn bounding_box(&self) -> BoundingBox3D {
141 let p_min = Point3D {
142 x: self.center.x() - self.radius.get(),
143 y: self.center.y() - self.radius.get(),
144 z: self.center.z() - self.radius.get(),
145 };
146 let p_max = Point3D {
147 x: self.center.x() + self.radius.get(),
148 y: self.center.y() + self.radius.get(),
149 z: self.center.z() + self.radius.get(),
150 };
151 BoundingBox3D::new(&p_min, &p_max).unwrap() }
153}
154
155impl HasBoundingBox3DMaybe for Sphere {
156 fn bounding_box_maybe(&self) -> Result<BoundingBox3D> {
157 Ok(self.bounding_box())
158 }
159}
160
161impl IsScalable for Sphere {
162 fn scale(&mut self, factor: Positive) {
163 self.radius *= factor;
164 }
165}