Drilling a square hole with a Reuleaux triangle
A Reuleaux triangle has the same width in every direction, so when it turns inside a square, it touches all four sides at once. A drill bit of that shape, guided to follow it, cuts an almost square hole. Only the corners stay slightly round, and the hole covers 2√3 + π/6 − 3, about 98.77 %, of the square. The example is a triangle of width 20, built from three arcs and turned through a third of a revolution, and every position is united into the hole.

[1]:
import math
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML
import planex as px
The triangle
The triangle consists of three arcs, each centered on the opposite corner of an equilateral triangle with the side s = 20 (Figure 1).
[3]:
s = 20.0
A = (0.0, 0.0)
B = (s, 0.0)
C = (s / 2, s * math.sqrt(3) / 2)
triangle = px.QuickSketch(B).Arc(center=A, sweep=60).Arc(center=B, sweep=60).Arc(center=C, sweep=60).Face()
center = (s / 2, s * math.sqrt(3) / 6)
Check: its area is (π − √3) s² / 2:
[5]:
print("area", triangle.mass, "exact", (math.pi - math.sqrt(3)) / 2 * s**2)
area 281.90836920418315 exact 281.9083692041832
Constant width
Turned to any angle, the triangle’s bounding box is s by s. Moving it so that the box sits on the square’s lower left corner places it touching all four sides. Check: in 360 positions over a third of a turn, the box keeps its size:
[6]:
def placed(angle):
t = triangle.Rotated(center, angle)
(x0, y0), (x1, y1) = t.bounding_box
return t.Translated((-x0, -y0)), (x1 - x0, y1 - y0)
boxes = [placed(120 * n / 360)[1] for n in range(360)]
print("bounding box differs from s by at most", max(max(abs(w - s), abs(h - s)) for w, h in boxes))
bounding box differs from s by at most 1.4210854715202004e-14
The hole
The hole is the union of all positions over a third of a turn, which by the triangle’s symmetry covers every position there is. Check: with more positions, the scallops between them shrink, and the area approaches the exact value:
[7]:
exact = (2 * math.sqrt(3) + math.pi / 6 - 3) * s**2
for count in (30, 120, 360, 1440):
hole = px.Unify([placed(120 * n / count)[0] for n in range(count)])
print(count, "positions:", round(hole.mass / s**2, 6), "of the square, exact", round(exact / s**2, 6))
30 positions: 0.985413 of the square, exact 0.9877
120 positions: 0.987215 of the square, exact 0.9877
360 positions: 0.987545 of the square, exact 0.9877
1440 positions: 0.987662 of the square, exact 0.9877
The hole of 1440 positions in the square, with some of the positions dashed, and one of its round corners:

(a) The hole in the square

(b) A corner
In motion
The triangle drilling the hole:
[9]: