mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 02:25:55 +00:00
doc: a join of many tools into one target unions them in a balanced tree
A Join with one target takes every tool, whichever it meets, but it grew the
target by one tool at a time: each union took the whole result so far, and
each step first meshed it to see whether the tool met it (which with one
target decides nothing). n tools cost n^2 in every per-body step of a
boolean (converting the operands, checking the result, exporting it back),
whichever kernel runs it: a combine of 64 separate pegs (booleans/3455) took
400 s on SMLib, of 36 lofted blades and a disk (crashes/2992, sweeps/1856)
485 s and 97 s.
With one target, the target and the tools are now unioned pairwise, level by
level, so each body takes part in about log2(n) unions. The result is the
same union under the target's name, with the lineage of every union. Several
targets keep the absorption order they need. The doc and engine join and
combine tests passed and failed on SMLib as before (measured before the
rebase).
Not built: base in progress (rebased onto kernel-smlib/no-truck 41adb372).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
This commit is contained in:
@@ -2995,6 +2995,31 @@ fn apply_traced_with(
|
||||
let u = kernel::boolean(&a.body, &b.body, BoolOp::Union)?.ok_or_else(|| DocError::Invalid("join produced nothing".into()))?;
|
||||
Ok(Traced::step(u, &[a, b]))
|
||||
};
|
||||
// One target takes every tool, whichever it meets: the result is the union of all of
|
||||
// them, made in a balanced tree of unions so that each body is in about log2(n) of
|
||||
// them, instead of the target growing by one tool at a time and taking part, ever
|
||||
// larger, in every one (n tools cost n²).
|
||||
if let [keep] = live.as_slice()
|
||||
&& tools.len() > 1
|
||||
{
|
||||
let Some(base) = state.body(keep).map(ModelBody::traced) else { return Ok(()) };
|
||||
let mut level: Vec<Traced> = std::iter::once(base).chain(tools).collect();
|
||||
while level.len() > 1 {
|
||||
let mut next = Vec::with_capacity(level.len().div_ceil(2));
|
||||
let mut it = level.into_iter();
|
||||
while let Some(a) = it.next() {
|
||||
next.push(match it.next() {
|
||||
Some(b) => union(&a, &b)?,
|
||||
None => a,
|
||||
});
|
||||
}
|
||||
level = next;
|
||||
}
|
||||
if let (Some(acc), Some(mb)) = (level.pop(), state.bodies.iter_mut().find(|b| b.name == *keep)) {
|
||||
*mb = ModelBody::traced_new(mb.name.clone(), acc, mb.feature);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
for tool in &tools {
|
||||
let mut met: Vec<String> = Vec::new();
|
||||
for name in &live {
|
||||
|
||||
Reference in New Issue
Block a user