Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I was wondering whether there is an option in mathematica that enables me to smooth the corners of a shape. The example I want to start with is the pentagon.

This can be crudely specified as

Graphics[
  Polygon[
    {{Sin[2π/5], Cos[2π/5]}, {Sin[4π/5], -Cos[π/5]}, 
     {-Sin[4π/5], -Cos[Pi/5]}, {-Sin[2π/5], Cos[2π/5]}, 
     {0, 1}}]
]

Unfortunately I see no easy way that enables me to round the corners. What I am after is something that looks like this

Smooth Pentagon

I would think Mathematica would have such a feature but I can't seem to find anything. I'd be grateful if you could shine some light on this. Maybe this isn't as trivial as it seems.

share|improve this question
up vote 15 down vote accepted

UPDATE:

The previous version of my answer worked, but did not give control on the rounding radius, nor did it fully work with as a starting point for a geometric region for further calculations. Here is a version that is still based on spline curves, but it gives full control over the corner rounding radius. It also returns a FilledCurve object that in my opinion is easier to style and can also be discretized reliably to use in further calculations.

Clear[splineRoundedNgon]
splineRoundedNgon[n_Integer /; n >= 3, roundingRadius_?(0 <= # <= 1 &)] :=
  Module[{vertices, circleCenters, tangentPoints, splineControlPoints},
   vertices = CirclePoints[n];
   circleCenters = CirclePoints[1 - Sec[Pi/n] roundingRadius, n];
   tangentPoints =
   {
    Table[RotationMatrix[2 i Pi/n].{circleCenters[[1, 1]], vertices[[1, 2]]}, {i, 0, n - 1}],
    Table[RotationMatrix[2 i Pi/n].{circleCenters[[-1, 1]], vertices[[-1, 2]]}, {i, 1, n}]
   };
   splineControlPoints = Flatten[Transpose[Insert[tangentPoints, vertices, 2]], 1];
   FilledCurve@BSplineCurve[splineControlPoints, SplineClosed -> True]
]

Here's the obligatory animation :-)

Animate[
 Graphics[
  {EdgeForm[{Thickness[0.01], Black}], FaceForm[Darker@Green], 
   splineRoundedNgon[5, radius]}
 ],
 {{radius, 0, "Rounding\nradius"}, 0, 1}
]

animation of rounding

And here is an example of a discretized region obtained from it:

DiscretizeGraphics[splineRoundedNgon[5, 0.3], MaxCellMeasure -> 0.001]

discretized region

Such regions can be used e.g. as domains for plotting and in NDSolve calculations. For instance:

Plot3D[
  y Sin[5 x] + x Cos[7 y], {x, y} ∈ DiscretizeGraphics@splineRoundedNgon[5, 0.4]
]

plot using region as domain


You can also create a spline curve to get a bit more roundness in the corners than allowed by JoinedForm. You need to double each control point in your spline definition to have the spline "hug" the points more closely. This is conveniently wrapped up in the roundRegPoly helper function below:

Clear[roundRegPoly]
roundRegPoly[n_Integer /; n >= 3] :=
 FilledCurve@BSplineCurve[
   Flatten[#, 1] &@Transpose[{#, #}] &@CirclePoints[n],
   SplineClosed -> True
 ]

Graphics[
  {Darker@Green, EdgeForm[{Thickness[0.01], Black}], roundRegPoly[5]},
  PlotRangePadding -> Scaled[.1]
]

Mathematica graphics

share|improve this answer
    
This is an excellent result. $+1$ upvote. I would also like to ask, as per my comment to C. E, how I would go about actually telling Mathematica that this is the domain that I want to work with for NDSolve. I'm ideally hoping to specify the above rounded pentagon as a domain $D$. In other words, I want to write $D= \cdots$. Usually I will write D=Polygon[...] but this won't work here. I apologise if this is a difficult question to ask. I've tried D = roundRegPoly[5] with no success. – Mr S 100 yesterday
    
@MrS100 Try using DiscretizeGraphics@roundRegPoly[5] as your region in NDSolve. It works as a plotting region: Plot3D[1, {x, y} ∈ DiscretizeGraphics[roundRegPoly[5], MaxCellMeasure -> 0.01]] returns this. – MarcoB yesterday
    
I'll give it a go now - thanks for the prompt response. I'll let you know the outcome – Mr S 100 yesterday
    
Works almost perfectly. The only flaw is that for some reason the bottom verticies of the polygon are not rounded. This is the case if I run Plot3D[1, {x, y} ∈ DiscretizeGraphics[roundRegPoly[5], MaxCellMeasure -> 0.01]]. In your image above the bottom corners are rounded so I wonder why this is happening. – Mr S 100 yesterday
    
@MrS100 That's odd. I am packing up to leave my office for the day, so I won't be able to test this immediately, but I'll look into it. – MarcoB yesterday

FilledCurve will do the job because it can be styled by JoinForm:

Graphics[{
  EdgeForm[{JoinForm["Round"], Thickness[0.05]}],
  FilledCurve[Line /@ Partition[CirclePoints[5], 2, 2, 1]]
  }, PlotRange -> 1.2]

Mathematica graphics

MarcoB found that this simpler version also works (see comments):

Graphics[{
  EdgeForm[{JoinForm["Round"], Thickness[0.05]}],
  FilledCurve[Line@CirclePoints[5]]
  }, PlotRange -> 1.2]

I also made a version where I combined a polygon with a list element but the list manipulation required is rather inelegant. It looks like this:

coords = ArrayPad[CirclePoints[5], {{0, 1}, {0, 0}}, "Periodic"];
coords = ArrayPad[coords, {{1, 1}, {0, 0}}, Mean[{coords[[1]], coords[[2]]}]];
Graphics[{
  Polygon[coords],
  JoinForm["Round"], Thickness[0.05],
  Line[coords]
  }]
share|improve this answer
    
Note that Line@CirclePoints[5] will work as well, instead of your partition expression (+1). – MarcoB yesterday
    
@MarcoB Actually you have to manipulate the coordinates to make that work, otherwise you will have one corner that is not rounded because the end will not be joined to the start by itself. I added my code for this to the end of my answer. – C. E. yesterday
1  
I think I wasn't clear: I meant to say that Graphics[{EdgeForm[{JoinForm["Round"], Thickness[0.05]}], FilledCurve[Line@CirclePoints[5]]}, PlotRangePadding -> Scaled[.1]] should work too. This is the output I get on 10.4, which seems to me to have all corners rounded. – MarcoB yesterday
    
@MarcoB Actually I see now that you wrote "instead of...". I was so wrapped up in my thinking that I missed that part of the sentence/jumped to my conclusion. – C. E. yesterday
    
This is a superb answer and is exactly what I'm looking for. $+1$ upvote! However, I'm hoping to use NDSolve with this as my domain but I'm unsure on what I should specify my domain as using the above. Is there a way of specifying this as a set of points rather than a graphics object? I'm trying to do NDSolve[eqn,u, {x,y}\[Element]D] where $D$ is the pentagon above with rounded corners. I'm just wondering how I should define $D$ using the above graphics object. – Mr S 100 yesterday

Since you mention that you want to use the rounded polygon in NDSolve[] as a region, you might want to look at the following construction:

With[{r = 1/5 (* rounding radius *)}, 
     rp = DiscretizeRegion[
          ImplicitRegion[RegionDistance[
          Polygon[CirclePoints[{1 - 2 Sqrt[5 - 2 Sqrt[5]] r, π/10}, 5]], {x, y}] <=
          r Sqrt[(5 - Sqrt[5])/2], {x, y}], MaxCellMeasure -> 1/200]];

Graphics[{{Yellow, Polygon[CirclePoints[{1, π/10}, 5]]},
          {Opacity[2/3, Blue], MeshPrimitives[rp, 2]}}]

pentagon and its discretized rounded version

Rescale/rotate/translate as needed.

share|improve this answer
    
I really like this solution. It is exceptionally well done. $+1$ upvote! – Mr S 100 21 hours ago
1  
You can also use BoundaryDiscretizeRegion and even get just a single Polygon with by applying MeshPrimitives[#, 2] & to the discretized region. – kirma 17 hours ago
    
@kirma, I'll edit that in later, but on the other hand, for a single polygon with rounded corners, I won't even need the fancy region functionality. I can fall back on a little trig for that one. ;) – J. M. 17 hours ago
    
@J.M. Using "fancy region functionality" may sometimes be easier than thinking of trigonometry, though... ;) – kirma 17 hours ago

Just wanted to add purely mathematical approach using complex mapping technique.

 PolyMap[n_, z_] := z Hypergeometric2F1[1/n, 2/n, (n + 1)/n, z^n]
(*Integrate[1/(1-\[Xi]^n)^(2/n),{\[Xi],0,z}]*) 

g = GraphicsGrid[
Table[
 ParametricPlot[
  z = PolyMap[n, r (Cos[t] + I Sin[t])]; {Re[z], Im[z]}, 
   {t, 0, 2 \[Pi]}, PlotRange -> All, Axes -> False] /. 
   Line[l_List] :> {{Lighter[ColorData[3, "ColorList"][[n]]], Polygon[l]}{Red, Thick, Line[l]}}, 
 {n, 3, 8}, {r, 0.799, 1., 0.1}], 
ImageSize -> 400]

enter image description here

share|improve this answer
    
This is excellent $+1$ upvote! – Mr S 100 21 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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