13
$\begingroup$

I want to draw a cuboid with rounded corners, like this:

key

RoundingRadius only works with Rectangle or Framed. I have no idea how to draw a cuboid with rounded corners. What are your ideas? Thanks.

$\endgroup$
1
  • $\begingroup$ I think should be possible to do this using 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$
    – Mr.Wizard
    Jun 8, 2014 at 10:08

9 Answers 9

10
$\begingroup$

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]

enter image description here


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]}]

enter image description here

$\endgroup$
2
  • $\begingroup$ The second way is great!Since I need to add one texture on cuboid, i just replace a Cuboid to Polygon,then I can use Texture.Thx. $\endgroup$
    – Apple
    Jun 8, 2014 at 7:35
  • $\begingroup$ Nice, I was to lazyto write this ;) p.s. you can skip Spheres and replace Cylinders with Tubes. $\endgroup$
    – Kuba
    Jun 8, 2014 at 8:24
17
$\begingroup$
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]

enter image description here

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]]]

enter image description here

$\endgroup$
4
  • $\begingroup$ not for keypad use: roundedCuboidF[1, 1, 0.01]. Nice thing to play with and very instructive :) $\endgroup$
    – eldo
    Jun 7, 2014 at 15:41
  • $\begingroup$ Thx!But I can not find ChartElementDataFunction in Reference Centre, so How should I learn this function? $\endgroup$
    – Apple
    Jun 7, 2014 at 15:42
  • 1
    $\begingroup$ @Chenminqi, try ChartElementFunction and examples there and Chart Element Schemes in the Palettes menu. $\endgroup$
    – kglr
    Jun 7, 2014 at 15:44
  • $\begingroup$ @eldo, thank you! -- looks nicer with Directive[Red, Specularity[White, 30]] and `Lighting->"Neutral" :) $\endgroup$
    – kglr
    Jun 7, 2014 at 15:47
9
$\begingroup$

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]

look at 'em ribs!

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:

no ribs, ma!

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]

still life of two rounded cuboids

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"]

peek-a-boo

$\endgroup$
2
  • $\begingroup$ B-spline surface was my first thought, too, but it would take me too long to figure out how to do it. Nice job. +1 $\endgroup$
    – Michael E2
    Mar 4, 2016 at 23:19
  • $\begingroup$ Thanks, Michael. I already knew how to build NURBS representations of sphere octants and cylinder quarters; organizing them to form the corner filleting was what took the most work from me. $\endgroup$ Mar 5, 2016 at 11:48
6
$\begingroup$
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}}]

enter image description here

Weakness of this approach: You have to find the right number for PlotPoints (here 55) by trial and error.

$\endgroup$
2
  • 2
    $\begingroup$ 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$
    – C. E.
    Jun 7, 2014 at 17:36
  • 1
    $\begingroup$ @C.E. Yes, it is (see last sentence of my answer). $\endgroup$
    – eldo
    Jun 7, 2014 at 18:53
6
$\begingroup$

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"]

enter image description here

This has less smoothness on the corners like the other answers, but I think it matches the image in the OP pretty well.

$\endgroup$
1
  • $\begingroup$ We can take it a step further and apply 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$
    – Greg Hurst
    Nov 30, 2023 at 19:53
3
$\begingroup$

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]]]

enter image description here

$\endgroup$
1
$\begingroup$

We can also use the ResourceFunction RoundedCuboid (added January 2022)

rcube = ResourceFunction["RoundedCuboid"];

Graphics3D[{MaterialShading["Pewter"], rcube[]},
 Boxed -> False,
 Lighting -> "ThreePoint"]

enter image description here

Graphics3D[{
  MaterialShading["Brass"],
  rcube[{0, 0, 0}, {6, 3, 3}, RoundingRadius -> {0.5, 0, 0.5}]},
 Boxed -> False,
 Lighting -> "ThreePoint"]

enter image description here

$\endgroup$
1
$\begingroup$
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

enter image description here

$\endgroup$
0
$\begingroup$
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"}
 ]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.