use crate::aabb::Aabb3;
use crate::triangle::Triangle3;
use crate::vec3::{self, Vec3};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Sphere3 {
pub center: Vec3,
pub radius: f64,
}
impl Sphere3 {
pub fn intersects_aabb(&self, aabb: &Aabb3) -> bool {
let cx = self.center[0].clamp(aabb.min[0], aabb.max[0]);
let cy = self.center[1].clamp(aabb.min[1], aabb.max[1]);
let cz = self.center[2].clamp(aabb.min[2], aabb.max[2]);
let d = vec3::sub(self.center, [cx, cy, cz]);
vec3::norm_squared(d) <= self.radius * self.radius
}
pub fn intersects_triangle(&self, tri: &Triangle3) -> bool {
let q = tri.closest_point(self.center);
vec3::norm_squared(vec3::sub(self.center, q)) <= self.radius * self.radius
}
pub fn intersects(&self, other: &Sphere3) -> bool {
let d2 = vec3::norm_squared(vec3::sub(self.center, other.center));
let r = self.radius + other.radius;
d2 <= r * r
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sphere_vs_aabb_overlap() {
let s = Sphere3 {
center: [0.0, 0.0, 0.0],
radius: 1.5,
};
let a = Aabb3::from_points([1.0, -1.0, -1.0], [3.0, 1.0, 1.0]);
assert!(s.intersects_aabb(&a));
let b = Aabb3::from_points([5.0, 5.0, 5.0], [10.0, 10.0, 10.0]);
assert!(!s.intersects_aabb(&b));
}
#[test]
fn sphere_vs_sphere() {
let a = Sphere3 {
center: [0.0, 0.0, 0.0],
radius: 1.0,
};
let b = Sphere3 {
center: [1.5, 0.0, 0.0],
radius: 1.0,
};
let c = Sphere3 {
center: [3.0, 0.0, 0.0],
radius: 0.5,
};
assert!(a.intersects(&b));
assert!(!a.intersects(&c));
}
#[test]
fn sphere_vs_triangle() {
let t = Triangle3 {
a: [0.0, 0.0, 0.0],
b: [1.0, 0.0, 0.0],
c: [0.0, 1.0, 0.0],
};
let s = Sphere3 {
center: [0.25, 0.25, 0.1],
radius: 0.5,
};
assert!(s.intersects_triangle(&t));
let s2 = Sphere3 {
center: [0.25, 0.25, 10.0],
radius: 0.5,
};
assert!(!s2.intersects_triangle(&t));
}
}