Creating new graphics primitive (EdgeForm, FaceForm)
I think you will need to use FilledCurve
to create objects with holes in.
For example:
points[r1_, r2_, n_] := With[{dphi = 2.0 Pi/(n - 1)},
Table[r {Cos[phi], Sin[phi]}, {phi, 0, 2 Pi, dphi}, {r, {r1, r2}}]];
poly = Polygon[Function[{p1, p2}, Join[p1, Reverse[p2]]] @@@
Partition[points[0.3, 0.7, 30], 2, 1]];
prim = FilledCurve[Thread[Graphics`Mesh`PolygonCombine @ poly] /.
Polygon[data_] :> {Line[data]}];
To make something that behaves more like a graphics primitive I will use my answer from here
SetAttributes[createPrimitive, HoldAll];
createPrimitive[patt_, expr_] :=
Typeset`MakeBoxes[p : patt, fmt_, Graphics] :=
Typeset`MakeBoxes[Interpretation[expr, p], fmt, Graphics]
createPrimitive[donut, Evaluate@prim]
Now you can use donut
in Graphics
:
Graphics@{EdgeForm[{Black, Thick}], FaceForm[Opacity[0.3, Red]], donut}
Because donut
has no downvalues, it remains unevaluated in the graphics expression:
InputForm[%]
(* Graphics[{EdgeForm[{GrayLevel[0], Thickness[Large]}],
FaceForm[Opacity[0.3, RGBColor[1, 0, 0]]], donut}] *)
You can use the undocumented PolygonCombine
to create a single polygon which behaves well with EdgeForm
and FaceForm
:
Boing2[] := Graphics`Mesh`PolygonCombine@Boing[]
Graphics[{EdgeForm[Black], FaceForm[Opacity[0.3, Blue]], Boing2[]}, AspectRatio -> Automatic]
In Mathematica 10/Wolfram Language/Mathematica-RPi, the function can be found under Graphics`PolygonUtils`
. There might be some issues with self-intersecting polygons (I haven't looked into it), but this is a good start.
In Mathematica 12 BoundaryMeshRegion
objects can be used as a Graphics
primitive. So, another idea is to use a BoundaryMeshRegion
as your primitive. For example:
Typeset`MakeBoxes[
CutoutEllipse[center_, out_, in_],
form_,
Graphics
] := With[
{
new = Replace[
RegionDifference[Disk[center, out], Disk[center, in]],
b_BooleanRegion :> BoundaryDiscretizeRegion[b]
]
},
Typeset`MakeBoxes[new, form, Graphics]
]
Examples:
Graphics[{Pink, EdgeForm[Blue], CutoutEllipse[{0,0}, {4,2}, .9 {1,2}]}]
Graphics[{Pink, EdgeForm[Blue], CutoutEllipse[{0,0}, {4,2}, 1.1 {1,2}]}]
You can use this answer to get the above approach to work in earlier versions of Mathematica.