#!/usr/bin/env python3 """Render the Daikoku PA junction from Circuit.luau geometry. MEASURE FIRST: code reasoning about elevation misleads (see project notes). This parses the ACTUAL baked samples + the lift profile out of Circuit.luau and draws what the builder will produce, so it can be compared against the real aerial photographs before pushing to Studio. Outputs a 3-panel figure: 1. top-down -- mainline vs PA ring footprint (shows the overlap) 2. elevation -- deck height through the junction (shows the clearance) 3. section -- cross-section at the PA, mainline flying over the apron """ import math import re import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt from matplotlib.patches import Circle, Rectangle SRC = "/home/jesse/roblox/tokyo-wangan-racing/src/shared/Circuit.luau" OUT = "/home/jesse/roblox/tokyo-wangan-racing/tools/daikoku_check.png" src = open(SRC).read() PA_C = tuple( float(x) for x in re.search( r"PA_CENTER = Vector3\.new\(([-\d.]+),\s*([-\d.]+),\s*([-\d.]+)\)", src ).groups() ) PA_R = float(re.search(r"PA_RADIUS\s*=\s*([\d.]+)", src).group(1)) LIFT = float(re.search(r"PA_LIFT\s*=\s*(\d+)", src).group(1)) FLAT = int(re.search(r"LIFT_FLAT\s*=\s*(\d+)", src).group(1)) RAMPN = int(re.search(r"LIFT_RAMP\s*=\s*(\d+)", src).group(1)) raw = re.findall( r'\{\s*(-?[\d.]+),\s*(-?[\d.]+),\s*(-?[\d.]+),\s*(\d),\s*(\d),\s*"([^"]+)"\s*\}', src ) S = [ {"x": float(a), "y": float(b), "z": float(c), "tun": int(d) == 1} for a, b, c, d, e, f in raw ] n = len(S) best, bd = 0, 1e18 for i, s in enumerate(S): d = math.hypot(s["x"] - PA_C[0], s["z"] - PA_C[2]) if not s["tun"] and d < bd: best, bd = i, d def circd(i, j): d = abs(i - j) return min(d, n - d) def lift_t(i): d = circd(i, best) if d <= FLAT: return 1.0 if d >= FLAT + RAMPN: return 0.0 u = (d - FLAT) / RAMPN return 1 - (u * u * (3 - 2 * u)) for i, s in enumerate(S): s["ly"] = s["y"] + LIFT * lift_t(i) RING_R = PA_R + 130 RING_W = 44 ringY = PA_C[1] entry, exitI = (best - 14) % n, (best + 14) % n fig = plt.figure(figsize=(17, 6.2)) fig.suptitle( "Daikoku PA junction — rebuilt from reference photos (expressway flies OVER the apron)", fontsize=13, fontweight="bold", ) # ---- 1. TOP-DOWN ----------------------------------------------------------- ax = fig.add_subplot(1, 3, 1) ax.set_title("Top-down: footprints overlap by design", fontsize=10) win = [i for i in range(n) if circd(i, best) <= 55] win.sort(key=lambda i: circd(i, best)) seq = sorted(win, key=lambda i: (i - best) % n if (i - best) % n < n / 2 else (i - best) % n - n) ax.plot([S[i]["x"] for i in seq], [S[i]["z"] for i in seq], "-", color="#333", lw=7, solid_capstyle="round", label="mainline deck (elevated)") ax.add_patch(Rectangle((PA_C[0] - PA_R, PA_C[2] - PA_R), PA_R * 2, PA_R * 2, fc="#9a9a9a", ec="#555", lw=1, alpha=.55, label="parking apron (ground)")) ax.add_patch(Circle((PA_C[0], PA_C[2]), RING_R + RING_W / 2, fill=False, ec="#c44", lw=2)) ax.add_patch(Circle((PA_C[0], PA_C[2]), RING_R - RING_W / 2, fill=False, ec="#c44", lw=2, label="PA ring road (ground)")) for nm, idx, col in (("entry", entry, "#1a7"), ("exit", exitI, "#17a")): r = S[idx] tox, toz = PA_C[0] - r["x"], PA_C[2] - r["z"] m = math.hypot(tox, toz) rp = (PA_C[0] - tox / m * RING_R, PA_C[2] - toz / m * RING_R) ax.plot([r["x"], rp[0]], [r["z"], rp[1]], color=col, lw=5, solid_capstyle="round", label=f"{nm} ramp (graded)") ax.set_aspect("equal") ax.legend(fontsize=7, loc="upper right") ax.set_xlabel("X (studs)") ax.set_ylabel("Z (studs)") ax.grid(alpha=.25) # ---- 2. ELEVATION PROFILE -------------------------------------------------- ax2 = fig.add_subplot(1, 3, 2) ax2.set_title("Elevation through junction: 38-stud clearance", fontsize=10) rng = [(best + k) % n for k in range(-60, 61)] xs = list(range(-60, 61)) ax2.plot(xs, [S[i]["y"] for i in rng], "--", color="#b00", lw=1.6, label="BEFORE — deck at apron level (wall in road)") ax2.plot(xs, [S[i]["ly"] for i in rng], "-", color="#0a0", lw=2.4, label="AFTER — lifted deck") ax2.axhline(ringY, color="#777", lw=1.4, ls=":", label="PA ring / apron level") ax2.fill_between(xs, [S[i]["ly"] for i in rng], ringY, color="#0a0", alpha=.10) for idx, lb, col in ((entry - best, "entry", "#1a7"), (exitI - best, "exit", "#17a")): ax2.axvline(idx, color=col, lw=1.3, ls="-.") ax2.text(idx, ringY - 7, lb, ha="center", fontsize=7, color=col) ax2.annotate("", xy=(0, ringY), xytext=(0, ringY + LIFT), arrowprops=dict(arrowstyle="<->", color="#333", lw=1.4)) ax2.text(2.5, ringY + LIFT / 2, f"{LIFT:.0f} studs\nclearance", fontsize=8, va="center") ax2.set_xlabel("sample offset from PA centre") ax2.set_ylabel("deck height Y (studs)") ax2.legend(fontsize=7, loc="lower left") ax2.grid(alpha=.25) # ---- 3. CROSS-SECTION ------------------------------------------------------ ax3 = fig.add_subplot(1, 3, 3) ax3.set_title("Section at PA — matches reference photos", fontsize=10) ax3.add_patch(Rectangle((-PA_R, ringY - 3), PA_R * 2, 3, fc="#9a9a9a", ec="#555")) ax3.text(0, ringY - 9, "parking apron (ground level)", ha="center", fontsize=8) for sgn in (-1, 1): ax3.add_patch(Rectangle((sgn * RING_R - RING_W / 2, ringY - 3), RING_W, 4, fc="#c44", ec="#822")) ax3.text(RING_R, ringY + 6, "ring road", ha="center", fontsize=7, color="#822") deckY = ringY + LIFT ax3.add_patch(Rectangle((-bd - 60, deckY), 120, 5, fc="#333", ec="#000")) ax3.text(-bd, deckY + 12, "elevated mainline", ha="center", fontsize=8, fontweight="bold") for px in (-bd - 40, -bd + 40): ax3.add_patch(Rectangle((px - 4, ringY - 2), 8, LIFT + 2, fc="#bbb", ec="#777")) for cx in (-160, -60, 40, 140, 240): ax3.add_patch(Rectangle((cx, ringY, ), 26, 9, fc="#4a7fb5", ec="#245")) ax3.annotate("", xy=(-bd + 70, ringY), xytext=(-bd + 70, deckY), arrowprops=dict(arrowstyle="<->", color="#0a0", lw=1.6)) ax3.text(-bd + 78, ringY + LIFT / 2, f"{LIFT:.0f} studs\n(cars pass under)", fontsize=8, va="center", color="#070") ax3.set_xlim(-PA_R - 220, PA_R + 220) ax3.set_ylim(ringY - 22, deckY + 30) ax3.set_xlabel("distance from PA centre (studs)") ax3.set_ylabel("Y (studs)") ax3.grid(alpha=.25) fig.tight_layout(rect=[0, 0, 1, .94]) fig.savefig(OUT, dpi=118) print("wrote", OUT) print(f"nearest sample={best} dist={bd:.1f} ring outer={RING_R + RING_W / 2:.1f}" f" overlap={RING_R + RING_W / 2 - bd:+.1f} studs")