--- jupyter: description: "A Penrose rhombus tiling grown by deflation of golden triangles; the\ \ exact tiles keep the area of the starting wheel, and thick to thin tends to\ \ \u03C6." --- # Penrose tiling by deflation Roger Penrose's rhombus tiling covers the plane without ever repeating. It grows by deflation: each half-rhombus, a golden triangle, splits into smaller ones by the golden ratio φ. The example starts from a wheel of ten golden triangles of radius 100, deflates it seven times and builds the tiles of the sixth generation. The tiles are exact planex2d faces. Their union must keep the area of the wheel it started from, and the ratio of thick to thin rhombs tends to φ. ![A Penrose tiling of thick and thin rhombs](../_static/gallery/penrose-tiling.png){.result} ```python import cmath import math import matplotlib.pyplot as plt import planex as px ``` ```python nbsphinx="hidden" from docs_figures import GUIDE, LIGHT, Row ``` ## Deflation A triangle is its kind, 0 for a half of a thin rhomb and 1 for a half of a thick one, and its corners A, B and C as complex numbers. `deflate` splits every triangle into two or three smaller ones. **Check:** the ratio of thick to thin halves tends to φ: ```python phi = (1 + math.sqrt(5)) / 2 radius = 100.0 def deflate(triangles): result = [] for kind, A, B, C in triangles: if kind == 0: P = A + (B - A) / phi result += [(0, C, P, B), (1, P, C, A)] else: Q = B + (A - B) / phi R = B + (C - B) / phi result += [(1, R, C, A), (1, Q, R, B), (0, R, Q, A)] return result wheel = [] for i in range(10): B = cmath.rect(radius, (2 * i - 1) * math.pi / 10) C = cmath.rect(radius, (2 * i + 1) * math.pi / 10) wheel.append((0, 0j, C, B) if i % 2 == 0 else (0, 0j, B, C)) generations = [wheel] for g in range(7): generations.append(deflate(generations[-1])) for g, triangles in enumerate(generations): thin = sum(1 for t in triangles if t[0] == 0) thick = len(triangles) - thin print("generation", g, thick, "thick and", thin, "thin halves, ratio", round(thick / thin if thin else 0, 6)) print("golden ratio", round(phi, 6)) ``` ## Exact tiles Each half-rhombus of the sixth generation is a planex2d face. **Check:** their union is the wheel of ten triangles they came from, one face with the area 10 r² sin(36°) / 2: ```python def face(A, B, C): return px.FromPolyline([(A.real, A.imag), (B.real, B.imag), (C.real, C.imag)], closed=True).Face() triangles = generations[6] halves = [(kind, face(A, B, C)) for kind, A, B, C in triangles] union = px.Unify([f for kind, f in halves]) print(len(halves), "triangles, union area", union.mass, "wheel", 10 * radius**2 * math.sin(math.radians(36)) / 2) print(len(union.faces), "face") ``` ## Rhombs Two halves that share their base make one rhomb, either a thick one of 72° or a thin one of 36° (Figure 1). ```python pairs = {} for (kind, A, B, C), (_, f) in zip(triangles, halves): key = (round((B + C).real / 2, 6), round((B + C).imag / 2, 6)) pairs.setdefault(key, []).append((kind, f)) rhombs = {0: [], 1: []} for parts in pairs.values(): if len(parts) == 2: rhombs[parts[0][0]].append(px.Unify([parts[0][1], parts[1][1]])) print(len(rhombs[1]), "thick and", len(rhombs[0]), "thin whole rhombs, ratio", round(len(rhombs[1]) / len(rhombs[0]), 4)) ``` ```python nbsphinx="hide-input" Row((union, "Thick rhombs orange, thin ones blue", {"fill": False, "fills": [(px.Compound(rhombs[1]), GUIDE), (px.Compound(rhombs[0]), LIGHT)]}), caption="A Penrose tiling of the sixth generation") ``` ```python nbsphinx="hidden" fig, ax = plt.subplots(figsize=(9, 9)) for kind, color in ((1, "goldenrod"), (0, "steelblue")): for r in rhombs[kind]: r.Plot(ax=ax, face_col=color, line_col="black", legend=False) ax.set_aspect("equal") ax.axis("off") import sys sys.path.insert(0, "..") from gallery import save_scene, save_figure, save_animation, HIDDEN save_figure(fig, "penrose-tiling") plt.close(fig) ```