discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

if(false) returns empty object in RC3, breaks code from 2019.05

A
adrianv
Fri, Dec 25, 2020 4:13 PM

I recall this being discussed a while back and I'm not sure about what the
ultimate conclusion was, and I can't remember what the issue was that gave
rise to the change.  But it seems like the RC3 version has the behavior that
if(false) returns an empty object rather than nothing.  This is different
from what happened in 2019.05, it seems, as shown by this example which
breaks in RC3 but works in 2019.

chamfer = false;  // Set to true to get chamfer
intersection(){
cube(10);
if (chamfer)
translate([0,-10,12]) rotate([-45,0,0])cube(30);
}

When chamfer is false I expect a cube but instead I get nothing because the
intersection is with an empty object.  Note that in the list context:
[1,2,if (false) 27, 3, 4] the conditional produces nothing, not an empty
list, so the new behavior makes the openscad language less internally
consistent.  Is there some advantage of the new behavior?  Note that if this
change is staying, it should be highlighted as a language change from the
2019 version.

--
Sent from: http://forum.openscad.org/

I recall this being discussed a while back and I'm not sure about what the ultimate conclusion was, and I can't remember what the issue was that gave rise to the change. But it seems like the RC3 version has the behavior that if(false) returns an empty object rather than nothing. This is different from what happened in 2019.05, it seems, as shown by this example which breaks in RC3 but works in 2019. chamfer = false; // Set to true to get chamfer intersection(){ cube(10); if (chamfer) translate([0,-10,12]) rotate([-45,0,0])cube(30); } When chamfer is false I expect a cube but instead I get nothing because the intersection is with an empty object. Note that in the list context: [1,2,if (false) 27, 3, 4] the conditional produces nothing, not an empty list, so the new behavior makes the openscad language less internally consistent. Is there some advantage of the new behavior? Note that if this change is staying, it should be highlighted as a language change from the 2019 version. -- Sent from: http://forum.openscad.org/
JB
Jordan Brown
Fri, Dec 25, 2020 8:12 PM

I don't think it returns an empty object in 2019.05.  (Check the CSG
tree.)  What I think is happening is that intersection in 2019.05
ignores the empty object.

Having it return nothing would break things in a different way.

want_sphere = false;

module foo() {
    children(1);
}

foo() {
    cube();
    if (want_sphere) sphere();
    cylinder();
}

should emit either a sphere or nothing, depending on how want_sphere is set.

I don't think it returns an empty object in 2019.05.  (Check the CSG tree.)  What I think is happening is that intersection in 2019.05 ignores the empty object. Having it return nothing would break things in a different way. want_sphere = false; module foo() { children(1); } foo() { cube(); if (want_sphere) sphere(); cylinder(); } should emit either a sphere or nothing, depending on how want_sphere is set.
A
adrianv
Fri, Dec 25, 2020 8:34 PM
-- Sent from: http://forum.openscad.org/
JB
Jordan Brown
Fri, Dec 25, 2020 8:38 PM

On 12/25/2020 12:12 PM, Jordan Brown wrote:

I don't think it returns an empty object in 2019.05.  (Check the CSG
tree.)

I mis-wrote.  I don't think it returns nothing in 2019.05.  In both
2019.05 and the current build, if(false) yields an empty group() in the
CSG tree.  As do echo(), for()-that-never-runs, and empty modules.

The difference is in what intersection() and difference() do with
children that don't contain any solid-generators.

2019.05's difference() and intersection() ignore children that don't
contain anything that generates a solid.
Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera
are all ignored.
An intersection or difference of a cube or other solid, that yields
nothing, is not ignored.

The current build respects those "super empty" structures.

What I think is happening is that intersection in 2019.05 ignores the
empty object.

Having it return nothing would break things in a different way.

 want_sphere = false;

 module foo() {
     children(1);
 }

 foo() {
     cube();
     if (want_sphere) sphere();
     cylinder();
 }

should emit either a sphere or nothing, depending on how want_sphere
is set.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

On 12/25/2020 12:12 PM, Jordan Brown wrote: > I don't think it returns an empty object in 2019.05.  (Check the CSG > tree.) I mis-wrote.  I don't think it returns *nothing* in 2019.05.  In both 2019.05 and the current build, if(false) yields an empty group() in the CSG tree.  As do echo(), for()-that-never-runs, and empty modules. The difference is in what intersection() and difference() do with children that don't contain any solid-generators. 2019.05's difference() and intersection() ignore children that don't contain anything that generates a solid. Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera are all ignored. An intersection or difference of a cube or other solid, that yields nothing, is *not* ignored. The current build respects those "super empty" structures. > What I think is happening is that intersection in 2019.05 ignores the > empty object. > > Having it return nothing would break things in a different way. > > want_sphere = false; > > module foo() { > children(1); > } > > foo() { > cube(); > if (want_sphere) sphere(); > cylinder(); > } > > should emit either a sphere or nothing, depending on how want_sphere > is set. > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
A
adrianv
Fri, Dec 25, 2020 8:48 PM

How do you view the CSG tree?

I noticed that the example you posted works the same in both versions, so
that does imply that it returns an empty object and that the question is
maybe what intersection or difference do with empty objects.  Here's a
simple example:

difference(){
union() {};
cube();
}

The above code produces a cube in 2019.05 and nothing in RC3.  To me the
old behavior makes more sense: if you haven't specified an object then
ignore it rather than "no object" being the same as the empty set.

I could see leaving the current behavior but introducing a nothing() object
that lets you not return geometry.  I could also see changing difference and
intersection to the old behavior and having a nothing() object that acts
like the empty set.  But maybe this second case doesn't work because the
change fixed a bug?  It seems like "if" is a weaker tool if it always has
to return geometry that is acted upon.

JordanBrown wrote

On 12/25/2020 12:12 PM, Jordan Brown wrote:

I don't think it returns an empty object in 2019.05.  (Check the CSG
tree.)

I mis-wrote.  I don't think it returns nothing in 2019.05.  In both
2019.05 and the current build, if(false) yields an empty group() in the
CSG tree.  As do echo(), for()-that-never-runs, and empty modules.

The difference is in what intersection() and difference() do with
children that don't contain any solid-generators.

2019.05's difference() and intersection() ignore children that don't
contain anything that generates a solid.
Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera
are all ignored.
An intersection or difference of a cube or other solid, that yields
nothing, is not ignored.

The current build respects those "super empty" structures.

What I think is happening is that intersection in 2019.05 ignores the
empty object.

Having it return nothing would break things in a different way.

 want_sphere = false;

 module foo() {
     children(1);
 }

 foo() {
     cube();
     if (want_sphere) sphere();
     cylinder();
 }

should emit either a sphere or nothing, depending on how want_sphere
is set.


OpenSCAD mailing list

Discuss@.openscad

Discuss@.openscad

How do you view the CSG tree? I noticed that the example you posted works the same in both versions, so that does imply that it returns an empty object and that the question is maybe what intersection or difference do with empty objects. Here's a simple example: difference(){ union() {}; cube(); } The above code produces a cube in 2019.05 and nothing in RC3. To me the old behavior makes more sense: if you haven't specified an object then ignore it rather than "no object" being the same as the empty set. I could see leaving the current behavior but introducing a nothing() object that lets you not return geometry. I could also see changing difference and intersection to the old behavior and having a nothing() object that acts like the empty set. But maybe this second case doesn't work because the change fixed a bug? It seems like "if" is a weaker tool if it always has to return geometry that is acted upon. JordanBrown wrote > On 12/25/2020 12:12 PM, Jordan Brown wrote: >> I don't think it returns an empty object in 2019.05.  (Check the CSG >> tree.) > > I mis-wrote.  I don't think it returns *nothing* in 2019.05.  In both > 2019.05 and the current build, if(false) yields an empty group() in the > CSG tree.  As do echo(), for()-that-never-runs, and empty modules. > > The difference is in what intersection() and difference() do with > children that don't contain any solid-generators. > > 2019.05's difference() and intersection() ignore children that don't > contain anything that generates a solid. > Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera > are all ignored. > An intersection or difference of a cube or other solid, that yields > nothing, is *not* ignored. > > The current build respects those "super empty" structures. > >> What I think is happening is that intersection in 2019.05 ignores the >> empty object. >> >> Having it return nothing would break things in a different way. >> >> want_sphere = false; >> >> module foo() { >> children(1); >> } >> >> foo() { >> cube(); >> if (want_sphere) sphere(); >> cylinder(); >> } >> >> should emit either a sphere or nothing, depending on how want_sphere >> is set. >> >> >> _______________________________________________ >> OpenSCAD mailing list >> > Discuss@.openscad >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > > _______________________________________________ > OpenSCAD mailing list > Discuss@.openscad > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org -- Sent from: http://forum.openscad.org/
M
MichaelAtOz
Fri, Dec 25, 2020 10:40 PM

adrianv wrote

How do you view the CSG tree?

Design/Display-CSG-tree


OpenSCAD Admin - email* me if you need anything,  or if I've done something stupid...

  • on the Forum, click on my MichaelAtOz label, there is a link to email me.

Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above.

--
Sent from: http://forum.openscad.org/

adrianv wrote > How do you view the CSG tree? Design/Display-CSG-tree ----- OpenSCAD Admin - email* me if you need anything, or if I've done something stupid... * on the Forum, click on my MichaelAtOz label, there is a link to email me. Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above. -- Sent from: http://forum.openscad.org/
A
adrianv
Sat, Dec 26, 2020 12:13 AM

Now that I know how to look at CSG trees I did some inspection.

It looks like some objects have changed behavior.

echo and assert give group(); in 2019.05 but give nothing in RC3.

if(false) and for(never) give group(); in both versions.

And I discovered something really bad:  it's now a warning to write a for
statement that doesn't run.  This is a terrible idea.  It's going to break a
bunch of base cases and degenerate cases all over the place.

JordanBrown wrote

On 12/25/2020 12:12 PM, Jordan Brown wrote:

I don't think it returns an empty object in 2019.05.  (Check the CSG
tree.)

I mis-wrote.  I don't think it returns nothing in 2019.05.  In both
2019.05 and the current build, if(false) yields an empty group() in the
CSG tree.  As do echo(), for()-that-never-runs, and empty modules.

The difference is in what intersection() and difference() do with
children that don't contain any solid-generators.

2019.05's difference() and intersection() ignore children that don't
contain anything that generates a solid.
Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera
are all ignored.
An intersection or difference of a cube or other solid, that yields
nothing, is not ignored.

The current build respects those "super empty" structures.

What I think is happening is that intersection in 2019.05 ignores the
empty object.

Having it return nothing would break things in a different way.

 want_sphere = false;

 module foo() {
     children(1);
 }

 foo() {
     cube();
     if (want_sphere) sphere();
     cylinder();
 }

should emit either a sphere or nothing, depending on how want_sphere
is set.


OpenSCAD mailing list

Discuss@.openscad

Discuss@.openscad

Now that I know how to look at CSG trees I did some inspection. It looks like some objects have changed behavior. echo and assert give group(); in 2019.05 but give nothing in RC3. if(false) and for(never) give group(); in both versions. And I discovered something really bad: it's now a warning to write a for statement that doesn't run. This is a terrible idea. It's going to break a bunch of base cases and degenerate cases all over the place. JordanBrown wrote > On 12/25/2020 12:12 PM, Jordan Brown wrote: >> I don't think it returns an empty object in 2019.05.  (Check the CSG >> tree.) > > I mis-wrote.  I don't think it returns *nothing* in 2019.05.  In both > 2019.05 and the current build, if(false) yields an empty group() in the > CSG tree.  As do echo(), for()-that-never-runs, and empty modules. > > The difference is in what intersection() and difference() do with > children that don't contain any solid-generators. > > 2019.05's difference() and intersection() ignore children that don't > contain anything that generates a solid. > Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera > are all ignored. > An intersection or difference of a cube or other solid, that yields > nothing, is *not* ignored. > > The current build respects those "super empty" structures. > >> What I think is happening is that intersection in 2019.05 ignores the >> empty object. >> >> Having it return nothing would break things in a different way. >> >> want_sphere = false; >> >> module foo() { >> children(1); >> } >> >> foo() { >> cube(); >> if (want_sphere) sphere(); >> cylinder(); >> } >> >> should emit either a sphere or nothing, depending on how want_sphere >> is set. >> >> >> _______________________________________________ >> OpenSCAD mailing list >> > Discuss@.openscad >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > > _______________________________________________ > OpenSCAD mailing list > Discuss@.openscad > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org -- Sent from: http://forum.openscad.org/
NH
nop head
Sat, Dec 26, 2020 9:50 AM

I think it is only a warning in for() if the range is literal. So a loop
that will never run with any input variables is a warning but one that
sometimes doesn't run is OK.

On Sat, 26 Dec 2020 at 00:14, adrianv avm4@cornell.edu wrote:

Now that I know how to look at CSG trees I did some inspection.

It looks like some objects have changed behavior.

echo and assert give group(); in 2019.05 but give nothing in RC3.

if(false) and for(never) give group(); in both versions.

And I discovered something really bad:  it's now a warning to write a for
statement that doesn't run.  This is a terrible idea.  It's going to break
a
bunch of base cases and degenerate cases all over the place.

JordanBrown wrote

On 12/25/2020 12:12 PM, Jordan Brown wrote:

I don't think it returns an empty object in 2019.05.  (Check the CSG
tree.)

I mis-wrote.  I don't think it returns nothing in 2019.05.  In both
2019.05 and the current build, if(false) yields an empty group() in the
CSG tree.  As do echo(), for()-that-never-runs, and empty modules.

The difference is in what intersection() and difference() do with
children that don't contain any solid-generators.

2019.05's difference() and intersection() ignore children that don't
contain anything that generates a solid.
Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera
are all ignored.
An intersection or difference of a cube or other solid, that yields
nothing, is not ignored.

The current build respects those "super empty" structures.

What I think is happening is that intersection in 2019.05 ignores the
empty object.

Having it return nothing would break things in a different way.

 want_sphere = false;

 module foo() {
     children(1);
 }

 foo() {
     cube();
     if (want_sphere) sphere();
     cylinder();
 }

should emit either a sphere or nothing, depending on how want_sphere
is set.


OpenSCAD mailing list

Discuss@.openscad

Discuss@.openscad

I think it is only a warning in for() if the range is literal. So a loop that will never run with any input variables is a warning but one that sometimes doesn't run is OK. On Sat, 26 Dec 2020 at 00:14, adrianv <avm4@cornell.edu> wrote: > Now that I know how to look at CSG trees I did some inspection. > > It looks like some objects have changed behavior. > > echo and assert give group(); in 2019.05 but give nothing in RC3. > > if(false) and for(never) give group(); in both versions. > > And I discovered something really bad: it's now a warning to write a for > statement that doesn't run. This is a terrible idea. It's going to break > a > bunch of base cases and degenerate cases all over the place. > > > > > JordanBrown wrote > > On 12/25/2020 12:12 PM, Jordan Brown wrote: > >> I don't think it returns an empty object in 2019.05. (Check the CSG > >> tree.) > > > > I mis-wrote. I don't think it returns *nothing* in 2019.05. In both > > 2019.05 and the current build, if(false) yields an empty group() in the > > CSG tree. As do echo(), for()-that-never-runs, and empty modules. > > > > The difference is in what intersection() and difference() do with > > children that don't contain any solid-generators. > > > > 2019.05's difference() and intersection() ignore children that don't > > contain anything that generates a solid. > > Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera > > are all ignored. > > An intersection or difference of a cube or other solid, that yields > > nothing, is *not* ignored. > > > > The current build respects those "super empty" structures. > > > >> What I think is happening is that intersection in 2019.05 ignores the > >> empty object. > >> > >> Having it return nothing would break things in a different way. > >> > >> want_sphere = false; > >> > >> module foo() { > >> children(1); > >> } > >> > >> foo() { > >> cube(); > >> if (want_sphere) sphere(); > >> cylinder(); > >> } > >> > >> should emit either a sphere or nothing, depending on how want_sphere > >> is set. > >> > >> > >> _______________________________________________ > >> OpenSCAD mailing list > >> > > > Discuss@.openscad > > >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > > > > > _______________________________________________ > > OpenSCAD mailing list > > > Discuss@.openscad > > > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
HL
Hans L
Sat, Dec 26, 2020 2:38 PM

On Fri, Dec 25, 2020 at 10:14 AM adrianv avm4@cornell.edu wrote:

I recall this being discussed a while back and I'm not sure about what the
ultimate conclusion was, and I can't remember what the issue was that gave
rise to the change.

On 12/25/2020 12:12 PM, Jordan Brown wrote:

I don't think it returns an empty object in 2019.05.  (Check the CSG
tree.)

I mis-wrote.  I don't think it returns nothing in 2019.05.  In both
2019.05 and the current build, if(false) yields an empty group() in the CSG
tree.  As do echo(), for()-that-never-runs, and empty modules.

The difference is in what intersection() and difference() do with children
that don't contain any solid-generators.

2019.05's difference() and intersection() ignore children that don't
contain anything that generates a solid.
Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera are
all ignored.
An intersection or difference of a cube or other solid, that yields
nothing, is not ignored.

Jordan is correct here, the old version basically had no concept of empty
geometry and treated it the same as "no geometry" (eg an echo or assert
node without children).
So I guess the issue is now whether or not an untaken conditional should be
counted as empty geometry or not geometry at all.

Without enabling the experimental feature of "lazy-union", a group
essentially implies a union.  So an empty group is treated much like
"union() {}" which means "the empty set" of geometry.

Hans

On Fri, Dec 25, 2020 at 10:14 AM adrianv <avm4@cornell.edu> wrote: > I recall this being discussed a while back and I'm not sure about what the > ultimate conclusion was, and I can't remember what the issue was that gave > rise to the change. > The change was introduced by https://github.com/openscad/openscad/pull/3342 which was a fix for at least 4 existing issues: https://github.com/openscad/openscad/issues/666 https://github.com/openscad/openscad/issues/3311 https://github.com/openscad/openscad/issues/3312 https://github.com/openscad/openscad/issues/3416 On Fri, Dec 25, 2020 at 2:38 PM Jordan Brown <openscad@jordan.maileater.net> wrote: > On 12/25/2020 12:12 PM, Jordan Brown wrote: > > I don't think it returns an empty object in 2019.05. (Check the CSG > tree.) > > > I mis-wrote. I don't think it returns *nothing* in 2019.05. In both > 2019.05 and the current build, if(false) yields an empty group() in the CSG > tree. As do echo(), for()-that-never-runs, and empty modules. > > The difference is in what intersection() and difference() do with children > that don't contain any solid-generators. > > 2019.05's difference() and intersection() ignore children that don't > contain anything that generates a solid. > Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera are > all ignored. > An intersection or difference of a cube or other solid, that yields > nothing, is *not* ignored. > Jordan is correct here, the old version basically had no concept of empty geometry and treated it the same as "no geometry" (eg an echo or assert node without children). So I guess the issue is now whether or not an untaken conditional should be counted as empty geometry or not geometry at all. Without enabling the experimental feature of "lazy-union", a group essentially implies a union. So an empty group is treated much like "union() {}" which means "the empty set" of geometry. Hans
NH
nop head
Sat, Dec 26, 2020 2:53 PM

I think a false if or an empty for() should not create empty geometry, just
as echo() doesn't. It is more backwards compatible and you can always force
empty geometry with else union();

On Sat, 26 Dec 2020 at 14:40, Hans L thehans@gmail.com wrote:

On Fri, Dec 25, 2020 at 10:14 AM adrianv avm4@cornell.edu wrote:

I recall this being discussed a while back and I'm not sure about what the
ultimate conclusion was, and I can't remember what the issue was that gave
rise to the change.

On 12/25/2020 12:12 PM, Jordan Brown wrote:

I don't think it returns an empty object in 2019.05.  (Check the CSG
tree.)

I mis-wrote.  I don't think it returns nothing in 2019.05.  In both
2019.05 and the current build, if(false) yields an empty group() in the CSG
tree.  As do echo(), for()-that-never-runs, and empty modules.

The difference is in what intersection() and difference() do with
children that don't contain any solid-generators.

2019.05's difference() and intersection() ignore children that don't
contain anything that generates a solid.
Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera are
all ignored.
An intersection or difference of a cube or other solid, that yields
nothing, is not ignored.

Jordan is correct here, the old version basically had no concept of empty
geometry and treated it the same as "no geometry" (eg an echo or assert
node without children).
So I guess the issue is now whether or not an untaken conditional should
be counted as empty geometry or not geometry at all.

Without enabling the experimental feature of "lazy-union", a group
essentially implies a union.  So an empty group is treated much like
"union() {}" which means "the empty set" of geometry.

Hans


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

I think a false if or an empty for() should not create empty geometry, just as echo() doesn't. It is more backwards compatible and you can always force empty geometry with else union(); On Sat, 26 Dec 2020 at 14:40, Hans L <thehans@gmail.com> wrote: > > On Fri, Dec 25, 2020 at 10:14 AM adrianv <avm4@cornell.edu> wrote: > >> I recall this being discussed a while back and I'm not sure about what the >> ultimate conclusion was, and I can't remember what the issue was that gave >> rise to the change. >> > > The change was introduced by > https://github.com/openscad/openscad/pull/3342 > which was a fix for at least 4 existing issues: > https://github.com/openscad/openscad/issues/666 > https://github.com/openscad/openscad/issues/3311 > https://github.com/openscad/openscad/issues/3312 > https://github.com/openscad/openscad/issues/3416 > > On Fri, Dec 25, 2020 at 2:38 PM Jordan Brown < > openscad@jordan.maileater.net> wrote: > >> On 12/25/2020 12:12 PM, Jordan Brown wrote: >> >> I don't think it returns an empty object in 2019.05. (Check the CSG >> tree.) >> >> >> I mis-wrote. I don't think it returns *nothing* in 2019.05. In both >> 2019.05 and the current build, if(false) yields an empty group() in the CSG >> tree. As do echo(), for()-that-never-runs, and empty modules. >> >> The difference is in what intersection() and difference() do with >> children that don't contain any solid-generators. >> >> 2019.05's difference() and intersection() ignore children that don't >> contain anything that generates a solid. >> Thus echo, if(false), "translate([0,0,0]);", empty modules, et cetera are >> all ignored. >> An intersection or difference of a cube or other solid, that yields >> nothing, is *not* ignored. >> > > Jordan is correct here, the old version basically had no concept of empty > geometry and treated it the same as "no geometry" (eg an echo or assert > node without children). > So I guess the issue is now whether or not an untaken conditional should > be counted as empty geometry or not geometry at all. > > Without enabling the experimental feature of "lazy-union", a group > essentially implies a union. So an empty group is treated much like > "union() {}" which means "the empty set" of geometry. > > Hans > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >