diff --git a/crates/smlib/src/core/blend_tests.rs b/crates/smlib/src/core/blend_tests.rs index ddacb74050..a5e05d814b 100644 --- a/crates/smlib/src/core/blend_tests.rs +++ b/crates/smlib/src/core/blend_tests.rs @@ -515,7 +515,6 @@ fn rounds_at_a_concave_face_corner_are_mitred() { /// The back and left top edges are each trimmed 8 by those rounds: (0, 30)-(32, 30) and (0, 8)-(0, 30) /// at z = 10, and each piece keeps its edge's attribute (`Behavior::Copy`), as on the fork. #[test] -#[ignore = "solidcore#1980 (PR #1977): SubtractRemovalRegion loses the attributes of target edges it replaces"] fn an_edge_tag_crosses_a_cliff_overflow() { use solidcore::blend::fillet_executive::session::FilletSession; use solidcore::boolean::api_brep::boolean_difference; @@ -560,9 +559,9 @@ fn an_edge_tag_crosses_a_cliff_overflow() { /// Solidcore alone: the pocket rim chamfered 5.5, as `fillet_mitre_concave_face_corners`' own test /// does it, with `keep_operand_uv_trims` on too, on the body the boolean gives: /// 21000 - (50 d² + 4/3 d³) = 19265.666666667 (the fork, and the same body through the flat -/// arrays). Refused: error 3, Corner Edge Computation Failure. +/// arrays). Without `fillet_run_on_bspline_trims` it is refused: error 3, Corner Edge Computation +/// Failure (solidcore#1981). #[test] -#[ignore = "solidcore#1981 (PR #1996)"] fn pocket_chamfer_on_a_boolean_body() { use solidcore::blend::fillet_executive::session::FilletSession; use solidcore::boolean::api_brep::boolean_difference; @@ -577,6 +576,7 @@ fn pocket_chamfer_on_a_boolean_body() { k.fixes.fillet_cliff_overflow = true; k.fixes.fillet_mitre_concave_face_corners = true; k.fixes.keep_operand_uv_trims = true; + k.fixes.fillet_run_on_bspline_trims = true; let plate = create_box(&mut k, Point3::ZERO, 60.0, 40.0, 10.0).unwrap(); let cut = create_box(&mut k, p(15.0, 10.0, 5.0), 30.0, 20.0, 6.0).unwrap(); let mut b = boolean_difference(&mut k, plate, cut).unwrap(); diff --git a/crates/smlib/src/core/boolean.rs b/crates/smlib/src/core/boolean.rs index d45fa6b0fb..f5a48519fc 100644 --- a/crates/smlib/src/core/boolean.rs +++ b/crates/smlib/src/core/boolean.rs @@ -9,15 +9,14 @@ use std::sync::PoisonError; use solidcore::SolidError; -use solidcore::boolean::api_brep as sm; +use solidcore::boolean::api_brep::{self as sm, Boolean2dOutcome}; use solidcore::boolean::merge::MergeOptions; use solidcore::geom::a_object::BooleanOperation; use solidcore::geom::attribute::ObjectKey; use solidcore::geom::object::ObjectRef; use solidcore::kernel::Kernel; -use solidcore::primitive::primitive_creation::p1::{Boolean2d, PrimitiveCreation}; +use solidcore::primitive::primitive_creation::p1::Boolean2d; use solidcore::topology::brep::{p1, p2, p3}; -use solidcore::topology::topology_traverser::Marks; use solidcore::topology::{Brep, edge}; use solidcore::{EntityRef, Result as SolidResult}; @@ -140,7 +139,7 @@ fn operation(op: BooleanOp) -> BooleanOperation { /// Whether every body is a manifold solid (`IsManifoldSolid` of each copy). fn all_solid(bodies: &[Brep]) -> SolidResult { - for b in bodies { + for (n, b) in bodies.iter().enumerate() { if !p2::is_manifold_solid(b)? { return Ok(false); } @@ -210,7 +209,7 @@ pub(crate) fn boolean2d(a: &Body, b: &Body, op: BooleanOp) -> Result Result Boolean2d::Difference, BooleanOp::Intersect => Boolean2d::Intersection, }; - // SmApiBoolean2d calls the static SmPrimitiveCreation::Boolean2D; its notifications are - // the operands' arena records, as solidcore's own merge calls it without a caller's. - let mut primitive = PrimitiveCreation::new(None, 0, false); - let (mut marks_a, mut marks_b) = (Marks::default(), Marks::default()); - let mut state = p2::ArenaNotifyState::new(&ca); - state.seed(&cb); - let mut out = None; - primitive.boolean_2d(k, &mut ca, &mut cb, kind, &mut out, (&mut marks_a, &mut marks_b), &mut state.env(None))?; - match out { - Some(r) => finish(r, false, false), - None => Ok(Done::Empty), + match sm::boolean_2d(k, ca, cb, kind)? { + Boolean2dOutcome::Result(r) => finish(r, false, false), + Boolean2dOutcome::Unassigned { .. } => Ok(Done::Empty), } })?; result(d, Ok(None)) diff --git a/crates/smlib/src/core/boolean_tests.rs b/crates/smlib/src/core/boolean_tests.rs index 3c8543bbdd..f894ecd6c1 100644 --- a/crates/smlib/src/core/boolean_tests.rs +++ b/crates/smlib/src/core/boolean_tests.rs @@ -646,7 +646,6 @@ mod history { /// Two overlapping squares combined as regions of one plane. #[test] - #[ignore = "solidcore#1462 (PR #1977): boolean_2d carries no attributes through its merge"] fn a_boolean2d_has_the_cpp_history() { use crate::sweeps::Curve; let square = |x: f64, y: f64, s: f64, operand: usize| { diff --git a/crates/smlib/src/core/offset.rs b/crates/smlib/src/core/offset.rs index 51c984d7c7..640660c0fb 100644 --- a/crates/smlib/src/core/offset.rs +++ b/crates/smlib/src/core/offset.rs @@ -53,16 +53,13 @@ const INVALID_INPUT: i32 = 1007; /// `SMLIB_ERR_WALLS_TOUCH`. const OFFSET_WALLS_TOUCH: i32 = 1042; -/// `SM_ERR_OFFSET_EDGE_VANISHES` (fork 34318f4): a vertex moved past an edge's other end, which -/// `status` (smlib_shim.h) reports as `SMLIB_ERR_UNSUPPORTED`. -const OFFSET_EDGE_VANISHES: i32 = 1043; - -/// `status` (smlib_shim.h): an offset whose walls touch is [`Error::WallsTouch`]; any other -/// status as the blends pass it on. +/// `status` (smlib_shim.h): an offset whose walls touch is [`Error::WallsTouch`]; a vertex moved +/// past an edge's other end (`SM_ERR_OFFSET_EDGE_VANISHES`, fork 34318f4) is +/// `SMLIB_ERR_UNSUPPORTED`; any other status as the blends pass it on. fn status(e: SolidError) -> Error { match e { SolidError::Upstream { code: OFFSET_WALLS_TOUCH, .. } => Error::WallsTouch, - SolidError::Upstream { code: OFFSET_EDGE_VANISHES, .. } => Error::Unsupported, + e if e.is_offset_edge_vanishes() => Error::Unsupported, e => blend_status(e), } } @@ -373,6 +370,9 @@ fn move_faces(k: &mut Kernel, b: &mut Brep, picked: &[FaceId], distance: f64) -> OffsetFacesRefusal::Unsupported => Error::Unsupported, OffsetFacesRefusal::NotExact => Error::NotExact, OffsetFacesRefusal::NoEffect => Error::NoEffect, + // Not in the fork (solidcore#2020, #2027): the blends cannot be put back, the fillet's + // status kept. SolidCraft has no such error: a move solidcore does not make. + OffsetFacesRefusal::NotPutBack => Error::Unsupported, OffsetFacesRefusal::None => status(e), }) } diff --git a/crates/smlib/src/core/offset_tests.rs b/crates/smlib/src/core/offset_tests.rs index cb32803efa..6d4efea346 100644 --- a/crates/smlib/src/core/offset_tests.rs +++ b/crates/smlib/src/core/offset_tests.rs @@ -775,7 +775,6 @@ mod history { } #[test] - #[ignore = "solidcore#1973 (PR #1977): the stitch in the shell drops the flat sheet's edge tags"] fn tags_cross_a_thicken_of_a_flat_sheet() { thicken_parity(false); } @@ -837,8 +836,11 @@ fn offset_faces_close_a_step_wall() { /// Rig case shell/4492's rounded box: four mitred rounds, r 3, come off a 40 x 30 x 10 box's top /// together and follow it. From height 0 the outline is the 34 x 24 top moved out by the round's -/// w(z) = sqrt(9 - (z - axis)^2), or 3 below the axis. With the fork's values at +19, and a body -/// whose rounds go all the way down at -7. With SMLib built, the C++ kernel gives the same. +/// w(z) = sqrt(9 - (z - axis)^2), or 3 below the axis. With the fork's values at +19, and bodies +/// whose rounds go all the way down from -7 and are cut short from -7.5 (solidcore#2027). At -9 +/// solidcore refuses to put the rounds back (solidcore#2020, open): SolidCraft says it does not +/// make that move, where the C++ kernel gives the analytic value, also checked here. With SMLib +/// built, the C++ kernel gives the same at every other move. #[test] fn mitred_rounds_follow_a_moved_top() { use super::blend::{Corners, blend}; @@ -856,13 +858,23 @@ fn mitred_rounds_follow_a_moved_top() { }) .sum::() }; - let moves = [(19.0, [10, 20, 12]), (1.0, [10, 20, 12]), (-1.0, [10, 20, 12]), (-6.9, [10, 20, 12]), (-7.0, [6, 12, 8])]; + let moves = [ + (19.0, [10, 20, 12]), + (1.0, [10, 20, 12]), + (-1.0, [10, 20, 12]), + (-6.9, [10, 20, 12]), + (-7.0, [6, 12, 8]), + (-7.5, [6, 12, 8]), + (-8.0, [6, 12, 8]), + (-9.5, [6, 12, 8]), + ]; for (d, n) in moves { let moved = offset_faces(&rounded, &[top], 0.1, d).unwrap(); let v = volume(&moved, 1e-8).unwrap(); assert_eq!(counts(&moved).unwrap(), n, "d {d}"); assert!(rel(v, analytic(d)) < 1e-6, "d {d}: {v} vs {}", analytic(d)); } + assert!(matches!(offset_faces(&rounded, &[top], 0.1, -9.0), Err(Error::Unsupported))); #[cfg(feature = "native")] { use crate::ffi; @@ -872,7 +884,13 @@ fn mitred_rounds_follow_a_moved_top() { for (d, _) in moves { let cpp = ffi::ops::pick_op(ffi::ops::Pick::OffsetFaces, &round, &[top], 0.1, d).unwrap(); let ours = offset_faces(&rounded, &[top], 0.1, d).unwrap(); - assert!(rel(volume(&ours, 1e-8).unwrap(), ffi::volume(&cpp, 1e-8).unwrap()) < 1e-9, "d {d}"); + let (o, c) = (volume(&ours, 1e-8).unwrap(), ffi::volume(&cpp, 1e-8).unwrap()); + // Below -7 the rounds are cut short, and the two differ in the seventh digit: each is + // within 1e-6 of the analytic value, and of the other. + let agree = if d < -7.0 { 1e-6 } else { 1e-9 }; + assert!(rel(o, c) < agree, "d {d}: {o} vs the C++ kernel's {c}"); } + let cpp = ffi::ops::pick_op(ffi::ops::Pick::OffsetFaces, &round, &[top], 0.1, -9.0).unwrap(); + assert!(rel(ffi::volume(&cpp, 1e-8).unwrap(), analytic(-9.0)) < 1e-6, "d -9"); } }