- 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>
118 lines
8.6 KiB
Python
118 lines
8.6 KiB
Python
"""Create the app pier '옥성교P1' (tapered T on piles, plan skew 18 deg; scope G1 + G5) through the web client:
|
|
new pier (Ulsan template as a starting copy), upload a copy of RAG/옥성교P1.dwg, then write params / expected from
|
|
the reading (판독/g1_values.json; DOC/02_분석/분석_옥성교P1교각도면판독_2026-10-14_v0.1.00.md) and decisions O1-O5.
|
|
usage: python make_pier.py (refuses if the pier already exists)
|
|
"""
|
|
import json
|
|
import sys
|
|
from io import BytesIO
|
|
from pathlib import Path
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
ROOT = HERE.parents[1]
|
|
APP = ROOT / "Code" / "교각모델링앱"
|
|
sys.path.insert(0, str(APP / "web"))
|
|
import app as webapp # noqa: E402
|
|
import store # noqa: E402
|
|
|
|
NAME = "옥성교P1"
|
|
V = json.loads((HERE / "판독" / "g1_values.json").read_text(encoding="utf-8"))
|
|
cf = V["coping_front"]
|
|
steps = cf["top_steps"]
|
|
prof = [(cf["bottom_flat_half"] * -1, cf["z_bottom"]), (cf["bottom_flat_half"], cf["z_bottom"]), (cf["tip_x"], cf["z_tip"])]
|
|
for s in reversed(steps):
|
|
prof += [(s["x1"], s["z"]), (s["x0"], s["z"])]
|
|
prof += [(-cf["tip_x"], cf["z_tip"])]
|
|
TABLE = {1: (21398, 173), 2: (21432, 173), 3: (21465, 173), 4: (21411, 173), 5: (21351, 173),
|
|
6: (21419, 194), 7: (21453, 194), 8: (21486, 194), 9: (21433, 194), 10: (21372, 194)}
|
|
pads = {int(k): v for k, v in V["pads_outer"].items()}
|
|
step_of = lambda no: steps[(no - 1) % 5]["z"] # NO.1-5 / 6-10 lie on step 1..5 (skewed bearing lines)
|
|
YF, YR = pads[1]["centre"][1], pads[6]["centre"][1]
|
|
pedestals = []
|
|
for i, pd in enumerate(V["pedestals"]):
|
|
zs = step_of(i + 1)
|
|
pedestals.append({"no": i + 1, "corners": pd["corners"], "z_bottom": zs,
|
|
"top": {"y0": YF, "z0": zs + 173, "y1": YR, "z1": zs + 194}, "src": pd["src"] + "; 상면 앞 +173 → 뒤 +194 (O2 [추론])"})
|
|
bearings = [{"no": no, "type": "3000 kN", "row": "front" if no <= 5 else "rear", "centre": pads[no]["centre"],
|
|
"rotation_deg": pads[no]["rotation_deg"], "seat_z": step_of(no), "el_x": TABLE[no][0], "h1": TABLE[no][1],
|
|
"h2": 50, "A": 700, "B": 650, "pedestal": (no - 1) % 5} for no in range(1, 11)]
|
|
|
|
params = {
|
|
"_schema": "pier-T/1", "pier_id": "P1",
|
|
"_meta": {"structure": "옥성교 P1 교각 (T형, 말뚝기초, 직선 경사 코핑, 평면 사각 18°)",
|
|
"status": "형상(G1)·받침(G5) 판독 2026-10-14, 결정 O1~O5 사용자 확정. 철근 G2~G4 미판독(범위 밖)",
|
|
"units": "mm; Z = EL x 1000", "frame": "X 코핑 길이 방향, Y 평면 위쪽, 원점 = 기둥 중심",
|
|
"sources": {"D1": "RAG/옥성교P1.dwg (교각 일반도(1) + 배근도)"},
|
|
"reading": "DOC/02_분석/분석_옥성교P1교각도면판독_2026-10-14_v0.1.00.md, Code/옥성P1판독/판독/g1_values.json"},
|
|
"scope": ["G1", "G5"], "builders": {"G1": "concrete_tapered.py"},
|
|
"lean_concrete": {"size_x": 9800.0, "size_y": 9800.0, "z_bottom": 12075.0, "z_top": 12175.0, "src": V["lean"]["src"]},
|
|
"footing": {"size_x": 9600.0, "size_y": 9600.0, "z_bottom": 12175.0, "thickness": 2200.0, "src": V["footing"]["src"]},
|
|
"piles": {"count_x": 5, "count_y": 5, "pitch_x": 2000.0, "pitch_y": 2000.0, "diameter": 609.0, "length": 22000.0,
|
|
"head_embedment": 100.0, "kind": "내부굴착강관말뚝 Ø609.0x12T (속찬 원기둥, O5)",
|
|
"src": V["piles"]["src"] + "; 기초 평면 '5@1.600'은 오기 (O1)"},
|
|
"column": {"shape": "circular", "diameter": 2500.0, "height": 3800.0, "src": V["column"]["src"]},
|
|
"coping": {"form": "tapered", "profile_xz": [list(p) for p in prof], "width_y": 3300.0, "plan_length": 12000.0,
|
|
"top_length": 12000.0, "z_tip": cf["z_tip"], "z_top_left": steps[0]["z"], "z_top_right": steps[-1]["z"],
|
|
"plan_corner_radius": 0,
|
|
"side_taper": {"half_width_top": 1650.0, "z_taper_top": 19675.0, "half_width_bottom": 1250.0},
|
|
"skew_deg": V["skew_deg"],
|
|
"src": {"profile": cf["src"] + " (Y = 0 단면, 상면 5단)", "side": V["coping_side"]["src"],
|
|
"skew": V["coping_plan"]["src"] + " (O3)"}},
|
|
"materials": {"fck": {"lean": "16MPa", "footing": "27MPa", "column": "35MPa", "coping": "35MPa", "seat": "35MPa"},
|
|
"src": "일반도 주기 '버림 CON'C fck = 16 MPa', '구체 fck = 27 MPa'(기초), '구체 fck = 35 MPa'; 대좌 35 [추론]"},
|
|
"bearing_seats": {"_note": "shared pedestals (one per bearing line, both rows), sloped top (O2); pads rotated with the skew",
|
|
"pad_margin_bottom": 200, "pad_margin_top": 100, "pedestals": pedestals, "bearings": bearings,
|
|
"src": "일반도 평면 대좌 1047F~104A2, 패드 10D96~10DB3; ELEVATION TABLE h1·h2·A·B"},
|
|
"sole_plates": {"table": [{"no": no, "S": 1.765, "L": 800, "W": 750, "T": 29, "T1": 22, "T2": 36} for no in range(1, 11)],
|
|
"h3": 148, "bearing_size": "AB", "bearing_shrink": 100,
|
|
"colours": {"bearing": [0, 0, 0], "sole_plate": [150, 150, 150]},
|
|
"sole_plate_src": "솔플레이트 상세 TABLE; S > 0 -> 두꺼운 쪽 +Y (T2 36, O4 [추론])",
|
|
"src": "교량받침 A x B (700 x 650), h3 148 (ELEVATION TABLE); T = h4 29"},
|
|
"rebar_marks": {}, "rebar_marks_src": "철근 G2~G4 다음 Task",
|
|
}
|
|
expected = {
|
|
"_schema": "pier-T-expected/1", "pier_id": "P1", "tol_mm": 1.0,
|
|
"_note": "독립 기대값: 일반도 치수 문자·EL 문자·받침 표. [작도] = 치수 문자 없음(사각 18°, 대좌 외곽, 받침 평면 위치)",
|
|
"checkers": {"G1": "g1_skew.py"},
|
|
"negative": {"G1": [{"id": "BP02", "d": [3, 0, 0]}, {"id": "BS03", "d": [0, 0, 2]}],
|
|
"G5": [{"id": "BB04", "d": [5, 0, 0]}, {"id": "SP03", "d": [0, 0, 5]}]},
|
|
"planned_fail": [],
|
|
"G1": {"footing": {"dx": 9600, "dy": 9600, "z0": 12175, "thickness": 2200, "src": "'9.600', '2.200', 'EL. 12.175'"},
|
|
"lean": {"dx": 9800, "dy": 9800, "thickness": 100, "src": "버림 '100', 9,800"},
|
|
"column": {"d": 2500, "height": 3800, "src": "'2.500', '3.800'"},
|
|
"piles": {"nx": 5, "ny": 5, "pitch": 2000, "edge": 800, "d": 609, "length": 22000, "head_embedment": 100,
|
|
"src": "'4@2.000=8.000' (정면·단면), '800', 'Ø609.0x12T, L=22.0M', 머리 '100' (O1)"},
|
|
"coping": {"bottom_flat_half": 1350, "tip_half": 6000, "soffit_rise": 1500, "width_y": 3300, "side_bottom_width": 2500,
|
|
"skew_deg": 18.0, "step_bounds": [-3773, -1297, 1179, 3655],
|
|
"step_z": [21175, 21209, 21242, 21188, 21128],
|
|
"src": "'12.000', '2.700'(1,350 x 2), '1.500' x 2, '3.300'(1,120+1,141+1,039), 기둥 폭 2,500; 상면 단 경계 '2.227, 3@2.476, 2.344'; "
|
|
"단 높이 = EL.'X' - h1 - h2 (NO.1~5); 사각 18° [작도]"},
|
|
"seats": {"n_pedestals": 5,
|
|
"table": {str(no): [TABLE[no][0], TABLE[no][1], 50, 700, 650] for no in range(1, 11)},
|
|
"pos": {str(no): pads[no]["centre"] for no in range(1, 11)},
|
|
"src": "ELEVATION TABLE; 받침 평면 위치 [작도] (단면 '1.120, 1.141, 1.039' = y -530 / 611 ✓)"}},
|
|
"G5": {"el_x": {str(no): TABLE[no][0] for no in range(1, 11)}, "S": {str(no): 1.765 for no in range(1, 11)},
|
|
"W": {str(no): 750 for no in range(1, 11)}, "L": 800, "T": 29, "h3": 148,
|
|
"bearing_size": {str(no): [700, 650] for no in range(1, 11)}, "bearing_shrink": 100, "thick_end": "+Y",
|
|
"colours": {"bearing": [0, 0, 0], "sole_plate": [150, 150, 150]},
|
|
"src": "ELEVATION TABLE (EL.'X', h3, A, B); 솔플레이트 상세 TABLE (S, L, W, T1 22 / T2 36 -> +Y, O4)"},
|
|
}
|
|
|
|
if __name__ == "__main__":
|
|
if (store.DATA / NAME).exists():
|
|
sys.exit(f"pier exists: {NAME}")
|
|
c = webapp.app.test_client()
|
|
assert c.post("/pier/new", data={"name": NAME, "type": "T형", "template": "tpl:산외교울산P1형"}).status_code == 302
|
|
dwg = ROOT / "RAG" / "옥성교P1.dwg"
|
|
r = c.post(f"/pier/{NAME}/upload", data={"dwg": [(BytesIO(dwg.read_bytes()), dwg.name)]}, content_type="multipart/form-data")
|
|
assert r.status_code == 302, r.status_code
|
|
p = store.Pier(NAME)
|
|
params["display"] = p.load("params")["display"]
|
|
expected["rebar_palette"] = p.load("expected")["rebar_palette"]
|
|
p.save("params", params)
|
|
p.save("expected", expected)
|
|
meta = store.rjson(p.dir / "pier.json")
|
|
meta["template"] = "신규 판독 (옥성교 P1 판독서 v0.1.00)"
|
|
store.wjson(p.dir / "pier.json", meta)
|
|
print("created", p.dir, "texts", len(p.texts()), "profile", prof)
|