pub mod cavity;
pub mod fastener;
pub mod joint;
pub mod mount;
pub mod pattern_sdf;
pub mod reinforcement;
pub mod skadis_sdf;
pub mod thin_sdf;
use alice_sdf::SdfNode;
use std::sync::Arc;
#[must_use]
pub fn balanced_union_fold(mut nodes: Vec<SdfNode>) -> Option<SdfNode> {
if nodes.is_empty() {
return None;
}
while nodes.len() > 1 {
let mut next: Vec<SdfNode> = Vec::with_capacity(nodes.len().div_ceil(2));
let mut iter = nodes.into_iter();
while let Some(a) = iter.next() {
match iter.next() {
Some(b) => next.push(SdfNode::Union {
a: Arc::new(a),
b: Arc::new(b),
}),
None => next.push(a),
}
}
nodes = next;
}
nodes.into_iter().next()
}
#[cfg(test)]
mod balanced_fold_tests {
use super::*;
#[test]
fn empty_returns_none() {
assert!(balanced_union_fold(Vec::new()).is_none());
}
#[test]
fn single_returns_self() {
let n = SdfNode::Sphere { radius: 1.0 };
let out = balanced_union_fold(vec![n]).unwrap();
assert!(matches!(out, SdfNode::Sphere { .. }));
}
#[test]
fn multi_returns_union_tree() {
let nodes: Vec<_> = (0..8).map(|_| SdfNode::Sphere { radius: 0.1 }).collect();
let out = balanced_union_fold(nodes).unwrap();
assert!(matches!(out, SdfNode::Union { .. }));
}
#[test]
fn depth_is_logarithmic() {
fn depth(n: &SdfNode) -> usize {
match n {
SdfNode::Union { a, b } => 1 + depth(a).max(depth(b)),
_ => 1,
}
}
let nodes: Vec<_> = (0..100).map(|_| SdfNode::Sphere { radius: 0.1 }).collect();
let out = balanced_union_fold(nodes).unwrap();
let d = depth(&out);
assert!(d <= 8, "100 nodes → depth {d} (期待: ≤ 8)");
}
}