mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 02:25:55 +00:00
kernel: a cut by a tool apart from the body is the body itself
The truck booleans answered a tool clear of the body without intersecting (the operand kept, its record shared). The SMLib boolean always rebuilt the body, so a cut that could not reach a body still handed back a new record: a hole far from a second body reported that body changed (#2904's test), and a body clear of a pocket's cutter was no longer the same solid. A cut or intersection whose operands are apart (their exact boxes, grown by twice the tolerance as union_apart takes them, do not meet) now gives the body itself with its faces and edges kept, or nothing, with no SMLib call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,9 +21,18 @@ pub enum BoolOp {
|
||||
/// everything or an intersection of disjoint bodies. A result SMLib's check refuses is an error.
|
||||
///
|
||||
/// The result carries its exact history ([`Body::history`]) over the operands `[a, b]`, from
|
||||
/// SMLib's own tags, or none where a body's order cannot be matched to SMLib's.
|
||||
/// SMLib's own tags, or none where a body's order cannot be matched to SMLib's. A cut by a tool
|
||||
/// apart from the body is the body itself (its faces and edges kept), and their intersection empty.
|
||||
pub fn boolean(a: &Body, b: &Body, op: BoolOp) -> Result<Option<Body>> {
|
||||
crate::profile::timed(crate::profile::Kind::Boolean, "boolean", || {
|
||||
// A tool apart from the body (their exact boxes, grown by the tolerances, do not meet)
|
||||
// leaves a cut the body itself and an intersection nothing, with no intersection work.
|
||||
if matches!(op, BoolOp::Cut | BoolOp::Intersect) && apart(a, b)? {
|
||||
return Ok(match op {
|
||||
BoolOp::Cut => Some(crate::boolean_record::operand(a, 0, &crate::record::counts(&[a, b]))),
|
||||
_ => None,
|
||||
});
|
||||
}
|
||||
let r = guard("SMLib boolean", || crate::smlib_boolean::smlib_boolean(a, b, op));
|
||||
with_operand_roles(a, b, op, r)
|
||||
})
|
||||
@@ -44,6 +53,16 @@ pub fn union_all(bodies: &[&Body]) -> Result<Body> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether B-rep bodies `a` and `b` are apart: their exact boxes, each grown by twice its
|
||||
/// record's tolerance (as [`union_apart`] takes them), do not meet.
|
||||
fn apart(a: &Body, b: &Body) -> Result<bool> {
|
||||
if a.is_mesh() || b.is_mesh() {
|
||||
return Ok(false);
|
||||
}
|
||||
let grown = |x: &Body| x.exact_bounds().map(|bb| bb.inflated(2.0 * x.record().tolerance));
|
||||
Ok(!grown(a)?.meets(&grown(b)?))
|
||||
}
|
||||
|
||||
/// A boolean's result with what its operands' faces stood for carried over: regularization
|
||||
/// protection and the planar construction and shell roles on supports it kept.
|
||||
fn with_operand_roles(a: &Body, b: &Body, op: BoolOp, r: Result<Option<Body>>) -> Result<Option<Body>> {
|
||||
|
||||
Reference in New Issue
Block a user