diff --git a/crates/smlib/src/core/blend_tests.rs b/crates/smlib/src/core/blend_tests.rs index d36d10ad29..1fb76a80c2 100644 --- a/crates/smlib/src/core/blend_tests.rs +++ b/crates/smlib/src/core/blend_tests.rs @@ -510,19 +510,54 @@ fn the_first_distance_goes_on_the_face_along_first() { /// the two results' histories must be the same. #[cfg(feature = "native")] mod history { + use solidcraft_geom::brep::history::Change; + + use crate::history::Raw; use crate::{Blend, Brep, ffi}; + /// A 20 x 30 x 10 box, tagged as operand 0, with `kind` of `size` on its top front edge + /// (y = 0, z = 10), on both kernels: solidcore's history, then the C++ kernel's. + fn one_edge(kind: Blend, size: f64) -> (Raw, Raw) { + crate::init().unwrap(); + let a = Brep::made(ffi::make_box(&[0.0; 3], &[20.0, 30.0, 10.0]).unwrap()).tagged(0).unwrap(); + let edge = [[10.0, 0.0, 10.0]]; + let code = match kind { + Blend::Round => ffi::ops::BLEND_ROUND, + Blend::Curvature => ffi::ops::BLEND_CURVATURE, + Blend::Chord => ffi::ops::BLEND_CHORD, + Blend::Chamfer => ffi::ops::BLEND_CHAMFER, + }; + let cpp = ffi::ops::blend(code, a.cpp().unwrap(), &edge, &[size], super::TOL).unwrap(); + let cpp = Brep::made(cpp).history().unwrap(); + let core = super::blend(a.core().unwrap(), kind, &edge, &[size], super::TOL, &[], &[], super::Corners::Filled).unwrap(); + (Brep::made_core(core).history().unwrap(), cpp) + } + + /// The changes of `h`'s faces, sorted: one blend of one box edge leaves the bottom and back + /// as they were, trims the top, front and both sides, and makes the blend face. + fn changes(h: &Raw) -> Vec { + let mut c: Vec = h.faces.iter().map(|f| f.change).collect(); + c.sort_by_key(|c| *c as u8); + c + } + + fn check(kind: Blend, size: f64) { + let (core, cpp) = one_edge(kind, size); + let want = [Change::Kept, Change::Kept, Change::Modified, Change::Modified, Change::Modified, Change::Modified, Change::Generated]; + assert_eq!(changes(&cpp), want, "C++ {kind:?}: {cpp:?}"); + assert_eq!(core.canonical(), cpp.canonical(), "{kind:?}"); + } + /// A 2 mm round on the top front edge of a box: the top and front are trimmed, the round is /// new. #[test] - #[ignore = "solidcore#1594: the fillet does not carry the body's attributes onto the faces it rebuilds (the top, front and sides come out Generated)"] fn tags_cross_a_fillet() { - crate::init().unwrap(); - let a = Brep::made(ffi::make_box(&[0.0; 3], &[20.0, 30.0, 10.0]).unwrap()).tagged(0).unwrap(); - let edge = [[10.0, 0.0, 10.0]]; - let cpp = ffi::ops::blend(ffi::ops::BLEND_ROUND, a.cpp().unwrap(), &edge, &[2.0], super::TOL).unwrap(); - let cpp = Brep::made(cpp).history().unwrap(); - let core = super::blend(a.core().unwrap(), Blend::Round, &edge, &[2.0], super::TOL, &[], &[], super::Corners::Filled).unwrap(); - assert_eq!(Brep::made_core(core).history().unwrap().canonical(), cpp.canonical()); + check(Blend::Round, 2.0); + } + + /// A 2 mm chamfer on the same edge: the same faces kept, trimmed and made as the round. + #[test] + fn tags_cross_a_chamfer() { + check(Blend::Chamfer, 2.0); } } diff --git a/crates/smlib/src/history.rs b/crates/smlib/src/history.rs index dafd1cf17a..b5b682e63a 100644 --- a/crates/smlib/src/history.rs +++ b/crates/smlib/src/history.rs @@ -87,9 +87,6 @@ impl Brep { /// that made the body: the tags never cross between them. pub fn history(&self) -> Result { if self.maker == route::Backend::Solidcore { - if let Some(what) = self.untracked { - return Err(Error::Solidcore(format!("smlib_history_read: not supported yet: {what}"))); - } return core::history::read(self.core()?); } let v = ffi::history::read(self.cpp()?).map_err(error)?; diff --git a/crates/smlib/src/lib.rs b/crates/smlib/src/lib.rs index 982915f524..46409751e8 100644 --- a/crates/smlib/src/lib.rs +++ b/crates/smlib/src/lib.rs @@ -236,9 +236,6 @@ pub struct Brep { /// `Some(k)` for [`Brep::tagged`]`(k)`: its faces and edges stand for their own positions in /// operand `k`, so the body converted for the other kernel is tagged the same way there. operand: Option, - /// Why [`Brep::history`] cannot be read, for a body made by a solidcore operation that does - /// not carry the attributes yet. - untracked: Option<&'static str>, } impl std::fmt::Debug for Brep { @@ -250,18 +247,12 @@ impl std::fmt::Debug for Brep { impl Brep { /// A body the C++ kernel made. fn made(h: ffi::Handle) -> Brep { - Brep { cpp: OnceLock::from(Ok(h)), core: OnceLock::new(), maker: route::Backend::Smlib, operand: None, untracked: None } + Brep { cpp: OnceLock::from(Ok(h)), core: OnceLock::new(), maker: route::Backend::Smlib, operand: None } } /// A body solidcore made. fn made_core(b: core::Body) -> Brep { - Brep { cpp: OnceLock::new(), core: OnceLock::from(Ok(b)), maker: route::Backend::Solidcore, operand: None, untracked: None } - } - - /// A body a solidcore blend made: solidcore's fillets do not carry the body's attributes onto - /// the faces they rebuild yet (solidcore#1594), so its history is not read. - fn made_core_blend(b: core::Body) -> Brep { - Brep { untracked: Some("the history of a blend on solidcore (solidcore#1594)"), ..Brep::made_core(b) } + Brep { cpp: OnceLock::new(), core: OnceLock::from(Ok(b)), maker: route::Backend::Solidcore, operand: None } } /// The C++ kernel's body: converted from solidcore's the first time it is asked for (and diff --git a/crates/smlib/src/ops.rs b/crates/smlib/src/ops.rs index c025280ecb..ef0cc37b9b 100644 --- a/crates/smlib/src/ops.rs +++ b/crates/smlib/src/ops.rs @@ -280,7 +280,7 @@ impl Brep { } if route::Op::Blend.backend() == route::Backend::Solidcore { return core::blend::blend_holes(self.core()?, kind, edges, sizes, tolerance, corners, setbacks, core::blend::Corners::Open) - .map(|(b, holes)| (Brep::made_core_blend(b), holes)); + .map(|(b, holes)| (Brep::made_core(b), holes)); } init()?; let kind = match kind { @@ -301,7 +301,7 @@ impl Brep { /// (the edge curve's parameter scaled to 0..1). pub fn fillet_variable(&self, edge: [f64; 3], tolerance: f64, start: [f64; 3], degree: usize, knots: &[f64], radii: &[f64]) -> Result { if route::Op::Blend.backend() == route::Backend::Solidcore { - return core::blend::fillet_variable(self.core()?, edge, tolerance, start, degree, knots, radii).map(Brep::made_core_blend); + return core::blend::fillet_variable(self.core()?, edge, tolerance, start, degree, knots, radii).map(Brep::made_core); } init()?; let degree = i32::try_from(degree).map_err(|_| Error::Argument)?; @@ -321,7 +321,7 @@ impl Brep { return Err(Error::Argument); } if route::Op::Blend.backend() == route::Backend::Solidcore { - return core::blend::chamfer_sides(self.core()?, edges, tolerance, distance, second, first).map(Brep::made_core_blend); + return core::blend::chamfer_sides(self.core()?, edges, tolerance, distance, second, first).map(Brep::made_core); } init()?; let (value, angle) = match second { @@ -417,7 +417,7 @@ impl Brep { if edges.len() > MAX_POINTS || edges.is_empty() { return Err(Error::Argument); } - core::blend::blend(self.core()?, kind, edges, sizes, tolerance, corners, setbacks, open).map(Brep::made_core_blend) + core::blend::blend(self.core()?, kind, edges, sizes, tolerance, corners, setbacks, open).map(Brep::made_core) } fn pick_op(&self, kind: ffi::ops::Pick, points: &[[f64; 3]], tolerance: f64, size: f64, allow_none: bool) -> Result {