use crate::compiled::real::{Real, Vec3R};
use glam::Vec3;
#[inline(always)]
pub fn sdf_capsule_r<R: Real>(p: Vec3R<R>, a: Vec3, b: Vec3, radius: f32) -> R {
let pa = p - Vec3R::splat(a);
let ba = Vec3R::<R>::splat(b - a);
let h = (pa.dot(ba) / ba.dot(ba)).clamp(R::zero(), R::one());
(pa - ba * h).length() - R::splat(radius)
}
#[inline(always)]
pub fn sdf_capsule(point: Vec3, a: Vec3, b: Vec3, radius: f32) -> f32 {
sdf_capsule_r::<f32>(point.into(), a, b, radius)
}
#[inline(always)]
pub fn sdf_capsule_vertical(point: Vec3, half_height: f32, radius: f32) -> f32 {
let p_y = point.y - super::clamp_total(point.y, -half_height, half_height);
(point.z * point.z + (point.x * point.x + (p_y * p_y))).sqrt() - radius
}
#[inline(always)]
pub fn sdf_capsule_horizontal(point: Vec3, half_length: f32, radius: f32) -> f32 {
let p_x = point.x - super::clamp_total(point.x, -half_length, half_length);
(point.z * point.z + (p_x * p_x + (point.y * point.y))).sqrt() - radius
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_capsule_at_endpoint() {
let a = Vec3::new(0.0, 0.0, 0.0);
let b = Vec3::new(0.0, 2.0, 0.0);
let radius = 0.5;
let d = sdf_capsule(a, a, b, radius);
assert!((d + radius).abs() < 0.0001);
let d = sdf_capsule(b, a, b, radius);
assert!((d + radius).abs() < 0.0001);
}
#[test]
fn test_capsule_at_middle() {
let a = Vec3::new(0.0, 0.0, 0.0);
let b = Vec3::new(0.0, 2.0, 0.0);
let radius = 0.5;
let d = sdf_capsule(Vec3::new(0.0, 1.0, 0.0), a, b, radius);
assert!((d + radius).abs() < 0.0001);
}
#[test]
fn test_capsule_surface() {
let a = Vec3::new(0.0, 0.0, 0.0);
let b = Vec3::new(0.0, 2.0, 0.0);
let radius = 0.5;
let d = sdf_capsule(Vec3::new(0.5, 1.0, 0.0), a, b, radius);
assert!(d.abs() < 0.0001);
let d = sdf_capsule(Vec3::new(0.0, 2.5, 0.0), a, b, radius);
assert!(d.abs() < 0.0001);
}
#[test]
fn test_capsule_outside() {
let a = Vec3::new(0.0, 0.0, 0.0);
let b = Vec3::new(0.0, 2.0, 0.0);
let radius = 0.5;
let d = sdf_capsule(Vec3::new(1.5, 1.0, 0.0), a, b, radius);
assert!((d - 1.0).abs() < 0.0001);
}
#[test]
fn test_capsule_vertical() {
let d = sdf_capsule_vertical(Vec3::ZERO, 1.0, 0.5);
assert!((d + 0.5).abs() < 0.0001);
let d = sdf_capsule_vertical(Vec3::new(0.5, 0.0, 0.0), 1.0, 0.5);
assert!(d.abs() < 0.0001);
}
#[test]
fn test_capsule_horizontal() {
let d = sdf_capsule_horizontal(Vec3::ZERO, 1.0, 0.5);
assert!((d + 0.5).abs() < 0.0001);
let d = sdf_capsule_horizontal(Vec3::new(1.5, 0.0, 0.0), 1.0, 0.5);
assert!(d.abs() < 0.0001);
}
}