# 手描きの見取り図(sketch.jpg)の読み取り値(画素)から、店の形(famires-layout/0.3 の layout)を起こす # 縮尺:標準の家具の大きさから、横 89px/m・縦 79px/m(notes.md 参照) # 原点:外壁の内側の左下の角 = 画素 (32, 1070) import json, sys, copy from pathlib import Path SX, SY = 89.0, 79.0 PX0, PY0 = 32, 1070 fx = lambda px: round((px - PX0) / SX, 2) fy = lambda py: round((PY0 - py) / SY, 2) W, D = 16.4, 12.1 # 右の壁 1495px → 16.44m、上の壁 115px → 12.09m def centered(px0, px1, py0, py1, w, h): """画素の箱の真ん中に、標準の大きさ w×h(m)の家具を置く""" cx, cy = (fx(px0) + fx(px1)) / 2, (fy(py0) + fy(py1)) / 2 return round(cx - w / 2, 2), round(cy - h / 2, 2) def t4(px0, px1, py0, py1, bottom=False): x, y = centered(px0, px1, py0, py1, 1.2, 1.2) if bottom: y = 0.0 return dict(type="t4", x=x, y=y, w=1.2, h=1.2, seats=4) def r4(px0, px1, py0, py1): x, y = centered(px0, px1, py0, py1, 1.1, 1.1) return dict(type="r4", x=x, y=y, w=1.1, h=1.1, seats=4) def lsofa(px1, py0, py1, flip, top=False, bottom=False): """L字席:種類に標準の大きさがないので、図の外形(左の壁に付けて描かれている)の大きさをそのまま使う(0.05m に丸める)""" r = lambda v: round(round(v / 0.05) * 0.05, 2) ytop, ybot = fy(min(py0, py1)), fy(max(py0, py1)) w, h = r(fx(px1)), r(ytop - ybot) y = D - h if top else (0.0 if bottom else r(ybot)) return dict(type="booth6L", x=0.0, y=round(y, 2), w=w, h=h, seats=6, flip=flip, mirror=False) def v0(): tables = [ lsofa(235, 323, 115, True, top=True), # 左上の6(帯が上・列が左 → 開いた角は右下) t4(300, 410, 135, 225), t4(463, 573, 133, 222), r4(252, 350, 288, 373), r4(427, 535, 288, 370), lsofa(195, 560, 357, False), # 左の真ん中の6(列が左・帯が下 → 開いた角は右上) t4(263, 373, 460, 555), t4(470, 585, 463, 562), lsofa(300, 867, 633, True), # 仕切りの下の6(帯が上) t4(345, 463, 633, 740), t4(500, 603, 639, 730), dict(type="long6", x=round((fx(285) + fx(570)) / 2 - 1.6, 2), y=round((fy(793) + fy(947)) / 2 - 0.97, 2), w=3.2, h=1.94, seats=6), lsofa(268, 1070, 810, False, bottom=True), # 左下の6(列が左・帯が下) t4(340, 447, 990, 1070, bottom=True), t4(575, 665, 997, 1070, bottom=True), t4(938, 1042, 1000, 1070, bottom=True), t4(1142, 1238, 1003, 1070, bottom=True), # 右下の8(U字・左が開いている)→ ボックス席(ベンチが上下・右は壁)の6人の大きさで、席数は8 dict(type="booth", axis="v", x=round(W - 1.8, 2), y=0.0, w=1.8, h=1.85, seats=8), ] toilet = [6.27, 11.33, 7.71, 12.1] # 590–718px, 175px〜上の壁 rooms = [ dict(label="パントリー", rect=[8.07, 3.5, 9.35, 10.1], kind="back"), dict(label="キッチン", rect=[9.35, 3.52, 15.12, 10.1], kind="back"), dict(label="冷凍庫・保存庫", rect=[15.12, 3.52, 16.4, 10.1], kind="back"), dict(label="洗い場", rect=[10.09, 10.1, 15.26, 12.1], kind="back"), dict(label="倉庫", rect=[15.26, 10.1, 16.4, 12.1], kind="back"), dict(label="トイレ", rect=toilet, kind="guest"), dict(label="ドリンクバー", rect=[7.8, 11.52, 9.84, 12.1], kind="drink"), dict(label="待合", rect=[9.55, 0.0, 10.1, 1.2], kind="guest"), # レジ:図の箱(710–870px, 928–980px)がカウンター。店員はパントリー側(上)に立つ dict(label="レジ", rect=[fx(710), fy(980), fx(870), fy(928)], kind="guest"), dict(label="レジ内", rect=[fx(710), fy(928), fx(870), round(fy(928) + 0.5, 2)], kind="back"), ] walls = [ dict(label="仕切り", rect=[0.0, fy(607), fx(615), fy(577)]), dict(label="パントリーの壁", rect=[fx(702), fy(824), fx(750), 10.1]), dict(label="キッチンの壁", rect=[fx(914), fy(840), W, fy(792)]), dict(label="トイレの壁", rect=[6.27, 11.33, 6.57, 12.1]), dict(label="トイレの壁", rect=[7.41, 11.33, 7.71, 12.1]), ] doors = [ dict(label="パントリーの下の出入り口", rect=[8.07, 3.4, 9.35, 3.6], kind="staff", door=False), dict(label="パントリーの上の出入り口", rect=[8.07, 10.0, 9.35, 10.2], kind="staff", door=False), dict(label="洗い場の出入り口", rect=[9.99, 10.66, 10.19, 11.5], kind="staff", door=True), ] return dict( name="⓪ 手描きの見取り図から自動で起こした店(記憶のファミレス)", style="効率重視", outer=dict(w=W, d=D), entrance=dict(side="bottom", a0=fx(710), a1=fx(875)), rooms=rooms, walls=walls, doors=doors, toilet_doors=[[6.57, 10.13, 7.41, 11.33]], dish_up=[dict(label="受け渡し口", rect=[8.07, 3.5, 9.35, 3.9])], robot_standby=dict(label="ロボット待機・充電", rect=[15.6, 2.0, 16.4, 2.8], slots=1), tables=tables, ) def final(): L = copy.deepcopy(v0()) T = L["tables"] # 1) 仕切りの下の6(T09)と左下の6(T13)が重なる・T09 と長テーブル(T12)が重なる・T09/T13 の座る側がない # → 2つのL字席を背中合わせに接して、仕切りの下に収める(T13 の奥行き 3.3→2.9m、T09 を y=2.9 へ)。 # T09 の幅を T13 と同じ 2.65m に(図では T09 の上の帯が長テーブルの上にかぶさって描かれている)。 # 長テーブルを右へ 0.31m(L字席との間を人が通れる 0.5m に) T[12]["h"] = 2.9 T[8].update(y=2.9, w=2.65) T[11]["x"] = round(T[8]["x"] + T[8]["w"] + 0.5, 2) # 2) トイレの入口から1m以内の T03(上の段の右の4人席)→ 入口の左に目隠しの壁を立てる L["walls"].append(dict(label="トイレの目隠しの壁", rect=[6.27, 10.13, 6.57, 11.33])) # 3) レジ:入口から1.5m以内・長さ2.5m未満・受け渡し口の前 → 入口の1.5m先へ上げ、2.5mに伸ばす。 # パントリーの壁の下の通路と、キッチンの壁の下の通路をふさがないよう、カウンター0.4m・店員の立つ所0.4mにし、 # 右の端をキッチンの壁の角から1m離す(9.1m) for r in L["rooms"]: if r["label"] == "レジ": r["rect"] = [6.6, 1.5, 9.1, 1.9] if r["label"] == "レジ内": r["rect"] = [6.6, 1.9, 9.1, 2.3] return L if __name__ == "__main__": out = Path("/home/claude/blind/out") for nm, L in (("auto_v0.json", v0()), ("auto_final.json", final())): json.dump({"layout": L}, open(out / nm, "w"), ensure_ascii=False, indent=1) print(nm, len(L["tables"]), "卓", sum(t["seats"] for t in L["tables"]), "席")