I have just published my universal OpenSCAD fidget spinner model: https://www.thingiverse.com/thing:2360208
Calculating the three circle Apollonius problem in OpenSCAD was a pretty challenge, but what really frustrated me was rounding off the edges of the final profile. I finally settled on minkowski sum with a sphere on a minimal height 2D profile extrusion, but for a high resolution model it takes about ten minutes to calculate. Is there any more efficient way to round these edges than this? I don't see how I can use hull() in this case. 
On 20170602 08:48, jsc wrote:
> Is there any more efficient way to round these edges than this? I don't see > how I can use hull() in this case. Maybe change your current linear extrude to several of them in a for loop and use the loop variable in some interesting way to change the value of offset. I put this in spinner_preview and it looks OK. Crank up slices based on whether previewing or not? slices = 50; curve = bearing_height/2; for (s = [0 : 1 : slices1]) translate ([0, 0, bearing_height/slices*s]) linear_extrude(height = bearing_height/slices+0.01, center = true) offset (curve*(1cos((s/slices0.5)*180))) profile(); The offset function is down to you and could easily be flat in the middle and then just curve at top and bottom. If you can handle Apollonius ... _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
> I put this in spinner_preview and it looks OK. Crank up slices based
on whether previewing or not? Hmm, still pretty slow at rendering, but could use plain extrude for the middle and just some offset slices at top and bottom? Or change approach and use rounded cylinders to construct your spinner? _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
Sorry, should be "offset (delta= ..." but maybe that's default?
You also may want to remove the bearing and weights as 2D objects and the offset can then apply to those too so the inner holes are chamfered, but maybe you don't actually want this? _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
In reply to this post by jsc
In your particular case of filleting circular forms, a faster method is to union rotated extrusions. The snapshot versions of OpenSCAD allow to prescribe an angle in the rotate_extrude to help things go easier. 20170602 4:48 GMT03:00 jsc <[hidden email]>: I have just published my universal OpenSCAD fidget spinner model: _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
In reply to this post by Gadgetmind
I simplified your code to:
slices = 40; curve_r = bearing_height/2; for (s = [1 : slices]) linear_extrude(height = s*bearing_height/slices, center = true) offset(delta = curve_r * (cos(90*(s1)/slices)  1)) profile();Instead of translating each slice into place, I just made taller and taller extrusions working in. As you noted, it is quite slow to render, and the curve is pointier than I would have expected, for some reason. 
In reply to this post by Ronaldo
There are more ways to skin that cat. I have sometimes, if I wanted rounded corners, done an intersection with a sphere (just big enough, to round the corners on a cube for instance).  Extra Ham Operator: K7AZJ Registered Linux User: 275424 Raspberry Pi and Openscad developer The most exciting phrase to hear in science  the one that heralds new discoveries  is not "Eureka!" but "That's funny...". On Fri, Jun 2, 2017 at 10:56 AM, Ronaldo Persiano <[hidden email]> wrote:
_______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
In reply to this post by Ronaldo
My star knob design has the same sort of profile as your spinner and
rounded edges all over, you can maybe get some ideas from how I modeled that. Its basically what ronaldo says, just do a bunch of partial rotate_extrudes. https://www.thingiverse.com/thing:1562501 There are some primitive fillet related functions in the star knob script that I think originated from here: https://github.com/jfhbrook/openscadfillets/blob/master/fillets.scad But IIRC I ended up modifying the functions many times to fit specific things I needed that they no longer resemble to original code. If I were to rewrite it today I would probably replace those fillet functions with some polygon generating functions that incorporate the "arc" function from my FunctionalOpenSCAD library ( https://github.com/thehans/FunctionalOpenSCAD/blob/master/functional.scad ) Also, I wish this sort of geometry problem was referred to as the Appolonius problem when I was solving it myself! Hans On Fri, Jun 2, 2017 at 12:56 PM, Ronaldo Persiano <[hidden email]> wrote: > In your particular case of filleting circular forms, a faster method is to > union rotated extrusions. The snapshot versions of OpenSCAD allow to > prescribe an angle in the rotate_extrude to help things go easier. > > 20170602 4:48 GMT03:00 jsc <[hidden email]>: >> >> I have just published my universal OpenSCAD fidget spinner model: >> https://www.thingiverse.com/thing:2360208 >> >> Calculating the three circle Apollonius problem in OpenSCAD was a pretty >> challenge, but what really frustrated me was rounding off the edges of the >> final profile. I finally settled on minkowski sum with a sphere on a >> minimal >> height 2D profile extrusion, but for a high resolution model it takes >> about >> ten minutes to calculate. >> >> Is there any more efficient way to round these edges than this? I don't >> see >> how I can use hull() in this case. >> >> >> >>  >> View this message in context: >> http://forum.openscad.org/Roundingconvexedgeswithoutminkowskitp21621.html >> Sent from the OpenSCAD mailing list archive at Nabble.com. >> >> _______________________________________________ >> OpenSCAD mailing list >> [hidden email] >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > > > _______________________________________________ > OpenSCAD mailing list > [hidden email] > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
In reply to this post by jsc
Oh, right, must base the curve on angle, not z height: slices = 40; curve_r = bearing_height/2; for (s = [1 : slices]) { h = s*bearing_height/slices; theta = asin(h / bearing_height); linear_extrude(height = h, center = true) offset(delta = curve_r * (cos(theta)  1)) profile(); } I will try out some of the suggestions other people have made to this thread, too. 
Your code spent more then 28 min. to render in my rather old notebook. The following code is a redesign of spinner_solid() using rotate_extrude instead of minkovsky. Now, it renders in 4 min in my computer.
module spinner_solid() { // from body() poly = [[0, bearing_to_weight_centers_dist], [tc[0], tc[1]], [cos(30)*bearing_to_weight_centers_dist, sin(30)*bearing_to_weight_centers_dist], [0, sqrt(tc[0]*tc[0] + tc[1]*tc[1])], [cos(30)*bearing_to_weight_centers_dist, sin(30)*bearing_to_weight_centers_dist], [tc[0], tc[1]]]; r = bearing_height/2; x1 = bearing_to_weight_centers_dist; R = lobe_r; x2 = norm([tc[0],tc[1]]); // the three lobes rotate( 90) translate([x1,0,0]) filled_torus(R,r); rotate(30) translate([x1,0,0]) filled_torus(R,r); rotate(210) translate([x1,0,0]) filled_torus(R,r); // the concave section intersection(){ translate([0,0,r]) linear_extrude(height=2*r) polygon(poly); union(){ rotate( 30) translate([x2,0,0]) torus(tc[2],r); rotate(90) translate([x2,0,0]) torus(tc[2],r); rotate(150) translate([x2,0,0]) torus(tc[2],r); } } // the center filling translate([0,0,r]) difference(){ linear_extrude(height=2*r) body(); rotate( 30) translate([x2,0,r]) cylinder(r=tc[2],h=2*r+1,center=true); rotate(90) translate([x2,0,r]) cylinder(r=tc[2],h=2*r+1,center=true); rotate(150) translate([x2,0,r]) cylinder(r=tc[2],h=2*r+1,center=true); } } 20170602 16:02 GMT03:00 jsc <[hidden email]>: jsc wrote _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
The functions filled_torus and torus are missing ?

In reply to this post by Ronaldo
Excellent. I had to adjust some of the parameters to get the dimensions to work out correctly, but the general scheme worked out very well. Rendering is much faster, and the preview version is no longer needed. I updated the script and credited you in the code, although only as "Ronaldo". Thank you.

This post was updated on .
In reply to this post by jsc
I tried to come up with my solution. First, I created a two_connected_circles module:
include <rotate_p.scad>; include <bezier_curve.scad>; include <rounded_extrude.scad>; $fn = 36; radius = 10; leng = 40; t_step = 0.1; tangent_angle = 40; module two_connected_circles(radius, dist, tangent_angle, t_step) { half_dist = dist / 2; p1 = rotate_p([0, radius], tangent_angle) + [half_dist, 0]; p2 = rotate_p([radius * tan(tangent_angle), radius], tangent_angle) + [half_dist, 0]; p3 = [p1[0], p1[1]]; p4 = [p2[0], p2[1]]; curve_pts = bezier_curve(t_step, [p1, p2, p4, p3]); leng_pts = len(curve_pts); upper_curve_pts = [ for(i = [0:leng_pts  1]) curve_pts[leng_pts  i  1] ]; lower_curve_pts = [ for(pt = curve_pts) [pt[0], pt[1]] ]; translate([half_dist, 0]) circle(radius); translate([half_dist, 0]) circle(radius); polygon( concat( upper_curve_pts, lower_curve_pts ) ); } two_connected_circles( radius, leng, tangent_angle, t_step ); After that, I created a tri_connected_circles module: module tri_connected_circles(radius, leng, tangent_angle, t_step) { angle = 60; half_leng = leng / 2; module two_circles() { two_connected_circles(radius, leng, tangent_angle, t_step, round_r); } translate([0, half_leng * tan(30), 0]) union() { two_circles(); translate([half_leng, 0, 0]) rotate(angle) translate([half_leng, 0, 0]) two_circles(); translate([half_leng, 0, 0]) rotate(angle) translate([half_leng, 0, 0]) two_circles(); } } tri_connected_circles(radius, leng, tangent_angle, t_step); Then, I can rounded it by the following code: round_r = 3; rounded_extrude([leng + 2 * radius, leng * tan(60) + 2 * radius], round_r, 180) union() { circle(radius * 1.5); tri_connected_circles(radius, leng, tangent_angle, t_step); } The complete code: include <rotate_p.scad>; include <bezier_curve.scad>; include <rounded_extrude.scad>; $fn = 36; radius = 10; leng = 40; t_step = 0.1; tangent_angle = 40; round_r = 3; module two_connected_circles(radius, dist, tangent_angle, t_step) { half_dist = dist / 2; p1 = rotate_p([0, radius], tangent_angle) + [half_dist, 0]; p2 = rotate_p([radius * tan(tangent_angle), radius], tangent_angle) + [half_dist, 0]; p3 = [p1[0], p1[1]]; p4 = [p2[0], p2[1]]; curve_pts = bezier_curve(t_step, [p1, p2, p4, p3]); leng_pts = len(curve_pts); upper_curve_pts = [ for(i = [0:leng_pts  1]) curve_pts[leng_pts  i  1] ]; lower_curve_pts = [ for(pt = curve_pts) [pt[0], pt[1]] ]; translate([half_dist, 0]) circle(radius); translate([half_dist, 0]) circle(radius); polygon( concat( upper_curve_pts, lower_curve_pts ) ); } module tri_connected_circles(radius, leng, tangent_angle, t_step) { angle = 60; half_leng = leng / 2; module two_circles() { two_connected_circles(radius, leng, tangent_angle, t_step, round_r); } translate([0, half_leng * tan(30), 0]) union() { two_circles(); translate([half_leng, 0, 0]) rotate(angle) translate([half_leng, 0, 0]) two_circles(); translate([half_leng, 0, 0]) rotate(angle) translate([half_leng, 0, 0]) two_circles(); } } * two_connected_circles( radius, leng, tangent_angle, t_step ); * tri_connected_circles(radius, leng, tangent_angle, t_step); rounded_extrude([leng + 2 * radius, leng * tan(60) + 2 * radius], round_r, 180) union() { circle(radius * 1.5); tri_connected_circles(radius, leng, tangent_angle, t_step); } You can find rotate_p.scad, bezier_curve.scad, rounded_extrude.scad here: https://justinsdk.github.io/dotSCAD/ 
In reply to this post by Neon22
You are right. Here they are:
module torus(R,r) rotate_extrude() translate([R,0,0]) circle(r); module filled_torus(R,r) { torus(R,r); cylinder(r=R,h=2*r, center=true); } 20170602 19:20 GMT03:00 Neon22 <[hidden email]>: The functions filled_torus and torus are missing ? _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
In reply to this post by caterpillar
I added a shape_glued2circles function into my library. Now, we can simplify the code:
include <rotate_p.scad>; include <bezier_curve.scad>; include <shape_pie.scad>; include <shape_glued2circles.scad>; include <rounded_extrude.scad>; $fn = 48; radius = 10; leng = 40; tangent_angle = 40; round_r = 3; module tri_connected_circles(radius, leng, tangent_angle) { angle = 60; half_leng = leng / 2; module two_circles() { polygon( shape_glued2circles(radius, leng, tangent_angle = tangent_angle) ); } translate([0, half_leng * tan(30), 0]) union() { two_circles(); translate([half_leng, 0, 0]) rotate(angle) translate([half_leng, 0, 0]) two_circles(); translate([half_leng, 0, 0]) rotate(angle) translate([half_leng, 0, 0]) two_circles(); } } rounded_extrude([leng + 2 * radius, leng * tan(60) + 2 * radius], round_r, 180) union() { circle(radius * 1.5); tri_connected_circles(radius, leng, tangent_angle); } 
In reply to this post by caterpillar
here a nice and simple constructor:
WITH minkowski the code for the fidget is quite straight forward. 4 minute render time is not at all bad.

Very clever use of offset that avoids the Apollonius circle computation. However, except for the generation of the profile, your code is essentially the same as the original spinner_solid and the running time should be about the same.
20170604 20:19 GMT03:00 Parkinbot <[hidden email]>: WITH minkowski the code for the fidget is quite straight forward. 4 minute _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
If you use the constructor with a circle you can even omit the first offset and enlarge the circle radius of course.
What a pity that we don't get hands on the coordinates ... 
On 20170605 10:30, Parkinbot wrote:
> What a pity that we don't get hands on the coordinates ... I've started creating lots of objects with functions that return points (some my own, some using shapes and transform from SCAD utils) for exactly this reason, and because I get rounding almost for free. For instance, this function gives me the points for a rounded rectangle, and I call it from a RoundedBox function (1) that uses similar loops to round in the other dimensions. Throw the points into Skin () and the job is done. function RoundedRect (xsize=10, ysize=10, r=1, fa=$fa) = [ let (xo=(xsize/2)r,yo=(ysize/2)r) for (a = [0: fa : 3601]) [cos(a)*r + xo * sign(cos(a)), sin(a)*r + yo * sign(sin(a))] ]; (1)  I'd supply the code but I haven't made generic yet and just have one for my rather special case. _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org 
For the same reason, I also created several 2D shapes in my library :)
 shape_taiwan  shape_arc  shape_pie  shape_ellipse  shape_square  shape_trapezium  shape_cyclicpolygon  shape_pentagram  shape_superformula  shape_glued2circles  shape_path_extend 
Free forum by Nabble  Edit this page 