diff --git a/crates/smlib/src/core.rs b/crates/smlib/src/core.rs index 3f35b0841f..fa1cbef530 100644 --- a/crates/smlib/src/core.rs +++ b/crates/smlib/src/core.rs @@ -254,22 +254,33 @@ pub(crate) fn fixes() -> UpstreamFixes { f } -/// Opt-in fixes left off because the C++ fork (`SMLIB_REV`) does not carry them yet, so turning -/// them on would part this backend from the C++ one. `precise_properties_trim_base_v` -/// (solidcore#1664, WR-563), `bspline_trim_keeps_rational_end_spans` (solidcore#1711, WR-575) and -/// `fillet_blend_curve_revolved_on_arc` (solidcore#1759, WR-581, an own design waiting for the -/// fork's fix) have no fork commit. `temporary_radius_setup_errors` (solidcore#644, #458), `ellipse_step_interval_checks` -/// (solidcore#686, #428) are the port's own fixes with no fork commit; the C++ build keeps -/// upstream's behaviour there. -/// `corner_patch_face_side_twist` (WR-613, fork 7fd9fb0) ports a fork commit that is not -/// published. +/// Opt-in fixes left off because the C++ fork (`SMLIB_REV`) does not behave as they do, so turning +/// them on would part this backend from the C++ one. Each was read in the fork's source at 2fc375f. /// -/// `boolean_union_refuses_solid_leak` (solidcore#1794, WR-619) is solidcore's own design; -/// `curve_loop_start_after_previous_end` (WR-96), `loop_use_reports_open_gaps` (WR-93), -/// `face_points_span_domain` (WR-86), -/// `drop_curve_v_domain_degeneracy` (WR-100) and `mirror_curve_keeps_euclidean_control_points` -/// (WR-98) are the port's fixes of upstream defects: none has a fork commit, and the C++ build -/// keeps upstream's behaviour there. +/// Upstream's defect is still there: `precise_properties_trim_base_v` (WR-563: `SmODEAreaIFEO` starts +/// at the domain's lowest v), `fillet_blend_curve_revolved_on_arc` (WR-581: `CalcTorusFilletGeom` takes +/// circular and linear sections only), `ellipse_step_interval_checks` (WR-211: `AdjustSTEPInterval` +/// tests no inverted or collapsed interval), `boolean_union_refuses_solid_leak` (WR-619: STEP 6 deletes +/// without testing regions), `curve_loop_start_after_previous_end` (WR-96), `loop_use_reports_open_gaps` +/// (WR-93), `face_points_span_domain` (WR-86), `drop_curve_v_domain_degeneracy` (WR-100), +/// `mirror_curve_keeps_euclidean_control_points` (WR-98), `geometric_g2_continuity` (WR-380: a normal +/// compared with itself), `fillet_corner_variable_radius_rail_on_opposite_fillet` (WR-645: no test of +/// the rail against the opposite fillet), `sphere_from_arcs_common_centre` (WR-103: `rOrigin` refers to +/// the origin it is compared with), `dupin_bottom_hyperbola_axis` (WR-69: k2 for both axes), +/// `extent3d_contains_both_segment_endpoints` (WR-3: `ContainsLineSeg3d` ors its two points), +/// `gap_samples_use_trimmed_spans` (WR-89: `BuildSampleSet` spans from the first knot), +/// `twist_simple_duw_sign` (WR-46: `EvaluateSimple`'s Duw y is -per cos) and +/// `translation_sweep_regularize` (solidcore#1937: nothing regularizes after the sweep). +/// +/// The fork deals with it another way: `bspline_trim_keeps_rational_end_spans` (WR-575: the fork keeps +/// a short span of a UV curve, and still removes a 3D conic's) and `corner_patch_face_side_twist` +/// (WR-613: the fork refines the patch, `corner_blend_coons_patch_tangent_to_sides`). +/// +/// The fork carries on softly where these refuse: `temporary_radius_setup_errors` (#458: a scope guard +/// cannot report), `fillet_corner_statuses` (`sm_TestG1Continuity`: no tangent is no tangency), +/// `fillet_edge_curve_domain_statuses` (`sm_CheckEdgeCurveDomains`: a failed trim keeps the edge's +/// curve), `offset_tangent_gap_statuses` (`HaveTangentGaps`: a failed sample shows no gap) and +/// `ssi_alignment_statuses` (`ALIGN_DIR_WITH_PREVIOUS_POINT`: no angle, no alignment). /// /// On since `SMLIB_REV` eaa998a: `fillet_trim_inside_by_best_dot` (fork de4dae6), /// `fillet_half_degree_crease` (2e8758b), `fillet_split_edge_keeps_near_half` (ceb3272) and diff --git a/crates/smlib/src/core/blend_tests.rs b/crates/smlib/src/core/blend_tests.rs index c8ce963797..ddacb74050 100644 --- a/crates/smlib/src/core/blend_tests.rs +++ b/crates/smlib/src/core/blend_tests.rs @@ -515,7 +515,7 @@ 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 bug: SubtractRemovalRegion loses the attributes of target edges it replaces (next-pin/bugs/cliff-overflow-loses-edge-attributes.md)"] +#[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; @@ -562,7 +562,7 @@ fn an_edge_tag_crosses_a_cliff_overflow() { /// 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. #[test] -#[ignore = "solidcore bug: next-pin/bugs/chamfer-boolean-body-keep-operand-uv-trims.md"] +#[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; diff --git a/crates/smlib/src/core/boolean_tests.rs b/crates/smlib/src/core/boolean_tests.rs index a3af43a235..3c8543bbdd 100644 --- a/crates/smlib/src/core/boolean_tests.rs +++ b/crates/smlib/src/core/boolean_tests.rs @@ -646,7 +646,7 @@ mod history { /// Two overlapping squares combined as regions of one plane. #[test] - #[ignore = "solidcore's boolean_2d carries no attributes through its merge (#1462's scope; write-up review-1031/bugs/boolean2d-drops-history.md, not filed yet)"] + #[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 a05e3966c6..51c984d7c7 100644 --- a/crates/smlib/src/core/offset.rs +++ b/crates/smlib/src/core/offset.rs @@ -18,10 +18,9 @@ use solidcore::EntityRef; use solidcore::SolidError; -use solidcore::curve::curve::Curve; -use solidcore::geom::attribute::{Attribute, AttributeStore, Behavior, ObjectKey, ids}; +use solidcore::geom::attribute::{Attribute, Behavior, ids}; use solidcore::geom::axis2_placement::Axis2Placement; -use solidcore::geom::object::{ObjectRef, Shape}; +use solidcore::geom::object::Shape; use solidcore::geom::vector3d::{Point3, Vec3}; use solidcore::intersect::point_class::PointClassType; use solidcore::kernel::Kernel; @@ -30,23 +29,17 @@ use solidcore::nurbs::b_spline_curve::ControlPointForm; use solidcore::nurbs::b_spline_surface::p1::SurfParamType; use solidcore::nurbs::b_spline_surface_n_lib::p2::OrientType; use solidcore::nurbs::knots::Side; -use solidcore::offset::offset_executive::p2::{ - OffsetNotifications, OffsetOptions, ShellCopyIdentities, ShellOptions, api_offset_brep_full, api_shell_brep_full, -}; +use solidcore::offset::offset_executive::p2::{OffsetOptions, ShellOptions, local_operation_simple, offset_brep_simple, shell_brep_simple}; use solidcore::offset::offset_faces::{OffsetFacesExecutive, OffsetFacesRefusal}; -use solidcore::query::api_queries::{BrepRef, face_bounding_box, face_classify_uv, face_closest_point_in_shape, face_internal_point}; +use solidcore::query::api_queries::{face_bounding_box, face_classify_uv, face_closest_point_in_shape, face_internal_point}; use solidcore::query::brep::{BrepIdentity, BrepQuery, LiveBrepObjects}; use solidcore::surface::cone::Cone; use solidcore::surface::surface::{Surface, SurfaceKind}; -use solidcore::sweep::topology_sweep::store::SweepIdentities; -use solidcore::topology::brep::local_operation::local_operation; use solidcore::topology::brep::{p1 as brep_p1, p2 as brep_p2}; use solidcore::topology::face::p2 as face_p2; -use solidcore::topology::topology::{NotifyRecords, Topology}; -use solidcore::topology::{Brep, BrepId, EdgeId, FaceId, FaceuseId, RegionId}; +use solidcore::topology::{Brep, BrepId, FaceId, FaceuseId}; use super::blend::{Miss, on_copy, p3, pick, points_ok, status as blend_status, tolerance_ok}; -use super::boolean::{domain, named}; use super::{Body, answer}; use crate::{Error, Result}; @@ -279,149 +272,21 @@ fn leaves_cavity(k: &mut Kernel, b: &mut Brep, open: &[FaceId], wall: f64) -> so Ok(false) } -// Each B-rep the offset executive touches (the source, its working copy, the result, the merge's -// bodies) names its objects in its own key domain ([`named`]), as solidcore's offset fixture does, -// so their notification records never collide. Curves and lists have domains of their own. -const SOURCE: u64 = domain(1); -const RESULT: u64 = domain(2); -const WORKING: u64 = domain(3); -/// The merge's B-rep `brep`: the domains of its objects, its curves and its lists. -fn merge_domain(brep: BrepId, which: u64) -> u64 { - domain(16 + u64::from(brep.index()) * 3 + which) -} - -fn source_key(e: EntityRef) -> ObjectRef { - named(e, SOURCE) -} - -fn result_key(e: EntityRef) -> ObjectRef { - named(e, RESULT) -} - -fn working_key(e: EntityRef) -> ObjectRef { - named(e, WORKING) -} - -fn curve_in(domain: u64, edge: EdgeId, type_code: i64) -> ObjectRef { - ObjectRef { key: ObjectKey(domain + u64::from(edge.index())), type_code } -} - -fn result_curve(edge: EdgeId, type_code: i64) -> ObjectRef { - curve_in(domain(4), edge, type_code) -} - -fn source_curve(edge: EdgeId, type_code: i64) -> ObjectRef { - curve_in(domain(5), edge, type_code) -} - -fn working_curve(edge: EdgeId, type_code: i64) -> ObjectRef { - curve_in(domain(6), edge, type_code) -} - -fn lists_in(domain: u64, region: RegionId) -> [ObjectRef; 2] { - [0, 1].map(|list| ObjectRef { key: ObjectKey(domain + u64::from(region.index()) * 2 + list), type_code: 0 }) -} - -fn source_lists(result: bool, region: RegionId) -> [ObjectRef; 2] { - lists_in(domain(if result { 8 } else { 7 }), region) -} - -fn working_lists(region: RegionId) -> [ObjectRef; 2] { - lists_in(domain(9), region) -} - -fn merge_curve(brep: BrepId, edge: EdgeId, type_code: i64) -> ObjectRef { - ObjectRef { key: ObjectKey(merge_domain(brep, 1) + u64::from(edge.index())), type_code } -} - -/// Identities of the B-reps the merge makes, disjoint from the keys above. -struct MergeBodies; - -impl SweepIdentities for MergeBodies { - fn topology(&self, brep: BrepId, entity: EntityRef) -> ObjectRef { - named(entity, merge_domain(brep, 0)) - } - fn owned_auxiliary_objects(&self, brep: BrepId, model: &Brep) -> Vec { - model.edges().iter().filter(|(_, e)| e.curve.is_some()).map(|(edge, _)| merge_curve(brep, edge, 0).key).collect() - } - fn curve(&self, brep: BrepId, edge: EdgeId, curve: &Curve) -> ObjectRef { - merge_curve(brep, edge, curve.type_code()) - } - fn new_curve(&self, brep: BrepId, edge: EdgeId, type_code: i64) -> solidcore::Result { - Ok(merge_curve(brep, edge, type_code)) - } - fn source_lists(&self, brep: BrepId, region: RegionId) -> solidcore::Result<[ObjectRef; 2]> { - Ok(lists_in(merge_domain(brep, 2), region)) - } -} - -/// The notification stores of one offset call on `source` (SM_API's context keeps them for the -/// process; each call here has its own). -struct Notifications { - records: NotifyRecords, - attributes: AttributeStore, -} - -impl Notifications { - /// Registers `source` (B-rep 0 of the source domain), its objects and the reserved result. - fn new(source: &mut Brep) -> Notifications { - source.set_key(source_key(EntityRef::Brep(ONE)).key); - let mut records = NotifyRecords::new(); - records.insert(source.key(), Topology::new()); - records.insert(result_key(EntityRef::Brep(ONE)).key, Topology::new()); - let entities = source - .shells() - .iter() - .map(|(id, _)| EntityRef::Shell(id)) - .chain(source.faces().iter().map(|(id, _)| EntityRef::Face(id))) - .chain(source.faceuses().iter().map(|(id, _)| EntityRef::Faceuse(id))) - .chain(source.edges().iter().map(|(id, _)| EntityRef::Edge(id))) - .chain(source.edgeuses().iter().map(|(id, _)| EntityRef::Edgeuse(id))) - .chain(source.vertices().iter().map(|(id, _)| EntityRef::Vertex(id))) - .chain(source.vertexuses().iter().map(|(id, _)| EntityRef::Vertexuse(id))) - .chain(source.loopuses().iter().map(|(id, _)| EntityRef::Loopuse(id))) - .chain(source.regions().iter().map(|(id, _)| EntityRef::Region(id))); - for e in entities { - records.insert(source_key(e).key, Topology::new()); - } - Notifications { records, attributes: AttributeStore::default() } - } - - fn context(&mut self) -> OffsetNotifications<'_> { - OffsetNotifications { - records: &mut self.records, - attributes: &mut self.attributes, - original_key_of: &source_key, - result_key_of: &result_key, - original_curve_ref: &source_curve, - result_curve_ref: &result_curve, - boolean_source_lists: &source_lists, - result_brep: result_key(EntityRef::Brep(ONE)), - merge_identities: Some(&MergeBodies), - } - } -} - /// `SmApiShellBrepFull(b, distance, TRUE, TRUE, TRUE, open, r)`: convex edges extended, results /// merged, side walls made at a sheet's edges, and (as the fork does, 5448b9a) a thickened /// sheet's coplanar side walls one face. -fn shell_brep_full(k: &mut Kernel, mut b: Brep, distance: f64, open: &[FaceId]) -> solidcore::Result { - let mut n = Notifications::new(&mut b); +fn shell_brep_full(k: &mut Kernel, b: &Brep, distance: f64, open: &[FaceId]) -> solidcore::Result { let options = ShellOptions { offset: OffsetOptions { distance, extend_convex_edges: true, merge_results: true }, create_offset_solid: true, merge_sheet_side_walls: true, }; - let faces: Vec<_> = open.iter().map(|&f| Some((ONE, f))).collect(); - let copy = ShellCopyIdentities { key_of: &working_key, curve_ref: &working_curve, boolean_source_lists: &working_lists }; - api_shell_brep_full(k, Some(BrepRef { brep: &b, handle: ONE }), options, &faces, ©, &mut n.context()) + shell_brep_simple(k, b, options, open) } /// `SmApiOffsetBrepFull(b, distance, TRUE, TRUE, r)`. fn offset_brep_full(k: &mut Kernel, b: &mut Brep, distance: f64) -> solidcore::Result { - let mut n = Notifications::new(b); - let options = OffsetOptions { distance, extend_convex_edges: true, merge_results: true }; - api_offset_brep_full(k, Some(b), options, &mut n.context()) + offset_brep_simple(k, b, OffsetOptions { distance, extend_convex_edges: true, merge_results: true }) } /// `finish`: the result must have faces, and a solid input must give a closed manifold solid. @@ -459,7 +324,7 @@ pub(crate) fn shell(body: &Body, points: &[[f64; 3]], tolerance: f64, thickness: if thickness < 0.0 && solid_in && !leaves_cavity(k, &mut w, &picked, -thickness)? { return Ok(Err(Error::NoRoom)); } - match called(shell_brep_full(k, w, thickness, &picked))? { + match called(shell_brep_full(k, &w, thickness, &picked))? { Ok(r) => finish(r, solid_in), Err(e) => Ok(Err(e)), } @@ -528,7 +393,7 @@ pub(crate) fn thicken(body: &Body, thickness: f64, symmetric: bool) -> Result return Ok(Err(e)), }; } - match called(shell_brep_full(k, w, thickness, &[]))? { + match called(shell_brep_full(k, &w, thickness, &[]))? { Ok(r) => finish(r, true), Err(e) => Ok(Err(e)), } @@ -787,8 +652,7 @@ pub(crate) fn draft( // `moved_faces(b, status(b->LocalOperation(faces, surfaces)))`, its marks on the picked // faces (`mark_moved`). mark_moved(&mut w, &picked)?; - let mut notes = Notifications::new(&mut w); - if let Err(e) = called(local_operation(k, &mut w, &picked, surfaces, &mut notes.context()))? { + if let Err(e) = called(local_operation_simple(k, &mut w, &picked, surfaces))? { return Ok(Err(e)); } if !moved_faces(&mut w)? { diff --git a/crates/smlib/src/core/offset_tests.rs b/crates/smlib/src/core/offset_tests.rs index 9ee10ba7ab..cb32803efa 100644 --- a/crates/smlib/src/core/offset_tests.rs +++ b/crates/smlib/src/core/offset_tests.rs @@ -775,7 +775,7 @@ mod history { } #[test] - #[ignore = "solidcore's stitch in the shell drops the flat sheet's edge tags (write-up review-1031/bugs/thicken-flat-sheet-edge-tags.md, not filed yet)"] + #[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); }