Here is a small Metapost function to draw a general Reuleaux polygon. Explanations below.
prologues := 3;
outputtemplate := "%j%c.eps";
vardef reuleaux(expr n) =
for t=0 step 360/n until 359:
1/2 up rotated t { left rotated (t+90/n) } .. { left rotated (t+270/n)}
endfor cycle enddef;
beginfig(1);
for i := 3 step 2 until 9:
draw reuleaux(i) scaled 40i withcolor .6 red withpen pencircle scaled 1;
draw fullcircle scaled 40i withcolor .6 white;
endfor
endfig;
end.
Scale, rotate, shift as required. It's sized so that it fits inside a fullcircle
scaled to the same amount.
![enter image description here](https://i.stack.imgur.com/aIzqu.png)
Each corner is a point
of the path, so if you want to join the vertices, join points 0, 1, ..., n-1
; if you want the mid-points of each arc, use points 1/2, 3/2, ..., n-1/2
, like this:
beginfig(2);
path t[];
for n := 3 upto 7:
t[n] = reuleaux(n) scaled 60 shifted (75n,0);
fill t[n] withcolor red+0.75green+0.2blue;
draw for i = 0 upto n-1: point i of t[n] -- endfor cycle withcolor .6 red;
draw for i = 0 upto n-1: point i+1/2 of t[n] -- endfor cycle withcolor .6 blue;
endfor
endfig;
![enter image description here](https://i.stack.imgur.com/fU5Ma.png)
Obviously, you also could pick out points to label as well.
beginfig(3);
path t; t = reuleaux(3) scaled 90;
draw t withcolor .6 red;
dotlabel.top (btex $A$ etex, point 0 of t);
dotlabel.llft(btex $B$ etex, point 1 of t);
dotlabel.lrt (btex $C$ etex, point 2 of t);
endfig;
![Labelled Reuleaux triangle](https://i.stack.imgur.com/DxEAC.png)
Explanations
I've revised this answer a couple of times, as I thought about the problem a bit more. The original versions used buildcycle
and the pre-defined circular paths, but they are not really needed. The final version here is a simple and correct as I can make it.
The reuleaux(n)
function returns a path
with n vertices connected by circular arcs, whose radius is the length of the longest diagonal of the corresponding regular polygon.
To understand what it does, consider first the following function that returns the path of a regular polygon with n vertices:
vardef polygon(expr n) =
for t=0 step 360/n until 359:
up rotated t --
endfor cycle enddef;
up
expands to (0,1)
, so with n=3 this function expands to
(0,1) -- (-0.866,-0.5) -- (0.866,-0.5) -- cycle
as required for a 3-sided regular polygon fitting inside a circle of unit radius. In Metapost however the predfined fullcircle
path has unit diameter so for consistency it would be better to scale our polygon down by 1/2,
vardef polygon(expr n) =
for t=0 step 360/n until 359:
1/2 up rotated t --
endfor cycle enddef;
The precedence rules in MP mean that 1/2 up
expands to (0,0.5)
which is what we want.
Now we have a regular polygon that fits inside a fullcircle
and to make it into a Reuleaux polygon we have to bend the straight lines into arcs centred on the opposite vertex (or the mid-point of the opposite vertices when n is even). We can do this using the path direction notation, and changing --
into ..
to allow the path to bend.
vardef reuleaux(expr n) =
for t=0 step 360/n until 359:
1/2 up rotated t { left rotated (t+90/n) } .. { left rotated (t+270/n)}
endfor cycle enddef;
Since left
is up rotated 90
, the required directions are given by the formulae shown, as you can work out with a little elementary geometry:
![Some elementary geometry](https://i.stack.imgur.com/en7Yy.png)
If you want to convince yourself that the resulting arcs really are circular and have the right centres then draw appropriately scaled and shifted circles on top. The radius of such a circle would be the length of the longest diagonal on the polygon - AC in the figure above - which you can find with length (point (n+1)/2 of r - point 0 of r)
where r=reuleaux(n)
.
Applications
The Reuleaux triangle features in some traditional geometric patterns, like this one:
![Traditional geometric tiling](https://i.stack.imgur.com/pWUHw.png)
which we can draw like this: (if there's a better way to do the tiling, please comment!)
beginfig(6);
path t, ring; s := 10;
t = reuleaux(3) scaled s;
ring = for i=0 upto 5: subpath(-1,1) of t shifted (0,s) rotated (i*60) .. endfor cycle;
pair offset;
for i=0 upto 5:
dx := 0;
for j=0 upto 13:
offset := (3*s,0) rotated (30*(j mod 2*2-1));
dx := dx + xpart offset;
dy := 3*i*s + 1/2 ypart offset;
draw ring shifted (dx,dy) withcolor (.5,.7,.9);
endfor
endfor
endfig;
This may form the basis for other explorations. For example just changing the definition of t
to t = reuleaux(2) scaled s
produced this rather wonderful pattern.
![enter image description here](https://i.stack.imgur.com/1jyyn.png)
Variations
If you want a Reuleaux polygon pointing right instead of up, then you just have to swap up
and left
in the definition for right
and up
.
vardef reuleaux(expr n) =
for t=0 step 360/n until 359:
1/2 right rotated t { up rotated (t+90/n) } .. { up rotated (t+270/n)}
endfor cycle enddef;
beginfig(7);
for n=3 upto 7:
draw fullcircle scaled 60 shifted (75n,0) withcolor .8 white;
draw reuleaux(n) scaled 60 shifted (75n,0) withcolor .67 red;
endfor
endfig;
This is slightly more consistent with plain MP as point 0 of these shapes corresponds to zero degrees rotation. They look like this:
![enter image description here](https://i.stack.imgur.com/DYRPK.png)
We can also swap the two directions in the definition to produce what might be called anti-Reuleaux polygons.
vardef antireuleaux(expr n) =
for t=0 step 360/n until 359:
1/2 right rotated t { up rotated (t+270/n) } .. { up rotated (t+90/n)}
endfor cycle enddef;
![enter image description here](https://i.stack.imgur.com/5pSCw.png)
As you can see below, these anti-shapes are similar to, but subtly differ from, hypocycloid curves.
vardef hypocycloid(expr k) =
for t=0 step 1 until 360:
point 0 of (fullcircle scaled (1/k) rotated (-t*k)
shifted (1/2 right scaled (1-1/k))) rotated t --
endfor cycle
enddef;
![enter image description here](https://i.stack.imgur.com/i8WT3.png)
It is also possible to round the corners of a Reuleaux polygon while still retaining the constant width property. Here is a function to produce a rounded shape that takes a slightly more generalized approach. The first parameter is the number of sides, the second is the radius of the rounded corners as a fraction of the width.
vardef polygon(expr n) =
for t=0 step 360/n until 359:
1/2 right rotated t --
endfor cycle
enddef;
vardef rounded_reuleaux(expr n, s) =
save m, a, b, p; m := (n+1)/2;
pair a,b; path p; p := polygon(n);
for i = 0 upto n-1:
hide(
a := point i of p - point i+m of p;
b := point i+1 of p - point i+m of p;
)
point i of p + s*unitvector(a) { up rotated angle a } ..
point i+1 of p + s*unitvector(b) { up rotated angle b } ..
endfor cycle
enddef;
beginfig(8);
for n := 3 upto 7:
fill rounded_reuleaux(n,1/6) scaled 60 shifted (85n,0) withcolor (1/2,3/4,5/6);
draw reuleaux(n) scaled 60 shifted (85n,0);
endfor
![enter image description here](https://i.stack.imgur.com/Q5VhH.png)
Best Answer
Here is my solution based on this answer.