Drawing a Reuleaux Triangle with TikZ – Step-by-Step Guide

asymptotediagramsmetaposttikz-pgf

A Reuleaux triangle is a shape of constant width sort of like a rounded equilateral triangle.

Reuleaux Triangle from Wikipedia

(Reuleaux triangle – Wikipedia, the free encyclopedia)

It can be formed by the intersection of three circles like in a three set Venn diagram.

Reuleaux Triangle from MathWorld

(Reuleaux Triangle — from Wolfram MathWorld)

What is the best way to draw a Reuleaux triangle using TikZ, Asymptote, or some language that is embeddable into LaTeX? Perhaps by drawing the three circles of a Venn diagram and cutting off the rest?

Best Answer

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

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

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

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

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

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

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

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

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

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