vox_geometry_rust/surface_set2.rs
1/*
2 * // Copyright (c) 2021 Feng Yang
3 * //
4 * // I am making my contributions/submissions to this project solely in my
5 * // personal capacity and am not conveying any rights to any intellectual
6 * // property of any third parties.
7 */
8
9use crate::surface2::*;
10use crate::bvh2::Bvh2;
11use crate::transform2::Transform2;
12use crate::vector2::Vector2D;
13use crate::bounding_box2::BoundingBox2D;
14use crate::ray2::Ray2D;
15use crate::nearest_neighbor_query_engine2::NearestNeighborQueryEngine2;
16use crate::intersection_query_engine2::IntersectionQueryEngine2;
17use std::sync::{RwLock, Arc};
18
19///
20/// # 2-D surface set.
21///
22/// This class represents 2-D surface set which extends Surface2 by overriding
23/// surface-related queries. This is class can hold a collection of other
24/// surface instances.
25///
26pub struct SurfaceSet2 {
27 _surfaces: Vec<Surface2Ptr>,
28 _unbounded_surfaces: Vec<Surface2Ptr>,
29 _bvh: RwLock<Bvh2<Surface2Ptr>>,
30 _bvh_invalidated: RwLock<bool>,
31
32 /// data from surface2
33 pub surface_data: Surface2Data,
34}
35
36impl SurfaceSet2 {
37 /// Constructs an empty surface set.
38 /// ```
39 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
40 /// let sset1 = SurfaceSet2::new_default();
41 /// assert_eq!(0, sset1.number_of_surfaces());
42 /// ```
43 pub fn new_default() -> SurfaceSet2 {
44 return SurfaceSet2 {
45 _surfaces: vec![],
46 _unbounded_surfaces: vec![],
47 _bvh: RwLock::new(Bvh2::new()),
48 _bvh_invalidated: RwLock::new(true),
49 surface_data: Surface2Data::new(None, None),
50 };
51 }
52
53 /// Constructs with a list of other surfaces.
54 /// ```
55 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
56 /// use vox_geometry_rust::sphere2::*;
57 /// use vox_geometry_rust::vector2::Vector2D;
58 /// use vox_geometry_rust::transform2::Transform2;;
59 /// let sph1 = Sphere2::builder().with_radius(1.0).with_center(Vector2D::new_default()).make_shared();
60 /// let sph2 = Sphere2::builder().with_radius(0.5).with_center(Vector2D::new(0.0, 3.0)).make_shared();
61 /// let sph3 = Sphere2::builder().with_radius(0.25).with_center(Vector2D::new(-2.0, 0.0)).make_shared();
62 /// let sset2 = SurfaceSet2::new(vec![sph1, sph2, sph3], Some(Transform2::new_default()), Some(false));
63 ///
64 /// assert_eq!(3, sset2.number_of_surfaces());
65 /// assert_eq!(Vector2D::new_default(), sset2.transform.translation());
66 /// assert_eq!(0.0, sset2.transform.orientation());
67 /// ```
68 pub fn new(others: Vec<Surface2Ptr>,
69 transform: Option<Transform2>,
70 is_normal_flipped: Option<bool>) -> SurfaceSet2 {
71 let mut unbounded_surfaces: Vec<Surface2Ptr> = vec![];
72 for surface in &others {
73 if !surface.read().unwrap().is_bounded() {
74 unbounded_surfaces.push(surface.clone());
75 }
76 }
77
78 return SurfaceSet2 {
79 _surfaces: others.clone(),
80 _unbounded_surfaces: unbounded_surfaces,
81 _bvh: RwLock::new(Bvh2::new()),
82 _bvh_invalidated: RwLock::new(true),
83 surface_data: Surface2Data::new(transform, is_normal_flipped),
84 };
85 }
86
87 /// Returns builder fox SurfaceSet2.
88 pub fn builder() -> Builder {
89 return Builder::new();
90 }
91
92 /// Returns the number of surfaces.
93 pub fn number_of_surfaces(&self) -> usize {
94 return self._surfaces.len();
95 }
96
97 /// Returns the i-th surface.
98 pub fn surface_at(&self, i: usize) -> Surface2Ptr {
99 return self._surfaces[i].clone();
100 }
101
102 /// Adds a surface instance.
103 /// ```
104 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
105 /// use vox_geometry_rust::sphere2::*;
106 /// use vox_geometry_rust::vector2::Vector2D;
107 /// let mut sset1 = SurfaceSet2::new_default();
108 /// assert_eq!(0, sset1.number_of_surfaces());
109 ///
110 /// let sph1 = Sphere2::builder().with_radius(1.0).with_center(Vector2D::new_default()).make_shared();
111 /// let sph2 = Sphere2::builder().with_radius(0.5).with_center(Vector2D::new(0.0, 3.0)).make_shared();
112 /// let sph3 = Sphere2::builder().with_radius(0.25).with_center(Vector2D::new(-2.0, 0.0)).make_shared();
113 ///
114 /// sset1.add_surface(sph1);
115 /// sset1.add_surface(sph2);
116 /// sset1.add_surface(sph3);
117 ///
118 /// assert_eq!(3, sset1.number_of_surfaces());
119 /// ```
120 pub fn add_surface(&mut self, surface: Surface2Ptr) {
121 self._surfaces.push(surface.clone());
122 if !surface.read().unwrap().is_bounded() {
123 self._unbounded_surfaces.push(surface.clone());
124 }
125 self.invalidate_bvh();
126 }
127
128 /// must call it manually in Rust!
129 pub fn build_bvh(&self) {
130 if *self._bvh_invalidated.read().unwrap() {
131 let mut surfs: Vec<Surface2Ptr> = Vec::new();
132 let mut bounds: Vec<BoundingBox2D> = Vec::new();
133 for i in 0..self._surfaces.len() {
134 if self._surfaces[i].read().unwrap().is_bounded() {
135 surfs.push(self._surfaces[i].clone());
136 bounds.push(self._surfaces[i].read().unwrap().bounding_box());
137 }
138 }
139 self._bvh.write().unwrap().build(&surfs, &bounds);
140 *(self._bvh_invalidated.write().unwrap()) = false;
141 }
142 }
143
144 fn invalidate_bvh(&self) {
145 *(self._bvh_invalidated.write().unwrap()) = true;
146 }
147}
148
149impl Surface2 for SurfaceSet2 {
150 /// ```
151 /// use vox_geometry_rust::surface2::*;
152 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
153 /// use vox_geometry_rust::sphere2::*;
154 /// use vox_geometry_rust::vector2::Vector2D;
155 /// use vox_geometry_rust::unit_tests_utils::*;
156 /// let mut sset1 = SurfaceSet2::new_default();
157 /// // Test empty set
158 /// let empty_point = sset1.closest_point(&Vector2D::new(1.0, 2.0));
159 /// assert_eq!(f64::MAX, empty_point.x);
160 /// assert_eq!(f64::MAX, empty_point.y);
161 ///
162 /// let num_samples = get_number_of_sample_points2();
163 ///
164 /// // Use first half of the samples as the centers of the spheres
165 /// for i in 0..num_samples/2 {
166 /// let sph = Sphere2::builder()
167 /// .with_radius(0.01)
168 /// .with_center(Vector2D::new_lst(get_sample_points2()[i]))
169 /// .make_shared();
170 /// sset1.add_surface(sph);
171 /// }
172 ///
173 /// let brute_force_search = |pt:&Vector2D| {
174 /// let mut min_dist2 = f64::MAX;
175 /// let mut result = Vector2D::new_default();
176 /// for i in 0..num_samples/2 {
177 /// let local_result = sset1.surface_at(i).read().unwrap().closest_point(pt);
178 /// let local_dist2 = pt.distance_squared_to(local_result);
179 /// if local_dist2 < min_dist2 {
180 /// min_dist2 = local_dist2;
181 /// result = local_result;
182 /// }
183 /// }
184 /// return result;
185 /// };
186 ///
187 /// // Use second half of the samples as the query points
188 /// for i in num_samples/2..num_samples {
189 /// let actual = sset1.closest_point(&Vector2D::new_lst(get_sample_points2()[i]));
190 /// let expected = brute_force_search(&Vector2D::new_lst(get_sample_points2()[i]));
191 /// assert_eq!(expected, actual);
192 /// }
193 ///
194 /// // Now with translation instead of center
195 /// let mut sset2 = SurfaceSet2::new_default();
196 /// for i in 0..num_samples/2 {
197 /// let sph = Sphere2::builder()
198 /// .with_radius(0.01)
199 /// .with_center(Vector2D::new_default())
200 /// .with_translation(Vector2D::new_lst(get_sample_points2()[i]))
201 /// .make_shared();
202 /// sset2.add_surface(sph);
203 /// }
204 ///
205 /// for i in num_samples/2..num_samples {
206 /// let actual = sset2.closest_point(&Vector2D::new_lst(get_sample_points2()[i]));
207 /// let expected = brute_force_search(&Vector2D::new_lst(get_sample_points2()[i]));
208 /// assert_eq!(expected, actual);
209 /// }
210 /// ```
211 fn closest_point_local(&self, other_point: &Vector2D) -> Vector2D {
212 self.build_bvh();
213
214 let mut distance_func = |surface: &Surface2Ptr, pt: &Vector2D| {
215 return surface.read().unwrap().closest_distance(pt);
216 };
217
218 let mut result = Vector2D::new(f64::MAX, f64::MAX);
219 let query_result = self._bvh.read().unwrap().nearest(other_point, &mut distance_func);
220 match query_result.item {
221 None => {}
222 Some(ptr) => {
223 result = ptr.read().unwrap().closest_point(other_point);
224 }
225 }
226
227 let mut min_dist = query_result.distance;
228 for surface in &self._unbounded_surfaces {
229 let pt = surface.read().unwrap().closest_point(other_point);
230 let dist = pt.distance_to(*other_point);
231 if dist < min_dist {
232 min_dist = dist;
233 result = surface.read().unwrap().closest_point(other_point);
234 }
235 }
236
237 return result;
238 }
239
240 /// ```
241 /// use vox_geometry_rust::surface2::*;
242 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
243 /// use vox_geometry_rust::sphere2::*;
244 /// use vox_geometry_rust::vector2::{Vector2D, Vector2};
245 /// use vox_geometry_rust::bounding_box2::BoundingBox2D;
246 /// use vox_geometry_rust::unit_tests_utils::*;
247 /// let mut sset1 = SurfaceSet2::new_default();
248 ///
249 /// let num_samples = get_number_of_sample_points2();
250 ///
251 /// // Use first half of the samples as the centers of the spheres
252 /// let mut answer = BoundingBox2D::new_default();
253 /// for i in 0..num_samples/2 {
254 /// let sph = Sphere2::builder()
255 /// .with_radius(0.01)
256 /// .with_center(Vector2D::new_lst(get_sample_points2()[i]))
257 /// .make_shared();
258 /// sset1.add_surface(sph.clone());
259 ///
260 /// answer.merge_box(&sph.read().unwrap().bounding_box());
261 /// }
262 /// assert_eq!(answer.lower_corner.is_similar(&sset1.bounding_box().lower_corner, Some(1e-9)), true);
263 /// assert_eq!(answer.upper_corner.is_similar(&sset1.bounding_box().upper_corner, Some(1e-9)), true);
264 ///
265 /// // Now with translation instead of center
266 /// let mut sset2 = SurfaceSet2::new_default();
267 /// let mut debug = BoundingBox2D::new_default();
268 /// for i in 0..num_samples/2 {
269 /// let sph = Sphere2::builder()
270 /// .with_radius(0.01)
271 /// .with_center(Vector2D::new_default())
272 /// .with_translation(Vector2D::new_lst(get_sample_points2()[i]))
273 /// .make_shared();
274 /// sset2.add_surface(sph.clone());
275 ///
276 /// debug.merge_box(&sph.read().unwrap().bounding_box());
277 /// }
278 /// assert_eq!(answer.lower_corner.is_similar(&debug.lower_corner, Some(1e-9)), true);
279 /// assert_eq!(answer.upper_corner.is_similar(&debug.upper_corner, Some(1e-9)), true);
280 ///
281 /// assert_eq!(answer.lower_corner.is_similar(&sset2.bounding_box().lower_corner, Some(1e-9)), true);
282 /// assert_eq!(answer.upper_corner.is_similar(&sset2.bounding_box().upper_corner, Some(1e-9)), true);
283 /// ```
284 fn bounding_box_local(&self) -> BoundingBox2D {
285 self.build_bvh();
286
287 return self._bvh.read().unwrap().bounding_box();
288 }
289
290 /// ```
291 /// use vox_geometry_rust::surface2::*;
292 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
293 /// use vox_geometry_rust::sphere2::*;
294 /// use vox_geometry_rust::vector2::{Vector2D, Vector2};
295 /// use vox_geometry_rust::ray2::Ray2D;
296 /// use vox_geometry_rust::unit_tests_utils::*;
297 /// let mut sset1 = SurfaceSet2::new_default();
298 ///
299 /// let num_samples = get_number_of_sample_points2();
300 ///
301 /// // Use first half of the samples as the centers of the spheres
302 /// for i in 0..num_samples/2 {
303 /// let sph = Sphere2::builder()
304 /// .with_radius(0.01)
305 /// .with_center(Vector2D::new_lst(get_sample_points2()[i]))
306 /// .make_shared();
307 /// sset1.add_surface(sph);
308 /// }
309 /// let brute_force_test = |ray:&Ray2D| {
310 /// let mut result = SurfaceRayIntersection2::new();
311 /// for i in 0..num_samples/2 {
312 /// let local_result = sset1.surface_at(i).read().unwrap().closest_intersection(ray);
313 /// if local_result.distance < result.distance {
314 /// result = local_result;
315 /// }
316 /// }
317 /// return result;
318 /// };
319 ///
320 /// // Use second half of the samples as the query points
321 /// for i in num_samples/2..num_samples {
322 /// let ray = Ray2D::new(Vector2D::new_lst(get_sample_points2()[i]), Vector2D::new_lst(get_sample_dirs2()[i]));
323 /// let actual = sset1.closest_intersection(&ray);
324 /// let expected = brute_force_test(&ray);
325 /// assert_eq!(expected.distance, actual.distance);
326 /// assert_eq!(expected.point, actual.point);
327 /// assert_eq!(expected.normal, actual.normal);
328 /// assert_eq!(expected.is_intersecting, actual.is_intersecting);
329 /// }
330 ///
331 /// // Now with translation instead of center
332 /// let mut sset2 = SurfaceSet2::new_default();
333 /// for i in 0..num_samples/2 {
334 /// let sph = Sphere2::builder()
335 /// .with_radius(0.01)
336 /// .with_center(Vector2D::new_default())
337 /// .with_translation(Vector2D::new_lst(get_sample_points2()[i]))
338 /// .make_shared();
339 /// sset2.add_surface(sph);
340 /// }
341 /// for i in num_samples/2..num_samples {
342 /// let ray = Ray2D::new(Vector2D::new_lst(get_sample_points2()[i]), Vector2D::new_lst(get_sample_dirs2()[i]));
343 /// let actual = sset2.closest_intersection(&ray);
344 /// let expected = brute_force_test(&ray);
345 /// assert_eq!(expected.distance, actual.distance);
346 /// assert_eq!(expected.point, actual.point);
347 /// assert_eq!(expected.normal, actual.normal);
348 /// assert_eq!(expected.is_intersecting, actual.is_intersecting);
349 /// }
350 /// ```
351 fn closest_intersection_local(&self, ray: &Ray2D) -> SurfaceRayIntersection2 {
352 self.build_bvh();
353
354 let mut test_func = |surface: &Surface2Ptr, ray: &Ray2D| {
355 let result = surface.read().unwrap().closest_intersection(ray);
356 return result.distance;
357 };
358
359 let query_result = self._bvh.read().unwrap().closest_intersection(ray, &mut test_func);
360 let mut result = SurfaceRayIntersection2::new();
361 result.distance = query_result.distance;
362 match query_result.item {
363 None => {
364 result.is_intersecting = false;
365 }
366 Some(ptr) => {
367 result.is_intersecting = true;
368 result.point = ray.point_at(query_result.distance);
369 result.normal = ptr.read().unwrap().closest_normal(&result.point);
370 }
371 }
372
373 for surface in &self._unbounded_surfaces {
374 let local_result = surface.read().unwrap().closest_intersection(ray);
375 if local_result.distance < result.distance {
376 result = local_result;
377 }
378 }
379
380 return result;
381 }
382
383 /// ```
384 /// use vox_geometry_rust::surface2::*;
385 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
386 /// use vox_geometry_rust::sphere2::*;
387 /// use vox_geometry_rust::vector2::{Vector2D, Vector2};
388 /// use vox_geometry_rust::unit_tests_utils::*;
389 /// let mut sset1 = SurfaceSet2::new_default();
390 ///
391 /// let num_samples = get_number_of_sample_points2();
392 ///
393 /// // Use first half of the samples as the centers of the spheres
394 /// for i in 0..num_samples/2 {
395 /// let sph = Sphere2::builder()
396 /// .with_radius(0.01)
397 /// .with_center(Vector2D::new_lst(get_sample_points2()[i]))
398 /// .make_shared();
399 /// sset1.add_surface(sph);
400 /// }
401 ///
402 /// let brute_force_search = |pt:&Vector2D| {
403 /// let mut min_dist2 = f64::MAX;
404 /// let mut result = Vector2D::new_default();
405 /// for i in 0..num_samples/2 {
406 /// let local_result = sset1.surface_at(i).read().unwrap().closest_normal(pt);
407 /// let closest_pt = sset1.surface_at(i).read().unwrap().closest_point(pt);
408 /// let local_dist2 = pt.distance_squared_to(closest_pt);
409 /// if local_dist2 < min_dist2 {
410 /// min_dist2 = local_dist2;
411 /// result = local_result;
412 /// }
413 /// }
414 /// return result;
415 /// };
416 ///
417 /// // Use second half of the samples as the query points
418 /// for i in num_samples/2..num_samples {
419 /// let actual = sset1.closest_normal(&Vector2D::new_lst(get_sample_points2()[i]));
420 /// let expected = brute_force_search(&Vector2D::new_lst(get_sample_points2()[i]));
421 /// assert_eq!(expected, actual);
422 /// }
423 ///
424 /// // Now with translation instead of center
425 /// let mut sset2 = SurfaceSet2::new_default();
426 /// for i in 0..num_samples/2 {
427 /// let sph = Sphere2::builder()
428 /// .with_radius(0.01)
429 /// .with_center(Vector2D::new_default())
430 /// .with_translation(Vector2D::new_lst(get_sample_points2()[i]))
431 /// .make_shared();
432 /// sset2.add_surface(sph);
433 /// }
434 ///
435 /// for i in num_samples/2..num_samples {
436 /// let actual = sset2.closest_normal(&Vector2D::new_lst(get_sample_points2()[i]));
437 /// let expected = brute_force_search(&Vector2D::new_lst(get_sample_points2()[i]));
438 /// assert_eq!(expected, actual);
439 /// }
440 /// ```
441 fn closest_normal_local(&self, other_point: &Vector2D) -> Vector2D {
442 self.build_bvh();
443
444 let mut distance_func = |surface: &Surface2Ptr, pt: &Vector2D| {
445 return surface.read().unwrap().closest_distance(pt);
446 };
447
448 let mut result = Vector2D::new(1.0, 0.0);
449 let query_result = self._bvh.read().unwrap().nearest(other_point, &mut distance_func);
450 match query_result.item {
451 None => {}
452 Some(ptr) => {
453 result = ptr.read().unwrap().closest_normal(other_point);
454 }
455 }
456
457 let mut min_dist = query_result.distance;
458 for surface in &self._unbounded_surfaces {
459 let pt = surface.read().unwrap().closest_point(other_point);
460 let dist = pt.distance_to(*other_point);
461 if dist < min_dist {
462 min_dist = dist;
463 result = surface.read().unwrap().closest_normal(other_point);
464 }
465 }
466
467 return result;
468 }
469
470 /// ```
471 /// use vox_geometry_rust::surface2::*;
472 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
473 /// use vox_geometry_rust::sphere2::*;
474 /// use vox_geometry_rust::vector2::{Vector2D, Vector2};
475 /// use vox_geometry_rust::ray2::Ray2D;
476 /// use vox_geometry_rust::unit_tests_utils::*;
477 /// let mut sset1 = SurfaceSet2::new_default();
478 ///
479 /// let num_samples = get_number_of_sample_points2();
480 ///
481 /// // Use first half of the samples as the centers of the spheres
482 /// for i in 0..num_samples/2 {
483 /// let sph = Sphere2::builder()
484 /// .with_radius(0.01)
485 /// .with_center(Vector2D::new_lst(get_sample_points2()[i]))
486 /// .make_shared();
487 /// sset1.add_surface(sph);
488 /// }
489 /// let brute_force_test = |ray:&Ray2D| {
490 /// for i in 0..num_samples/2 {
491 /// if sset1.surface_at(i).read().unwrap().intersects(ray) {
492 /// return true;
493 /// }
494 /// }
495 /// return false;
496 /// };
497 ///
498 /// // Use second half of the samples as the query points
499 /// for i in num_samples/2..num_samples {
500 /// let ray = Ray2D::new(Vector2D::new_lst(get_sample_points2()[i]), Vector2D::new_lst(get_sample_dirs2()[i]));
501 /// let actual = sset1.intersects(&ray);
502 /// let expected = brute_force_test(&ray);
503 /// assert_eq!(expected, actual);
504 /// }
505 ///
506 /// // Now with translation instead of center
507 /// let mut sset2 = SurfaceSet2::new_default();
508 /// for i in 0..num_samples/2 {
509 /// let sph = Sphere2::builder()
510 /// .with_radius(0.01)
511 /// .with_center(Vector2D::new_default())
512 /// .with_translation(Vector2D::new_lst(get_sample_points2()[i]))
513 /// .make_shared();
514 /// sset2.add_surface(sph);
515 /// }
516 /// for i in num_samples/2..num_samples {
517 /// let ray = Ray2D::new(Vector2D::new_lst(get_sample_points2()[i]), Vector2D::new_lst(get_sample_dirs2()[i]));
518 /// let actual = sset2.intersects(&ray);
519 /// let expected = brute_force_test(&ray);
520 /// assert_eq!(expected, actual);
521 /// }
522 /// ```
523 fn intersects_local(&self, ray_local: &Ray2D) -> bool {
524 self.build_bvh();
525
526 let mut test_func = |surface: &Surface2Ptr, ray: &Ray2D| {
527 return surface.read().unwrap().intersects(ray);
528 };
529
530 let mut result = self._bvh.read().unwrap().intersects_ray(ray_local, &mut test_func);
531 for surface in &self._unbounded_surfaces {
532 result |= surface.read().unwrap().intersects(ray_local);
533 }
534
535 return result;
536 }
537
538 /// ```
539 /// use vox_geometry_rust::surface2::*;
540 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
541 /// use vox_geometry_rust::sphere2::*;
542 /// use vox_geometry_rust::vector2::{Vector2D, Vector2};
543 /// use vox_geometry_rust::unit_tests_utils::*;
544 /// let mut sset1 = SurfaceSet2::new_default();
545 ///
546 /// let num_samples = get_number_of_sample_points2();
547 ///
548 /// // Use first half of the samples as the centers of the spheres
549 /// for i in 0..num_samples/2 {
550 /// let sph = Sphere2::builder()
551 /// .with_radius(0.01)
552 /// .with_center(Vector2D::new_lst(get_sample_points2()[i]))
553 /// .make_shared();
554 /// sset1.add_surface(sph);
555 /// }
556 /// let brute_force_search = |pt:&Vector2D| {
557 /// let mut min_dist = f64::MAX;
558 /// for i in 0..num_samples/2 {
559 /// let local_dist = sset1.surface_at(i).read().unwrap().closest_distance(pt);
560 /// if local_dist < min_dist {
561 /// min_dist = local_dist;
562 /// }
563 /// }
564 /// return min_dist;
565 /// };
566 ///
567 /// // Use second half of the samples as the query points
568 /// for i in num_samples/2..num_samples {
569 /// let actual = sset1.closest_distance(&Vector2D::new_lst(get_sample_points2()[i]));
570 /// let expected = brute_force_search(&Vector2D::new_lst(get_sample_points2()[i]));
571 /// assert_eq!(expected, actual);
572 /// }
573 ///
574 /// // Now with translation instead of center
575 /// let mut sset2 = SurfaceSet2::new_default();
576 /// for i in 0..num_samples/2 {
577 /// let sph = Sphere2::builder()
578 /// .with_radius(0.01)
579 /// .with_center(Vector2D::new_default())
580 /// .with_translation(Vector2D::new_lst(get_sample_points2()[i]))
581 /// .make_shared();
582 /// sset2.add_surface(sph);
583 /// }
584 /// for i in num_samples/2..num_samples {
585 /// let actual = sset2.closest_distance(&Vector2D::new_lst(get_sample_points2()[i]));
586 /// let expected = brute_force_search(&Vector2D::new_lst(get_sample_points2()[i]));
587 /// assert_eq!(expected, actual);
588 /// }
589 /// ```
590 fn closest_distance_local(&self, other_point: &Vector2D) -> f64 {
591 self.build_bvh();
592
593 let mut distance_func = |surface: &Surface2Ptr, pt: &Vector2D| {
594 return surface.read().unwrap().closest_distance(pt);
595 };
596
597 let query_result = self._bvh.read().unwrap().nearest(other_point, &mut distance_func);
598
599 let mut min_dist = query_result.distance;
600 for surface in &self._unbounded_surfaces {
601 let pt = surface.read().unwrap().closest_point(other_point);
602 let dist = pt.distance_to(*other_point);
603 if dist < min_dist {
604 min_dist = dist;
605 }
606 }
607
608 return min_dist;
609 }
610
611 /// ```
612 /// use vox_geometry_rust::surface2::*;
613 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
614 /// use vox_geometry_rust::sphere2::*;
615 /// use vox_geometry_rust::plane2::*;
616 /// use vox_geometry_rust::bounding_box2::*;
617 /// use vox_geometry_rust::transform2::*;
618 /// use vox_geometry_rust::vector2::{Vector2D, Vector2};
619 ///
620 /// let domain = BoundingBox2D::new(Vector2D::new_default(), Vector2D::new(1.0, 2.0));
621 /// let offset = Vector2D::new(1.0, 2.0);
622 ///
623 /// let plane = Plane2::builder()
624 /// .with_normal(Vector2D::new(0.0, 1.0))
625 /// .with_point(Vector2D::new(0.0, 0.25 * domain.height()))
626 /// .make_shared();
627 ///
628 /// let sphere = Sphere2::builder()
629 /// .with_center(domain.mid_point())
630 /// .with_radius(0.15 * domain.width())
631 /// .make_shared();
632 ///
633 /// let surface_set = SurfaceSet2::builder()
634 /// .with_surfaces(vec![plane, sphere])
635 /// .with_transform(Transform2::new(offset, 0.0))
636 /// .make_shared();
637 ///
638 /// assert_eq!(surface_set.read().unwrap().is_inside(&(Vector2D::new(0.5, 0.25) + offset)), true);
639 /// assert_eq!(surface_set.read().unwrap().is_inside(&(Vector2D::new(0.5, 1.0) + offset)), true);
640 /// assert_eq!(surface_set.read().unwrap().is_inside(&(Vector2D::new(0.5, 1.5) + offset)), false);
641 /// ```
642 fn is_inside_local(&self, other_point_local: &Vector2D) -> bool {
643 for surface in &self._surfaces {
644 if surface.read().unwrap().is_inside(other_point_local) {
645 return true;
646 }
647 }
648
649 return false;
650 }
651
652 /// ```
653 /// use vox_geometry_rust::surface2::*;
654 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
655 /// use vox_geometry_rust::sphere2::*;
656 /// use vox_geometry_rust::plane2::*;
657 /// use vox_geometry_rust::bounding_box2::*;
658 /// use vox_geometry_rust::transform2::*;
659 /// use vox_geometry_rust::vector2::{Vector2D, Vector2};
660 ///
661 /// let sphere =
662 /// Sphere2::builder().with_center(Vector2D::new(-1.0, 1.0)).with_radius(0.5).make_shared();
663 ///
664 /// let surface_set = SurfaceSet2::builder()
665 /// .with_surfaces(vec![sphere.clone()])
666 /// .with_transform(Transform2::new(Vector2D::new(1.0, 2.0), 0.0))
667 /// .make_shared();
668 ///
669 /// let bbox1 = surface_set.read().unwrap().bounding_box();
670 /// assert_eq!(BoundingBox2D::new(Vector2D::new(-0.5, 2.5), Vector2D::new(0.5, 3.5)).upper_corner, bbox1.upper_corner);
671 /// assert_eq!(BoundingBox2D::new(Vector2D::new(-0.5, 2.5), Vector2D::new(0.5, 3.5)).lower_corner, bbox1.lower_corner);
672 ///
673 /// surface_set.write().unwrap().transform = Transform2::new(Vector2D::new(3.0, -4.0), 0.0);
674 /// surface_set.write().unwrap().update_query_engine();
675 /// let bbox2 = surface_set.read().unwrap().bounding_box();
676 /// assert_eq!(BoundingBox2D::new(Vector2D::new(1.5, -3.5), Vector2D::new(2.5, -2.5)).upper_corner, bbox2.upper_corner);
677 /// assert_eq!(BoundingBox2D::new(Vector2D::new(1.5, -3.5), Vector2D::new(2.5, -2.5)).lower_corner, bbox2.lower_corner);
678 ///
679 /// sphere.write().unwrap().transform = Transform2::new(Vector2D::new(-6.0, 9.0), 0.0);
680 /// surface_set.write().unwrap().update_query_engine();
681 /// let bbox3 = surface_set.read().unwrap().bounding_box();
682 /// assert_eq!(BoundingBox2D::new(Vector2D::new(-4.5, 5.5), Vector2D::new(-3.5, 6.5)).upper_corner, bbox3.upper_corner);
683 /// assert_eq!(BoundingBox2D::new(Vector2D::new(-4.5, 5.5), Vector2D::new(-3.5, 6.5)).lower_corner, bbox3.lower_corner);
684 ///
685 /// // Plane is unbounded. Total bbox should ignore it.
686 /// let plane = Plane2::builder().with_normal(Vector2D::new(1.0, 0.0)).make_shared();
687 /// surface_set.write().unwrap().add_surface(plane);
688 /// surface_set.write().unwrap().update_query_engine();
689 /// let bbox4 = surface_set.read().unwrap().bounding_box();
690 /// assert_eq!(BoundingBox2D::new(Vector2D::new(-4.5, 5.5), Vector2D::new(-3.5, 6.5)).upper_corner, bbox4.upper_corner);
691 /// assert_eq!(BoundingBox2D::new(Vector2D::new(-4.5, 5.5), Vector2D::new(-3.5, 6.5)).lower_corner, bbox4.lower_corner);
692 /// ```
693 fn update_query_engine(&self) {
694 self.invalidate_bvh();
695 self.build_bvh();
696 }
697
698 /// ```
699 /// use vox_geometry_rust::surface2::*;
700 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
701 /// use vox_geometry_rust::sphere2::*;
702 /// use vox_geometry_rust::plane2::*;
703 /// use vox_geometry_rust::bounding_box2::*;
704 /// use vox_geometry_rust::vector2::{Vector2D, Vector2};
705 /// use vox_geometry_rust::unit_tests_utils::*;
706 /// let mut sset1 = SurfaceSet2::new_default();
707 ///
708 /// let domain = BoundingBox2D::new(Vector2D::new_default(), Vector2D::new(1.0, 2.0));
709 ///
710 /// let plane = Plane2::builder()
711 /// .with_normal(Vector2D::new(0.0, 1.0))
712 /// .with_point(Vector2D::new(0.0, 0.25 * domain.height()))
713 /// .make_shared();
714 ///
715 /// let sphere = Sphere2::builder()
716 /// .with_center(domain.mid_point())
717 /// .with_radius(0.15 * domain.width())
718 /// .make_shared();
719 ///
720 /// let surface_set = SurfaceSet2::builder().with_surfaces(vec![plane, sphere]).make_shared();
721 /// assert_eq!(surface_set.read().unwrap().is_bounded(), false);
722 ///
723 /// let cp = surface_set.read().unwrap().closest_point(&Vector2D::new(0.5, 0.4));
724 /// let answer = Vector2D::new(0.5, 0.5);
725 ///
726 /// assert_eq!(answer.is_similar(&cp, Some(1.0e-9)), true);
727 /// ```
728 fn is_bounded(&self) -> bool {
729 // All surfaces should be bounded.
730 for surface in &self._surfaces {
731 if !surface.read().unwrap().is_bounded() {
732 return false;
733 }
734 }
735
736 // Empty set is not bounded.
737 return !self._surfaces.is_empty();
738 }
739
740 /// ```
741 /// use vox_geometry_rust::surface2::*;
742 /// use vox_geometry_rust::surface_set2::SurfaceSet2;
743 /// use vox_geometry_rust::sphere2::*;
744 /// use vox_geometry_rust::plane2::*;
745 /// use vox_geometry_rust::bounding_box2::*;
746 /// use vox_geometry_rust::vector2::{Vector2D, Vector2};
747 /// use vox_geometry_rust::unit_tests_utils::*;
748 /// let surfaceSet = SurfaceSet2::builder().make_shared();
749 ///
750 /// assert_eq!(surfaceSet.read().unwrap().is_valid_geometry(), false);
751 ///
752 /// let domain = BoundingBox2D::new(Vector2D::new_default(), Vector2D::new(1.0, 2.0));
753 ///
754 /// let plane = Plane2::builder()
755 /// .with_normal(Vector2D::new(0.0, 1.0))
756 /// .with_point(Vector2D::new(0.0, 0.25 * domain.height()))
757 /// .make_shared();
758 ///
759 /// let sphere = Sphere2::builder()
760 /// .with_center(domain.mid_point())
761 /// .with_radius(0.15 * domain.width())
762 /// .make_shared();
763 ///
764 /// let surfaceSet2 =
765 /// SurfaceSet2::builder().with_surfaces(vec![plane, sphere]).make_shared();
766 ///
767 /// assert_eq!(surfaceSet2.read().unwrap().is_valid_geometry(), true);
768 ///
769 /// surfaceSet2.write().unwrap().add_surface(surfaceSet);
770 ///
771 /// assert_eq!(surfaceSet2.read().unwrap().is_valid_geometry(), false);
772 /// ```
773 fn is_valid_geometry(&self) -> bool {
774 // All surfaces should be valid.
775 for surface in &self._surfaces {
776 if !surface.read().unwrap().is_valid_geometry() {
777 return false;
778 }
779 }
780
781 // Empty set is not valid.
782 return !self._surfaces.is_empty();
783 }
784
785 fn view(&self) -> &Surface2Data {
786 return &self.surface_data;
787 }
788}
789
790/// Shared pointer for the SurfaceSet2 type.
791pub type SurfaceSet2Ptr = Arc<RwLock<SurfaceSet2>>;
792
793///
794/// # Front-end to create SurfaceSet2 objects step by step.
795///
796pub struct Builder {
797 _surfaces: Vec<Surface2Ptr>,
798
799 _surface_data: Surface2Data,
800}
801
802impl Builder {
803 /// Returns builder with other surfaces.
804 pub fn with_surfaces(&mut self, others: Vec<Surface2Ptr>) -> &mut Self {
805 self._surfaces = others;
806 return self;
807 }
808
809 /// Builds SurfaceSet2.
810 pub fn build(&mut self) -> SurfaceSet2 {
811 return SurfaceSet2::new(self._surfaces.clone(),
812 Some(self._surface_data.transform.clone()),
813 Some(self._surface_data.is_normal_flipped));
814 }
815
816 /// Builds shared pointer of SurfaceSet2 instance.
817 pub fn make_shared(&mut self) -> SurfaceSet2Ptr {
818 return SurfaceSet2Ptr::new(RwLock::new(self.build()));
819 }
820
821 /// constructor
822 pub fn new() -> Builder {
823 return Builder {
824 _surfaces: vec![],
825 _surface_data: Surface2Data::new(None, None),
826 };
827 }
828}
829
830impl SurfaceBuilderBase2 for Builder {
831 fn view(&mut self) -> &mut Surface2Data {
832 return &mut self._surface_data;
833 }
834}