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:
commit
964a841de1
3978 files changed
+58013356
No files matched your search
@@ -0,0 +1,158 @@
|
||||
"""G3 gate checker, form "mats" (Ulsan P1, 2026-10-13): footing rebar groups, perimeter hoops, verticals.
|
||||
|
||||
Globals: __rhino_doc__, EXPECTED_PATH, RESULT_PATH. Expected values (section G3) from the schedule and the
|
||||
position chains of the rebar drawing (layer heights are drawn values, marked [derived]); params are not read.
|
||||
expected.G3: schedule {mark: [L, n]}, dia {mark: d}, rows {name: {first, start, pitch, n, last}},
|
||||
layers {mark: {axis, z, row | pos, subset}} (subset "on"/"off": positions on / off the `of` row)
|
||||
hoops {mark, half, chain {start, groups}}, verticals {mark, grid_x row, grid_y row, parity, z0, a}
|
||||
Optional (Ulsan P2, 2026-10-15; absent -> unchanged): G1.footing.rot_deg (bars are checked after turning their centrelines back by the
|
||||
foundation rotation), hoops.half_x / half_y, verticals {exclude {x, y} (grid points with |x| <= x and |y| <= y are absent), legs {bottom, top}}.
|
||||
Checks (C9): counts, original length, layer z, positions, hoop levels / size, vertical grid, containment in the
|
||||
footing, minimum cover (record), rebar colours by diameter.
|
||||
"""
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
|
||||
import Rhino.Geometry as rg
|
||||
from Rhino.DocObjects import ObjectColorSource
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
from _common import all_objects, chain, load_expected, write_result # noqa: E402
|
||||
|
||||
doc = __rhino_doc__
|
||||
X = load_expected(EXPECTED_PATH)
|
||||
PID, G = X["pier_id"], X["G3"]
|
||||
FB = X["G1"]["footing"]["z0"]
|
||||
SCHED = {m: tuple(v) for m, v in G["schedule"].items()}
|
||||
DIA = G["dia"]
|
||||
PALETTE = {int(k): tuple(v) for k, v in X["rebar_palette"].items()}
|
||||
ROT = X["G1"]["footing"].get("rot_deg", 0.0)
|
||||
results = []
|
||||
|
||||
|
||||
def bbx(o):
|
||||
"""Bounding box of the bar centreline in the foundation's own axes."""
|
||||
g = o.Geometry
|
||||
if ROT:
|
||||
g = g.DuplicateCurve()
|
||||
g.Transform(rg.Transform.Rotation(-math.radians(ROT), rg.Vector3d.ZAxis, rg.Point3d.Origin))
|
||||
return g.GetBoundingBox(True)
|
||||
|
||||
|
||||
def check(item, exp, act, tol=1.0):
|
||||
results.append(dict(check="C9", item=item, expected=round(exp, 3), actual=round(act, 3),
|
||||
diff=round(act - exp, 3), tol=tol, result="PASS" if abs(act - exp) <= tol else "FAIL"))
|
||||
|
||||
|
||||
def flag(item, ok, detail=""):
|
||||
results.append(dict(check="C9", item=item, detail=detail, result="PASS" if ok else "FAIL"))
|
||||
|
||||
|
||||
def info(item, detail):
|
||||
results.append(dict(check="C9", item=item, detail=detail, result="INFO"))
|
||||
|
||||
|
||||
def row(spec):
|
||||
return sorted(list(spec.get("first", [])) + [spec["start"] + spec["pitch"] * i for i in range(spec["n"])]
|
||||
+ list(spec.get("last", [])))
|
||||
|
||||
|
||||
def positions(lay):
|
||||
if "pos" in lay:
|
||||
return sorted(lay["pos"])
|
||||
base = row(G["rows"][lay["row"]])
|
||||
if "subset" in lay:
|
||||
ref = set(row(G["rows"][lay["of"]]))
|
||||
base = [v for v in base if (v in ref) == (lay["subset"] == "on")]
|
||||
return base
|
||||
|
||||
|
||||
def objs(prefix, mark):
|
||||
return [o for o in all_objects(doc) if (o.Attributes.GetUserString("id") or "").startswith(prefix)
|
||||
and o.Attributes.GetUserString("mark") == mark]
|
||||
|
||||
|
||||
def main():
|
||||
cl = {m: objs(f"{PID}-RC-", m) for m in SCHED}
|
||||
pp = {m: objs(f"{PID}-R-", m) for m in SCHED}
|
||||
for m, (L, n) in SCHED.items():
|
||||
check(f"{m} bar count vs schedule", n, len(cl[m]), tol=0)
|
||||
flag(f"{m} pipes closed & paired", len(pp[m]) == len(cl[m]) and all(o.Geometry.IsSolid for o in pp[m]),
|
||||
f"{len(pp[m])}/{len(cl[m])}")
|
||||
if cl[m]:
|
||||
check(f"{m} original length vs L (worst)", 0,
|
||||
max(abs(float(o.Attributes.GetUserString("design_length")) - L) for o in cl[m]))
|
||||
dev = [o.Geometry.GetLength() - L for o in cl[m]]
|
||||
info(f"{m} curve length - L (bend fillets / laps)", f"min {min(dev):.1f} / max {max(dev):.1f}")
|
||||
for m, lay in G["layers"].items():
|
||||
if not cl[m]:
|
||||
continue
|
||||
# horizontal part: the lowest (legs up / none) or highest (legs down) straight segment -> bbox mid level
|
||||
zs, ps = [], []
|
||||
for o in cl[m]:
|
||||
bb = bbx(o)
|
||||
leg_down = lay.get("leg", 0) < 0
|
||||
zs.append((bb.Max.Z if leg_down else bb.Min.Z) - FB)
|
||||
ps.append(round((bb.Min.X + bb.Max.X) / 2 if lay["axis"] == "Y" else (bb.Min.Y + bb.Max.Y) / 2, 1))
|
||||
check(f"{m} layer z (worst) [derived]", 0, max(abs(z - lay["z"]) for z in zs))
|
||||
exp = positions(lay)
|
||||
got = sorted(ps)
|
||||
ok = len(got) == len(exp)
|
||||
check(f"{m} positions vs chain (worst, n={len(got)}/{len(exp)})", 0,
|
||||
max(abs(a - b) for a, b in zip(got, exp)) if ok else 1e9)
|
||||
hp = G["hoops"]
|
||||
lv = chain(hp["chain"], 0)
|
||||
hz = sorted(round(bbx(o).Min.Z - FB, 1) for o in cl[hp["mark"]])
|
||||
check(f"{hp['mark']} levels vs chain (worst)", 0, max(abs(a - b) for a, b in zip(hz, lv)) if len(hz) == len(lv) else 1e9)
|
||||
if cl[hp["mark"]]:
|
||||
bb = bbx(cl[hp["mark"]][0])
|
||||
check(f"{hp['mark']} centreline size X [derived]", 2 * hp.get("half_x", hp.get("half")), bb.Max.X - bb.Min.X)
|
||||
check(f"{hp['mark']} centreline size Y [derived]", 2 * hp.get("half_y", hp.get("half")), bb.Max.Y - bb.Min.Y)
|
||||
vt = G["verticals"]
|
||||
gx, gy = row(G["rows"][vt["grid_x"]]), row(G["rows"][vt["grid_y"]])
|
||||
pts = {(round(bbx(o).Min.X), round(bbx(o).Min.Y)) for o in cl[vt["mark"]]}
|
||||
if "exclude" in vt: # Ulsan P2: grid minus the central rectangle
|
||||
ex = vt["exclude"]
|
||||
exp = {(round(x), round(y)) for x in gx for y in gy if not (abs(x) <= ex["x"] and abs(y) <= ex["y"])}
|
||||
flag(f"{vt['mark']} positions = {len(gx)}x{len(gy)} grid minus |x|<={ex['x']} & |y|<={ex['y']} [추론]", pts == exp, f"{len(pts)} / {len(exp)}")
|
||||
else:
|
||||
exp = {(round(x), round(y)) for i, x in enumerate(gx) for j, y in enumerate(gy) if (i + j) % 2 == vt["parity"]}
|
||||
flag(f"{vt['mark']} positions = checkerboard of {len(gx)}x{len(gy)} grid [추론]", pts == exp, f"{len(pts)} / {len(exp)}")
|
||||
if cl[vt["mark"]]:
|
||||
check(f"{vt['mark']} bottom z (worst)", 0,
|
||||
max(abs(bbx(o).Min.Z - FB - vt["z0"]) for o in cl[vt["mark"]]))
|
||||
bb = bbx(cl[vt["mark"]][0])
|
||||
check(f"{vt['mark']} vertical extent a", vt["a"], bb.Max.Z - bb.Min.Z)
|
||||
if "legs" in vt: # both legs run towards +Y from the same point: Y extent = the longer leg
|
||||
check(f"{vt['mark']} leg extent along Y (longer leg)", max(vt["legs"].values()), bb.Max.Y - bb.Min.Y)
|
||||
ft = [o for o in all_objects(doc) if o.Attributes.GetUserString("id") == f"{PID}-FT"][0].Geometry
|
||||
cover = {}
|
||||
for m in SCHED:
|
||||
bad, cov = 0, 1e9
|
||||
r = DIA[m] / 2
|
||||
for o in cl[m]:
|
||||
c = o.Geometry
|
||||
for t in c.DivideByCount(max(4, int(c.GetLength() / 200)), True):
|
||||
p = c.PointAt(t)
|
||||
for q in (p, p + rg.Vector3d(r, 0, 0), p - rg.Vector3d(r, 0, 0), p + rg.Vector3d(0, r, 0),
|
||||
p - rg.Vector3d(0, r, 0), p + rg.Vector3d(0, 0, r), p - rg.Vector3d(0, 0, r)):
|
||||
if not ft.IsPointInside(q, 0.01, False):
|
||||
bad += 1
|
||||
cov = min(cov, p.DistanceTo(ft.ClosestPoint(p)) - r)
|
||||
cover[m] = round(cov, 1)
|
||||
check(f"{m} sample points outside footing", 0, bad, tol=0)
|
||||
info("min cover to footing surface per mark (record; top face under the column counted)", json.dumps(cover))
|
||||
wrong = 0
|
||||
for o in all_objects(doc):
|
||||
if (o.Attributes.GetUserString("id") or "").startswith(f"{PID}-R-"):
|
||||
d = int(o.Attributes.GetUserString("dia")[1:])
|
||||
c = o.Attributes.ObjectColor
|
||||
if o.Attributes.ColorSource != ObjectColorSource.ColorFromObject or (c.R, c.G, c.B) != PALETTE.get(d):
|
||||
wrong += 1
|
||||
check("rebar pipe colour by diameter mismatches (all rebar)", 0, wrong, tol=0)
|
||||
write_result(RESULT_PATH, results, dict(cover=cover))
|
||||
|
||||
|
||||
main()
|
||||
Reference in new issue
Block a user