"""Plot ideal spur-gear contact overlap; write PNG in the current directory. Tested with Python 3.14.4; dependencies: NumPy and Matplotlib (root pyproject.toml). """ from pathlib import Path import os os.environ.setdefault("MPLCONFIGDIR", "/tmp/codex-wiki-laplace-mpl") import numpy as np import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt alpha = np.deg2rad(20.0) r1, r2, module = 20.0, 40.0, 2.0 rb1, rb2 = r1 * np.cos(alpha), r2 * np.cos(alpha) length = np.sqrt(22.0**2-rb1**2) + np.sqrt(42.0**2-rb2**2) - 60.0*np.sin(alpha) base_pitch = np.pi * module * np.cos(alpha) epsilon = length / base_pitch fig, (ax, count_ax) = plt.subplots(2, 1, figsize=(7.6, 4.2), dpi=100, sharex=True, gridspec_kw={"height_ratios": [2, 1]}, constrained_layout=True) fig.patch.set_facecolor("white") colors = ["#6b7280", "#147d92", "#d17b16", "#477b39"] for j, color in zip(range(-1,3), colors): ax.broken_barh([(j, epsilon)], (j-.25, .5), facecolors=color) ax.set_yticks([-1,0,1,2], ["Pair -1", "Pair 0", "Pair 1", "Pair 2"]) ax.set_ylim(-1.6, 2.6) ax.set_title(f"Ideal tooth-contact timing: contact ratio = {epsilon:.3f}", fontsize=12) ax.set_ylabel("Successive tooth pairs") x = np.linspace(0, 3, 3001) count = np.zeros_like(x) for j in range(-2,4): count += ((x >= j) & (x < j+epsilon)).astype(int) count_ax.step(x, count, where="post", color="#173a56", linewidth=2) count_ax.set_yticks([1,2]) count_ax.set_ylim(.7, 2.3) count_ax.set_ylabel("Pairs in contact") count_ax.set_xlabel("Time / tooth-passage period") for axis in [ax,count_ax]: axis.set_facecolor("white") axis.grid(axis="x", color="#d6dce0", linewidth=.7) axis.spines[["right","top"]].set_visible(False) count_ax.set_xlim(0, 3) fig.savefig(Path.cwd()/"gear-contact-ratio-overlap.png", facecolor="white") plt.close(fig)