Search code examples
openscadcsg

OpenSCAD: How to avoid extra grouping in CSG tree


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?


Solution

  • 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.