discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

relationship between lazy union and PR#4478

JB
Jordan Brown
Sun, Oct 29, 2023 8:22 PM

There seem to have been two distinct rationales for lazy union:

  • Avoid unions as much as possible because unions are expensive. 
    Maybe the top-level shapes are disjoint anyway and so you don't have
    to union them, or maybe the downstream consumer will be OK with
    overlapping shapes.
  • Have some way to pass around sets of shapes, e.g. to allow module A
    to pass its children individually to module B as its children.

PR#4478 https://github.com/openscad/openscad/pull/4478 adds several
features, some of which may be relevant.

In particular, it adds the notion of a "geometry literal" and a
"geometry value".

x = {{ cube(); }};

will create a cube, but does not add it to the model.  Instead, it's
put into a variable, from whence it might be later added to the model,
or more than once, or not at all.

Geometry values are values, and can be used in all of the normal value
contexts.  You can have arrays of them, you can pass them to functions
and modules, you can have functions return them, et cetera.

In particular, arrays of geometry values are a way to pass around
multiple geometric objects without accidentally unioning them.  There's
no obvious way to turn such an array into children for another module,
but you can achieve very similar effects.

For instance, here's a pair of modules A and B.  If you pass a bunch of
children to A, it turns them into an array and passes that array to B,
which then processes them individually.

module A() {
    x = [ for (i=[0:1:$children-1]) {{ children(i); }} ];
    B(x);
}

module B(shapes) {
    for (i=[0:1:len(shapes)-1]) {
        translate([10*i,0,0]) shapes[i];
    }
}

A() {
    cube();
    sphere();
    cylinder();
}

Note that this is subtly different from normal child processing.  In
normal child processing, the child is not evaluated until the parent
calls children() on it.  It may never be evaluated, or it may be
evaluated many times.  Here A's children are evaluated once only, when A
calls children.  What B receives are the results of that evaluation
(internally, a list of CSG trees); they are not re-evaluated when B adds
them to the model.

If you want B to evaluate them individually, you could use another
mechanism that #4478 introduces, the module literal and corresponding
module value (or module reference?).  While not syntactically similar to
children, it has some of the same effects, including being able to
trigger evaluation whenever desired, with different context each time:

module A(shapes) {
    B(shapes);
}

module B(shapes) {
    for (j = [1:5]) {
        for (i=[0:1:len(shapes)-1]) {
            translate([10*i,10*j,0]) shapes[i](j);
        }
    }
}

A([
    module (size) { cube(size); },
    module (size) { sphere(size); },
    module (size) { cylinder(size); }
]);

Here B calls each module passed to it with a different value for the
argument, but the difference could be in the arguments, the $ variables,
or in the modules' use of rands().

There seem to have been two distinct rationales for lazy union: * Avoid unions as much as possible because unions are expensive.  Maybe the top-level shapes are disjoint anyway and so you don't have to union them, or maybe the downstream consumer will be OK with overlapping shapes. * Have some way to pass around sets of shapes, e.g. to allow module A to pass its children individually to module B as its children. PR#4478 <https://github.com/openscad/openscad/pull/4478> adds several features, some of which may be relevant. In particular, it adds the notion of a "geometry literal" and a "geometry value". x = {{ cube(); }}; will create a cube, but does *not* add it to the model.  Instead, it's put into a variable, from whence it might be later added to the model, or more than once, or not at all. Geometry values are values, and can be used in all of the normal value contexts.  You can have arrays of them, you can pass them to functions and modules, you can have functions return them, et cetera. In particular, arrays of geometry values are a way to pass around multiple geometric objects without accidentally unioning them.  There's no obvious way to turn such an array into children for another module, but you can achieve very similar effects. For instance, here's a pair of modules A and B.  If you pass a bunch of children to A, it turns them into an array and passes that array to B, which then processes them individually. module A() { x = [ for (i=[0:1:$children-1]) {{ children(i); }} ]; B(x); } module B(shapes) { for (i=[0:1:len(shapes)-1]) { translate([10*i,0,0]) shapes[i]; } } A() { cube(); sphere(); cylinder(); } Note that this is subtly different from normal child processing.  In normal child processing, the child is not evaluated until the parent calls children() on it.  It may never be evaluated, or it may be evaluated many times.  Here A's children are evaluated once only, when A calls children.  What B receives are the results of that evaluation (internally, a list of CSG trees); they are not re-evaluated when B adds them to the model. If you want B to evaluate them individually, you could use another mechanism that #4478 introduces, the module literal and corresponding module value (or module reference?).  While not syntactically similar to children, it has some of the same effects, including being able to trigger evaluation whenever desired, with different context each time: module A(shapes) { B(shapes); } module B(shapes) { for (j = [1:5]) { for (i=[0:1:len(shapes)-1]) { translate([10*i,10*j,0]) shapes[i](j); } } } A([ module (size) { cube(size); }, module (size) { sphere(size); }, module (size) { cylinder(size); } ]); Here B calls each module passed to it with a different value for the argument, but the difference could be in the arguments, the $ variables, or in the modules' use of rands().
GB
Glenn Butcher
Sun, Oct 29, 2023 9:34 PM

On 10/29/2023 2:22 PM, Jordan Brown wrote:

or maybe the downstream consumer will be OK with overlapping shapes.

Indeed.  For 3d printing of scale model parts, all I care about is that
at a given point in a layer, at least one object renders a "1" pixel.
With that thinking, I defined and translated enough cubes, cylinders,
and extruded polygons to model this:

On 10/29/2023 2:22 PM, Jordan Brown wrote: > or maybe the downstream consumer will be OK with overlapping shapes. Indeed.  For 3d printing of scale model parts, all I care about is that at a given point in a layer, at least one object renders a "1" pixel. With that thinking, I defined and translated enough cubes, cylinders, and extruded polygons to model this:
SP
Sanjeev Prabhakar
Mon, Oct 30, 2023 1:04 AM

Wow
Wonderful work, especially if it is all done in openscad

Wow Wonderful work, especially if it is all done in openscad
RD
Revar Desmera
Mon, Oct 30, 2023 1:12 AM

On Oct 29, 2023, at 1:22 PM, Jordan Brown openscad@jordan.maileater.net wrote:

There seem to have been two distinct rationales for lazy union:
Avoid unions as much as possible because unions are expensive.  Maybe the top-level shapes are disjoint anyway and so you don't have to union them, or maybe the downstream consumer will be OK with overlapping shapes.
Have some way to pass around sets of shapes, e.g. to allow module A to pass its children individually to module B as its children.

I have to wonder how much the unions-are-expensive issue is affected by the move to Manifold.  Is that rationale going to be important anymore?

  • Revar
> On Oct 29, 2023, at 1:22 PM, Jordan Brown <openscad@jordan.maileater.net> wrote: > > There seem to have been two distinct rationales for lazy union: > Avoid unions as much as possible because unions are expensive. Maybe the top-level shapes are disjoint anyway and so you don't have to union them, or maybe the downstream consumer will be OK with overlapping shapes. > Have some way to pass around sets of shapes, e.g. to allow module A to pass its children individually to module B as its children. I have to wonder how much the unions-are-expensive issue is affected by the move to Manifold. Is that rationale going to be important anymore? - Revar
RD
Revar Desmera
Mon, Oct 30, 2023 1:15 AM

Master Class work on that train model!

  • Revar

On Oct 29, 2023, at 2:34 PM, Glenn Butcher glenn.butcher@gmail.com wrote:

On 10/29/2023 2:22 PM, Jordan Brown wrote:

or maybe the downstream consumer will be OK with overlapping shapes.

Indeed.  For 3d printing of scale model parts, all I care about is that at a given point in a layer, at least one object renders a "1" pixel. With that thinking, I defined and translated enough cubes, cylinders, and extruded polygons to model this:

<2023-10-19_stl_integration-800x600.png>


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Master Class work on that train model! - Revar > On Oct 29, 2023, at 2:34 PM, Glenn Butcher <glenn.butcher@gmail.com> wrote: > > > > On 10/29/2023 2:22 PM, Jordan Brown wrote: >> or maybe the downstream consumer will be OK with overlapping shapes. > Indeed. For 3d printing of scale model parts, all I care about is that at a given point in a layer, at least one object renders a "1" pixel. With that thinking, I defined and translated enough cubes, cylinders, and extruded polygons to model this: > > <2023-10-19_stl_integration-800x600.png> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
GB
Glenn Butcher
Mon, Oct 30, 2023 1:51 AM

Every bit of it is OpenSCAD.  I've posted all of it to a Github repo
with a Creative Commons license:

https://github.com/butcherg/DRG_168

Made a lot of it with extrusions of polygons rounded with the
Round-Anything polyround() module.

From an engineering standpoint, OpenSCAD is an excellent environment
for such.  The design is clearly communicated in the scripts; the only
thing I wish I could do would be to generate drawings from the model.

To be noted is that this is a scale model, not a CAD representation of
the real article.  Many, many abstractions and compromises in order to
print a model that's only about six inches long.  Some scale dimensions
are up to twice that of the corresponding prototype, in order to
accommodate the resin printing medium.  For example, I kept losing the
handrail stanchions in the alcohol wash, kept increasing the dimensions
until they survived...

On 10/29/2023 7:04 PM, Sanjeev Prabhakar wrote:

Wow
Wonderful work, especially if it is all done in openscad


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Every bit of it is OpenSCAD.  I've posted all of it to a Github repo with a Creative Commons license: https://github.com/butcherg/DRG_168 Made a lot of it with extrusions of polygons rounded with the Round-Anything polyround() module. From an engineering standpoint, OpenSCAD is an excellent environment for such.  The design is clearly communicated in the scripts; the only thing I wish I could do would be to generate drawings from the model. To be noted is that this is a scale model, not a CAD representation of the real article.  Many, many abstractions and compromises in order to print a model that's only about six inches long.  Some scale dimensions are up to twice that of the corresponding prototype, in order to accommodate the resin printing medium.  For example, I kept losing the handrail stanchions in the alcohol wash, kept increasing the dimensions until they survived... On 10/29/2023 7:04 PM, Sanjeev Prabhakar wrote: > Wow > Wonderful work, especially if it is all done in openscad > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
GB
Glenn Butcher
Mon, Oct 30, 2023 1:53 AM

Preview rendering is very important to me, primarily in integrating
parts that have things like common screwholes. Manifold doesn't (yet)
improve that.

On 10/29/2023 7:12 PM, Revar Desmera wrote:

On Oct 29, 2023, at 1:22 PM, Jordan Brown
openscad@jordan.maileater.net wrote:

There seem to have been two distinct rationales for lazy union:

  • Avoid unions as much as possible because unions are expensive. 
    Maybe the top-level shapes are disjoint anyway and so you don't
    have to union them, or maybe the downstream consumer will be OK
    with overlapping shapes.
  • Have some way to pass around sets of shapes, e.g. to allow module
    A to pass its children individually to module B as its children.

I have to wonder how much the unions-are-expensive issue is affected
by the move to Manifold.  Is that rationale going to be important
anymore?

  • Revar

OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

Preview rendering is very important to me, primarily in integrating parts that have things like common screwholes. Manifold doesn't (yet) improve that. On 10/29/2023 7:12 PM, Revar Desmera wrote: > >> On Oct 29, 2023, at 1:22 PM, Jordan Brown >> <openscad@jordan.maileater.net> wrote: >> >> There seem to have been two distinct rationales for lazy union: >> >> * Avoid unions as much as possible because unions are expensive.  >> Maybe the top-level shapes are disjoint anyway and so you don't >> have to union them, or maybe the downstream consumer will be OK >> with overlapping shapes. >> * Have some way to pass around sets of shapes, e.g. to allow module >> A to pass its children individually to module B as its children. >> > I have to wonder how much the unions-are-expensive issue is affected > by the move to Manifold.  Is that rationale going to be important > anymore? > > - Revar > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org
GB
Glenn Butcher
Mon, Oct 30, 2023 1:58 AM

Nah, a fair bit of hack code.  Particularly nasty is an unholy amalgam
of polyround() and a path_extrude() routine I found on Thingiverse to
make the bell hangar.

I started this about a year ago, no previous experience with CAD or 3d
printing. I just wanted to build a model of the locomotive, OpenSCAD
appealed to the programmer I am, so I just started beating it until it
puked a locomotive...  :D

On 10/29/2023 7:15 PM, Revar Desmera wrote:

Master Class work on that train model!

  • Revar

On Oct 29, 2023, at 2:34 PM, Glenn Butcher glenn.butcher@gmail.com
wrote:

On 10/29/2023 2:22 PM, Jordan Brown wrote:

or maybe the downstream consumer will be OK with overlapping shapes.

Indeed.  For 3d printing of scale model parts, all I care about is
that at a given point in a layer, at least one object renders a "1"
pixel. With that thinking, I defined and translated enough cubes,
cylinders, and extruded polygons to model this:

<2023-10-19_stl_integration-800x600.png>


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

Nah, a fair bit of hack code.  Particularly nasty is an unholy amalgam of polyround() and a path_extrude() routine I found on Thingiverse to make the bell hangar. I started this about a year ago, no previous experience with CAD or 3d printing. I just wanted to build a model of the locomotive, OpenSCAD appealed to the programmer I am, so I just started beating it until it puked a locomotive...  :D On 10/29/2023 7:15 PM, Revar Desmera wrote: > Master Class work on that train model! > > - Revar > > >> On Oct 29, 2023, at 2:34 PM, Glenn Butcher <glenn.butcher@gmail.com> >> wrote: >> >> >> On 10/29/2023 2:22 PM, Jordan Brown wrote: >>> or maybe the downstream consumer will be OK with overlapping shapes. >> >> Indeed.  For 3d printing of scale model parts, all I care about is >> that at a given point in a layer, at least one object renders a "1" >> pixel. With that thinking, I defined and translated enough cubes, >> cylinders, and extruded polygons to model this: >> >> <2023-10-19_stl_integration-800x600.png> >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org
JB
Jordan Brown
Mon, Oct 30, 2023 4:34 AM

On 10/29/2023 6:53 PM, Glenn Butcher wrote:

Preview rendering is very important to me, primarily in integrating
parts that have things like common screwholes.  Manifold doesn't (yet)
improve that.

I believe that union is very fast in preview.  It just throws all of the
triangles at OpenGL and OpenGL figures it out, quite possibly in hardware.

On 10/29/2023 6:53 PM, Glenn Butcher wrote: > > Preview rendering is very important to me, primarily in integrating > parts that have things like common screwholes.  Manifold doesn't (yet) > improve that. > I believe that union is very fast in preview.  It just throws all of the triangles at OpenGL and OpenGL figures it out, quite possibly in hardware.
P
pca006132
Mon, Oct 30, 2023 5:06 AM

I have to wonder how much the unions-are-expensive issue is affected by

the move to Manifold.  Is that rationale going to be important anymore?

Probably not that important now. Manifold will only compose disjoint
objects (i.e. same as lazy union, but written into the same mesh). If
objects are intersecting, we will compute their union, but it is in general
still pretty fast. We also optimize the union order to minimize overall
time.

> I have to wonder how much the unions-are-expensive issue is affected by the move to Manifold. Is that rationale going to be important anymore? Probably not that important now. Manifold will only compose disjoint objects (i.e. same as lazy union, but written into the same mesh). If objects are intersecting, we will compute their union, but it is in general still pretty fast. We also optimize the union order to minimize overall time.