Mathematica, 193 183 177 173 169 166 bytes
Yay, maths! I'm plotting the region that satisfies a certain (rather complicated) set of inequalities:
e=RegionPlot[(1<Abs@y<3||c)&&{x,y+12}.(d=2{-5Sin@40°-6,m=5Cos@40°})*{x+15,y+1-2Sign@y}.d<0||c&&x<2m/.c->100<x^2+y^2<144,{x,-15,9},{y,-12,12},Frame->0>1,ImageSize->#]&
Usage is e[height]
, e.g. e[100]
:

Or e[200]
:

You may notice, that the sharper edges are slightly rounded off. That's because the region can only be plotted by sampling the points in space, and Mathematica doesn't sample each pixel by default. The sampling resolution can be increased by adding another option PlotPoints->#
(which uses one sample per pixel), which adds 14 characters. I don't recommend running it with that option, because it significantly increases runtime and barely increases visual appeal beyond #/4
or so. Hence, (after approval of the OP) it is not included in the score.
Here is a slightly ungolfed version:
e[height_] := (
angle = 40°;
d = {-5 Sin[angle] - 6, 5 Cos[angle]};
RegionPlot[
(Abs[y] > .5 && Abs[y] < 1.5
||
r > 25 && r < 36)
&&
{x, y + 6}.d > 0
&&
{x + 7.5, y + .5 - Sign[y]}.d < 0
||
r > 25 && r < 36 && x < 5 Cos[angle]
/. r -> x^2 + y^2
,
{x, -7.5, 4.5},
{y, -6, 6},
Frame -> False,
ImageSize -> height
]
);
Note that in the golfed version, I've scaled the coordinate system by a factor of 2 to avoid the .5
s, but it turns out that the character count is actually identical.
Here is an explanation for how I worked out the formula. I divided the shape into two regions. One contains the ring and the stripes and is cut off to the right with the BCDE
slope and to the left with the IJ
and GH
slopes (more on that later). The other contains the same ring, but is simply cut off at the x coordinate of point D
. The conditions for the two regions are combined with ||
, which acts as a set union here.
The ring is just defined as 5 < r < 6
, where r
is the distance from the origin. r²
is easier to work out though (x²+y²
), so I'm using 25 < x² + y² < 36
to get all the points in the ring.
The stripes are between ±.5
and ±1.5
. We can handle both stripes at the same time, by taking the modulus of y, so the stripes (of infinite length) just fulfil .5 < |y| < 1.5
. Again, to take the union of the stripes and the ring, I'm just using ||
.
The interesting thing is probably how to get the "masks" though. Point D
has an x coordinate of 5 cos 40°
, so the mask taking care of lower edge (combined with the ring only) is just x < 5 cos 40°
. This can be applied via set intersection which translates to &&
in logic.
The other masks are the really tricky part. First, let's get the slope of BCDE
. We can easily construct points C
and D
, as (0, -6)
and 5 (cos 40°, sin 40°)
, respectively. The vector pointing along the line is then just D - C = (5 cos 40°, 5 sin 40° + 6)
. To apply the mask on the right, I only need to figure out if a point lies to the left or the right of that line (let's call line vector p
). I can figure this out by taking the vector from C
to my point of interest and projecting it onto a vector perpendicular to p
. The sign of the projection will tell me the side the point is on. Obtaining the perpendicular vector is pretty simple in 2D: flip the coordinates and reverse the sign of one of them. That's the variable d
in my code: (-5 sin 40° - 6, 5 cos 40°)
. The vector from C
to a point of interest q = (x, y)
is q - C = (x, y + 6)
. The projection is just the scalar product (or dot product) between q
and d
. The way I chose d
it happens to point to the left, so I want d.(q-C) > 0
. This condition applies the right-hand mask.
For the left-hand mask I can use basically the same idea. The slope is the same and therefore so is d
. I just need offset my point from the lower-left corners of stripes instead of from C
. Those have coordinates (-7.5, 0.5)
(upper stripe) and (-7.5, -1.5)
(lower stripe). So that would call for two independent rules for the two stripes. However, note that all points affected by the lower mask are in the lower stripe and hence have negative y. And all points affected by the upper mask have positive y. So I can simply switch my offset using Sign[y]
which is 1
for positive and -1
for negative y
. So my offset point becomes (-7.5, -0.5 + Sign[y])
. Otherwise the mask works just like the right-hand mask. Of course, this time the projection needs to be negative. So, naively that would be something like RH-projection > 0 && LH-projection < 0
(which is also what I originally had in the code). But we can shorten this, because multiplying a positive and a negative number has to give a negative number, so it's just RH * LH < 0
(where RH
and LH
are the respective projections).
That's it. Putting it all together leads to the following logical structure:
(
(is_in_circle || is_in_stripe)
&&
is_between_left_and_right_mask
)
||
(
is_in_circle && left_of_edge
)
Just to be clear, the coordinates in my explanation refer to the construction diagram given in the challenge. As mentioned above my code actually multiplies all of them by 2
- I changed it to save bytes, but the byte count is actually identical, and I couldn't be bothered to revert the change again. Also integers look nicer.