use cadrum::{Compound, Solid};
use std::fs::File;
use std::path::Path;
use crate::Result;
pub fn run(a: &Path, b: &Path, max_ratio: u32, tol: f64, union: bool) -> Result<()> {
println!("Loading STEP: {}", a.display());
let solids_a = read_step_file(a)?;
println!("Loading STEP: {}", b.display());
let solids_b = read_step_file(b)?;
let v_a = solids_a.volume();
let v_b = solids_b.volume();
println!("V_A = {:.6e}, V_B = {:.6e}", v_a, v_b);
if v_a <= 0.0 || v_b <= 0.0 {
return Err(format!("non-positive volume detected: V_A={}, V_B={}", v_a, v_b).into());
}
let (small, large) = if v_a < v_b { (v_a, v_b) } else { (v_b, v_a) };
let ratio = large / small;
let k = ratio.round();
let rel_err_ratio = ((ratio - k) / k).abs();
let within_int = (1.0..=max_ratio as f64).contains(&k) && rel_err_ratio < tol;
println!(
"ratio = {:.6} (≈ {}, rel err {:.3}%) {}",
ratio,
k as u32,
rel_err_ratio * 100.0,
if within_int { "OK" } else { "FAIL" }
);
let within_union = if union {
println!("Running boolean_union (may take several minutes on large STEPs)...");
let (union_solids, _metadata) =
Solid::boolean_union(solids_a.iter(), solids_b.iter())
.map_err(|e| format!("boolean_union failed: {:?}", e))?;
let v_union = union_solids.volume();
let rel_err_union = ((v_union - large) / large).abs();
let ok = rel_err_union < tol;
println!(
"V_union = {:.6e}, expected ≈ V_max = {:.6e} (rel err {:.3}%) {}",
v_union,
large,
rel_err_union * 100.0,
if ok { "OK" } else { "FAIL" }
);
ok
} else {
println!("Union check skipped (pass --union to enable)");
true
};
if !within_int || !within_union {
return Err(format!(
"validation failed (integer-ratio={}, union-non-growth={})",
within_int, within_union
)
.into());
}
println!("validate: PASS");
Ok(())
}
fn read_step_file(path: &Path) -> Result<Vec<Solid>> {
let mut f = File::open(path)
.map_err(|e| format!("open {}: {}", path.display(), e))?;
cadrum::read_step(&mut f)
.map_err(|e| format!("read_step {}: {:?}", path.display(), e).into())
}