I want to draw a cuboid with rounded corners, like this:
RoundingRadius
only works with Rectangle
or Framed
. I have no idea how to draw a cuboid with rounded corners. What are your ideas? Thanks.
Two more options. These allow direct control of the box dimensions and the rounding radius.
Using ContourPlot3D
:
signedDistance[p_, p0_, p1_] := Piecewise[
{{-Min[p - p0, p1 - p], And @@ Thread[p0 <= p <= p1]},
{EuclideanDistance[p, MapThread[Min[Max[#1, #2], #3] &, {p, p0, p1}]], True}}]
roundedCuboidPlot[p0 : {x0_, y0_, z0_}, p1 : {x1_, y1_, z1_}, r_, opts : OptionsPattern[]] :=
ContourPlot3D[signedDistance[{x, y, z}, p0 + r, p1 - r] == r,
{x, x0 - r, x1 + r}, {y, y0 - r, y1 + r}, {z, z0 - r, z1 + r}, opts]
roundedCuboidPlot[{0, 0, 0}, {1, 2, 3}, 1/4, BoxRatios -> Automatic, Mesh -> None]
Using Graphics3D
primitives:
roundedCuboid[p0 : {x0_, y0_, z0_}, p1 : {x1_, y1_, z1_}, r_] :=
{EdgeForm[None],
Cuboid[p0 + {0, r, r}, p1 - {0, r, r}],
Cuboid[p0 + {r, 0, r}, p1 - {r, 0, r}],
Cuboid[p0 + {r, r, 0}, p1 - {r, r, 0}],
Table[Cylinder[{{x0 + r, y, z}, {x1 - r, y, z}}, r],
{y, {y0 + r, y1 - r}}, {z, {z0 + r, z1 - r}}],
Table[Cylinder[{{x, y0 + r, z}, {x, y1 - r, z}}, r],
{x, {x0 + r, x1 - r}}, {z, {z0 + r, z1 - r}}],
Table[Cylinder[{{x, y, z0 + r}, {x, y, z1 - r}}, r],
{x, {x0 + r, x1 - r}}, {y, {y0 + r, y1 - r}}],
Table[Sphere[{x, y, z}, r],
{x, {x0 + r, x1 - r}}, {y, {y0 + r, y1 - r}}, {z, {z0 + r, z1 - r}}]}
Graphics3D[{roundedCuboid[{0, 0, 0}, {1, 2, 3}, 1/4]}]
Spheres
and replace Cylinders
with Tubes
.
$\endgroup$
ClearAll[roundedCuboidF]
roundedCuboidF[hprof_: 10, vprof_: 10, taper_: 1][box_] :=
ChartElementDataFunction["DoubleProfileCube", "HorizontalProfile" -> hprof,
"VerticalProfile" -> vprof, "TaperRatio" -> taper][box]
Graphics3D[roundedCuboidF[][{{0, 1}, {0, 1}, {0, 1}}], Boxed -> False]
or
ContourPlot3D[Norm[{x, y, z}, 4], {x, -1, 1}, {y, -1, 1}, {z, -1, 1},
Mesh -> None, Boxed -> False, Axes -> False, Lighting -> "Neutral",
ContourStyle -> Directive[Orange, Opacity[0.8], Specularity[White, 30]]]
roundedCuboidF[1, 1, 0.01]
. Nice thing to play with and very instructive :)
$\endgroup$
Chart Element Schemes
in the Palettes
menu.
$\endgroup$
Directive[Red, Specularity[White, 30]]
and `Lighting->"Neutral" :)
$\endgroup$
Rahul's otherwise fine approach has a drawback that can be seen if you include an Opacity[]
directive:
Graphics3D[{Opacity[2/3, Pink], roundedCuboid[{0, 0, 0}, {1, 2, 3}, 1/4]},
Boxed -> False]
The "ribs" may or may not be desirable in an application, so I sought an alternative that does not use too many Polygon[]
s (as with the solutions based on plotting) and yet looks fine when made translucent.
The following routine is not quite Mr. Wizard's wish in the comments, but it is certainly built from BSplineSurface[]
+ Polygon[]
components:
roundedCuboid[p1_?VectorQ, p2_?VectorQ, r_?NumericQ] :=
Module[{csk, csw, cv, ei, fi, ocp, osk, owt},
cv = Tuples[Transpose[{p1 + r, p2 - r}]];
ocp = {{{1, 0, 0}, {1, 1, 0}, {0, 1, 0}},
{{1, 0, 1}, {1, 1, 1}, {0, 1, 1}},
{{0, 0, 1}, {0, 0, 1}, {0, 0, 1}}};
osk = {{0, 0, 0, 1, 1, 1}, {0, 0, 0, 1, 1, 1}};
owt = {{1, 1/Sqrt[2], 1}, {1/Sqrt[2], 1/2, 1/Sqrt[2]},
{1, 1/Sqrt[2], 1}};
ei = {{{4, 8}, {2, 6}, {1, 5}, {3, 7}},
{{6, 8}, {2, 4}, {1, 3}, {5, 7}},
{{7, 8}, {3, 4}, {1, 2}, {5, 6}}};
csk = {{0, 0, 1, 1}, {0, 0, 0, 1, 1, 1}};
csw = {{1, 1/Sqrt[2], 1}, {1, 1/Sqrt[2], 1}};
fi = {{8, 6, 5, 7}, {8, 7, 3, 4}, {8, 4, 2, 6},
{4, 3, 1, 2}, {2, 1, 5, 6}, {1, 3, 7, 5}};
Flatten[{EdgeForm[], BSplineSurface3DBoxOptions ->
{Method -> {"SplinePoints" -> 35}},
MapIndexed[BSplineSurface[Map[
AffineTransform[{RotationMatrix[π Mod[#2[[1]] - 1, 4]/2,
{0, 0, 1}], #1}],
ocp.DiagonalMatrix[r {1, 1, If[Mod[#2[[1]] - 1, 8] < 4,
1, -1]}], {2}],
SplineDegree -> 2, SplineKnots -> osk, SplineWeights -> owt] &,
cv[[{8, 4, 2, 6, 7, 3, 1, 5}]]],
MapIndexed[Function[{idx, pos},
BSplineSurface[Outer[Plus, cv[[idx]],
Composition[Insert[#, 0, pos[[1]]] &,
RotationTransform[π (pos[[2]] - 1)/2]] /@
(r {{1, 0}, {1, 1}, {0, 1}}), 1], SplineDegree -> {1, 2},
SplineKnots -> csk, SplineWeights -> csw]], ei, {2}],
Polygon[MapThread[Map[TranslationTransform[r #2], cv[[#1]]] &,
{fi, Join[#, -#] &[IdentityMatrix[3]]}]]}]]
Using this version instead in the first snippet yields the following picture:
Some more examples:
Graphics3D[{Yellow, roundedCuboid[{0, 0, 0}, {1, 3, 1}, 1/10],
Blue, roundedCuboid[{2, 1, 1}, {4, 2, 3}, 1/4]}, Boxed -> False]
Graphics3D[{{EdgeForm[Gray], Opacity[1/2, Green], Cuboid[{2, 1, 1}, {4, 2, 3}]},
{Pink, roundedCuboid[{2, 1, 1}, {4, 2, 3}, 1/5]}},
Boxed -> False, Lighting -> "Neutral"]
f = PolyhedronData["Cube", "RegionFunction"][x, y, z];
r = 2; u = 0.6;
RegionPlot3D[f, {x, -r, r}, {y, -r, r}, {z, -r, r}, Mesh -> False,
PlotPoints -> 55, PlotRange -> {{-u, u}, {-u, u}, {-u, u}}]
Weakness of this approach: You have to find the right number for PlotPoints
(here 55) by trial and error.
f
is a cube with straight edges covering {{-0.5,0.5},{-0.5,0.5},{-0.5,0.5}}
. This volume is completely inside {{-2,2},...}
and {{-0.6,0.6},...}
so how does this even work? Is it a side effect of RegionPlot3D
not having high enough resolution?
$\endgroup$
This approach takes advantage of a weakness in the implementation of DiscretizeRegion
wherein I give it a perfectly cubic region, and it returns a poor approximation of it,
MeshRegion[
DiscretizeRegion@
ImplicitRegion[{0, 0, 0} <= {x, y, z} <= {1, 1, 1}, {x, y, z}],
PlotTheme -> "SmoothShading"]
This has less smoothness on the corners like the other answers, but I think it matches the image in the OP pretty well.
LoopSubdivide
(defined here). Nest[LoopSubdivide, BoundaryDiscretizeRegion[ImplicitRegion[{0, 0, 0} <= {x, y, z} <= {1, 1, 1}, {x, y, z}], Method -> "MarchingCubes"], 2]
i.stack.imgur.com/ttUaQ.png
$\endgroup$
Nov 30, 2023 at 19:53
A new command RegionDilation
(since 2021) does the job:
RegionDilation[Region[Cuboid[{0, 0, 0}, {1, 2, 3}]], Region[Ball[{0, 0, 0}, 1/2]]]
We can also use the ResourceFunction RoundedCuboid (added January 2022)
rcube = ResourceFunction["RoundedCuboid"];
Graphics3D[{MaterialShading["Pewter"], rcube[]},
Boxed -> False,
Lighting -> "ThreePoint"]
Graphics3D[{
MaterialShading["Brass"],
rcube[{0, 0, 0}, {6, 3, 3}, RoundingRadius -> {0.5, 0, 0.5}]},
Boxed -> False,
Lighting -> "ThreePoint"]
Needs["OpenCascadeLink`"];
solid = Cuboid[];
solid = PolyhedronData["Dodecahedron", "Polyhedron"];
n = MeshCellCount[solid, 1];
bmesh[solid_, k_] :=
Module[{shape, fillet, bm}, shape = OpenCascadeShape[solid];
fillet = OpenCascadeShapeFillet[shape, .15, Take[Range[2 n], k]];
bm = OpenCascadeShapeSurfaceMeshToBoundaryMesh[fillet,
"ShapeSurfaceMeshOptions" -> {"AngularDeflection" -> .1}];
groups = bm["BoundaryElementMarkerUnion"];
colors = ColorData["BrightBands"] /@ Subdivide[Length@groups];
bm["Wireframe"[
"MeshElementStyle" -> (Directive[EdgeForm[], FaceForm[#]] & /@
colors)]]];
ani = Table[
Show[bmesh[solid, k], PlotRange -> RegionBounds[solid]], {k, 1,
2 n}];
Export["test.gif", ani, "AnimationRepetitions" -> ∞,
"DisplayDurations" -> .2, "ControlAppearance" -> None] // SystemOpen
Manipulate[
RegionPlot3D[
Norm[{x, y, z}, norm] <= 1
, {x, -1.5, 1.5}, {y, -1.5, 1.5}, {z, -1.5, 1.5}
, Mesh -> Ceiling /@ {norm, norm, norm}
]
, {{norm, 2}, 1, 10, Appearance -> "Labeled"}
]
BSplineSurface
and it would be the "ultimate" way, creating a precise, single-piece shape, but frankly I'm too lazy to figure it out as it's far from trivial. $\endgroup$