diff --git a/tools/sim_layouts/famires_gen2.py b/tools/sim_layouts/famires_gen2.py index 93b5b2f..a7dba5a 100644 --- a/tools/sim_layouts/famires_gen2.py +++ b/tools/sim_layouts/famires_gen2.py @@ -172,7 +172,8 @@ def p1_efficient_corner(): rooms += [toilet] walls += twalls rooms += [dict(label="待合", rect=[0.0, 0.9, 0.5, 3.3], kind="guest"), - *register([3.3, 2.2, 6.1, 2.9], [3.3, 1.3, 6.1, 2.2]), + # 縦のカウンター。客は入口の側(左)に立ち、入口へ向かって並ぶ。下の通路をふさがない(2026-10-23 エイイチと決めた) + *register([3.3, 0.4, 4.0, 2.9], [4.0, 0.4, 4.9, 2.9]), dict(label="ドリンクバー", rect=[16.8, 2.8, 20.8, 3.5], kind="drink")] t = strip(0.0, 4.6, "v", 4) # 左の壁ぞいのソファ(トイレの手前で止める) t += island(2.4, 4.8, "v", 4) # 背中合わせのソファの列(間の通路1.2m) @@ -236,7 +237,8 @@ def p4_relaxed_side(): rooms += [toilet] walls += twalls rooms += [dict(label="待合", rect=[0.6, 0.0, 3.0, 0.5], kind="guest"), - *register([2.8, 2.0, 5.8, 2.7], [2.8, 1.0, 5.8, 2.0]), + # 縦のカウンター。客は入口の側(左)に立ち、入口へ向かって並ぶ。下の通路をふさがない(2026-10-23 エイイチと決めた) + *register([2.8, 0.7, 3.5, 3.2], [3.5, 0.7, 4.4, 3.2]), dict(label="ドリンクバー", rect=[16.0, 3.4, 20.0, 4.1], kind="drink")] t = strip(0.3, 15.2, "h", 4, seats=6, walls=walls) # 家族用の6人ボックス(上の壁ぞい) t += strip(0.0, 5.2, "v", 5, walls=walls) # 左の壁ぞい diff --git a/tools/sim_layouts/famires_v3.py b/tools/sim_layouts/famires_v3.py index 73849e6..816f6de 100644 --- a/tools/sim_layouts/famires_v3.py +++ b/tools/sim_layouts/famires_v3.py @@ -68,6 +68,7 @@ SETTINGS = dict( dish_front_depth=1.2, # 料理の受け渡し口の前、この奥行きは何も置かない joint_max_depth=0.08, # 仕切りが家具に食い込んでよい深さ(背もたれの上に立つ仕切り) register_min_len=2.5, + register_clear=0.75, # 会計に立つ点・レジに並ぶ点は、ロボットの道からこの距離以上(人がロボットをよける距離と同じ) lsofa_end_reach=0.6, # L字席:開いた辺から、ソファの端に沿ってこの長さまで止まってよい(端の席の人が受け取れる所) standby_slot=0.8, # 待機場所の1台分の最小の大きさ(m×m) ) @@ -967,6 +968,30 @@ def export_unity(L, res_t, ctx, nm, out, gen_id): return U +def check_register_clear(U): + """会計に立つ点とレジに並ぶ点が、ロボットの道(受け渡し口から卓・卓から卓。ふだんの道も狭い道も)から + register_clear 以上離れているか。レジの置き方で通路を狭くしない(2026-10-23 エイイチと決めた)""" + S = SETTINGS + def segd(p, a, b): + dx, dy = b[0] - a[0], b[1] - a[1] + L2 = dx * dx + dy * dy + t = 0.0 if L2 == 0 else max(0.0, min(1.0, ((p[0] - a[0]) * dx + (p[1] - a[1]) * dy) / L2)) + return math.hypot(p[0] - a[0] - t * dx, p[1] - a[1] - t * dy) + segs = [] + for group in ("from_pass", "between"): + for name, r in ((U.get("routes") or {}).get(group) or {}).items(): + if r: + segs += [(name, a, b) for a, b in zip(r["points"], r["points"][1:])] + v = [] + for p in U["places"]: + if p["kind"] not in ("Register", "RegisterQueue") or not segs: + continue + d, name = min((segd(p["point"], a, b), n) for n, a, b in segs) + if d < S["register_clear"] - 1e-6: + v.append(("入口まわり", f"{p['label']} がロボットの道({name})から{d:.2f}m({S['register_clear']}m以上離す)")) + return v + + def generation_id(): """出力の版の番号:作り方のコードと記憶の店の原本、設定から決まる(同じなら毎回同じ)。 layout・analysis・summary に同じ番号を入れ、組み合わせが同じ版かを読む側で確かめられるようにする""" @@ -1025,7 +1050,15 @@ def main(): fig.savefig(tmp / f"{nm}.png", bbox_inches="tight", facecolor="white") plt.close(fig) export(L, res_a, summ, conv, nm, tmp, gen_id) - export_unity(L, res_a, ctx, nm, tmp, gen_id) + U = export_unity(L, res_a, ctx, nm, tmp, gen_id) + vr = check_register_clear(U) + if vr: + failed = True + print(f"[NG] {nm}: {L['name']}") + for k, msg in vr: + print(f" - {k}: {msg}") + allsum.append(dict(file=nm, name=L["name"], status="NG", violations=[f"{k}: {m}" for k, m in vr])) + continue allsum.append(dict(file=nm, status="OK", generation=gen_id, resolution_mismatch=conv, **summ)) print(f"[OK] {nm}: {summ} マス目の差: {conv}") if failed: