chore(rebar): Pier_T_rebar 작업 폴더 초기 구성 및 외부 의존 파일 통합

- 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>
This commit is contained in:
ahnyongjooandClaude Sonnet 5.5 committed 2026-10-28 11:20:18 +09:00
commit 964a841de1
3978 files changed
+58013356

No files matched your search

@@ -0,0 +1,74 @@
"""Read the coping top-step outline of D1 (front view) straight from the DXF geometry (2026-10-19, trial of geometry reading).
Finds the two end-batter tip lines on layer CS-CONC-MAJR (|dx|~200, |dy| 1300..1900), chains the horizontal / vertical lines between their top
ends, converts x to the pier axis (centre of the two tips) and the heights to EL with the 'EL. xx.xxx' label next to the highest step.
Reads only. usage: python tools/extract_coping_outline.py <D1.dxf> <texts.json> [params.json] (params.json: compare with coping.top_steps)"""
import json
import re
import sys
import ezdxf
dxf, texts = sys.argv[1], sys.argv[2]
doc = ezdxf.readfile(dxf)
L = [(e.dxf.start.x, e.dxf.start.y, e.dxf.end.x, e.dxf.end.y) for e in doc.modelspace() if e.dxftype() == "LINE" and e.dxf.layer == "CS-CONC-MAJR"]
tips = [l for l in L if 150 < abs(l[2] - l[0]) < 250 and 1300 < abs(l[3] - l[1]) < 1900 and l[1] < 25000 and l[1] > 0]
tips = sorted({(round(l[0], 1), round(l[1], 1), round(l[2], 1), round(l[3], 1)) for l in tips})
if len(tips) != 2:
sys.exit(f"expected 2 tip lines, found {len(tips)}: {tips}")
top = lambda l: (l[0], l[1]) if l[1] > l[3] else (l[2], l[3]) # noqa: E731
bot = lambda l: (l[2], l[3]) if l[1] > l[3] else (l[0], l[1]) # noqa: E731
left, right = sorted(tips, key=lambda l: top(l)[0])
cx = (bot(left)[0] + bot(right)[0]) / 2
cur, end = top(left), top(right)
hv = [(round(a, 1), round(b, 1), round(c, 1), round(d, 1)) for a, b, c, d in L if (abs(a - c) < 0.05 or abs(b - d) < 0.05)]
steps, used = [], set()
while abs(cur[0] - end[0]) > 0.5 or abs(cur[1] - end[1]) > 0.5:
nxt = None
for s in hv:
if s in used:
continue
for p, q in (((s[0], s[1]), (s[2], s[3])), ((s[2], s[3]), (s[0], s[1]))):
if abs(p[0] - cur[0]) < 0.5 and abs(p[1] - cur[1]) < 0.5 and q[0] >= cur[0] - 0.5 and (q[1] >= cur[1] - 0.5 or abs(q[0] - cur[0]) > 0.5):
nxt = (s, q)
break
if nxt:
break
if not nxt:
sys.exit(f"chain broken at {cur}")
used.add(nxt[0])
if abs(nxt[1][1] - cur[1]) < 0.05:
steps.append([cur[0], nxt[1][0], cur[1]])
cur = nxt[1]
y_hi = max(s[2] for s in steps)
els = [(t["text"], t["x"], t["y"]) for t in json.load(open(texts, encoding="utf-8")) if t["dwg"] == "D1" and t["text"].startswith("EL.")
and abs(t["x"] - end[0]) < 1500 and 0 < t["y"] - y_hi < 1200]
if len(els) != 1:
sys.exit(f"need exactly one EL label next to the highest step, found {els}")
el_hi = float(re.search(r"\d+\.\d+", els[0][0]).group()) * 1000
res = [{"x0": round(a - cx), "x1": round(b - cx), "z": round(el_hi - (y_hi - y))} for a, b, y in steps]
print("axis x =", round(cx, 1), "| EL label", els[0][0])
for r in res:
print(r)
if len(sys.argv) > 3:
ref = json.load(open(sys.argv[3], encoding="utf-8"))["coping"]["top_steps"]
d = max(max(abs(a[k] - b[k]) for k in ("x0", "x1", "z")) for a, b in zip(ref, res)) if len(ref) == len(res) else None
print("max difference from params coping.top_steps (mm):", d)
# ---- other coping dimensions from the same geometry
other = {"length_bottom_tip_to_tip": round(bot(right)[0] - bot(left)[0]),
"tip_bottom_rise": round(top(left)[1] - bot(left)[1]),
"end_batter_top_inset": round(abs(top(left)[0] - bot(left)[0]))}
arcs = {round(e.dxf.radius) for e in doc.modelspace() if e.dxftype() == "ARC" and e.dxf.layer == "CS-CONC-MAJR" and e.dxf.radius > 3000}
other["soffit_radius"] = sorted(arcs)
flat = [(a, b, c_, d) for a, b, c_, d in hv if abs(b - d) < 0.05 and 1800 < abs(c_ - a) < 2600 and abs((a + c_) / 2 - cx) < 600 and bot(left)[1] - 1700 < b < y_hi]
flat = sorted({(round(f[0], 1), round(f[1], 1), round(f[2], 1)) for f in flat if f[1] < bot(left)[1] + 100})
if flat:
f = flat[0]
other["flat_bottom_half_width"] = round(abs(f[2] - f[0]) / 2)
other["z_bottom_flat"] = round(el_hi - (y_hi - f[1]))
other["_flat_candidates"] = len(flat)
sect = sorted({round(abs(c_ - a), 1) for a, b, c_, d in hv if abs(b - d) < 0.05 and 3000 <= abs(c_ - a) <= 3200 and a > 20000})
other["width_y_candidates"] = sect
print("other:", other)
if len(sys.argv) > 3:
print("params:", {k: ref_ for k, ref_ in json.load(open(sys.argv[3], encoding="utf-8"))["coping"].items() if k in other})