Updates:
- 2020/12/31:
rcube()extended,RCUBE_FLAT{BOTTOM, TOP, FRONT, BACK, LEFT, RIGHT}support added,rcylinder()withRCYLINDER_FLAT{TOP, BOTTOM} - 2020/12/30:
rcube()source code extended, supportRCUBE_FLATX, RCUBE_FLATY, RCUBE_FLATZ - 2020/12/28: inital post
While working on Ashtar D (Classic XY) I looked at some pieces I rushed to design with cube() and hull() and they didn’t appeal to me – yes, it kind of hurt my eyes.
A while back I coded a simple rcube([x,y,z],r) which takes r as a radius for the edges, internally it’s an OpenSCAD module which uses 8 spheres and hulls them together, providing round edges; but I hesitated to actually use it in my designs – until now. Further I thought, let’s do the same with cylinder() using rcylinder(d=10,h=5,r=1) providing round edges by using two torii and hull them together.
These two new functions, rcube([x,y,z],r) and rcylinder(h,d,r) allow to create more organic and elegant pieces, see for yourself:
From Bulky To Elegance
The position of the Y pulley mount is given, a bit of an X- & Y-offset to ensure printable area is not sacrificed for the Y carriage:
Using Chained Hulls
And another example . . . replacing hull() with chainhull():
The final version is composed by only 3 pieces chain hulled together:
difference() {
chainhull() {
rcylinder(...);
translate([0,0,-20]) rcube(...);
translate([...,-60]) rcube([5,20,50],2); // 2020 mount plate
}
rcube(...); // pulley cutout
}
rcube() & rcylinder()

rcube(); translate([5,0,0]) rcube(0.75); translate([10,0,0]) rcube([2,1,1],0.2); translate([0,2,0]) rcube([2,1,1],0.2,false); translate([5,2,0]) rcube([2,1,1],0.2,true); translate([0,4,0]) rcube([2,1,1],0.2,RCUBE_FLATX); translate([5,4,0]) rcube([2,1,1],0.2,RCUBE_FLATY); translate([10,4,0]) rcube([2,1,1],0.2,RCUBE_FLATZ); translate([0,6,0]) rcube([2,1,1],0.2,RCUBE_FLATBOTTOM); translate([5,6,0]) rcube([2,1,1],0.2,RCUBE_FLATTOP); translate([0,8,0]) rcube([2,1,1],0.2,RCUBE_FLATFRONT); translate([5,8,0]) rcube([2,1,1],0.2,RCUBE_FLATBACK); translate([0,10,0]) rcube([2,1,1],0.2,RCUBE_FLATLEFT); translate([5,10,0]) rcube([2,1,1],0.2,RCUBE_FLATRIGHT); translate([0+1,14,0]) rcylinder(3,1.5,0.2); translate([3+1,14,0]) rcylinder(3,1.5,0.2,false); translate([6+1,14,0]) rcylinder(3,1.5,0.2,RCYLINDER_FLATBOTTOM); translate([9+1,14,0]) rcylinder(3,1.5,0.2,RCYLINDER_FLATTOP);
The library code (I might later release it as a separate library):
// Title: rcube(), rcylinder() & torus()
// Author: Rene K. Mueller
// License: MIT License 2020
// Version: 0.0.2
RCUBE_FLATX = [false,true,true];
RCUBE_FLATY = [true,false,true];
RCUBE_FLATZ = [true,true,false];
RCUBE_FLATBOTTOM = [false,false,false,false,true,true,true,true];
RCUBE_FLATTOP = [true,true,true,true,false,false,false,false];
RCUBE_FLATFRONT = [false,false,true,true,false,false,true,true];
RCUBE_FLATBACK = [true,true,false,false,true,true,false,false];
RCUBE_FLATLEFT = [false,true,true,false,false,true,true,false];
RCUBE_FLATRIGHT = [true,false,false,true,true,false,false,true];
module rcube(a=1,r=0.1,rd=[true,true,true],center=false,$fn=32) {
if(FAST_RCUBE)
cube(a);
else {
x = len(a) ? a[0] : a;
y = len(a) ? a[1] : a;
z = len(a) ? a[2] : a;
rd = len(rd) ? rd : [rd,rd,rd];
if((len(rd)==3 && rd[0] && rd[1] && rd[2]) || (len(a)==0 && rd)) // rd=[true,true,true] or true
hull() {
translate([r,r,r]) sphere(r);
translate([x-r,r,r]) sphere(r);
translate([x-r,y-r,r]) sphere(r);
translate([r,y-r,r]) sphere(r);
translate([r,r,z-r]) sphere(r);
translate([x-r,r,z-r]) sphere(r);
translate([x-r,y-r,z-r]) sphere(r);
translate([r,y-r,z-r]) sphere(r);
}
else // anything else
hull() {
translate([r,r,r]) rcube_prim(r,rd,0);
translate([x-r,r,r]) rcube_prim(r,rd,1);
translate([x-r,y-r,r]) rcube_prim(r,rd,2);
translate([r,y-r,r]) rcube_prim(r,rd,3);
translate([r,r,z-r]) rcube_prim(r,rd,4);
translate([x-r,r,z-r]) rcube_prim(r,rd,5);
translate([x-r,y-r,z-r]) rcube_prim(r,rd,6);
translate([r,y-r,z-r]) rcube_prim(r,rd,7);
}
}
}
module rcube_prim(r,rd,i) {
a = len(rd);
if(a<=3) {
if(a && rd[0] && rd[1] && rd[2])
sphere(r);
else if(a && rd[0] && rd[1])
translate([0,0,-r]) cylinder(r=r,h=r*2);
else if(a && rd[1] && rd[2])
translate([-r,0,0]) rotate([0,90,0]) cylinder(r=r,h=r*2);
else if(a && rd[0] && rd[2])
translate([0,-r,0]) rotate([-90,0,0]) cylinder(r=r,h=r*2);
else
translate([-r,-r,-r]) cube(r*2);
} else
if(rd[i])
sphere(r);
else
translate([-r,-r,-r]) cube(r*2);
}
RCYLINDER_FLATBOTTOM = [false,true];
RCYLINDER_FLATTOP = [true,false];
module rcylinder(h=2,d=1,r=0.1,rd=[true,true],$fn=40) {
if(FAST_RCYLINDER)
cylinder(d=d,h=h);
else
hull() {
translate([0,0,r])
if(len(rd) && rd[0]) torus(do=d,di=r*2); else translate([0,0,-r]) cylinder(d=d,h=r);
translate([0,0,h-r])
if(len(rd) && rd[1]) torus(do=d,di=r*2); else cylinder(d=d,h=r);
}
}
module torus(do=2,di=0.1,a=360) {
rotate_extrude(convexity=10,angle=a) {
translate([do/2-di/2,0,0]) circle(d=di,$fn=20);
}
}
chainhull()
module chainhull() {
for(i=[0:1:$children-2])
hull() {
children(i);
children(i+1);
}
}
There is one drawback using chainhull() { } as you can’t use conditional if else with { } within as it combines them as a group and becomes a child structure and so it will act as hull(), so you only can list non-conditional pieces within chainhull() as of OpenSCAD 2019.05, perhaps at a later time this limit vanishes.
That’s it.












