Reputation: 20394
It doesn't seem to be easy (or possible?) to get a truly rounded corners 3D cube in OpenSCAD. I tried something with hull()
and spheres but that didn't work correctly. Then I tried to make something with hulls of circles in each plane, then intersect all 3 planes. The edges are good but the corners are not smooth. I understand that the linear extrusion of each edge is the problem because it won't follow the curve defines on another plane. I didn't get my head around the minkowski()
function yet but it doesn't look like it would solve the problem either.
So is there any hope to get this working properly?
Here's my code so far:
// Lengths in X, Y, Z dimension
dx = 10;
dy = 20;
dz = 5;
// Corner radius on XY plane (from origin clockwise around positive Z axis)
rxy = [1, 1, 3, 1];
// Corner radius on YZ plane (from origin clockwise around positive X axis)
ryz = [1, 1, 1, 1];
// Corner radius on XZ plane (from origin clockwise around positive Y axis)
rxz = [1, 1, 2, 1];
intersection()
{
// XY plane
linear_extrude(dz)
hull()
{
for (ix = [0:1], iy = [0:1])
{
i = [0, 1, 3, 2][ix * 2 + iy];
r = rxy[i] == 0 ? 0.0001 : rxy[i];
x = ix == 0 ? r : dx - r;
y = iy == 0 ? r : dy - r;
translate([x, y, 0])
circle(r, $fn=40);
}
}
// YZ plane
translate([0, 0, dz])
rotate([0, 90, 0])
linear_extrude(dx)
hull()
{
for (iy = [0:1], iz = [0:1])
{
i = [1, 0, 2, 3][iy * 2 + iz];
r = ryz[i] == 0 ? 0.0001 : ryz[i];
y = iy == 0 ? r : dy - r;
z = iz == 0 ? r : dz - r;
intersection()
{
translate([z, y, 0])
circle(r, $fn=40);
square([dz, dy]);
}
}
}
// XZ plane
translate([0, dy, 0])
rotate([90, 0, 0])
linear_extrude(dy)
hull()
{
for (ix = [0:1], iz = [0:1])
{
i = [0, 3, 1, 2][ix * 2 + iz];
r = rxz[i] == 0 ? 0.0001 : rxz[i];
x = ix == 0 ? r : dx - r;
z = iz == 0 ? r : dz - r;
intersection()
{
translate([x, z, 0])
circle(r, $fn=40);
square([dx, dz]);
}
}
}
}
The corners look like this:
One application of this would be a shape like this thing: https://www.printables.com/model/62314-cable-clamp#preview It has slightly rounded corners everywhere and a massively rounded corner at exactly one edge.
Upvotes: 2
Views: 2424
Reputation: 2153
Also worth to look at is the immensive NopSCADLib, especially: https://github.com/nophead/NopSCADlib?tab=readme-ov-file#rounded_rectangle
Example:
rounded_cube_xy(size, r = 0, xy_center = false, z_center = false)
Like cube() but corners rounded in XY plane and separate centre options for xy and z.
Upvotes: 1
Reputation: 647
I found a partial solution to your problem : you can only determine 6 radii (all the radii of the edges of the top face are the same and the same thing applies to the bottom face) but I think it's enough for the example you shown.
code:
module rounded_cube(size = [4, 2, 1], face_radii = [1/8, 1/16], edges_radii = [1, 1/2, 1/4, 1/8, ], $fn = 16){
module block(size = [1, 2], radii = [1/2, 1/4], $fn = 16){
intersection(){
union(){
square([size.x - radii[0], radii[0]]);
translate([0, size.y - radii[1]])
square([size.x - radii[1], radii[1]]);
translate([0, radii[0]])
square([size.x, size.y - radii[0] - radii[1]]);
translate([size.x - radii[0], radii[0]])
circle(radii[0]);
translate([size.x - radii[1], size.y - radii[1]])
circle(radii[1]);
}
square([size.x, size.y]);
}
}
//block();
assert(max(face_radii) <= min(edges_radii), "all face radii must be smaller than all edges radii");
assert(face_radii[0] + face_radii[1] <= size.z, "the sum of the face radii must be smaller than the height of the rounded cube");
assert(
edges_radii[0] + edges_radii[1] <= size.x &&
edges_radii[1] + edges_radii[2] <= size.y &&
edges_radii[2] + edges_radii[3] <= size.x &&
edges_radii[3] + edges_radii[0] <= size.y,
"the sum of two consecutive edges radii must be smaller than the side they lie on");
for(e = [0 : 3]){
translate([size.x * [0, 1, 1, 0][e], size.y * [0, 0, 1, 1][e]])
rotate([0, 0, 180 + e*90]){
translate([-edges_radii[e], -edges_radii[e]])
rotate_extrude(angle = 90, $fn = $fn * 4)
block([edges_radii[e], size.z], [face_radii[0], face_radii[1]], $fn = $fn * 4);
rotate([-90, 0, 90])
translate([-size[(e + 1) % 2] / 2, -size.z, edges_radii[e]])
linear_extrude(size[e % 2] - edges_radii[e] - edges_radii[(e + 1) % 4])
block([size[(e + 1) % 2] / 2, size.z], [face_radii[1], face_radii[0]], $fn = $fn * 4);
}
}
}
rounded_cube(size = [4, 2, 1], face_radii = [1/8, 1/16], edges_radii = [1, 1/2, 1/4, 1/8], $fn = 16);
Upvotes: 2
Reputation: 368
There is an OpenSCAD module that does this. That page also lists a link to a simple version that uses Minkowski. Here is the code from the simple version.
// More information: https://danielupshaw.com/openscad-rounded-corners/
module roundedcube_simple(size = [1, 1, 1], center = false, radius = 0.5) {
// If single value, convert to [x, y, z] vector
size = (size[0] == undef) ? [size, size, size] : size;
translate = (center == false) ?
[radius, radius, radius] :
[
radius - (size[0] / 2),
radius - (size[1] / 2),
radius - (size[2] / 2)
];
translate(v = translate)
minkowski() {
cube(size = [
size[0] - (radius * 2),
size[1] - (radius * 2),
size[2] - (radius * 2)
]);
sphere(r = radius);
}
}
radius * 2
is subtracted from the cube dimensions since Minkowski adds the radius to all sides.
Upvotes: 3