//! Is a body one valid solid? The kernel regression rig (`tests/kernel-cases`) asks this of every //! result: the schema 4 record's structure and geometry (`Brep::validate`, `check_geometry`), //! and SMLib's own check of the same record. use crate::{Body, brep_record}; /// What the validity checks found for one body. `Err` holds why a check failed. #[derive(Clone, Debug)] pub struct Validity { /// The record: structure, then geometry against topology within tolerances. pub record: Result<(), String>, /// SMLib's `check(All)` of the record. pub smlib: Option, } /// SMLib's verdict on a body. #[derive(Clone, Debug)] pub enum SmlibCheck { Valid, Invalid(String), /// The record can't be built in SMLib yet (a geometry kind the conversion doesn't take): no /// verdict, and no fault of the body's. NotSupported(String), } impl Validity { pub fn ok(&self) -> bool { self.record.is_ok() && !matches!(self.smlib, Some(SmlibCheck::Invalid(_))) } } /// Runs every validity check this build has on `body`. pub fn validity(body: &Body) -> Validity { let record = brep_record(body).map_err(|e| e.to_string()); let checked = record.as_ref().map_err(Clone::clone).and_then(|r| { solidcraft_geom::brep::check::validate_built(r).map_err(|e| format!("structure: {e}"))?; solidcraft_geom::brep::geometry::check(r).map_err(|e| format!("geometry: {e}")) }); Validity { record: checked, smlib: smlib_validity(body) } } fn smlib_validity(body: &Body) -> Option { let b = match crate::smlib_body(body) { Ok(b) => b, Err(e) => { let e = e.to_string(); return Some(if e.contains("not supported yet") { SmlibCheck::NotSupported(e) } else { SmlibCheck::Invalid(e) }); } }; Some(match b.check(solidcraft_smlib::CheckLevel::All) { Ok(r) if r.is_valid() => SmlibCheck::Valid, Ok(r) => SmlibCheck::Invalid(format!("SMLib check: {r}")), Err(e) => SmlibCheck::Invalid(format!("SMLib check: {e}")), }) } /// Where every kernel call that fails from now on leaves its inputs for replay /// (`solidcraft_smlib::set_dump_dir`: the call and its B-reps, which `Brep::read` reads back); /// `None` stops it. pub fn smlib_dump_dir(dir: Option<&std::path::Path>) { solidcraft_smlib::set_dump_dir(dir); }