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,181 @@
|
||||
"""G3 gate checker, form "shaft cage" (Ramp-A P1, 2026-10-13): drilled-shaft cage bars and the anti-uplift plate.
|
||||
|
||||
Globals: __rhino_doc__, EXPECTED_PATH, RESULT_PATH. Expected values (section G3) come from the D4 schedule (L, N),
|
||||
the 구조물 치수표 chains measured from the shaft top EL (D1), the section radii and the user decisions S1-S6;
|
||||
generator params are not read.
|
||||
Checks (C9): counts, original length (+coupler) vs schedule L, main radius / division / piece levels, hoop and
|
||||
tie level grids, hoop radius, X / Y ties apart, U bars (count, bottom level, width, planes), plate (size,
|
||||
thickness, centre, cover), containment in the pile segments, min side cover (record).
|
||||
"""
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
|
||||
import Rhino.Geometry as rg
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
from _common import all_objects, load_expected, write_result # noqa: E402
|
||||
|
||||
doc = __rhino_doc__
|
||||
X = load_expected(EXPECTED_PATH)
|
||||
PID, TOL, G = X["pier_id"], X["tol_mm"], X["G3"]
|
||||
SCHED_L, SCHED_N, DIA = G["schedule_L"], G["schedule_n"], G["dia"]
|
||||
M, HP, TI, U, PL = G["main"], G["hoops"], G["ties"], G["u_bars"], G["plate"]
|
||||
TOP = G["shaft_top"]
|
||||
PILE = X["G1"]["pile"]
|
||||
Z_BOT = PILE["z_bottom"]
|
||||
SEG = [] # (z0, z1, radius) bottom to top
|
||||
z = Z_BOT
|
||||
for s in PILE["segments"]:
|
||||
SEG.append((z, z + s["length"], s["d"] / 2))
|
||||
z += s["length"]
|
||||
|
||||
|
||||
def chain(c):
|
||||
"""Levels from the shaft top: first offset, then (count, pitch) groups downwards; returned bottom to top."""
|
||||
out = [TOP - c["first"]]
|
||||
for n, p in c["groups"]:
|
||||
out += [out[-1] - p * k for k in range(1, n + 1)]
|
||||
return sorted(out)
|
||||
|
||||
|
||||
HOOP_LEVELS, TIE_LEVELS = chain(HP["chain"]), chain(TI["chain"])
|
||||
results = []
|
||||
|
||||
|
||||
def check(item, exp, act, tol=TOL):
|
||||
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 ids(prefix):
|
||||
return [o for o in all_objects(doc) if (o.Attributes.GetUserString("id") or "").startswith(prefix)]
|
||||
|
||||
|
||||
def main():
|
||||
cl = {m: [o for o in ids(f"{PID}-RC-") if o.Attributes.GetUserString("mark") == m] for m in SCHED_L}
|
||||
pipes = {m: [o for o in ids(f"{PID}-R-") if o.Attributes.GetUserString("mark") == m] for m in SCHED_L}
|
||||
occ = lambda o: o.Attributes.GetUserString("occurrence").rstrip("ab")
|
||||
hm, tm = HP["mark"], TI["mark"]
|
||||
for m in SCHED_L:
|
||||
n_occ = len({occ(o) for o in cl[m]}) if m == hm else len(cl[m])
|
||||
check(f"{m} bar count", SCHED_N[m], n_occ, tol=0)
|
||||
flag(f"{m} pipes closed & paired with centrelines",
|
||||
len(pipes[m]) == len(cl[m]) and all(o.Geometry.IsSolid for o in pipes[m]), f"{len(pipes[m])}/{len(cl[m])}")
|
||||
for m in SCHED_L:
|
||||
per, curve = {}, {}
|
||||
for o in cl[m]:
|
||||
k = occ(o) if m == hm else o.Attributes.GetUserString("occurrence")
|
||||
cp = float(o.Attributes.GetUserString("coupler_length") or 0)
|
||||
per[k] = per.get(k, 0) + float(o.Attributes.GetUserString("design_length")) + cp
|
||||
curve[k] = curve.get(k, 0) + o.Geometry.GetLength() + cp
|
||||
if per:
|
||||
check(f"{m} original length (+coupler) vs schedule L (worst of {len(per)})", 0,
|
||||
max(abs(v - SCHED_L[m]) for v in per.values()))
|
||||
dev = [v - SCHED_L[m] for v in curve.values()]
|
||||
info(f"{m} curve length (+coupler) - L (record)", f"min {min(dev):.1f} / max {max(dev):.1f} mm")
|
||||
# main bars: pieces stacked between the first and the last hoop level (S6: coupler length 0)
|
||||
zb, zt = HOOP_LEVELS[0], HOOP_LEVELS[-1]
|
||||
check("main span (last - first hoop level) = sum of piece L", zt - zb, sum(SCHED_L[mk] for mk in M["pieces"]))
|
||||
z = zb
|
||||
for mk in M["pieces"]: # bottom to top
|
||||
lo = [min(o.Geometry.PointAtStart.Z, o.Geometry.PointAtEnd.Z) for o in cl[mk]]
|
||||
hi = [max(o.Geometry.PointAtStart.Z, o.Geometry.PointAtEnd.Z) for o in cl[mk]]
|
||||
check(f"{mk} bottom EL (worst)", 0, max(abs(v - z) for v in lo))
|
||||
check(f"{mk} top EL = bottom + L (worst)", 0, max(abs(v - (z + SCHED_L[mk])) for v in hi))
|
||||
z += SCHED_L[mk]
|
||||
rr = [math.hypot(o.Geometry.PointAtStart.X, o.Geometry.PointAtStart.Y) for o in cl[mk]]
|
||||
check(f"{mk} radius (worst)", 0, max(abs(r - M["radius"]) for r in rr), tol=0.5)
|
||||
a = sorted(math.degrees(math.atan2(o.Geometry.PointAtStart.Y, o.Geometry.PointAtStart.X)) % 360 for o in cl[mk])
|
||||
check(f"{mk} angle vs {M['start_deg']} + i*360/{M['divisions']} (worst, deg)", 0,
|
||||
max(abs(x - (M["start_deg"] + i * 360 / M["divisions"])) for i, x in enumerate(a)), tol=0.01)
|
||||
# hoops
|
||||
hz = {}
|
||||
for o in cl[hm]:
|
||||
bb = o.Geometry.GetBoundingBox(True)
|
||||
hz.setdefault(round((bb.Max.Z + bb.Min.Z) / 2, 1), []).append(o)
|
||||
zs = sorted(hz)
|
||||
flag(f"{hm} levels {len(HOOP_LEVELS)} x 2 pieces", len(zs) == len(HOOP_LEVELS) and all(len(v) == 2 for v in hz.values()),
|
||||
f"{len(zs)} levels")
|
||||
check(f"{hm} levels vs 구조물 치수표 chain (worst)", 0,
|
||||
max(abs(a - b) for a, b in zip(zs, HOOP_LEVELS)) if len(zs) == len(HOOP_LEVELS) else 1e9)
|
||||
for o in cl[hm][:4]:
|
||||
c = o.Geometry
|
||||
p = c.PointAt(c.Domain.Mid)
|
||||
check(f"{hm} radius at mid point ({o.Attributes.GetUserString('occurrence')})", HP["radius"], math.hypot(p.X, p.Y), tol=0.5)
|
||||
# ties
|
||||
by = lambda s: sorted((o.Geometry for o in cl[tm] if o.Attributes.GetUserString("occurrence").endswith(s)),
|
||||
key=lambda g: g.GetBoundingBox(True).Max.Z)
|
||||
xs, ys = by("X"), by("Y")
|
||||
txm = [g.GetBoundingBox(True).Max.Z for g in xs]
|
||||
tym = [g.GetBoundingBox(True).Max.Z for g in ys]
|
||||
flag(f"{tm} X / Y per level, {len(TIE_LEVELS)} levels", len(txm) == len(tym) == len(TIE_LEVELS), f"X {len(txm)} Y {len(tym)}")
|
||||
if len(txm) == len(TIE_LEVELS) == len(tym):
|
||||
check(f"{tm} X levels vs chain (worst)", 0, max(abs(a - b) for a, b in zip(txm, TIE_LEVELS)))
|
||||
check(f"{tm} Y levels = X + {TI['y_lift']} (worst)", 0, max(abs(a - b - TI["y_lift"]) for a, b in zip(tym, TIE_LEVELS)))
|
||||
gaps = []
|
||||
for a, b in zip(xs, ys):
|
||||
ok, pa, pb = a.ClosestPoints(b)
|
||||
gaps.append(pa.DistanceTo(pb) if ok else 0.0)
|
||||
gap = min(gaps) if gaps else 0.0
|
||||
check(f"{tm} X / Y centrelines apart >= bar diameter {DIA[tm]} (min, capped)", DIA[tm], min(gap, DIA[tm]), tol=0.01)
|
||||
# U bars: bottom level, overall width (vertical legs on the hoop circle), one plane each through the centre
|
||||
um = U["mark"]
|
||||
bots = [o.Geometry.GetBoundingBox(True).Min.Z for o in cl[um]]
|
||||
check(f"{um} bottom EL = shaft bottom + {U['bottom_above']} (worst, centreline)", 0,
|
||||
max(abs(b - (Z_BOT + U["bottom_above"])) for b in bots) if bots else 1e9)
|
||||
w, planar = [], 0
|
||||
for o in cl[um]:
|
||||
c = o.Geometry
|
||||
a, b = c.PointAtStart, c.PointAtEnd
|
||||
w.append(math.hypot(a.X - b.X, a.Y - b.Y))
|
||||
ok, pl = c.TryGetPlane(0.01)
|
||||
if ok and abs(pl.Normal.Z) < 1e-6 and abs(pl.DistanceTo(rg.Point3d(0, 0, pl.Origin.Z))) < 0.5:
|
||||
planar += 1
|
||||
check(f"{um} leg spacing (worst) = 2 x hoop radius {2 * HP['radius']:.0f}", 0, max(abs(x - 2 * HP["radius"]) for x in w) if w else 1e9)
|
||||
check(f"{um} vertical planes through the centre", len(cl[um]), planar, tol=0)
|
||||
# plate
|
||||
pts = ids(f"{PID}-PT")
|
||||
flag("plate count 1", len(pts) == 1, str(len(pts)))
|
||||
if pts:
|
||||
bb = pts[0].Geometry.GetBoundingBox(True)
|
||||
check("plate size X", PL["size"], bb.Max.X - bb.Min.X)
|
||||
check("plate size Y", PL["size"], bb.Max.Y - bb.Min.Y)
|
||||
check("plate thickness", PL["thickness"], bb.Max.Z - bb.Min.Z, tol=0.01)
|
||||
check("plate centre X / Y offset", 0, math.hypot((bb.Max.X + bb.Min.X) / 2, (bb.Max.Y + bb.Min.Y) / 2))
|
||||
check(f"plate top = U bottom - {DIA[um] / 2:.0f} (S4)", Z_BOT + U["bottom_above"] - DIA[um] / 2, bb.Max.Z, tol=0.01)
|
||||
info("plate bottom cover (record)", f"{bb.Min.Z - Z_BOT:.1f} mm")
|
||||
# containment and side cover in the pile segments
|
||||
solids = [o.Geometry for o in all_objects(doc) if (o.Attributes.GetUserString("id") or "").startswith(f"{PID}-PL")]
|
||||
min_cover = {}
|
||||
for m in SCHED_L:
|
||||
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() / 150)), True):
|
||||
p = c.PointAt(t)
|
||||
radial = rg.Vector3d(p.X, p.Y, 0)
|
||||
radial.Unitize() if radial.Length > 1e-6 else None
|
||||
for q in (p, p + radial * r, p - radial * r, p + rg.Vector3d(0, 0, r), p - rg.Vector3d(0, 0, r)):
|
||||
if not any(s.IsPointInside(q, 0.01, False) for s in solids):
|
||||
bad += 1
|
||||
R = next((rad for z0, z1, rad in SEG if z0 <= p.Z <= z1), None)
|
||||
if R is not None:
|
||||
cov = min(cov, R - math.hypot(p.X, p.Y) - r, p.Z - Z_BOT - r)
|
||||
min_cover[m] = round(cov, 1)
|
||||
check(f"{m} sample points outside the pile concrete", 0, bad, tol=0)
|
||||
info("min cover per mark (side or bottom, record)", json.dumps(min_cover))
|
||||
write_result(RESULT_PATH, results, dict(min_cover=min_cover))
|
||||
|
||||
|
||||
main()
|
||||
Reference in new issue
Block a user