use crate::compiled::real::Real;
use std::f32::consts::FRAC_1_SQRT_2;
#[inline(always)]
pub fn chamfer_min(a: f32, b: f32, r: f32) -> f32 {
chamfer_min_r::<f32>(a, b, r)
}
#[inline(always)]
pub fn chamfer_max(a: f32, b: f32, r: f32) -> f32 {
-chamfer_min(-a, -b, r)
}
#[inline(always)]
pub fn sdf_chamfer_union(d1: f32, d2: f32, r: f32) -> f32 {
chamfer_min(d1, d2, r)
}
#[inline(always)]
pub fn sdf_chamfer_intersection(d1: f32, d2: f32, r: f32) -> f32 {
chamfer_max(d1, d2, r)
}
#[inline(always)]
pub fn sdf_chamfer_subtraction(d1: f32, d2: f32, r: f32) -> f32 {
chamfer_max(d1, -d2, r)
}
#[inline(always)]
pub fn chamfer_min_r<R: Real>(a: R, b: R, r: f32) -> R {
a.min(b)
.min((a + b) * R::splat(FRAC_1_SQRT_2) - R::splat(r))
}
#[inline(always)]
pub fn chamfer_max_r<R: Real>(a: R, b: R, r: f32) -> R {
-chamfer_min_r(-a, -b, r)
}
#[inline(always)]
pub fn sdf_chamfer_union_r<R: Real>(d1: R, d2: R, r: f32) -> R {
chamfer_min_r(d1, d2, r)
}
#[inline(always)]
pub fn sdf_chamfer_intersection_r<R: Real>(d1: R, d2: R, r: f32) -> R {
chamfer_max_r(d1, d2, r)
}
#[inline(always)]
pub fn sdf_chamfer_subtraction_r<R: Real>(d1: R, d2: R, r: f32) -> R {
chamfer_max_r(d1, -d2, r)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_chamfer_union_basic() {
let a = 5.0;
let b = 10.0;
let r = 0.5;
let result = sdf_chamfer_union(a, b, r);
assert!(result <= a, "chamfer union should be <= min(a,b)");
}
#[test]
fn test_chamfer_union_symmetry() {
let d1 = 0.5;
let d2 = 0.8;
let r = 0.3;
assert!((sdf_chamfer_union(d1, d2, r) - sdf_chamfer_union(d2, d1, r)).abs() < 1e-6);
}
#[test]
fn test_chamfer_intersection() {
let d1 = -0.5;
let d2 = -0.3;
let r = 0.1;
let result = sdf_chamfer_intersection(d1, d2, r);
assert!(result >= d1.max(d2) - r * 2.0);
}
#[test]
fn test_chamfer_creates_bevel() {
let a = 0.1;
let b = 0.1;
let r = 0.5;
let chamfer = sdf_chamfer_union(a, b, r);
let hard_union = a.min(b);
assert!(chamfer < hard_union);
}
}