I want to write a module that can optionally combine its children as either a union or a difference.
module u_or_d(option="d") {
if (option == "d") {
difference() children();
} else {
union() children();
}
}
module thing(option) {
u_or_d(option) {
cube(10, center=true);
cylinder(h=20, d=5, center=true);
}
}
translate([-15, 0, 0]) thing("d");
translate([ 15, 0, 0]) thing("u");
I was surprised that this doesn't work. Both instances of thing appear to create a union of the cube and the cylinder.
The CSG Tree Dump shows the problem. Here's the relevant excerpt:
difference() {
group() {
cube(size = [10, 10, 10], center = true);
cylinder($fn = 0, $fa = 12, $fs = 2, h = 20, r1 = 2.5, r2 = 2.5, center = true);
}
}
The children are wrapped in a group, so the difference()
effectively has only one child, which happens to be an implicit union of the wrapped children.
Is there a way to invoke children()
that avoids this unwanted grouping? If not, is there another way for a module to allow the invoker to select how the module combines its children?
I found a solution:
module u_or_d(option="d") {
if (option == "d" && $children > 1) {
difference() {
children([0]);
children([1:$children-1]);
}
} else {
union() children();
}
}
You still get a group wrapped around each invocation of children, but at least we can make two groups.