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}