discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Behaviour of 2D in 3D space?

RS
Rob Sherwood
Fri, Apr 12, 2019 6:07 AM

Thank you for the super detailed reply!  I'm going to have to think about
redesigning some of my work based on this.

As an aside, the computer science person in me wonders if it's not possible
to reduce the complexity of the designs algorithmically rather than
changing the input (e.g., make the compiler smarter rather than the
programmer), but that's probably complex...

Thank you again!

  • Rob
    .

On Wed, Apr 10, 2019 at 10:24 AM nop head nop.head@gmail.com wrote:

Here is simple example. I have these printed knobs that take a hex screw.
They are printed upside down with a complicated hanging hole that can be
printed without support material.  See
http://hydraraptor.blogspot.com/2014/03/buried-nuts-and-hanging-holes.html

[image: image.png]

They were taking six seconds to preview when wrapped with render() because
the hole is being subtracted from a complex shape in 3D. This was the
original code

knob_wall = 2;
function knob_nut_trap_depth(screw) =
round_to_layer(screw_head_height(screw));
knob_stem_h = 6;
knob_thickness = 4;
knob_r = 8;
knob_wave = 1;
knob_waves = 9;
knob_height = knob_stem_h + knob_thickness;
function knob_height() = knob_height;

module screw_knob(screw) {
stl(str("screw_knob_M", screw_radius(screw) * 20));

 knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall;

 function wave(a) = knob_r + sin(a * knob_waves) * knob_wave;

 render() difference() {
     union() {
         cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);

         linear_extrude(height = knob_thickness, convexity = 3)
             polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a),

wave(a) * cos(a)]]);
}
hanging_hole(knob_nut_trap_depth(screw),
screw_clearance_radius(screw))
rotate(45)
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
}

To make it faster I now have this:

module screw_knob(screw) {
stl(str("screw_knob_M", screw_radius(screw) * 20));

 knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall;

 function wave(a) = knob_r + sin(a * knob_waves) * knob_wave;

 union() {
     render() difference() {
         cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);

         hanging_hole(knob_nut_trap_depth(screw),

screw_clearance_radius(screw))
rotate(45)
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
linear_extrude(height = knob_thickness, convexity = 3)
difference() {
polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a),
wave(a) * cos(a)]]);

             circle(knob_stem_r - eps);
         }
 }

}

The differences is now a on a plain cylinder, so is a lot faster because
there are less vertices and CGAL slows with the square of the vertices I
think.

[image: image.png]

I then union with the outer bit, which I make with a slightly smaller
hole in the middle. That is very fast because it is an extruded 2D shape
and I don't need to use CGAL when previewing unions.

[image: image.png]

So my test which draws two difference sizes goes from 6 seconds, to 0
seconds.

[image: image.png]

Another thing I found is avoiding any unions inside a 3D hull by using
repetition instead of for loops and not using translations or rotations to
operate on more than one child as that does a union as well. Same with if.
I.e. I repeat the if or the translation instead of using one with braces.
This even speeds up difference but the code gets uglier and uglier.

E.g. This handle which also prints without support material was very slow

[image: image.png]

module handle_stl() {
stl("handle");

 render() difference() {
     translate_z(dia / 2)
         union() {
             hull()
                 handle_screw_positions()
                     rotate_extrude()
                         intersection() {
                             rotate(180)
                                 teardrop_2D(r = dia / 2);

                             translate([0, - (dia + 1) / 2])
                                 square([dia / 2 + 1, dia + 1]);
                         }
             handle_screw_positions()
                 cylinder(d = dia, h = height + dia / 2);
         }

     handle_screw_positions()
         translate_z(dia + height) {
             insert_hole(insert);

             poly_cylinder(r = screw_clearance_radius(screw), h =

(insert_length(insert) + 6) * 2, center = true);
}
}
}

I got it down to a couple of seconds like this:

module handle_stl() {
stl("handle");

 module end(end)
     translate([end * pitch / 2, 0])
         rotate_extrude()
             intersection() {
                 rotate(180)
                     teardrop(r = dia / 2, h = 0);

                 translate([0, - (dia + 1) / 2])
                     square([dia / 2 + 1, dia + 1]);
             }

 translate_z(dia / 2)
     union() {
         hull() {
             end(-1);

             end(1);
         }

         handle_screw_positions()
             render() difference() {
                 h =  height + dia / 2;
                 cylinder(d = dia, h = h);

                 translate_z(h)
                     insert_hole(insert, 6);
             }
     }

}

Again moving the subtraction to a simple cylinder and placing the ends in
the hull with repetition instead of a loop to avoid unioning two objects
with a lot of vertices before the hull is taken.

On Wed, 10 Apr 2019 at 17:38, Rob Sherwood rob.sherwood@gmail.com wrote:

Fascinating work - thank you!  I’ve has complicated designs (e.g.,
complex compound planetary gears) that take up to 30 minutes (!!) to
render.  I’ll have to rethink parts of it using your insights.

Any thoughts about posting some example code?

Cheers,

  • Rob
    .

On Mon, Apr 8, 2019 at 10:56 AM nop head nop.head@gmail.com wrote:

I have been going through all my objects rewriting them to be unions of
extruded 2D objects to avoid as many 3D differences and  intersections as I
can. By doing that I have reduced the time to draw all my objects from 972
seconds to 194.

I have learned a few tricks on the way to make things that look
inescapably 3D out unions of extruded 2D. For example these draw in 0
seconds. I think they used to take about 17.

[image: image.png]

I previously made the cavities by subtracting two linear extrudes. That
takes ages because I render all differences with CGAL to avoid clashes
between negative objects and the curved cavities have lots of vertices. I
now linear extrude the difference to make the walls of the cavity and then
fill in the back with another linear extrude.

The countersinks are creative because on the face of it you need to
subtract 3D shapes. What I actually do is put some slightly bigger straight
holes in the linear_extrude() of the flange by subtracting circles. I then
rotate_extrude a cylinder with the counter sunk hole in it and union those
into the holes in the flange. Union is free in preview because it just
draws both parts and there is never any z-fighting if they are the same
colour.

I did the opposite thing with countersunk, pan and dome screw heads.

[image: image.png]

I rotate extrude the basic shape of the head with a cylinder missing
where the slots go and the linear extrude a circle with the slot cut in it
and inlay it into the head.

It has taken me weeks because I have had to re-code everything, moving
all the differences and intersections into 2D.

On Mon, 8 Apr 2019 at 16:44, lar3ry@sasktel.net wrote:

On 7 Apr 2019 at 23:34, Troberg wrote:

I keep 2D objects in the XY plane. I don't think they were ever

intended to

exist in a 3D space, and that's why you get that result.

That brings up something that has always made me wonder. In the docs,
the example of
making a torus using a rotate_extrude of a circle, just doesn't make
sense to me. The circle
is in the X/Y plane, but the extruded object looks like the circle has
been rotated before being
extruded.

One thing this discussion has done for me is to point out just how many
ways one can use
2D objects to create some rather interesting shapes.

--
Magic trumps science for most people,
and wishful thinking drives a lot of decision-making.
- Joe Haldeman


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

Thank you for the super detailed reply! I'm going to have to think about redesigning some of my work based on this. As an aside, the computer science person in me wonders if it's not possible to reduce the complexity of the designs algorithmically rather than changing the input (e.g., make the compiler smarter rather than the programmer), but that's probably complex... Thank you again! - Rob . On Wed, Apr 10, 2019 at 10:24 AM nop head <nop.head@gmail.com> wrote: > Here is simple example. I have these printed knobs that take a hex screw. > They are printed upside down with a complicated hanging hole that can be > printed without support material. See > http://hydraraptor.blogspot.com/2014/03/buried-nuts-and-hanging-holes.html > > [image: image.png] > > They were taking six seconds to preview when wrapped with render() because > the hole is being subtracted from a complex shape in 3D. This was the > original code > > knob_wall = 2; > function knob_nut_trap_depth(screw) = > round_to_layer(screw_head_height(screw)); > knob_stem_h = 6; > knob_thickness = 4; > knob_r = 8; > knob_wave = 1; > knob_waves = 9; > knob_height = knob_stem_h + knob_thickness; > function knob_height() = knob_height; > > module screw_knob(screw) { > stl(str("screw_knob_M", screw_radius(screw) * 20)); > > knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall; > > function wave(a) = knob_r + sin(a * knob_waves) * knob_wave; > > render() difference() { > union() { > cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h); > > linear_extrude(height = knob_thickness, convexity = 3) > polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), > wave(a) * cos(a)]]); > } > hanging_hole(knob_nut_trap_depth(screw), > screw_clearance_radius(screw)) > rotate(45) > circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6); > } > } > > To make it faster I now have this: > > module screw_knob(screw) { > stl(str("screw_knob_M", screw_radius(screw) * 20)); > > knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall; > > function wave(a) = knob_r + sin(a * knob_waves) * knob_wave; > > union() { > render() difference() { > cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h); > > hanging_hole(knob_nut_trap_depth(screw), > screw_clearance_radius(screw)) > rotate(45) > circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6); > } > linear_extrude(height = knob_thickness, convexity = 3) > difference() { > polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), > wave(a) * cos(a)]]); > > circle(knob_stem_r - eps); > } > } > } > > The differences is now a on a plain cylinder, so is a lot faster because > there are less vertices and CGAL slows with the square of the vertices I > think. > > [image: image.png] > > I then union with the outer bit, which I make with a slightly smaller > hole in the middle. That is very fast because it is an extruded 2D shape > and I don't need to use CGAL when previewing unions. > > [image: image.png] > > So my test which draws two difference sizes goes from 6 seconds, to 0 > seconds. > > [image: image.png] > > Another thing I found is avoiding any unions inside a 3D hull by using > repetition instead of for loops and not using translations or rotations to > operate on more than one child as that does a union as well. Same with if. > I.e. I repeat the if or the translation instead of using one with braces. > This even speeds up difference but the code gets uglier and uglier. > > E.g. This handle which also prints without support material was very slow > > [image: image.png] > > module handle_stl() { > stl("handle"); > > render() difference() { > translate_z(dia / 2) > union() { > hull() > handle_screw_positions() > rotate_extrude() > intersection() { > rotate(180) > teardrop_2D(r = dia / 2); > > translate([0, - (dia + 1) / 2]) > square([dia / 2 + 1, dia + 1]); > } > handle_screw_positions() > cylinder(d = dia, h = height + dia / 2); > } > > handle_screw_positions() > translate_z(dia + height) { > insert_hole(insert); > > poly_cylinder(r = screw_clearance_radius(screw), h = > (insert_length(insert) + 6) * 2, center = true); > } > } > } > > I got it down to a couple of seconds like this: > > module handle_stl() { > stl("handle"); > > module end(end) > translate([end * pitch / 2, 0]) > rotate_extrude() > intersection() { > rotate(180) > teardrop(r = dia / 2, h = 0); > > translate([0, - (dia + 1) / 2]) > square([dia / 2 + 1, dia + 1]); > } > > translate_z(dia / 2) > union() { > hull() { > end(-1); > > end(1); > } > > handle_screw_positions() > render() difference() { > h = height + dia / 2; > cylinder(d = dia, h = h); > > translate_z(h) > insert_hole(insert, 6); > } > } > } > > Again moving the subtraction to a simple cylinder and placing the ends in > the hull with repetition instead of a loop to avoid unioning two objects > with a lot of vertices before the hull is taken. > > On Wed, 10 Apr 2019 at 17:38, Rob Sherwood <rob.sherwood@gmail.com> wrote: > >> Fascinating work - thank you! I’ve has complicated designs (e.g., >> complex compound planetary gears) that take up to 30 minutes (!!) to >> render. I’ll have to rethink parts of it using your insights. >> >> Any thoughts about posting some example code? >> >> Cheers, >> >> - Rob >> . >> >> On Mon, Apr 8, 2019 at 10:56 AM nop head <nop.head@gmail.com> wrote: >> >>> I have been going through all my objects rewriting them to be unions of >>> extruded 2D objects to avoid as many 3D differences and intersections as I >>> can. By doing that I have reduced the time to draw all my objects from 972 >>> seconds to 194. >>> >>> I have learned a few tricks on the way to make things that look >>> inescapably 3D out unions of extruded 2D. For example these draw in 0 >>> seconds. I think they used to take about 17. >>> >>> [image: image.png] >>> >>> I previously made the cavities by subtracting two linear extrudes. That >>> takes ages because I render all differences with CGAL to avoid clashes >>> between negative objects and the curved cavities have lots of vertices. I >>> now linear extrude the difference to make the walls of the cavity and then >>> fill in the back with another linear extrude. >>> >>> The countersinks are creative because on the face of it you need to >>> subtract 3D shapes. What I actually do is put some slightly bigger straight >>> holes in the linear_extrude() of the flange by subtracting circles. I then >>> rotate_extrude a cylinder with the counter sunk hole in it and union those >>> into the holes in the flange. Union is free in preview because it just >>> draws both parts and there is never any z-fighting if they are the same >>> colour. >>> >>> I did the opposite thing with countersunk, pan and dome screw heads. >>> >>> [image: image.png] >>> >>> I rotate extrude the basic shape of the head with a cylinder missing >>> where the slots go and the linear extrude a circle with the slot cut in it >>> and inlay it into the head. >>> >>> It has taken me weeks because I have had to re-code everything, moving >>> all the differences and intersections into 2D. >>> >>> >>> On Mon, 8 Apr 2019 at 16:44, <lar3ry@sasktel.net> wrote: >>> >>>> On 7 Apr 2019 at 23:34, Troberg wrote: >>>> > I keep 2D objects in the XY plane. I don't think they were ever >>>> intended to >>>> > exist in a 3D space, and that's why you get that result. >>>> >>>> That brings up something that has always made me wonder. In the docs, >>>> the example of >>>> making a torus using a rotate_extrude of a circle, just doesn't make >>>> sense to me. The circle >>>> is in the X/Y plane, but the extruded object looks like the circle has >>>> been rotated before being >>>> extruded. >>>> >>>> One thing this discussion has done for me is to point out just how many >>>> ways one can use >>>> 2D objects to create some rather interesting shapes. >>>> >>>> >>>> -- >>>> Magic trumps science for most people, >>>> and wishful thinking drives a lot of decision-making. >>>> - Joe Haldeman >>>> >>>> >>>> _______________________________________________ >>>> OpenSCAD mailing list >>>> Discuss@lists.openscad.org >>>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>>> >>> _______________________________________________ >>> OpenSCAD mailing list >>> Discuss@lists.openscad.org >>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>> >> _______________________________________________ >> OpenSCAD mailing list >> Discuss@lists.openscad.org >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
NH
nop head
Fri, Apr 12, 2019 7:02 AM

Allowing modules to return multiple children and getting rid of implicit
unions that are only there to force one child would be a big
improvement.That would avoid the need to unroll code to make it faster. It
would also make children(i) work properly.

Reordering the operands to union and difference to have the low vertices
ones first (second for difference) should not be too hard.

Decomposing everything into union of 2D extrusions would be difficult to
automate. It is only necessary because CGAL is so slow.

I think there is a lot of scope to make CGAL go faster because it seems to
depend on the number of vertices, regardless of whether they take part in
the union or difference. I.e. the union of two non-overlapping objects is
slow but it should be easy to simply concatenate the polyhedra when their
bounding boxes don't intersect. Also many faces in a union or difference
don't need modifying. For example a hole down the middle of a cylinder only
changes the endcaps but it it gets much slower with facets around the edge,
which should simply be passed through to the result. The slow bit should be
where the objects overlap and new vertices and facets need to be generated.
Perhaps there is something I don't understand but these seem easy
optimisations inside CGAL.

On Fri, 12 Apr 2019 at 07:08, Rob Sherwood rob.sherwood@gmail.com wrote:

Thank you for the super detailed reply!  I'm going to have to think about
redesigning some of my work based on this.

As an aside, the computer science person in me wonders if it's not
possible to reduce the complexity of the designs algorithmically rather
than changing the input (e.g., make the compiler smarter rather than the
programmer), but that's probably complex...

Thank you again!

  • Rob
    .

On Wed, Apr 10, 2019 at 10:24 AM nop head nop.head@gmail.com wrote:

Here is simple example. I have these printed knobs that take a hex screw.
They are printed upside down with a complicated hanging hole that can be
printed without support material.  See
http://hydraraptor.blogspot.com/2014/03/buried-nuts-and-hanging-holes.html

[image: image.png]

They were taking six seconds to preview when wrapped with render()
because the hole is being subtracted from a complex shape in 3D. This was
the original code

knob_wall = 2;
function knob_nut_trap_depth(screw) =
round_to_layer(screw_head_height(screw));
knob_stem_h = 6;
knob_thickness = 4;
knob_r = 8;
knob_wave = 1;
knob_waves = 9;
knob_height = knob_stem_h + knob_thickness;
function knob_height() = knob_height;

module screw_knob(screw) {
stl(str("screw_knob_M", screw_radius(screw) * 20));

 knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall;

 function wave(a) = knob_r + sin(a * knob_waves) * knob_wave;

 render() difference() {
     union() {
         cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);

         linear_extrude(height = knob_thickness, convexity = 3)
             polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a),

wave(a) * cos(a)]]);
}
hanging_hole(knob_nut_trap_depth(screw),
screw_clearance_radius(screw))
rotate(45)
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
}

To make it faster I now have this:

module screw_knob(screw) {
stl(str("screw_knob_M", screw_radius(screw) * 20));

 knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall;

 function wave(a) = knob_r + sin(a * knob_waves) * knob_wave;

 union() {
     render() difference() {
         cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);

         hanging_hole(knob_nut_trap_depth(screw),

screw_clearance_radius(screw))
rotate(45)
circle(r = nut_trap_radius(screw_nut(screw)), $fn =
6);
}
linear_extrude(height = knob_thickness, convexity = 3)
difference() {
polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a),
wave(a) * cos(a)]]);

             circle(knob_stem_r - eps);
         }
 }

}

The differences is now a on a plain cylinder, so is a lot faster because
there are less vertices and CGAL slows with the square of the vertices I
think.

[image: image.png]

I then union with the outer bit, which I make with a slightly smaller
hole in the middle. That is very fast because it is an extruded 2D shape
and I don't need to use CGAL when previewing unions.

[image: image.png]

So my test which draws two difference sizes goes from 6 seconds, to 0
seconds.

[image: image.png]

Another thing I found is avoiding any unions inside a 3D hull by using
repetition instead of for loops and not using translations or rotations to
operate on more than one child as that does a union as well. Same with if.
I.e. I repeat the if or the translation instead of using one with braces.
This even speeds up difference but the code gets uglier and uglier.

E.g. This handle which also prints without support material was very slow

[image: image.png]

module handle_stl() {
stl("handle");

 render() difference() {
     translate_z(dia / 2)
         union() {
             hull()
                 handle_screw_positions()
                     rotate_extrude()
                         intersection() {
                             rotate(180)
                                 teardrop_2D(r = dia / 2);

                             translate([0, - (dia + 1) / 2])
                                 square([dia / 2 + 1, dia + 1]);
                         }
             handle_screw_positions()
                 cylinder(d = dia, h = height + dia / 2);
         }

     handle_screw_positions()
         translate_z(dia + height) {
             insert_hole(insert);

             poly_cylinder(r = screw_clearance_radius(screw), h =

(insert_length(insert) + 6) * 2, center = true);
}
}
}

I got it down to a couple of seconds like this:

module handle_stl() {
stl("handle");

 module end(end)
     translate([end * pitch / 2, 0])
         rotate_extrude()
             intersection() {
                 rotate(180)
                     teardrop(r = dia / 2, h = 0);

                 translate([0, - (dia + 1) / 2])
                     square([dia / 2 + 1, dia + 1]);
             }

 translate_z(dia / 2)
     union() {
         hull() {
             end(-1);

             end(1);
         }

         handle_screw_positions()
             render() difference() {
                 h =  height + dia / 2;
                 cylinder(d = dia, h = h);

                 translate_z(h)
                     insert_hole(insert, 6);
             }
     }

}

Again moving the subtraction to a simple cylinder and placing the ends in
the hull with repetition instead of a loop to avoid unioning two objects
with a lot of vertices before the hull is taken.

On Wed, 10 Apr 2019 at 17:38, Rob Sherwood rob.sherwood@gmail.com
wrote:

Fascinating work - thank you!  I’ve has complicated designs (e.g.,
complex compound planetary gears) that take up to 30 minutes (!!) to
render.  I’ll have to rethink parts of it using your insights.

Any thoughts about posting some example code?

Cheers,

  • Rob
    .

On Mon, Apr 8, 2019 at 10:56 AM nop head nop.head@gmail.com wrote:

I have been going through all my objects rewriting them to be unions of
extruded 2D objects to avoid as many 3D differences and  intersections as I
can. By doing that I have reduced the time to draw all my objects from 972
seconds to 194.

I have learned a few tricks on the way to make things that look
inescapably 3D out unions of extruded 2D. For example these draw in 0
seconds. I think they used to take about 17.

[image: image.png]

I previously made the cavities by subtracting two linear extrudes. That
takes ages because I render all differences with CGAL to avoid clashes
between negative objects and the curved cavities have lots of vertices. I
now linear extrude the difference to make the walls of the cavity and then
fill in the back with another linear extrude.

The countersinks are creative because on the face of it you need to
subtract 3D shapes. What I actually do is put some slightly bigger straight
holes in the linear_extrude() of the flange by subtracting circles. I then
rotate_extrude a cylinder with the counter sunk hole in it and union those
into the holes in the flange. Union is free in preview because it just
draws both parts and there is never any z-fighting if they are the same
colour.

I did the opposite thing with countersunk, pan and dome screw heads.

[image: image.png]

I rotate extrude the basic shape of the head with a cylinder missing
where the slots go and the linear extrude a circle with the slot cut in it
and inlay it into the head.

It has taken me weeks because I have had to re-code everything, moving
all the differences and intersections into 2D.

On Mon, 8 Apr 2019 at 16:44, lar3ry@sasktel.net wrote:

On 7 Apr 2019 at 23:34, Troberg wrote:

I keep 2D objects in the XY plane. I don't think they were ever

intended to

exist in a 3D space, and that's why you get that result.

That brings up something that has always made me wonder. In the docs,
the example of
making a torus using a rotate_extrude of a circle, just doesn't make
sense to me. The circle
is in the X/Y plane, but the extruded object looks like the circle has
been rotated before being
extruded.

One thing this discussion has done for me is to point out just how
many ways one can use
2D objects to create some rather interesting shapes.

--
Magic trumps science for most people,
and wishful thinking drives a lot of decision-making.
- Joe Haldeman


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

Allowing modules to return multiple children and getting rid of implicit unions that are only there to force one child would be a big improvement.That would avoid the need to unroll code to make it faster. It would also make children(i) work properly. Reordering the operands to union and difference to have the low vertices ones first (second for difference) should not be too hard. Decomposing everything into union of 2D extrusions would be difficult to automate. It is only necessary because CGAL is so slow. I think there is a lot of scope to make CGAL go faster because it seems to depend on the number of vertices, regardless of whether they take part in the union or difference. I.e. the union of two non-overlapping objects is slow but it should be easy to simply concatenate the polyhedra when their bounding boxes don't intersect. Also many faces in a union or difference don't need modifying. For example a hole down the middle of a cylinder only changes the endcaps but it it gets much slower with facets around the edge, which should simply be passed through to the result. The slow bit should be where the objects overlap and new vertices and facets need to be generated. Perhaps there is something I don't understand but these seem easy optimisations inside CGAL. On Fri, 12 Apr 2019 at 07:08, Rob Sherwood <rob.sherwood@gmail.com> wrote: > Thank you for the super detailed reply! I'm going to have to think about > redesigning some of my work based on this. > > As an aside, the computer science person in me wonders if it's not > possible to reduce the complexity of the designs algorithmically rather > than changing the input (e.g., make the compiler smarter rather than the > programmer), but that's probably complex... > > Thank you again! > > - Rob > . > > On Wed, Apr 10, 2019 at 10:24 AM nop head <nop.head@gmail.com> wrote: > >> Here is simple example. I have these printed knobs that take a hex screw. >> They are printed upside down with a complicated hanging hole that can be >> printed without support material. See >> http://hydraraptor.blogspot.com/2014/03/buried-nuts-and-hanging-holes.html >> >> [image: image.png] >> >> They were taking six seconds to preview when wrapped with render() >> because the hole is being subtracted from a complex shape in 3D. This was >> the original code >> >> knob_wall = 2; >> function knob_nut_trap_depth(screw) = >> round_to_layer(screw_head_height(screw)); >> knob_stem_h = 6; >> knob_thickness = 4; >> knob_r = 8; >> knob_wave = 1; >> knob_waves = 9; >> knob_height = knob_stem_h + knob_thickness; >> function knob_height() = knob_height; >> >> module screw_knob(screw) { >> stl(str("screw_knob_M", screw_radius(screw) * 20)); >> >> knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall; >> >> function wave(a) = knob_r + sin(a * knob_waves) * knob_wave; >> >> render() difference() { >> union() { >> cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h); >> >> linear_extrude(height = knob_thickness, convexity = 3) >> polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), >> wave(a) * cos(a)]]); >> } >> hanging_hole(knob_nut_trap_depth(screw), >> screw_clearance_radius(screw)) >> rotate(45) >> circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6); >> } >> } >> >> To make it faster I now have this: >> >> module screw_knob(screw) { >> stl(str("screw_knob_M", screw_radius(screw) * 20)); >> >> knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall; >> >> function wave(a) = knob_r + sin(a * knob_waves) * knob_wave; >> >> union() { >> render() difference() { >> cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h); >> >> hanging_hole(knob_nut_trap_depth(screw), >> screw_clearance_radius(screw)) >> rotate(45) >> circle(r = nut_trap_radius(screw_nut(screw)), $fn = >> 6); >> } >> linear_extrude(height = knob_thickness, convexity = 3) >> difference() { >> polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), >> wave(a) * cos(a)]]); >> >> circle(knob_stem_r - eps); >> } >> } >> } >> >> The differences is now a on a plain cylinder, so is a lot faster because >> there are less vertices and CGAL slows with the square of the vertices I >> think. >> >> [image: image.png] >> >> I then union with the outer bit, which I make with a slightly smaller >> hole in the middle. That is very fast because it is an extruded 2D shape >> and I don't need to use CGAL when previewing unions. >> >> [image: image.png] >> >> So my test which draws two difference sizes goes from 6 seconds, to 0 >> seconds. >> >> [image: image.png] >> >> Another thing I found is avoiding any unions inside a 3D hull by using >> repetition instead of for loops and not using translations or rotations to >> operate on more than one child as that does a union as well. Same with if. >> I.e. I repeat the if or the translation instead of using one with braces. >> This even speeds up difference but the code gets uglier and uglier. >> >> E.g. This handle which also prints without support material was very slow >> >> [image: image.png] >> >> module handle_stl() { >> stl("handle"); >> >> render() difference() { >> translate_z(dia / 2) >> union() { >> hull() >> handle_screw_positions() >> rotate_extrude() >> intersection() { >> rotate(180) >> teardrop_2D(r = dia / 2); >> >> translate([0, - (dia + 1) / 2]) >> square([dia / 2 + 1, dia + 1]); >> } >> handle_screw_positions() >> cylinder(d = dia, h = height + dia / 2); >> } >> >> handle_screw_positions() >> translate_z(dia + height) { >> insert_hole(insert); >> >> poly_cylinder(r = screw_clearance_radius(screw), h = >> (insert_length(insert) + 6) * 2, center = true); >> } >> } >> } >> >> I got it down to a couple of seconds like this: >> >> module handle_stl() { >> stl("handle"); >> >> module end(end) >> translate([end * pitch / 2, 0]) >> rotate_extrude() >> intersection() { >> rotate(180) >> teardrop(r = dia / 2, h = 0); >> >> translate([0, - (dia + 1) / 2]) >> square([dia / 2 + 1, dia + 1]); >> } >> >> translate_z(dia / 2) >> union() { >> hull() { >> end(-1); >> >> end(1); >> } >> >> handle_screw_positions() >> render() difference() { >> h = height + dia / 2; >> cylinder(d = dia, h = h); >> >> translate_z(h) >> insert_hole(insert, 6); >> } >> } >> } >> >> Again moving the subtraction to a simple cylinder and placing the ends in >> the hull with repetition instead of a loop to avoid unioning two objects >> with a lot of vertices before the hull is taken. >> >> On Wed, 10 Apr 2019 at 17:38, Rob Sherwood <rob.sherwood@gmail.com> >> wrote: >> >>> Fascinating work - thank you! I’ve has complicated designs (e.g., >>> complex compound planetary gears) that take up to 30 minutes (!!) to >>> render. I’ll have to rethink parts of it using your insights. >>> >>> Any thoughts about posting some example code? >>> >>> Cheers, >>> >>> - Rob >>> . >>> >>> On Mon, Apr 8, 2019 at 10:56 AM nop head <nop.head@gmail.com> wrote: >>> >>>> I have been going through all my objects rewriting them to be unions of >>>> extruded 2D objects to avoid as many 3D differences and intersections as I >>>> can. By doing that I have reduced the time to draw all my objects from 972 >>>> seconds to 194. >>>> >>>> I have learned a few tricks on the way to make things that look >>>> inescapably 3D out unions of extruded 2D. For example these draw in 0 >>>> seconds. I think they used to take about 17. >>>> >>>> [image: image.png] >>>> >>>> I previously made the cavities by subtracting two linear extrudes. That >>>> takes ages because I render all differences with CGAL to avoid clashes >>>> between negative objects and the curved cavities have lots of vertices. I >>>> now linear extrude the difference to make the walls of the cavity and then >>>> fill in the back with another linear extrude. >>>> >>>> The countersinks are creative because on the face of it you need to >>>> subtract 3D shapes. What I actually do is put some slightly bigger straight >>>> holes in the linear_extrude() of the flange by subtracting circles. I then >>>> rotate_extrude a cylinder with the counter sunk hole in it and union those >>>> into the holes in the flange. Union is free in preview because it just >>>> draws both parts and there is never any z-fighting if they are the same >>>> colour. >>>> >>>> I did the opposite thing with countersunk, pan and dome screw heads. >>>> >>>> [image: image.png] >>>> >>>> I rotate extrude the basic shape of the head with a cylinder missing >>>> where the slots go and the linear extrude a circle with the slot cut in it >>>> and inlay it into the head. >>>> >>>> It has taken me weeks because I have had to re-code everything, moving >>>> all the differences and intersections into 2D. >>>> >>>> >>>> On Mon, 8 Apr 2019 at 16:44, <lar3ry@sasktel.net> wrote: >>>> >>>>> On 7 Apr 2019 at 23:34, Troberg wrote: >>>>> > I keep 2D objects in the XY plane. I don't think they were ever >>>>> intended to >>>>> > exist in a 3D space, and that's why you get that result. >>>>> >>>>> That brings up something that has always made me wonder. In the docs, >>>>> the example of >>>>> making a torus using a rotate_extrude of a circle, just doesn't make >>>>> sense to me. The circle >>>>> is in the X/Y plane, but the extruded object looks like the circle has >>>>> been rotated before being >>>>> extruded. >>>>> >>>>> One thing this discussion has done for me is to point out just how >>>>> many ways one can use >>>>> 2D objects to create some rather interesting shapes. >>>>> >>>>> >>>>> -- >>>>> Magic trumps science for most people, >>>>> and wishful thinking drives a lot of decision-making. >>>>> - Joe Haldeman >>>>> >>>>> >>>>> _______________________________________________ >>>>> OpenSCAD mailing list >>>>> Discuss@lists.openscad.org >>>>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>>>> >>>> _______________________________________________ >>>> OpenSCAD mailing list >>>> Discuss@lists.openscad.org >>>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>>> >>> _______________________________________________ >>> OpenSCAD mailing list >>> Discuss@lists.openscad.org >>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>> >> _______________________________________________ >> OpenSCAD mailing list >> Discuss@lists.openscad.org >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
RW
Rogier Wolff
Sun, Apr 14, 2019 6:19 AM

On Fri, Apr 12, 2019 at 08:02:20AM +0100, nop head wrote:

The slow bit should be
where the objects overlap and new vertices and facets need to be generated.
Perhaps there is something I don't understand but these seem easy
optimisations inside CGAL.

YOU have the 3D insight that the facets of the cylinder have no chance
of interfering with the hole down the middle. Computers need to "do
the math" and check every vertex / facet against the to-be-subtracted
cylinder to find out that they indeed do not mess with eachother.

Roger.

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.

On Fri, Apr 12, 2019 at 08:02:20AM +0100, nop head wrote: > The slow bit should be > where the objects overlap and new vertices and facets need to be generated. > Perhaps there is something I don't understand but these seem easy > optimisations inside CGAL. YOU have the 3D insight that the facets of the cylinder have no chance of interfering with the hole down the middle. Computers need to "do the math" and check every vertex / facet against the to-be-subtracted cylinder to find out that they indeed do not mess with eachother. Roger. -- ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 ** ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** The plan was simple, like my brother-in-law Phil. But unlike Phil, this plan just might work.
NH
nop head
Sun, Apr 14, 2019 7:27 AM

Yes the faces that don't intersect with any others need to be checked to
know they can be passed through intact, but surely that doesn't take
seconds on a processor running at GHz. A crude test like looking if the
bounding boxes overlap would eliminate most of the faces in a typical union
or difference.

On Sun, 14 Apr 2019 at 07:20, Rogier Wolff R.E.Wolff@bitwizard.nl wrote:

On Fri, Apr 12, 2019 at 08:02:20AM +0100, nop head wrote:

The slow bit should be
where the objects overlap and new vertices and facets need to be

generated.

Perhaps there is something I don't understand but these seem easy
optimisations inside CGAL.

YOU have the 3D insight that the facets of the cylinder have no chance
of interfering with the hole down the middle. Computers need to "do
the math" and check every vertex / facet against the to-be-subtracted
cylinder to find out that they indeed do not mess with eachother.

     Roger.

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110
**
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.


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

Yes the faces that don't intersect with any others need to be checked to know they can be passed through intact, but surely that doesn't take seconds on a processor running at GHz. A crude test like looking if the bounding boxes overlap would eliminate most of the faces in a typical union or difference. On Sun, 14 Apr 2019 at 07:20, Rogier Wolff <R.E.Wolff@bitwizard.nl> wrote: > On Fri, Apr 12, 2019 at 08:02:20AM +0100, nop head wrote: > > The slow bit should be > > where the objects overlap and new vertices and facets need to be > generated. > > Perhaps there is something I don't understand but these seem easy > > optimisations inside CGAL. > > YOU have the 3D insight that the facets of the cylinder have no chance > of interfering with the hole down the middle. Computers need to "do > the math" and check every vertex / facet against the to-be-subtracted > cylinder to find out that they indeed do not mess with eachother. > > Roger. > > -- > ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 > ** > ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** > The plan was simple, like my brother-in-law Phil. But unlike > Phil, this plan just might work. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
RS
Rob Sherwood
Sun, Apr 14, 2019 8:34 PM

I’m not sure I agree with the statement “computers need to do the math and
check every vertex”.  All sorts of possible optimizations exist for this
type of computation including precomputing binary space partitions
and/oct-trees to avoid the N^2 vertex check.  Cgal may not implement these
(which is absolutely fine) but I don’t believe this is an inherent
limitation.  Because all of the vertices are in a Euclidean space (e.g.,
where the triangle inequality applies), if face A does not intersect face
B, then it’s not possible for face A to intersect any face C where all of
the vertices are further from A than the vertices of B.

I’m not trying to nit pick but if some aspiring young programmer out there
wants to take a spin at improving this, I wouldn’t want anyone to think
it’s an  impossible task.

  • Rob
    .

On Sat, Apr 13, 2019 at 11:20 PM Rogier Wolff R.E.Wolff@bitwizard.nl
wrote:

On Fri, Apr 12, 2019 at 08:02:20AM +0100, nop head wrote:

The slow bit should be
where the objects overlap and new vertices and facets need to be

generated.

Perhaps there is something I don't understand but these seem easy
optimisations inside CGAL.

YOU have the 3D insight that the facets of the cylinder have no chance
of interfering with the hole down the middle. Computers need to "do
the math" and check every vertex / facet against the to-be-subtracted
cylinder to find out that they indeed do not mess with eachother.

     Roger.

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110
**
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.


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

I’m not sure I agree with the statement “computers need to do the math and check every vertex”. All sorts of possible optimizations exist for this type of computation including precomputing binary space partitions and/oct-trees to avoid the N^2 vertex check. Cgal may not implement these (which is absolutely fine) but I don’t believe this is an inherent limitation. Because all of the vertices are in a Euclidean space (e.g., where the triangle inequality applies), if face A does not intersect face B, then it’s not possible for face A to intersect any face C where all of the vertices are further from A than the vertices of B. I’m not trying to nit pick but if some aspiring young programmer out there wants to take a spin at improving this, I wouldn’t want anyone to think it’s an impossible task. - Rob . On Sat, Apr 13, 2019 at 11:20 PM Rogier Wolff <R.E.Wolff@bitwizard.nl> wrote: > On Fri, Apr 12, 2019 at 08:02:20AM +0100, nop head wrote: > > The slow bit should be > > where the objects overlap and new vertices and facets need to be > generated. > > Perhaps there is something I don't understand but these seem easy > > optimisations inside CGAL. > > YOU have the 3D insight that the facets of the cylinder have no chance > of interfering with the hole down the middle. Computers need to "do > the math" and check every vertex / facet against the to-be-subtracted > cylinder to find out that they indeed do not mess with eachother. > > Roger. > > -- > ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 > ** > ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** > The plan was simple, like my brother-in-law Phil. But unlike > Phil, this plan just might work. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >