Skip to main content

rustsim_geometry/
sphere.rs

1//! 3-D spheres with overlap tests.
2
3use crate::aabb::Aabb3;
4use crate::triangle::Triangle3;
5use crate::vec3::{self, Vec3};
6
7/// 3-D sphere.
8#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct Sphere3 {
10    /// Centre.
11    pub center: Vec3,
12    /// Radius (non-negative).
13    pub radius: f64,
14}
15
16impl Sphere3 {
17    /// Does this sphere overlap the AABB?
18    pub fn intersects_aabb(&self, aabb: &Aabb3) -> bool {
19        let cx = self.center[0].clamp(aabb.min[0], aabb.max[0]);
20        let cy = self.center[1].clamp(aabb.min[1], aabb.max[1]);
21        let cz = self.center[2].clamp(aabb.min[2], aabb.max[2]);
22        let d = vec3::sub(self.center, [cx, cy, cz]);
23        vec3::norm_squared(d) <= self.radius * self.radius
24    }
25
26    /// Does this sphere overlap the triangle?
27    pub fn intersects_triangle(&self, tri: &Triangle3) -> bool {
28        let q = tri.closest_point(self.center);
29        vec3::norm_squared(vec3::sub(self.center, q)) <= self.radius * self.radius
30    }
31
32    /// Does this sphere overlap `other`?
33    pub fn intersects(&self, other: &Sphere3) -> bool {
34        let d2 = vec3::norm_squared(vec3::sub(self.center, other.center));
35        let r = self.radius + other.radius;
36        d2 <= r * r
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn sphere_vs_aabb_overlap() {
46        let s = Sphere3 {
47            center: [0.0, 0.0, 0.0],
48            radius: 1.5,
49        };
50        let a = Aabb3::from_points([1.0, -1.0, -1.0], [3.0, 1.0, 1.0]);
51        assert!(s.intersects_aabb(&a));
52        let b = Aabb3::from_points([5.0, 5.0, 5.0], [10.0, 10.0, 10.0]);
53        assert!(!s.intersects_aabb(&b));
54    }
55
56    #[test]
57    fn sphere_vs_sphere() {
58        let a = Sphere3 {
59            center: [0.0, 0.0, 0.0],
60            radius: 1.0,
61        };
62        let b = Sphere3 {
63            center: [1.5, 0.0, 0.0],
64            radius: 1.0,
65        };
66        let c = Sphere3 {
67            center: [3.0, 0.0, 0.0],
68            radius: 0.5,
69        };
70        assert!(a.intersects(&b));
71        assert!(!a.intersects(&c));
72    }
73
74    #[test]
75    fn sphere_vs_triangle() {
76        let t = Triangle3 {
77            a: [0.0, 0.0, 0.0],
78            b: [1.0, 0.0, 0.0],
79            c: [0.0, 1.0, 0.0],
80        };
81        let s = Sphere3 {
82            center: [0.25, 0.25, 0.1],
83            radius: 0.5,
84        };
85        assert!(s.intersects_triangle(&t));
86        let s2 = Sphere3 {
87            center: [0.25, 0.25, 10.0],
88            radius: 0.5,
89        };
90        assert!(!s2.intersects_triangle(&t));
91    }
92}