"""いまの並びと、T06 を右へ1.0m 寄せた案を、上の区画だけ並べて描く(2026-10-29)。 使い方: python3 round_compare_img.py <出力フォルダ/>""" import sys, json sys.path.insert(0, sys.argv[1]) import famires_v3 as v, famires_p0, unity_export as ux import matplotlib; matplotlib.use('Agg') import matplotlib.pyplot as plt from matplotlib.patches import Rectangle, Circle from matplotlib import font_manager as fm fm.fontManager.addfont('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc') plt.rcParams['font.family'] = fm.FontProperties(fname='/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc').get_name() D = sys.argv[2] fig, axes = plt.subplots(1, 2, figsize=(15, 8.0)) for ax, (title, sh) in zip(axes, (("いま", 0.0), ("案:T06(右の丸テーブル)を右へ1.0m", 1.0))): L = v.prepare(famires_p0.p0_memory()) for t in L["tables"]: if t["id"] == "T06": t["x"] = round(t["x"] + sh, 3) ctx = {} res, _ = v.analyze(L, v.SETTINGS["res"], ctx) U = ux.build(L, res, ctx["grid"], ctx["d_norm"], ctx["d_pass"], ctx["sides"], v.standby_slots(L["robot_standby"]), v.FURNITURE_TYPES, {}) R = ux.build_routes(L, res, ctx["grid"], v.SETTINGS["normal_width"], v.ROBOT_MODELS[v.SETTINGS["model"]]["pass_width"]) for r in U["rooms"]: x0, y0, x1, y1 = r["rect"]; ax.add_patch(Rectangle((x0, y0), x1-x0, y1-y0, fc='#eceef2', ec='#999', lw=0.6)) if x0 < 10 and y0 < 17.5: ax.text(min((x0+x1)/2, 10.6), (y0+y1)/2, r["label"], ha='center', va='center', fontsize=9, color='#666') for w in U["walls"] + [dict(rect=r) for r in U["outer_walls"]]: x0, y0, x1, y1 = w["rect"]; ax.add_patch(Rectangle((x0, y0), x1-x0, y1-y0, fc='#7d8590', ec='none')) for tid in ("T03", "T04", "T05", "T06"): pts = R["from_pass"][tid]["points"] ax.plot([p[0] for p in pts], [p[1] for p in pts], color='#e8590c', lw=1, alpha=0.45) for t in U["tables"]: p = t["parts"]; x0, y0, x1, y1 = t["footprint"] for b in p["benches"]: ax.add_patch(Rectangle((b[0], b[1]), b[2]-b[0], b[3]-b[1], fc='#d6d9df', ec='#555', lw=0.6)) tp = p["top"] if p.get("top_shape") == "circle": ax.add_patch(Circle(((tp[0]+tp[2])/2, (tp[1]+tp[3])/2), (tp[2]-tp[0])/2, fc='white', ec='#222', lw=1.2)) else: ax.add_patch(Rectangle((tp[0], tp[1]), tp[2]-tp[0], tp[3]-tp[1], fc='white', ec='#222', lw=1.2)) for c in p["chairs"]: r = c["rect"]; ax.add_patch(Circle(((r[0]+r[2])/2, (r[1]+r[3])/2), (r[2]-r[0])/2, fc='#f2a33a', ec='#333', lw=0.5)) if t["stop"]: ax.add_patch(Circle(tuple(t["stop"]), 0.09, fc='#e8590c', ec='white', lw=0.6, zorder=5)) if x1 < 10.5 and y0 > 8: ax.text((x0+x1)/2, y1+0.12, t["id"], ha='center', fontsize=9) T = {t["id"]: t for t in U["tables"]} s5 = T["T05"]["stop"] ax.add_patch(Circle(tuple(s5), 0.25, fc='#e8590c', alpha=0.35, ec='#e8590c', lw=1.2, zorder=4)) x6 = T["T06"]["footprint"][0] free = x6 - (s5[0] + 0.25) ax.annotate('', xy=(x6, 13.2), xytext=(s5[0]+0.25, 13.2), arrowprops=dict(arrowstyle='<->', color='#c92a2a', lw=1.4)) ax.text((x6 + s5[0] + 0.25)/2, 13.32, f"{free:.2f}m", ha='center', fontsize=10, color='#c92a2a', weight='bold') gap = x6 - 4.75 ax.annotate('', xy=(x6, 12.5), xytext=(4.75, 12.5), arrowprops=dict(arrowstyle='<->', color='#1c7ed6', lw=1.2)) ax.text((x6+4.75)/2, 12.25, f"卓の間 {gap:.1f}m", ha='center', fontsize=9, color='#1c7ed6') x6r = T["T06"]["footprint"][2] ax.annotate('', xy=(9.5, 13.0), xytext=(x6r, 13.0), arrowprops=dict(arrowstyle='<->', color='#1c7ed6', lw=1.2)) ax.text((x6r+9.5)/2, 13.12, f"{9.5-x6r:.2f}m", ha='center', fontsize=9, color='#1c7ed6') ax.set_xlim(-0.3, 10.2); ax.set_ylim(8.3, 17.5); ax.set_aspect('equal'); ax.axis('off') ax.set_title(title, fontsize=13) fig.text(0.5, 0.02, "赤い丸=T05 に料理を置くロボット(止まる位置)。赤い数字=その横を別のロボットが抜けられる幅(ふだん走らせる幅 1.0m・通れる幅 0.8m)。線=受け渡し口から T03〜T06 への道", ha='center', fontsize=10, color='#444') plt.tight_layout(rect=(0, 0.04, 1, 0.97)); plt.savefig(D + 'p0_round_compare.png', dpi=110)