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,100 @@
|
||||
"""Reading aids for the Ungok P2 drawings (read only): render a region, dump entities of a region.
|
||||
|
||||
usage:
|
||||
python dxftools.py render <D1|D2|D3> x0 y0 x1 y1 <name> [px] -> 판독/<name>.png
|
||||
python dxftools.py dump <D1|D2|D3> x0 y0 x1 y1 [layer-regex] -> prints LINE/LWPOLYLINE/ARC/CIRCLE/TEXT
|
||||
DXF source: Code/교각모델링앱/data/운곡교p2/drawings/dxf (converted from the uploaded DWG copies).
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import ezdxf
|
||||
from ezdxf import bbox
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
DXF = HERE.parent / "교각모델링앱" / "data" / "운곡교p2" / "drawings" / "dxf"
|
||||
_CACHE = {}
|
||||
|
||||
|
||||
def doc(label):
|
||||
if label not in _CACHE:
|
||||
path = sorted(DXF.glob("*.dxf"))[int(label[1]) - 1]
|
||||
_CACHE[label] = ezdxf.readfile(path)
|
||||
return _CACHE[label]
|
||||
|
||||
|
||||
def in_region(e, x0, y0, x1, y1):
|
||||
try:
|
||||
b = bbox.extents([e], fast=True)
|
||||
except Exception:
|
||||
return False
|
||||
return b.has_data and b.extmax.x >= x0 and b.extmin.x <= x1 and b.extmax.y >= y0 and b.extmin.y <= y1
|
||||
|
||||
|
||||
def entities(label, x0, y0, x1, y1, layer=None):
|
||||
rx = re.compile(layer) if layer else None
|
||||
for e in doc(label).modelspace():
|
||||
if rx and not rx.search(e.dxf.layer):
|
||||
continue
|
||||
if in_region(e, x0, y0, x1, y1):
|
||||
yield e
|
||||
|
||||
|
||||
def describe(e):
|
||||
t, L, h = e.dxftype(), e.dxf.layer, e.dxf.handle
|
||||
r = lambda v: round(v, 1)
|
||||
if t == "LINE":
|
||||
s, f = e.dxf.start, e.dxf.end
|
||||
return f"{h} {L} LINE ({r(s.x)},{r(s.y)})-({r(f.x)},{r(f.y)}) len {r(s.distance(f))}"
|
||||
if t == "LWPOLYLINE":
|
||||
pts = [(r(p[0]), r(p[1])) for p in e.get_points()]
|
||||
return f"{h} {L} PLINE closed={e.closed} {pts}"
|
||||
if t == "ARC":
|
||||
c = e.dxf.center
|
||||
return f"{h} {L} ARC c({r(c.x)},{r(c.y)}) r {r(e.dxf.radius)} {r(e.dxf.start_angle)}..{r(e.dxf.end_angle)}"
|
||||
if t == "CIRCLE":
|
||||
c = e.dxf.center
|
||||
return f"{h} {L} CIRCLE c({r(c.x)},{r(c.y)}) r {r(e.dxf.radius)}"
|
||||
if t in ("TEXT", "MTEXT"):
|
||||
p = e.dxf.insert
|
||||
s = e.plain_text() if t == "MTEXT" else e.dxf.text
|
||||
return f"{h} {L} {t} ({r(p.x)},{r(p.y)}) '{s.strip()}'"
|
||||
if t == "INSERT":
|
||||
p = e.dxf.insert
|
||||
return f"{h} {L} INSERT {e.dxf.name} ({r(p.x)},{r(p.y)})"
|
||||
return f"{h} {L} {t}"
|
||||
|
||||
|
||||
def render(label, x0, y0, x1, y1, name, px=2400):
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
from ezdxf.addons.drawing import Frontend, RenderContext
|
||||
from ezdxf.addons.drawing.config import BackgroundPolicy, ColorPolicy, Configuration
|
||||
from ezdxf.addons.drawing.matplotlib import MatplotlibBackend
|
||||
d = doc(label)
|
||||
keep = list(entities(label, x0, y0, x1, y1))
|
||||
fig = plt.figure(figsize=(px / 100, px * (y1 - y0) / (x1 - x0) / 100), dpi=100)
|
||||
ax = fig.add_axes([0, 0, 1, 1])
|
||||
cfg = Configuration(background_policy=BackgroundPolicy.WHITE, color_policy=ColorPolicy.BLACK)
|
||||
Frontend(RenderContext(d), MatplotlibBackend(ax), config=cfg).draw_entities(keep)
|
||||
ax.set_xlim(x0, x1)
|
||||
ax.set_ylim(y0, y1)
|
||||
ax.set_aspect("equal")
|
||||
ax.axis("off")
|
||||
out = HERE / "판독" / f"{name}.png"
|
||||
out.parent.mkdir(exist_ok=True)
|
||||
fig.savefig(out, facecolor="white")
|
||||
plt.close(fig)
|
||||
return out
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cmd, label = sys.argv[1], sys.argv[2]
|
||||
x0, y0, x1, y1 = map(float, sys.argv[3:7])
|
||||
if cmd == "render":
|
||||
print(render(label, x0, y0, x1, y1, sys.argv[7], int(sys.argv[8]) if len(sys.argv) > 8 else 2400))
|
||||
else:
|
||||
for e in entities(label, x0, y0, x1, y1, sys.argv[7] if len(sys.argv) > 7 else None):
|
||||
print(describe(e))
|
||||
@@ -0,0 +1,212 @@
|
||||
"""R1 (shape) reading of the Ungok P2 drawings -> app params / expected (data/운곡교p2).
|
||||
|
||||
params = drawn CAD entities (D1, read by handle) + D2 ELEVATION TABLE for bearing values (user rule from P1:
|
||||
table wins over drawn pedestal/pad sizes).
|
||||
expected = dimension texts / EL texts / tables (D1, D2), typed below with their text as the source.
|
||||
Drawing frame (same as P1): front view column CL x=12159.4, column top y=16515.6, footing bottom y=8115.6;
|
||||
side view CL x=30133.6; plan datum (12162.4, 26412.3).
|
||||
Writes only the R1 sections (others stay as they are); previous files go to data/운곡교p2/backup/.
|
||||
"""
|
||||
import json
|
||||
import math
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
APP = HERE.parent / "교각모델링앱"
|
||||
PIER = APP / "data" / "운곡교p2"
|
||||
sys.path.insert(0, str(HERE))
|
||||
sys.path.insert(0, str(APP))
|
||||
import dxftools as T # noqa: E402
|
||||
from engine import reader # noqa: E402
|
||||
|
||||
D1 = T.doc("D1").entitydb
|
||||
FX, COL_TOP_Y, FT_BOT_Y = 12159.4, 16515.6, 8115.6
|
||||
PLAN = (12162.4, 26412.3)
|
||||
EL_FT_BOT = 25123 # D1 'EL. 25.123'
|
||||
FT_T, COL_H = 2200, 12133 # D1 '2.200', '12.133'
|
||||
Z_COL_TOP = EL_FT_BOT + FT_T + COL_H # 39456
|
||||
PITCH = 7507 / 3 # D1 평면도 '3@2.502=7.507'
|
||||
|
||||
|
||||
def line(h):
|
||||
e = D1[h]
|
||||
return (e.dxf.start.x, e.dxf.start.y), (e.dxf.end.x, e.dxf.end.y)
|
||||
|
||||
|
||||
def pts(h):
|
||||
return [(p[0], p[1]) for p in D1[h].get_points()]
|
||||
|
||||
|
||||
def rel(p):
|
||||
return [round(p[0] - PLAN[0], 1), round(p[1] - PLAN[1], 1)]
|
||||
|
||||
|
||||
def centre(q):
|
||||
return [sum(p[0] for p in q) / 4, sum(p[1] for p in q) / 4]
|
||||
|
||||
|
||||
def angle_deg(a, b):
|
||||
return math.degrees(math.atan2(b[0] - a[0], b[1] - a[1]))
|
||||
|
||||
|
||||
def z_front(y):
|
||||
"""Front-view coping region y -> elevation (mm); coping is drawn to scale above the column top."""
|
||||
return Z_COL_TOP + (y - COL_TOP_Y)
|
||||
|
||||
|
||||
def table():
|
||||
texts = json.loads((PIER / "drawings" / "texts.json").read_text(encoding="utf-8"))
|
||||
tabs = {t["key"]: t for t in reader.table_candidates(texts)}
|
||||
el = {int(r["_key"]): r for _, r in reader.table_records(tabs["elevation"]["rows"], str.isdigit)}
|
||||
sp = {int(r["_key"]): r for _, r in reader.table_records(tabs["sole_plate"]["rows"], str.isdigit)}
|
||||
return el, sp
|
||||
|
||||
|
||||
def params_r1(el):
|
||||
ft = line("21A76") # footing bottom 6984.4..17334.4
|
||||
lc = line("21B62") # lean bottom 6884.4..17434.4
|
||||
side_ft, side_lc = line("21CFC"), line("21DCF")
|
||||
steps_x = [line(h)[0][0] - FX for h in ("20E78", "20E7A", "20E7C", "20E7E")] # step risers
|
||||
steps_y = [line(h)[1][1] for h in ("20E77", "20E79", "20E7B", "20E7D", "20E7F")] # step treads
|
||||
xs = [-6000.0] + [round(x, 1) for x in steps_x] + [6000.0]
|
||||
top_steps = [{"x0": xs[i], "x1": xs[i + 1], "z": round(z_front(steps_y[i]), 1)} for i in range(5)]
|
||||
tipL, topL = line("20D63") # (6159.4,19515.6) -> (5959.4,18015.6)
|
||||
tipR = line("20E74")[0] # (18359.4,18015.6)
|
||||
flat = line("20E87") # coping flat bottom 11059.4..13259.4
|
||||
p = {
|
||||
"lean_concrete": {"size_x": round(lc[0][0] - lc[1][0], 1), "size_y": round(side_lc[0][0] - side_lc[1][0], 1),
|
||||
"z_bottom": EL_FT_BOT - 100, "z_top": EL_FT_BOT,
|
||||
"src": {"size": "D1 정면도 21B62 / 측면도 21DCF", "thickness": "D1 21B61 (100)"}},
|
||||
"footing": {"size_x": round(ft[0][0] - ft[1][0], 1), "size_y": round(side_ft[0][0] - side_ft[1][0], 1),
|
||||
"z_bottom": EL_FT_BOT, "thickness": round(line("21A75")[1][1] - line("21A75")[0][1], 1),
|
||||
"src": {"size": "D1 정면도 21A76 / 측면도 21CFC", "z_bottom": "D1 'EL. 25.123'",
|
||||
"thickness": "D1 21A75"}},
|
||||
"column": {"shape": "circular", "diameter": round(line("214C2")[0][0] - line("214C1")[0][0], 1), "height": COL_H,
|
||||
"src": {"diameter": "D1 정면도 214C1/214C2", "height": "D1 dim '12.133' (column drawn with break lines)"}},
|
||||
"coping": {"length_bottom_tip_to_tip": round(tipR[0] - topL[0], 1), "width_y": round(line("2143A")[1][0] - line("2143A")[0][0], 1),
|
||||
"z_bottom_flat": Z_COL_TOP, "flat_bottom_half_width": round((flat[1][0] - flat[0][0]) / 2, 1),
|
||||
"soffit_radius": round(D1["20E89"].dxf.radius, 1), "tip_bottom_rise": round(topL[1] - COL_TOP_Y, 1),
|
||||
"end_batter_top_inset": round(tipL[0] - topL[0], 1), "top_steps": top_steps,
|
||||
"src": {"outline": "D1 정면도 20D63, 20E74, 20E77~20E7F, 20E87, ARC 20E89/20E8B",
|
||||
"width_y": "D1 측면도 2143A", "z": "y - 16515.6 + EL 39.456 (column top)"}},
|
||||
"piles": {"diameter": 600, "count_x": 6, "count_y": 5,
|
||||
"pitch_x": round(line("21C6D")[0][0] - line("21B44")[0][0], 1),
|
||||
"pitch_y": round(line("21DD6")[0][0] - line("21DD4")[0][0], 1) * -1,
|
||||
"edge": round(line("21B44")[0][0] - ft[1][0], 1), "length": 25900,
|
||||
"head_embedment": round(line("21B45")[0][1] - FT_BOT_Y, 1), "kind": "composite pile",
|
||||
"src": {"layout": "D1 CS-CNTL 21B44/21C6D/21C88 (X), 21DD2/21DD4/21DD6 (Y)",
|
||||
"diameter_length": "D1 '(Φ600.0X9T, L=25.9M)'"}},
|
||||
"materials": {"fck": {"lean": "15MPa", "footing": "27MPa", "column": "40MPa", "coping": "40MPa", "seat": "40MPa"},
|
||||
"src": "D1 주기 fck=40MPa(기둥·코핑), 27MPa(기초), 정면도 'CON'C fck = 15 MPa'"},
|
||||
}
|
||||
# bearing seats (pattern of Code/교각모델링/extract_bearing_seats.py)
|
||||
(fl, rl), rr, fr = line("20C1E"), line("20C1F")[1], line("20C20")[1]
|
||||
sr, sl = line("21A3F") # split line: right point, left point
|
||||
ped = [fl, rl, rr, fr]
|
||||
front_half, rear_half = [fl, sl, sr, fr], [sl, rl, rr, sr]
|
||||
rows = {}
|
||||
for row, (b, t_) in {"front": ("20C6D", "20C6E"), "rear": ("20C64", "20C65")}.items():
|
||||
q, qt = pts(b), pts(t_)
|
||||
rows[row] = dict(centre_rel_girder5=rel(centre(q)), rotation_deg=round(angle_deg(q[0], q[1]), 3),
|
||||
drawn_bottom_along=round(math.dist(q[0], q[1]), 1), drawn_bottom_across=round(math.dist(q[1], q[2]), 1),
|
||||
drawn_top_along=round(math.dist(qt[0], qt[1]), 1), drawn_top_across=round(math.dist(qt[1], qt[2]), 1),
|
||||
src=f"D1 평면도 {b} (bottom), {t_} (top)")
|
||||
checks = []
|
||||
g4 = [line("20C26")[0], line("20C26")[1], line("20C27")[1], line("20C28")[1]]
|
||||
for a, b in zip(ped, g4):
|
||||
checks.append(dict(item="girder4 pedestal vertex", dx=round(b[0] - (a[0] - PITCH), 2), dy=round(b[1] - a[1], 2)))
|
||||
for row, hs in (("front", ("20C6D", "20C70")), ("rear", ("20C64", "20C67"))):
|
||||
c5, c4 = centre(pts(hs[0])), centre(pts(hs[1]))
|
||||
checks.append(dict(item=f"girder4 {row} pad centre", dx=round(c4[0] - (c5[0] - PITCH), 2), dy=round(c4[1] - c5[1], 2)))
|
||||
bearings = []
|
||||
for no in range(1, 11):
|
||||
r = el[no]
|
||||
g, row = (no - 1) % 5 + 1, "front" if no <= 5 else "rear"
|
||||
pr = rows[row]
|
||||
bearings.append(dict(no=no, type=r["교량받침"], girder_line=g, row=row,
|
||||
centre=[round(pr["centre_rel_girder5"][0] + (g - 5) * PITCH, 1), pr["centre_rel_girder5"][1]],
|
||||
rotation_deg=pr["rotation_deg"], el_x=round(float(r["EL.'X'"]) * 1000), h1=int(r["h1"]),
|
||||
h2=int(r["h2"]), A=int(r["A"]), B=int(r["B"]), inferred=g <= 2))
|
||||
p["bearing_seats"] = dict(
|
||||
_note="pedestal (h1) per girder line split front/rear; pad (h2) = frustum (A+200)x(B+200) -> (A+100)x(B+100)",
|
||||
plan_datum=list(PLAN), pitch_x=PITCH, reference_girder=5, pad_margin_bottom=200, pad_margin_top=100,
|
||||
pad_margin_src="P1 rule (D1 평면도 pad = (A+200)x(B+200) / (A+100)x(B+100))",
|
||||
pedestal_girder5=dict(front_half=[rel(q) for q in front_half], rear_half=[rel(q) for q in rear_half],
|
||||
rotation_deg=round(angle_deg(fl, rl), 3),
|
||||
src="D1 평면도 20C1E~20C21 (2500x1200), 21A3F (front/rear split)"),
|
||||
pad_rows=rows, bearings=bearings, translation_checks=checks,
|
||||
src={"h1_h2_A_B_ELX": "D2 교량받침 ELEVATION TABLE (table wins over drawn sizes: P1 user rule)",
|
||||
"row_mapping": "front NO.1-5 (S1 851), rear NO.6-10 (S1 950); 851+1299+950=3100",
|
||||
"girder_mapping": "NO.k / NO.k+5 -> girder line k, left->right",
|
||||
"drawn_vs_table": "D1 평면도 pads 900x840 (B=640) and 측면도 h1 163.4/139, h3 181 = P1 values not updated "
|
||||
"-> CONFLICT, table used"})
|
||||
return p
|
||||
|
||||
|
||||
def expected_g1(el):
|
||||
tops = {1: 42456, 3: 42602, 5: 42748} # D1 'EL. 42.456' / 'EL. 42.602' / 'EL. 42.748'
|
||||
step = 72.9 # drawn step rise (no dimension text) [derived]
|
||||
step_top = {str(k): round(tops[1] + (k - 1) * step) if k in (2, 4) else tops[k] for k in range(1, 6)}
|
||||
step_top["2"], step_top["4"] = 42529, 42675
|
||||
sx = [-6000, -6000 + 2219, -6000 + 2219 + 2502, 6000 - 2274 - 2502, 6000 - 2274, 6000]
|
||||
return {
|
||||
"footing": {"dx": 10350, "dy": 7800, "z0": EL_FT_BOT, "thickness": 2200, "src": "D1 '10.350' '7.800' 'EL. 25.123' '2.200'"},
|
||||
"lean": {"margin": 100, "thickness": 100, "src": "D1 lean +100 each side, 100 thick"},
|
||||
"column": {"d": 2000, "height": 12133, "src": "D1 단면 C-C '2.000', 정면도 '12.133'"},
|
||||
"coping": {"dx": 12400, "dy": 3100, "z_top_left": 42456, "rise_upper": 1500, "rise_lower": 1500,
|
||||
"z_top_right": 42748, "z_top_center": 42602, "flat_from_tip": 5100, "end_inset": 200, "radius": 12000,
|
||||
"src": "D1 '12.400' '3.100' 'EL. 42.456' '1.500' x2 'EL. 42.748' 'EL. 42.602' '5.100' '200' 'R=12.000'"},
|
||||
"coping_outline": [[-1100, Z_COL_TOP], [1100, Z_COL_TOP], [6200, Z_COL_TOP + 1500], [6000, 42748], [sx[4], 42748],
|
||||
[sx[4], 42675], [sx[3], 42675], [sx[3], 42602], [sx[2], 42602], [sx[2], 42529], [sx[1], 42529],
|
||||
[sx[1], 42456], [-6000, 42456], [-6200, Z_COL_TOP + 1500]],
|
||||
"coping_outline_src": "D1 정면도 외형 from dims '200','2.219','3@2.502=7.507','2.274','200' and EL texts; "
|
||||
"intermediate step EL 42.529 / 42.675 from drawn risers 72.9 [derived]",
|
||||
"dxf_arc_centres": {"datum_x": FX, "datum_y": COL_TOP_Y, "datum_el": Z_COL_TOP,
|
||||
"left": [5207.5, 6039.2], "right": [19111.2, 6039.2],
|
||||
"src": "DXF ARC 20E8B / 20E89 centre; datum CS-CNTL 21539 / coping bottom line 20E87"},
|
||||
"piles": {"nx": 6, "ny": 5, "pitch_x": 1750, "pitch_y": 1550, "edge": 800, "d": 600, "length": 25900,
|
||||
"head_embedment": 100, "src": "D1 '5@1.750=8.750' '4@1.550=6.200' '800' 'Φ600' 'L=25.9M'"},
|
||||
"seats": {"table": {str(n): [round(float(r["EL.'X'"]) * 1000), int(r["h1"]), int(r["h2"]), int(r["A"]), int(r["B"])]
|
||||
for n, r in el.items()},
|
||||
"table_columns": ["EL.'X'", "h1", "h2", "A", "B"], "girders": 5, "step_top": step_top,
|
||||
"step_x": {str(i + 1): [sx[i], sx[i + 1]] for i in range(5)},
|
||||
"row_y": {"front": -(1550 - int(el[1]["S1"])), "rear": 1550 - int(el[6]["S1"])},
|
||||
"pitch_chain": [3, 7507], "pedestal_plan": [1250, 1200], "pad_margin": [200, 100],
|
||||
"rear_first_from_tip": 1223,
|
||||
"src": "D2 ELEVATION TABLE; D1 EL texts + drawn steps; S1 851/950; '3@2.502=7.507'; 대좌 2500x1200; '1.223'"},
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
el, _ = table()
|
||||
P = json.loads((PIER / "params.json").read_text(encoding="utf-8"))
|
||||
E = json.loads((PIER / "expected.json").read_text(encoding="utf-8"))
|
||||
stamp = time.strftime("%Y%m%d_%H%M%S")
|
||||
for f in ("params.json", "expected.json"):
|
||||
shutil.copy2(PIER / f, PIER / "backup" / f"{Path(f).stem}_before_R1_{stamp}.json")
|
||||
P.update(params_r1(el))
|
||||
P.pop("_meta", None)
|
||||
P["_meta"] = {"structure": "운곡교 P2 교각 (완도방향)", "status": "R1 형상 판독 2026-10-12 (Agent 초안, 사용자 확정 전)",
|
||||
"units": "mm; Z = EL x 1000", "frame": "X 교축직각, Y 교축, 원점 = 교각 중심",
|
||||
"sources": {"D1": "C0050205-028 교각도(1) P2", "D2": "C0050205-029 교각도(2) P2", "D3": "C0050205-030 교각도(3) P2"}}
|
||||
P["pier_id"] = "P2"
|
||||
P["display"]["hidden_ids"] = []
|
||||
P["display"]["src"] = "R8 팔레트(2026-10-07); 숨김 없음(요구사항 기본값 '모두 표시')"
|
||||
E["pier_id"] = "P2"
|
||||
E["G1"] = expected_g1(el)
|
||||
(PIER / "params.json").write_text(json.dumps(P, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
(PIER / "expected.json").write_text(json.dumps(E, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
s = P["bearing_seats"]
|
||||
print(json.dumps({k: P[k] for k in ("footing", "column", "piles")}, ensure_ascii=False))
|
||||
print("coping", {k: v for k, v in P["coping"].items() if k != "src"})
|
||||
print("pedestal rot", s["pedestal_girder5"]["rotation_deg"], "rows", {r: (v["centre_rel_girder5"], v["rotation_deg"]) for r, v in s["pad_rows"].items()})
|
||||
print("translation checks", s["translation_checks"])
|
||||
print("bearing 1/6", s["bearings"][0], s["bearings"][5])
|
||||
print("expected step_top", E["G1"]["seats"]["step_top"], "row_y", E["G1"]["seats"]["row_y"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,112 @@
|
||||
"""R2 (column rebar) reading of the Ungok P2 drawings -> data/운곡교p2 params.column_rebar / rebar_marks(P*) /
|
||||
expected.G2.
|
||||
|
||||
Findings (D1 front view + sections C-C/D-D/E-E, D3 schedule):
|
||||
- sections identical to P1 drawing: main bars r 870.5 / 825.5 (46 div, start 0.001 deg), hoop arc 897.5 drawn
|
||||
- D3: P4/P5 R904 (H29, coupler gap 85), P3 R899 (H19), P1 A 16.343, P2 16.683, P3 37 pcs
|
||||
- D1 labels 'P4 H29@100', 'P5 H29@100', chain '150','1.030','8@120','22@120','37@300=11.100', ties '8@1.800'
|
||||
- front view: P2 bottom = footing bottom + 300 (214CA), P1 leg at +300 with R340 / leg 500 (214CB/214CC)
|
||||
Rules reused from P1 (HITL H1/H2): main radii = section CAD, hoop radius = schedule R, bar tops = schedule.
|
||||
"""
|
||||
import json
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
APP = HERE.parent / "교각모델링앱"
|
||||
PIER = APP / "data" / "운곡교p2"
|
||||
sys.path.insert(0, str(APP))
|
||||
from engine import reader # noqa: E402
|
||||
|
||||
FB = 25123 # footing bottom (R1)
|
||||
|
||||
|
||||
def schedule():
|
||||
texts = json.loads((PIER / "drawings" / "texts.json").read_text(encoding="utf-8"))
|
||||
out = {}
|
||||
for t in reader.table_candidates(texts):
|
||||
if not t["key"].startswith("schedule"):
|
||||
continue
|
||||
last = None
|
||||
for _, r in reader.table_records(t["rows"], lambda s: bool(reader.MARK_RE.match(s))):
|
||||
dia = r.get("직경", "")
|
||||
last = last if dia in ('"', "") else dia
|
||||
r["_dia"] = last
|
||||
out[r["_key"]] = r
|
||||
return out
|
||||
|
||||
|
||||
def chain(start, groups, base):
|
||||
z = base + sum(start)
|
||||
pts = [z]
|
||||
for n, p in groups:
|
||||
for _ in range(n):
|
||||
z += p
|
||||
pts.append(z)
|
||||
return pts
|
||||
|
||||
|
||||
def main():
|
||||
S = schedule()
|
||||
P = json.loads((PIER / "params.json").read_text(encoding="utf-8"))
|
||||
E = json.loads((PIER / "expected.json").read_text(encoding="utf-8"))
|
||||
stamp = time.strftime("%Y%m%d_%H%M%S")
|
||||
for f in ("params.json", "expected.json"):
|
||||
shutil.copy2(PIER / f, PIER / "backup" / f"{Path(f).stem}_before_R2_{stamp}.json")
|
||||
sch = {}
|
||||
for m in ("P1", "P2", "P3", "P4", "P5", "P6"):
|
||||
r = S[m]
|
||||
d = {"mark": m, "shape": r["형식"], "dia": r.get("직경", ""), "n": r["개수"], "L": r["길이"]}
|
||||
for k in ("A", "B", "C", "R"):
|
||||
if k in r:
|
||||
d[k] = r[k]
|
||||
sch[m] = d
|
||||
groups = [[8, 120], [22, 120], [37, 300]]
|
||||
levels = chain([150, 1030], groups, FB)
|
||||
marks = ["P4"] * 9 + ["P5"] * 22 + ["P3"] * 37
|
||||
ties = chain([150, 1030], [[8, 1800]], FB)
|
||||
a1, a2 = float(S["P1"]["A"]) * 1000, float(S["P2"]["A"]) * 1000
|
||||
cr = P["column_rebar"]
|
||||
cr["_note"] = "Column rebar P1-P6 (Ungok P2). Z = EL x 1000. Angles from +X counter-clockwise (plan)."
|
||||
cr["schedule"] = sch
|
||||
mb = cr["main_bars"]
|
||||
mb["p1"].update({"hook_leg_z": FB + 300, "straight_from": FB + 300 + 340, "straight_len": round(a1)})
|
||||
mb["p2"].update({"z0": FB + 300, "length": round(a2)})
|
||||
mb["src"] = {"radii": "D1 단면 C-C/D-D/E-E dots 870.5 / 825.5 (46 each, start 0.001 deg) = P1 drawing (HITL H2 rule)",
|
||||
"bottom": "D1 정면도 214CA bottom = footing bottom + 300; 214CB leg 500, 214CC R340",
|
||||
"top": "D3 schedule A (P1 16.343, P2 16.683) -> top EL 42.106 both (P1 rule H1)"}
|
||||
cr["hoops"] = {"radius": 904, "radius_by_mark": {"P3": 899}, "levels": levels, "marks": marks,
|
||||
"src": {"levels": "D1 정면도 '150','1.030','8@120=960','22@120=2.640','37@300=11.100'; front dots 1180 + 120n",
|
||||
"radius": "D3 R: P4/P5 904 (2*pi*904 = 5680 = L), P3 899 (pi*899 = A 2.824); "
|
||||
"section arc drawn 897.5 = P1 drawing not updated -> schedule adopted (P1 rule H2)"}}
|
||||
cr["ties"].update({"levels": ties, "src": {"levels": "D1 정면도 '150','1.030','8@1.800=14.400'",
|
||||
"angles": "D1 단면 tie lines 0/45/90/135 (1795 drawn), D3 P6 A 1.836 / B 150"}})
|
||||
for m, r in sch.items():
|
||||
P["rebar_marks"][m] = {"dia": S[m]["_dia"], "shape": r["shape"]}
|
||||
dia = {m: int(S[m]["_dia"][1:]) for m in sch}
|
||||
E["G2"] = {
|
||||
"schedule_L": {m: round(float(S[m]["길이"]) * 1000) for m in sch},
|
||||
"schedule_n": {m: int(S[m]["개수"]) for m in sch},
|
||||
"dia": dia,
|
||||
"hoop_chain": {"start": [150, 1030], "groups": groups},
|
||||
"hoop_marks_by_zone": [["P4", 9], ["P5", 22], ["P3", 37]],
|
||||
"tie_chain": {"start": [150, 1030], "groups": [[8, 1800]]},
|
||||
"tie_offset": dia["P4"] / 2 + dia["P6"] / 2,
|
||||
"r_outer": 870.5, "r_inner": 825.5, "r_hoop": 904,
|
||||
"main_divisions": 46, "bottom_above_footing": 300,
|
||||
"p1_top_parts": [300, int(S["P1"]["R"]), round(a1)],
|
||||
"no_fillet_marks": ["P1", "P2", "P4", "P5"],
|
||||
"src": "D3 L·수량·R·A (Ungok P2); D1 '150','1.030','8@120=960','22@120=2.640','37@300=11.100','8@1.800=14.400'; "
|
||||
"section radii (HITL H2 rule); tie offset = H29/2 + H16/2 (hoop P4 H29 label, P6 H16)",
|
||||
}
|
||||
(PIER / "params.json").write_text(json.dumps(P, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
(PIER / "expected.json").write_text(json.dumps(E, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
print("levels", len(levels), levels[0], levels[-1], "ties", ties[0], ties[-1])
|
||||
print("marks dia", {m: P["rebar_marks"][m] for m in sch})
|
||||
print("schedule L", E["G2"]["schedule_L"], "n", E["G2"]["schedule_n"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,94 @@
|
||||
"""R3 (footing rebar) reading of the Ungok P2 drawings -> params.footing_rebar / rebar_marks(B*) / expected.G3.
|
||||
|
||||
Drawn facts (D1 front / side view dots, relative to the view centre, z above the footing bottom):
|
||||
- layer heights as P1 (F1 rule): 122 / 178 / 227.5 / 277 / 2073 / 2127; B10 rings 350..1950 @200, dots x 5093 / y 3818
|
||||
- front (Y-direction bars at X): ends +-5075, series -4875 + 125 i (79) -> B2/B4; -4875 + 250 i (40) -> B1, B3
|
||||
- side (X-direction bars at Y): as P1 (+-3800, -3625 + 125 i (59) / + 250 i (30))
|
||||
- mid layers: B12 (front) 550/1350: +-1875, 2875, 3875; 950/1750: +-375 .. +-4375 -> 32 drawn (D3 38);
|
||||
B11 (side) as P1 -> 28 (D3 28)
|
||||
- B9 EREC lines x -4625 .. 4625 @250 (38), y -3500 .. 3500 @250 (29), z 150..2100 -> checker 551 drawn (D3 493)
|
||||
Conflicts B9 / B12 count: drawn adopted (P1 rule F2), schedule difference recorded as planned FAIL.
|
||||
"""
|
||||
import json
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
APP = HERE.parent / "교각모델링앱"
|
||||
PIER = APP / "data" / "운곡교p2"
|
||||
sys.path.insert(0, str(HERE))
|
||||
from extract_r2 import schedule # noqa: E402
|
||||
|
||||
|
||||
def series(start, pitch, n):
|
||||
return [float(start + pitch * i) for i in range(n)]
|
||||
|
||||
|
||||
def sym(vals):
|
||||
return sorted([-v for v in vals] + list(vals))
|
||||
|
||||
|
||||
def main():
|
||||
S = schedule()
|
||||
P = json.loads((PIER / "params.json").read_text(encoding="utf-8"))
|
||||
E = json.loads((PIER / "expected.json").read_text(encoding="utf-8"))
|
||||
stamp = time.strftime("%Y%m%d_%H%M%S")
|
||||
for f in ("params.json", "expected.json"):
|
||||
shutil.copy2(PIER / f, PIER / "backup" / f"{Path(f).stem}_before_R3_{stamp}.json")
|
||||
fr = P["footing_rebar"]
|
||||
y_bot = sorted([-5075.0, 5075.0] + series(-4875, 125, 79))
|
||||
y_250 = sorted([-5075.0, 5075.0] + series(-4875, 250, 40))
|
||||
L = fr["layers"]
|
||||
L["bottom_Y1"]["pos"], L["bottom_Y3"]["pos"], L["top_Y"]["pos"] = y_bot, y_250, y_250
|
||||
mid_y = {"550.0": sym([1875.0, 2875.0, 3875.0]), "950.0": sym([375.0, 1375.0, 2375.0, 3375.0, 4375.0]),
|
||||
"1350.0": sym([1875.0, 2875.0, 3875.0]), "1750.0": sym([375.0, 1375.0, 2375.0, 3375.0, 4375.0])}
|
||||
L["mid_Y"]["levels"] = mid_y
|
||||
fr["a_x"], fr["a_y"] = float(S["B5"]["A"]) * 1000, float(S["B1"]["A"]) * 1000
|
||||
fr["a_src"] = "D3 B5 a '10.150' (X bars), B1 a '7.600' (Y bars)"
|
||||
fr["b9"].update({"grid_x": series(-4625, 250, 38), "count": 551,
|
||||
"src": "D1 정면 EREC x -4625..4625 @250 (chain '450','37@250=9.250'), 측면 -3500..3500 @250; "
|
||||
"checker parity as P1 -> 551 drawn; D3 개수 493 (= P1 value) -> CONFLICT, drawn adopted"})
|
||||
fr["b10"].update({"size_x": float(S["B10"]["A"]) * 1000, "size_y": float(S["B10"]["B"]) * 1000,
|
||||
"src": "D1 정면 '150','9@200=1.800'; dots x=5093 / y=3818; D3 B10 a 10.198 b 7.644"})
|
||||
fr["_note"] = "Footing rebar B1-B12 (Ungok P2); z above the footing bottom EL 25.123"
|
||||
rows = {}
|
||||
for m in ("B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "B10", "B11", "B12"):
|
||||
r = S[m]
|
||||
rows[m] = [m, r["형식"], r.get("직경", ""), r["개수"], r["A"]] + [r[k] for k in ("B", "C") if k in r] + [r["길이"], r["총길이"]]
|
||||
P["rebar_marks"][m] = {"dia": r["_dia"], "shape": r["형식"]}
|
||||
fr["schedule"] = rows
|
||||
fr["counts_check"] = {"bottom_Y1": len(y_bot), "bottom_X2": len(L["bottom_X2"]["pos"]), "bottom_Y3": len(y_250),
|
||||
"bottom_X4": len(L["bottom_X4"]["pos"]), "top_Y": len(y_250), "top_X": len(L["top_X"]["pos"]),
|
||||
"mid_X": sum(len(v) for v in L["mid_X"]["levels"].values()),
|
||||
"mid_Y": sum(len(v) for v in mid_y.values())}
|
||||
sched = {m: [round(float(S[m]["길이"]) * 1000), int(S[m]["개수"])] for m in rows}
|
||||
g3 = E["G3"]
|
||||
g3.update({
|
||||
"schedule": sched,
|
||||
"dia": {m: int(S[m]["_dia"][1:]) for m in rows},
|
||||
"rows": {"Y_BOT": {"ends": [-5075, 5075], "start": -4875, "pitch": 125, "n": 79},
|
||||
"Y_250": {"ends": [-5075, 5075], "start": -4875, "pitch": 250, "n": 40},
|
||||
"X_BOT": {"ends": [-3800, 3800], "start": -3625, "pitch": 125, "n": 59},
|
||||
"X_250": {"ends": [-3800, 3800], "start": -3625, "pitch": 250, "n": 30}},
|
||||
"b10_size": [10198, 7644],
|
||||
"b9_grid": {"x": {"start": -4625, "pitch": 250, "n": 38}, "y": {"start": -3500, "pitch": 250, "n": 29}},
|
||||
"src": "D3 L·수량 (P2); D1 '100','200','78@125=9.750' / '39@250=9.750' / '100','175','58@125=7.250' / '29@250'; "
|
||||
"F1 층 높이(작도점, P1과 같음); '150','9@200=1.800'; '450','37@250=9.250' / '300','28@250=7.000'; "
|
||||
"EREC 150~2100; 중간층 작도점 [derived]",
|
||||
})
|
||||
pf = [x for x in E.get("planned_fail", []) if x["gate"] != "G3"]
|
||||
pf += [{"gate": "G3", "item": "B12 bar count vs schedule", "reason": "작도 32본 채택 vs D3 38본 (P1 F2 규칙, P1도 28/34)",
|
||||
"approved": "P1 결정(2026-10-07) 준용 — P2 사용자 확인 대기"},
|
||||
{"gate": "G3", "item": "B9 bar count vs schedule", "reason": "작도 551본(38×29 엇갈림) 채택 vs D3 493본(P1 값 그대로)",
|
||||
"approved": "P1 결정(2026-10-07) 준용 — P2 사용자 확인 대기"}]
|
||||
E["planned_fail"] = pf
|
||||
(PIER / "params.json").write_text(json.dumps(P, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
(PIER / "expected.json").write_text(json.dumps(E, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
print("counts", fr["counts_check"], "b9", fr["b9"]["count"], "a", fr["a_x"], fr["a_y"], "b10", fr["b10"]["size_x"])
|
||||
print("schedule", sched)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,102 @@
|
||||
"""R4 (coping rebar) reading of the Ungok P2 drawings -> params.coping_rebar / rebar_marks(C*, S*) / expected.G4.
|
||||
|
||||
D1 front view (right half, EL = y - 16515.6 + 39456): the coping rebar is the P1 drawing lowered by 955 mm
|
||||
(coping bottom 40411 -> 39456), with right-end values following the P2 coping (right top 42748):
|
||||
- bottom C7/C8: flat z 39556 (20E88, 0..1074), arcs R12100 concentric with the soffit (20E8A)
|
||||
- top tiers: 42356 (20DB8, half 5941.6), 42256 (20DB6), 42156 (20E9F); legs // end faces (20DB7)
|
||||
- loops C12/C13: 9 levels 39806..41806 @250 (20D9D..20D95), right ends 1548.3..6003.6 (= P1)
|
||||
- stirrups (verticals 20DB5..20D9E): x 0..900 @300, 1150..5900 @250; tops 42501.9 (x<3900) / 42647.8 (x>=3900)
|
||||
- C14 dots (41): 42133.5 at 0, 900 .. 4900; 42233.5 / 40056 / 41056 / 40556 / 41556 at 13 + 1000k / 913 + 1000k;
|
||||
42489.5 at 2913 (right only)
|
||||
- C15 42647.8 x 3825.6..5900 (20E80); C16 42501.9 x 0..4075.6 (20E82), left end = step-3 left + 100 = -1179 [추론]
|
||||
D3 (P2): counts as P1; C3/C6 H25; ranges C9 2.958~1.376, C11 2.958~1.668, C10 3.000, C12 12.228~3.151,
|
||||
C13 12.167~12.044 (range texts read by position; the app table reader does not map them).
|
||||
Rules reused from P1: stirrup top-left bands = left steps - 100 [추론], b = height + 54.3, loop widths drawn (K1),
|
||||
C14 hooks up where a down hook would leave the soffit (4 bars, same positions as P1).
|
||||
"""
|
||||
import json
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
APP = HERE.parent / "교각모델링앱"
|
||||
PIER = APP / "data" / "운곡교p2"
|
||||
sys.path.insert(0, str(HERE))
|
||||
from extract_r2 import schedule # noqa: E402
|
||||
|
||||
|
||||
def sym(pts):
|
||||
out = []
|
||||
for x, z in pts:
|
||||
out.append([x, z])
|
||||
if x > 20:
|
||||
out.append([-x, z])
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
S = schedule()
|
||||
P = json.loads((PIER / "params.json").read_text(encoding="utf-8"))
|
||||
E = json.loads((PIER / "expected.json").read_text(encoding="utf-8"))
|
||||
stamp = time.strftime("%Y%m%d_%H%M%S")
|
||||
for f in ("params.json", "expected.json"):
|
||||
shutil.copy2(PIER / f, PIER / "backup" / f"{Path(f).stem}_before_R4_{stamp}.json")
|
||||
cr = P["coping_rebar"]
|
||||
cr["_note"] = "Coping rebar C1-C16, S1, S2 (Ungok P2)"
|
||||
a = lambda m: round(float(S[m]["A"]) * 1000)
|
||||
cr["top"]["tiers"] = {"1": {"z": 42356, "marks": ["C1", "C4"], "a": a("C1"), "legs": [1319, 1315]},
|
||||
"2": {"z": 42256, "marks": ["C2", "C5"], "a": a("C2"), "legs": [101, 101]},
|
||||
"3": {"z": 42156, "marks": ["C3", "C6"], "a": a("C3"), "legs": [101, 101]}}
|
||||
cr["top"]["src"] = "D1 정면도 20DB8/20DB6/20E9F 42,356/42,256/42,156 (P1 - 955); D3 a 11.856/11.880/11.905, legs 1.319/1.315, 101"
|
||||
cr["bottom"].update({"z_flat": 39556, "half_flat": 1073.9,
|
||||
"src": "D1 20E88 z 39,556 (0~1,074) = 하면 100 위; ARC 20E8A R 12,100 동심; arc_len = (13,994 - 2,148 - 2x650)/2"})
|
||||
cr["soffit_arc_centre"] = [6951.9, 28979.6]
|
||||
cr["soffit_arc_centre_src"] = "right soffit arc centre (P2), rounded to 0.1 mm as P1; DXF 20E89 / 20E8A"
|
||||
st = cr["stirrups"]
|
||||
st["top_right"] = [[0, 42501.9], [3900, 42647.8]]
|
||||
st["top_left"] = [[0, 42502], [1279, 42429], [3781, 42356]]
|
||||
st["src"] = ("D1 정면도 수직선 20DB5~20D9E (우측 절반) 상단 42,501.9 / 42,647.8; 좌측 상단 = 좌측 소단 - 100 [추론] "
|
||||
"(C9 최소 1,376 일치); 재료표 b = 높이 + 54.3 (C10 3,000, C11 2,958~1,668 일치)")
|
||||
st["bottom"] = "z=39,556 for |X|<=1,073.9 else circle R 12,100 about (+-6,951.9, 28,979.6)"
|
||||
lp = cr["loops"]
|
||||
lp["levels"] = [39806 + 250 * k for k in range(9)]
|
||||
lp["src"] = "D1 정면도 수평선 9단 39,806~41,806 @250 (20D9D~20D95, 우측 끝 1,548~6,004 = P1); 폭 = 작도 (K1)"
|
||||
c14 = sym([(0, 42133.5), (900, 42133.5), (1900, 42133.5), (2900, 42133.5), (3900, 42133.5), (4900, 42133.5)])
|
||||
c14 += sym([(13, 42233.5), (913, 42233.5), (1913, 42233.5), (2913, 42233.5), (3913, 42233.5), (4913, 42233.5)])
|
||||
c14 += sym([(13, 40056), (1913, 40056)]) + sym([(13, 41056), (1913, 41056), (3913, 41056)])
|
||||
c14 += sym([(913, 40556), (2913, 40556)]) + sym([(913, 41556), (2913, 41556), (4913, 41556)])
|
||||
c14 += [[2913, 42489.5]]
|
||||
cr["c14"].update({"points": c14, "a": a("C14"), "hook": int(S["C14"]["B"]),
|
||||
"hooks_up": [[1913, 40056], [-1913, 40056], [2913, 40556], [-2913, 40556]],
|
||||
"src": "D1 정면도 철근 점 41 (우측 절반, 대칭 환산; 42,489.5는 우측만); hooks_up = P1 HITL 규칙과 같은 4본"})
|
||||
cr["c15"].update({"z": 42647.8, "x0": 3825.6, "x1": 5900, "hooks": [350, 350],
|
||||
"src": "D1 20E80 42,647.8 (3,825.6~5,900 = a 2,074); D3 C15 A 2.074 B 350"})
|
||||
cr["c16"].update({"z": 42501.9, "x0": -1179.4, "x1": 4075.6, "hook_left": 350,
|
||||
"src": "D1 20E82 42,501.9 (0~4,075.6, 좌측 미작도) -> a 5,255로 좌단 -1,179.4 (소단3 좌단 +100) [추론]"})
|
||||
for m in [f"C{i}" for i in range(1, 17)] + ["S1", "S2"]:
|
||||
P["rebar_marks"][m] = {"dia": S[m]["_dia"], "shape": S[m]["형식"]}
|
||||
g4 = E["G4"]
|
||||
g4.update({
|
||||
"count": {m: int(S[m]["개수"]) for m in g4["count"]},
|
||||
"L": {m: round(float(S[m]["길이"]) * 1000) for m in g4["L"]},
|
||||
"range": {"C9": ["b_sched", 2958, 1376], "C11": ["b_sched", 2958, 1668], "C10": ["b_sched", 3000, 3000],
|
||||
"C12": ["a_sched", 12228, 3151], "C13": ["a_sched", 12167, 12044]},
|
||||
"dia": {m: int(S[m]["_dia"][1:]) for m in g4["dia"]},
|
||||
"tier_z": {"C1": 42356, "C4": 42356, "C2": 42256, "C5": 42256, "C3": 42156, "C6": 42156},
|
||||
"c10_bottom": 39556,
|
||||
"loop_z": {"C12": {"start": 39806, "pitch": 250, "n": 6}, "C13": [41306, 41556, 41806]},
|
||||
"c15_top": 42647.8, "c16_top": 42501.9,
|
||||
"c14_levels": [[42133.5, 11], [42233.5, 11], [40056, 3], [41056, 5], [40556, 4], [41556, 6], [42489.5, 1]],
|
||||
"step_top": {"1": 42456, "2": 42529, "3": 42602, "4": 42675, "5": 42748},
|
||||
"src": "D3 (P2) 수량·L·a/b 범위; D1 A-A 사슬 '100','137','21@125','3000' / B-B '10@250'; 정면도 단 높이·스터럽 X·루프 EL; D2 '50','50'",
|
||||
})
|
||||
(PIER / "params.json").write_text(json.dumps(P, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
(PIER / "expected.json").write_text(json.dumps(E, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
print("c14", len(c14), "L", g4["L"])
|
||||
print("dia", {m: P["rebar_marks"][m]["dia"] for m in ("C1", "C3", "C6", "C7", "C9", "C14")})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,60 @@
|
||||
"""R5 (bridge bearings + sole plates) reading of the Ungok P2 drawings -> params.sole_plates / expected.G5.
|
||||
|
||||
D2 솔플레이트 상세 TABLE (NO., S(%), L, W, T, T1, T2) and ELEVATION TABLE (EL.'X', h3) via the app table reader.
|
||||
P2: h3 165 (P1 181); W 640 / 750 (NO.3, 8) = B + 100 (B 540 / 650); L 800 = A + 100.
|
||||
Rules reused from P1 (user 2026-10-08): bearing = (L-100) x (W-100) black box of height h3 on the pad top;
|
||||
slope S along the pad axis only, thick end at -Y [HITL P1, not re-confirmed for P2].
|
||||
"""
|
||||
import json
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
APP = HERE.parent / "교각모델링앱"
|
||||
PIER = APP / "data" / "운곡교p2"
|
||||
sys.path.insert(0, str(HERE))
|
||||
from extract_r1 import table # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
el, sp = table()
|
||||
P = json.loads((PIER / "params.json").read_text(encoding="utf-8"))
|
||||
E = json.loads((PIER / "expected.json").read_text(encoding="utf-8"))
|
||||
stamp = time.strftime("%Y%m%d_%H%M%S")
|
||||
for f in ("params.json", "expected.json"):
|
||||
shutil.copy2(PIER / f, PIER / "backup" / f"{Path(f).stem}_before_R5_{stamp}.json")
|
||||
h3 = {int(r["h3"]) for r in el.values()}
|
||||
assert len(h3) == 1, h3
|
||||
h3 = h3.pop()
|
||||
rows, checks = [], []
|
||||
for no, r in sorted(sp.items()):
|
||||
row = {"no": no, "S": float(r["S(%)"]), "L": int(r["L"]), "W": int(r["W"]), "T": int(r["T"]),
|
||||
"T1": int(r["T1"]), "T2": int(r["T2"])}
|
||||
rows.append(row)
|
||||
A, B = int(el[no]["A"]), int(el[no]["B"])
|
||||
half = row["S"] / 100 * row["L"] / 2
|
||||
checks.append({"no": no, "L_eq_A100": row["L"] == A + 100, "W_eq_B100": row["W"] == B + 100,
|
||||
"end_thick": [round(row["T"] - half, 2), round(row["T"] + half, 2)], "T1T2": [row["T1"], row["T2"]]})
|
||||
s = P["sole_plates"]
|
||||
s.update({"table": rows, "h3": h3, "checks": checks,
|
||||
"bearing_height": f"h3 (D2 ELEVATION TABLE, {h3})",
|
||||
"src": "D2 솔플레이트 상세 TABLE (NO., S(%), L, W, T, T1, T2); ELEVATION TABLE h3; 규칙 = P1 사용자 지시(2026-10-08)"})
|
||||
E["G5"] = {
|
||||
"el_x": {str(n): round(float(r["EL.'X'"]) * 1000) for n, r in el.items()},
|
||||
"S": {str(r["no"]): r["S"] for r in rows},
|
||||
"W": {str(r["no"]): r["W"] for r in rows},
|
||||
"L": rows[0]["L"], "T": rows[0]["T"], "h3": h3, "bearing_shrink": 100,
|
||||
"colours": {"bearing": [0, 0, 0], "sole_plate": [150, 150, 150]},
|
||||
"src": "D2 ELEVATION TABLE (EL.'X', h3), 솔플레이트 상세 TABLE (S, L, W, T); (L-100)x(W-100)·색 = P1 사용자 지시 준용",
|
||||
}
|
||||
assert len({r["L"] for r in rows}) == 1 and len({r["T"] for r in rows}) == 1
|
||||
P["_meta"]["status"] = "R1~R5 판독 2026-10-12 (Agent 초안, 사용자 확정 전)"
|
||||
(PIER / "params.json").write_text(json.dumps(P, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
(PIER / "expected.json").write_text(json.dumps(E, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
print("h3", h3, "checks", [(c["no"], c["L_eq_A100"], c["W_eq_B100"], c["end_thick"]) for c in checks])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 706 KiB |
Reference in new issue
Block a user