Filling a user-defined geometric shape

As @m_goldberg points out, we can't build nice graphics objects out of circular arcs generated by Circle as you have cleverly done. This has been a problem for me in the past as I also love to use the angle specification in curve to generate circular arcs when building a graphic.

Use Bezier Curves

One option is to use Polygon as m_goldberg has shown you, however this will necessarily give you a collection of straight edges. Another is to use BezierCurves, which will allow us to make use of FilledCurve.

There are many guide out there describing how to approximate circles with Bezier curves, the upshot is that for quarter circles and less the approximation is very very good.

I have therefore written for myself a function which takes exactly the same arguments as Circle and generates an arc with BezierCurve underlying it:

BezierCircleArc[{x_, y_}, r_, {θ1_, θ2_}] := 
 Module[{α, p0, p1, p2, p3},
  α = 4/3 Tan[(θ2 - θ1)/4];

  p0 = {x, y} + r {Cos[θ1], Sin[θ1]};
  p3 = {x, y} + r {Cos[θ2], Sin[θ2]};
  p1 = p0 + α r {-Sin[θ1], Cos[θ1]};
  p2 = p3 + α r {Sin[θ2], -Cos[θ2]};

  BezierCurve[{p0, p1, p2, p3}]
  ]

We can therefore recreate your claw graphic using a direct replacement of Circle -> BezierCircleArc:

Graphics[{
  BezierCircleArc[{106.79, 0}, 20, claw1a = {0.8, 2.89}], 
  BezierCircleArc[{106.79, 0}, 25, claw1a],
  BezierCircleArc[{85, 5.6}, 2.5, claw1b = {2.89, 6.03}], 
  BezierCircleArc[{122.54, 16.07}, 2.5, claw1c = {0.8, -2.35}]
  }]

enter image description here

However we now have the ability to use functions such as FilledCurve that allow use to use the full power of Graphics styling options:

Graphics[{EdgeForm[Black], GrayLevel[.84],
 FilledCurve[{
   BezierCircleArc[{106.79, 0}, 20, claw1a = {0.8, 2.89}],
   BezierCircleArc[{85, 5.6}, 2.5, claw1b = {6.03 - 2π, 2.89 - 2π}][[;;, 2 ;;]],
   BezierCircleArc[{106.79, 0}, 25, Reverse@claw1a - 2π][[;;, 2 ;;]],
   BezierCircleArc[{122.54, 16.07}, 2.5, claw1c = {0.8, -2.35}][[;;, 2 ;;]]
   }]
 }]

The [[;;,2]] is to remove the first point from the BezierCurve as FilledCurve automatically adds it to stitch the curves together.

enter image description here

Accuracy

A note on the accuracy of BezierCircleArc. It's really great up to and a little beyond a quarter circle. It starts to deviate a little by a semicircle and goes awol beyond that. Simply break the arc into multiple sections to overcome this.

GraphicsRow[Table[
  Graphics[{Text[ToString[i/4.] <> "π", {0, 0}],
    Circle[{0, 0}, 1, {0, π i/4}],
    ColorData["Rainbow"][(i - 1)/5],
    BezierCircleArc[{0, 0}, 1, {0, π i/4}]
    }, PlotRange -> {{-1.1, 1.1}, {-1.1, 1.1}}],
  {i, 1, 6}], 0.2]

enter image description here


Your problem is that your claw shape is just a collection of circular arcs. It isn't recognized by Mathematica as a graphics object like Disk. We will have to build a graphics object that looks likes your collection of arcs, but which Graphics will recognize. I think the easiest such object is a polygon which has vertices taken from your arcs.

Your claw shape (for reference).

claw =
  {Circle[{106.79, 0}, 20, {0.8, 2.89}],
   Circle[{106.79, 0}, 25, {0.8, 2.89}],
   Circle[{85, 5.6}, 2.5, {2.89, 6.03}],
   Circle[{122.54, 16.07}, 2.5, {0.8, -2.35}]};

Points that lie along the arcs in your claw shape.

claw1aPts =
   Join[
     Table[ReIm[20. Exp[I u] + 106.9], {u, Subdivide[.8, 2.89, 15]}],
     Reverse @ 
       Table[ReIm[2.5 Exp[I u] + 85. + 5.6 I], {u, Subdivide[2.89, 6.03, 7]}],
     Reverse @ 
       Table[ReIm[25. Exp[I u] + 106.9], {u, Subdivide[.8, 2.89, 15]}],
     Table[ReIm[2.5 Exp[I u] + 122.54 + 16.07 I], {u, Subdivide[0.8, -2.35, 7]}]];

The order of the points is critical -- hence the use of Reverse. Let's see how these point lie along your claw shape.

Graphics[{claw, AbsolutePointSize[6], Point[claw1aPts]}]

points

They don't look too bad, but you can always refine the set of points for your actual application if necessary. Now lets make a demo of opening and closing claws from these points.

Manipulate[
  Graphics[
    {u = 
       GeometricTransformation[
         {EdgeForm[Black], GrayLevel[.84], 
          Polygon[claw1aPts]}, {RotationTransform[θ Degree, {85, 5.6}]}], 
     GeometricTransformation[u, ReflectionTransform[{0, 1}, {85, 0}]], 
     Dashed, InfiniteLine[{{0, 0}, {1, 0}}]},
     PlotRange -> {{75, 130}, {-45, 45}}, Frame -> True],
  {u, None},
  {θ, -15, 45, 1, Appearance -> "Labeled"}]

demo


Here's a routine based on this previous answer for drawing a rounded version of Annulus[], which uses FilledCurve[] + BSplineCurve[]. Its only caveat is that it is restricted to acute and obtuse angles:

roundedSector[{h_, k_}, {r1_, r2_}, {θ1_, θ2_}] /; 0 < r1 < r2 && 0 < θ2 - θ1 <= π := 
       Module[{cw, p1, p2, rs, rt, scp, ska, skb, sw, ϕ1, ϕ2},
              scp = (r2 - r1) {{1, 1}, {-1, 1}, {-1, 0}}/2; sw = {1, 1/2, 1/2, 1};
              ska = {0, 0, 0, 1, 1, 1}; skb = {0, 0, 0, 1/2, 1, 1, 1}; 
              rs = r1^2 + 6 r1 r2 + r2^2; rt = (r1 - r2) Sqrt[(3 r1 + r2) (r1 + 3 r2)];
              ϕ1 = ArcTan @@ -RotationTransform[θ1][{-rs, rt}] // N;
              ϕ2 = ArcTan @@ RotationTransform[θ2][{rs, rt}] // N;
              cw = Cos[(ϕ2 - ϕ1)/2];
              p1 = Through[{Cos, Sin}[ϕ1]]; p2 = Through[{Cos, Sin}[ϕ2]];
              {BSplineCurve[TranslationTransform[{h, k}][
                            r2 {p1, Normalize[(p1 + p2)/2]/cw , p2}], SplineDegree -> 2,
                            SplineKnots -> ska, SplineWeights -> {1, cw, 1}], 
               BSplineCurve[Composition[TranslationTransform[{h, k} + (r1 + r2) p2/2],
                                        RotationTransform[ϕ2]][scp], SplineDegree -> 2, 
                            SplineKnots -> skb, SplineWeights -> sw], 
               BSplineCurve[TranslationTransform[{h, k}][
                            r1 {Normalize[(p1 + p2)/2]/cw , p1}], SplineDegree -> 2, 
                            SplineKnots -> ska, SplineWeights -> {1, cw, 1}], 
               BSplineCurve[Composition[TranslationTransform[{h, k} + (r1 + r2) p1/2], 
                                        RotationTransform[ϕ1 + π]][scp], SplineDegree -> 2,
                            SplineKnots -> skb, SplineWeights -> sw]} // FilledCurve]

Example:

Graphics[{Annulus[{1, 1}, {3/2, 2.}, {π/6, 7 π/8}],
          Blue, roundedSector[{1, 1}, {3/2, 2}, {π/6, 7 π/8}]}]

annulus and its rounded version

Tags:

Graphics