Join a floor into the hole it fills: grow the boss into the wall around it (#1212) (#1217)

Join a floor into the hole it fills: grow the boss into the wall around it (#1212).
This commit is contained in:
Tobias Breckle authored and GitHub committed 2026-10-14 18:28:17 -04:00
1 parent a4a8b48567
commit a629236650
6 files changed
+253 -22

No files matched your search

+49 -4
View File
@@ -14,6 +14,8 @@ pub enum BooleanStrategy {
ShiftedOperands,
CoplanarSeparation,
CommonBore,
/// A boss in the other body's bore, grown into the material around it (nothing recut).
GrownBoss,
PlanarFallback,
ToolNudge,
Piecewise,
@@ -34,6 +36,15 @@ pub struct BooleanFallback {
pub tolerance_mm: f64,
}
impl BooleanStrategy {
/// Whether a result made this way can differ from the exact one: the tool was moved
/// against the other body, or part of where they meet was ignored. The other retries work
/// on temporary geometry or tolerances only, and their results are the exact ones.
pub fn alters_result(self) -> bool {
matches!(self, BooleanStrategy::ToolNudge | BooleanStrategy::UnverifiedShortcut)
}
}
impl BooleanFallback {
pub(crate) fn new(strategy: BooleanStrategy) -> Self {
Self { strategy, translation_mm: 0., rotation_rad: 0., face_shift_mm: 0., tolerance_mm: 0. }
@@ -47,6 +58,7 @@ impl BooleanFallback {
}
BooleanStrategy::CoplanarSeparation => format!("temporary coincident-face separation up to {:.6e} mm per face", self.face_shift_mm),
BooleanStrategy::CommonBore => format!("temporary bore offset {:.6e} mm, followed by recutting the original bore", self.face_shift_mm),
BooleanStrategy::GrownBoss => format!("boss grown {:.6e} mm into the material around the bore it fills", self.face_shift_mm),
BooleanStrategy::PlanarFallback => "exact planar fallback (no displacement)".into(),
BooleanStrategy::ToolNudge => format!("tool displacement {:.6e} mm, rotation {:.6e} rad", self.translation_mm, self.rotation_rad),
BooleanStrategy::Piecewise => "piecewise retry (no displacement)".into(),
@@ -79,13 +91,26 @@ impl BooleanDiagnostics {
self.events.iter().find(|event| event.strategy == BooleanStrategy::UnverifiedShortcut).map(BooleanFallback::description)
}
/// Every retry the result took, for a message about the boolean (one that failed its
/// checks lists what was tried).
pub fn summary(&self) -> Option<String> {
self.described(&self.events.iter().collect::<Vec<_>>())
}
/// The note a feature carries: the retries that can make its result differ from the exact
/// one ([`BooleanStrategy::alters_result`]). Exact retries are in `events` all the same
/// (`timeline.inspect`), but they leave the result as it should be: no reason to warn.
pub fn warning(&self) -> Option<String> {
if self.events.is_empty() && !self.truncated {
self.described(&self.events.iter().filter(|e| e.strategy.alters_result()).collect::<Vec<_>>())
}
fn described(&self, events: &[&BooleanFallback]) -> Option<String> {
if events.is_empty() && !self.truncated {
return None;
}
let mut descriptions: Vec<String> = self.events.iter().take(4).map(BooleanFallback::description).collect();
if self.events.len() > 4 {
descriptions.push(format!("{} additional retries", self.events.len() - 4));
let mut descriptions: Vec<String> = events.iter().take(4).map(|e| e.description()).collect();
if events.len() > 4 {
descriptions.push(format!("{} additional retries", events.len() - 4));
}
if self.truncated {
descriptions.push(format!("report capped at {MAX_EVENTS} retries"));
@@ -169,6 +194,26 @@ mod tests {
assert!(capture_boolean_diagnostics(|| {}).1.events.is_empty());
}
/// Only retries whose result can differ from the exact one make a warning; the summary
/// lists every retry.
#[test]
fn only_retries_that_alter_the_result_warn() {
let report = |strategies: &[BooleanStrategy]| {
capture_boolean_diagnostics(|| {
for s in strategies {
record(BooleanFallback::new(*s));
}
})
.1
};
let exact = report(&[BooleanStrategy::ShiftedOperands, BooleanStrategy::GrownBoss, BooleanStrategy::CoplanarSeparation]);
assert!(exact.warning().is_none(), "{exact:?}");
assert!(exact.summary().is_some_and(|s| s.contains("shifted operands") && s.contains("boss grown")));
let nudged = report(&[BooleanStrategy::GrownBoss, BooleanStrategy::ToolNudge]);
let warning = nudged.warning().unwrap();
assert!(warning.contains("tool displacement") && !warning.contains("boss grown"), "{warning}");
}
#[test]
fn exact_operations_and_failed_calls_have_no_retry_report() {
use solidcraft_geom::Vec3;