- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환 - Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용 - pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관) - worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md) - D:\Rhino-MCP 경로 참조를 새 위치로 치환 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
73 lines
3.2 KiB
Python
73 lines
3.2 KiB
Python
"""Compile the D3 rebar schedule (SD400 / SD500 tables) and compare bar counts with the model.
|
|
|
|
Schedule: 판독/3_survey.json text rows (mark rows + diameter-group subtotal rows).
|
|
Model counts: verification result files (bar count checks) in 검증/ - not the build inputs.
|
|
Writes 검증/rebar_schedule_compare.json and prints a compact table.
|
|
"""
|
|
import json
|
|
from collections import defaultdict
|
|
from pathlib import Path
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
OFF = {False: 0, True: 23750} # SD500 table is shifted by ~23,750 in x
|
|
COL = {"mark": 2100, "shape": 3000, "dia": 3900, "n": 4800, "L": 19500, "tot": 20750}
|
|
|
|
|
|
def rows():
|
|
texts = json.loads((HERE / "판독" / "3_survey.json").read_text(encoding="utf-8"))["texts"]
|
|
out = {False: defaultdict(dict), True: defaultdict(dict)}
|
|
for t in texts:
|
|
if t["y"] < 15000 or t["y"] > 31000:
|
|
continue
|
|
sd500 = t["x"] > 21000
|
|
x = t["x"] - OFF[sd500]
|
|
col = min(COL, key=lambda c: abs(COL[c] - x))
|
|
if abs(COL[col] - x) < 400:
|
|
out[sd500][round(t["y"] / 10)][col] = t["text"]
|
|
elif 21000 - 300 < x < 23500: # subtotal columns right of total
|
|
out[sd500][round(t["y"] / 10)].setdefault("extra", []).append((round(x), t["text"]))
|
|
return out
|
|
|
|
|
|
def model_counts():
|
|
counts = {}
|
|
for f in ("verify_rebar_v0.1.04_reloaded.json", "verify_footing_rebar_v0.1.04_reloaded.json",
|
|
"verify_coping_rebar_v0.1.08_reloaded.json"):
|
|
for r in json.loads((HERE / "검증" / f).read_text(encoding="utf-8"))["results"]:
|
|
if r["item"].endswith("bar count") or r["item"].endswith("bar count vs schedule"):
|
|
counts[r["item"].split()[0]] = r["actual"]
|
|
return counts
|
|
|
|
|
|
def main():
|
|
data, mc = rows(), model_counts()
|
|
marks, groups = [], []
|
|
for sd500, rs in data.items():
|
|
last_dia = None
|
|
for y in sorted(rs, reverse=True):
|
|
r = rs[y]
|
|
if r.get("mark", "").strip() and r["mark"][0] in "PBCSU" and r["mark"][1:].isdigit() or r.get("mark") == "UA1":
|
|
dia = r.get("dia", "")
|
|
dia = last_dia if dia in ('"', "") else dia
|
|
last_dia = dia
|
|
n = r.get("n")
|
|
L = float(r["L"])
|
|
tot = float(r["tot"])
|
|
if n is None: # B9: quantity blank -> derived
|
|
n = f"{tot / L:.0f}*"
|
|
marks.append(dict(table="SD500" if sd500 else "SD400", mark=r["mark"], shape=r.get("shape"),
|
|
dia=dia, n=n, L=L, total=tot, model=mc.get(r["mark"])))
|
|
elif "tot" in r and "extra" in r:
|
|
ex = sorted(r["extra"])
|
|
groups.append(dict(table="SD500" if sd500 else "SD400", total=r["tot"], extra=[v for _, v in ex]))
|
|
json.dump(dict(marks=marks, groups=groups), open(HERE / "검증" / "rebar_schedule_compare.json", "w",
|
|
encoding="utf-8"), ensure_ascii=False, indent=1)
|
|
for m in marks:
|
|
print(m["table"], m["mark"], m["shape"], m["dia"], m["n"], m["L"], m["total"], "model", m["model"])
|
|
for g in groups:
|
|
print("GROUP", g)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|