vox_geometry_rust/
sphere3.rs1use crate::surface3::*;
10use crate::vector3::Vector3D;
11use crate::transform3::Transform3;
12use crate::bounding_box3::BoundingBox3D;
13use crate::ray3::Ray3D;
14use std::sync::{RwLock, Arc};
15
16pub struct Sphere3 {
23 pub center: Vector3D,
25
26 pub radius: f64,
28
29 pub surface_data: Surface3Data,
31}
32
33impl Sphere3 {
34 pub fn new_default(transform: Option<Transform3>,
36 is_normal_flipped: Option<bool>) -> Sphere3 {
37 return Sphere3 {
38 center: Vector3D::new_default(),
39 radius: 0.0,
40 surface_data: Surface3Data::new(transform, is_normal_flipped),
41 };
42 }
43
44 pub fn new(center: Vector3D,
46 radius: f64,
47 transform: Option<Transform3>,
48 is_normal_flipped: Option<bool>) -> Sphere3 {
49 return Sphere3 {
50 center,
51 radius,
52 surface_data: Surface3Data::new(transform, is_normal_flipped),
53 };
54 }
55
56 pub fn builder() -> Builder {
58 return Builder::new();
59 }
60}
61
62impl Surface3 for Sphere3 {
63 fn closest_point_local(&self, other_point: &Vector3D) -> Vector3D {
64 return self.closest_normal_local(other_point) * self.radius + self.center;
65 }
66
67 fn bounding_box_local(&self) -> BoundingBox3D {
68 let r = Vector3D::new(self.radius, self.radius, self.radius);
69 return BoundingBox3D::new(self.center - r, self.center + r);
70 }
71
72 fn closest_intersection_local(&self, ray: &Ray3D) -> SurfaceRayIntersection3 {
73 let mut intersection = SurfaceRayIntersection3::new();
74 let r = ray.origin - self.center;
75 let b = ray.direction.dot(&r);
76 let c = r.length_squared() - crate::math_utils::square(self.radius);
77 let mut d = b * b - c;
78
79 if d > 0.0 {
80 d = f64::sqrt(d);
81 let mut t_min = -b - d;
82 let t_max = -b + d;
83
84 if t_min < 0.0 {
85 t_min = t_max;
86 }
87
88 if t_min < 0.0 {
89 intersection.is_intersecting = false;
90 } else {
91 intersection.is_intersecting = true;
92 intersection.distance = t_min;
93 intersection.point = ray.origin + ray.direction * t_min;
94 intersection.normal = (intersection.point - self.center).normalized();
95 }
96 } else {
97 intersection.is_intersecting = false;
98 }
99
100 return intersection;
101 }
102
103 fn closest_normal_local(&self, other_point: &Vector3D) -> Vector3D {
104 return if self.center.is_similar(&other_point, None) {
105 Vector3D::new(1.0, 0.0, 0.0)
106 } else {
107 (*other_point - self.center).normalized()
108 };
109 }
110
111 fn intersects_local(&self, ray_local: &Ray3D) -> bool {
112 let r = ray_local.origin - self.center;
113 let b = ray_local.direction.dot(&r);
114 let c = r.length_squared() - crate::math_utils::square(self.radius);
115 let mut d = b * b - c;
116
117 if d > 0.0 {
118 d = f64::sqrt(d);
119 let mut t_min = -b - d;
120 let t_max = -b + d;
121
122 if t_min < 0.0 {
123 t_min = t_max;
124 }
125
126 if t_min >= 0.0 {
127 return true;
128 }
129 }
130
131 return false;
132 }
133
134 fn closest_distance_local(&self, other_point_local: &Vector3D) -> f64 {
135 return f64::abs(self.center.distance_to(*other_point_local) - self.radius);
136 }
137
138 fn view(&self) -> &Surface3Data {
139 return &self.surface_data;
140 }
141}
142
143pub type Sphere3Ptr = Arc<RwLock<Sphere3>>;
145
146pub struct Builder {
151 _center: Vector3D,
152 _radius: f64,
153
154 _surface_data: Surface3Data,
155}
156
157impl Builder {
158 pub fn with_center(&mut self, center: Vector3D) -> &mut Self {
160 self._center = center;
161 return self;
162 }
163
164 pub fn with_radius(&mut self, radius: f64) -> &mut Self {
166 self._radius = radius;
167 return self;
168 }
169
170 pub fn build(&mut self) -> Sphere3 {
172 return Sphere3::new(self._center,
173 self._radius,
174 Some(self._surface_data.transform.clone()),
175 Some(self._surface_data.is_normal_flipped),
176 );
177 }
178
179 pub fn make_shared(&mut self) -> Sphere3Ptr {
181 return Sphere3Ptr::new(RwLock::new(self.build()));
182 }
183
184 pub fn new() -> Builder {
186 return Builder {
187 _center: Vector3D::new_default(),
188 _radius: 0.0,
189 _surface_data: Surface3Data::new(None, None),
190 };
191 }
192}
193
194impl SurfaceBuilderBase3 for Builder {
195 fn view(&mut self) -> &mut Surface3Data {
196 return &mut self._surface_data;
197 }
198}