rustsim-geometry 0.0.1

2-D and 3-D geometric primitives and queries for rustsim (points, AABB, segments, rays, triangles, closest-point, raycast)
Documentation
//! 3-D spheres with overlap tests.

use crate::aabb::Aabb3;
use crate::triangle::Triangle3;
use crate::vec3::{self, Vec3};

/// 3-D sphere.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Sphere3 {
    /// Centre.
    pub center: Vec3,
    /// Radius (non-negative).
    pub radius: f64,
}

impl Sphere3 {
    /// Does this sphere overlap the AABB?
    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
    }

    /// Does this sphere overlap the triangle?
    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
    }

    /// Does this sphere overlap `other`?
    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));
    }
}