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

+37
View File
@@ -0,0 +1,37 @@
"""Debug (2026-10-13): build the tapered coping pieces step by step and report validity / boolean results.
Run through the app runner: python -c "..." (see tools usage in the session log)."""
import json
import math
import Rhino.Geometry as rg
P = json.load(open(PARAMS_PATH, encoding="utf-8"))
c = P["coping"]
TOL = 0.01
out = {}
w, R, L0, z_tip = c["width_y"], c["plan_corner_radius"], c["plan_length"], c["z_tip"]
zmin = min(z for _, z in c["profile_xz"])
trap = [(-1250, zmin), (1250, zmin), (L0 / 2, z_tip), (-L0 / 2, z_tip)]
prof = rg.PolylineCurve([rg.Point3d(x, -w / 2, z) for x, z in trap + trap[:1]])
srf = rg.Surface.CreateExtrusion(prof, rg.Vector3d(0, w, 0))
low = srf.ToBrep().CapPlanarHoles(TOL)
out["lower"] = dict(valid=low.IsValid, solid=low.IsSolid, orient=str(low.SolidOrientation),
vol=rg.VolumeMassProperties.Compute(low).Volume if low.IsSolid else None)
if low.SolidOrientation == rg.BrepSolidOrientation.Inward:
low.Flip()
cx, cy = L0 / 2 - R, w / 2 - R
blk = rg.Box(rg.BoundingBox(cx, cy, zmin - 100, cx + R + 100, cy + R + 100, z_tip + 100)).ToBrep()
cyl = rg.Cylinder(rg.Circle(rg.Plane(rg.Point3d(cx, cy, zmin - 200), rg.Vector3d.ZAxis), R), z_tip - zmin + 400).ToBrep(True, True)
waste = rg.Brep.CreateBooleanDifference(blk, cyl, TOL)
out["waste"] = dict(n=len(waste) if waste else 0, valid=[b.IsValid for b in waste] if waste else None,
solid=[b.IsSolid for b in waste] if waste else None)
if waste:
d1 = rg.Brep.CreateBooleanDifference(low, waste[0], TOL)
out["low_minus_one"] = dict(n=len(d1) if d1 else 0)
inter = rg.Brep.CreateBooleanIntersection(low, waste[0], TOL)
out["low_and_one"] = dict(n=len(inter) if inter else 0,
vol=[rg.VolumeMassProperties.Compute(b).Volume for b in inter] if inter else None)
x = rg.Intersect.Intersection.BrepBrep(low, waste[0], TOL)
out["brepbrep"] = dict(ok=x[0], curves=len(x[1]), pts=len(x[2]))
json.dump(out, open(OUT_PATH, "w"), indent=1, default=str)
print(json.dumps(out, default=str))
+18
View File
@@ -0,0 +1,18 @@
"""Dump DIMENSION entities (defpoints, measurement, text) of a region (read only)."""
import sys
from dxftools import doc
lab = sys.argv[1]
x0, y0, x1, y1 = map(float, sys.argv[2:6])
for e in doc(lab).modelspace().query("DIMENSION"):
p = e.dxf.defpoint
q2, q3 = e.dxf.get("defpoint2"), e.dxf.get("defpoint3")
pts = [v for v in (p, q2, q3) if v is not None]
if not any(x0 <= v.x <= x1 and y0 <= v.y <= y1 for v in pts):
continue
try:
m = e.get_measurement()
except Exception:
m = None
f = lambda v: f"({v.x:.1f},{v.y:.1f})" if v is not None else "-"
print(e.dxf.handle, f"{m:.1f}" if isinstance(m, float) else m, repr(e.dxf.get("text", "")), f(q2), f(q3), f(p), e.dxf.get("angle", 0))
+9
View File
@@ -0,0 +1,9 @@
[
{
"source": "교각배근도(울산P1).dwg",
"source_sha256": "5805357b67af903ef0a9f17007a31e3ab513accb69d83e5b8950a0272c20707a",
"dxf": "교각배근도(울산P1).dxf",
"dxf_sha256": "705e7370f102a0127b45db56db36484d6e5ee0ddc9439e532a4a5c9d986c2428",
"engine": "ODA File Converter 27.1.0"
}
]
File diff suppressed because it is too large. Load diff
+100
View File
@@ -0,0 +1,100 @@
"""Reading aids for the Ulsan P1 drawing (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/울산P1판독/dxf (converted from a copy of RAG/교각배근도(울산P1).dwg).
"""
import re
import sys
from pathlib import Path
import ezdxf
from ezdxf import bbox
HERE = Path(__file__).resolve().parent
DXF = HERE / "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))
+104
View File
@@ -0,0 +1,104 @@
"""R2 (column rebar) reading of the Ulsan P1 drawing -> data/산외교울산P1 params.column_rebar / rebar_marks /
display palette, expected.G2; adds G2 to the pier scope.
배근도(1) (sheet x 0..46000): front view footing bottom y -40253.3, column CL x 10473.9; sections C-C / D-D / E-E.
- main P1: 68 bars (CSBSEC1 inserts) on r 1125, pitch 360/68, start 0 deg; drawn 0/180-deg bars: vertical from
FB+540, R340 bend (B041/B042), leg at FB+200 outwards; schedule A 27.510, B 534 (= pi/2 x 340), C 500
- hoops R 1.149 (schedule; drawn arc 1147.5): chain '150','625','11@150=1.650','25@150=3.750','70@300=21.000'
-> P3 (V, coupler 55) 12 levels in the footing, P4 (X, coupler 55) 25, P2 (VI, laps 380, hooks 200) 70
- ties P5 (I, 2.295 + 2 x 150): chain '150','625','3@1.800','11@1.800','1.200' -> 16 levels x 4 (64);
section lines at 0 / 42.4 / 90 / 132.4 deg (bar positions 0, 8, 17, 25)
"""
import json
import shutil
import sys
import time
from pathlib import Path
HERE = Path(__file__).resolve().parent
APP = HERE.parent / "교각모델링앱"
PIER = APP / "data" / "산외교울산P1"
FB = 42763
S = json.loads((HERE / "판독" / "schedule.json").read_text(encoding="utf-8"))
ROWS = {r["mark"]: r for t in S.values() for r in t["rows"]}
def L(m):
"""Schedule length (first value right of J/R columns) in mm."""
return round(float(ROWS[m]["_right"][-2][1]) * 1000)
def chain(start, groups, base):
z = base + sum(start)
out = [z]
for n, p in groups:
for _ in range(n):
z += p
out.append(z)
return out
def main():
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")
(PIER / "backup").mkdir(exist_ok=True)
for f in ("params.json", "expected.json"):
shutil.copy2(PIER / f, PIER / "backup" / f"{Path(f).stem}_before_R2_{stamp}.json")
hoop_chain = {"start": [150, 625], "groups": [[11, 150], [25, 150], [70, 300]]}
levels = chain(hoop_chain["start"], hoop_chain["groups"], FB)
zones = [("P3", 12), ("P4", 25), ("P2", 70)]
cut = [0, 12, 37, 107]
tie_chain = {"start": [150, 625], "groups": [[14, 1800], [1, 1200]]}
a = lambda m: round(float(ROWS[m]["A"]) * 1000) if "." in ROWS[m]["A"] else int(ROWS[m]["A"])
P["column_rebar"] = {
"form": "ring",
"schedule": {m: {k: v for k, v in ROWS[m].items() if k not in ("y", "_right")} | {"L": ROWS[m]["_right"][-2][1]}
for m in ("P1", "P2", "P3", "P4", "P5")},
"main": {"mark": "P1", "count": 68, "start_deg": 0.0, "radius": 1125.0, "hook_leg_z": FB + 200, "bend_r": 340,
"hook_leg": 500, "straight_from": FB + 540, "straight_len": a("P1"),
"src": "배근도(1) 단면 C-C/D-D/E-E CSBSEC1 68개 r 1,125 (start 0 deg); 정면 B041/B042 R340, A91D/A920 시작 FB+540; 재료표 P1"},
"hoops": {"radius": 1149, "zones": [
{"mark": "P3", "type": "coupler_half", "levels": levels[cut[0]:cut[1]], "a": a("P3"), "gap": int(ROWS["P3"]["B"])},
{"mark": "P4", "type": "coupler_ring", "levels": levels[cut[1]:cut[2]], "a": a("P4"), "gap": int(ROWS["P4"]["B"])},
{"mark": "P2", "type": "lap_half", "levels": levels[cut[2]:cut[3]], "a": a("P2"), "lap": int(ROWS["P2"]["J"]),
"hook": int(ROWS["P2"]["B"])}],
"src": "재료표 R 1.149 (단면 원호 작도 1,147.5); 정면 사슬 '150','625','11@150','25@150','70@300'; 이음 위치 [추론]"},
"ties": {"mark": "P5", "levels": chain(tie_chain["start"], tie_chain["groups"], FB),
"angles_deg": [0.0, 8 * 360 / 68, 90.0, 25 * 360 / 68], "straight": a("P5"), "hook": int(ROWS["P5"]["B"]),
"z_offset": 16 / 2 + 19 / 2,
"src": "정면 사슬 '3@1.800','11@1.800','1.200' (+ 첫 단 775) = 16단 x 4 = 64; 단면 선 0/42.4/90/132.4 deg; 갈고리 아래 [추론]"},
}
P["rebar_marks"] = {m: {"dia": r["dia"], "shape": r["shape"]} for m, r in ROWS.items()}
P["rebar_marks_src"] = "배근도(3) 철근재료표 SD400·SD500 (34 마크)"
pal = P["display"]["rebar_palette"]
pal.setdefault("22", [23, 190, 207])
pal.setdefault("13", [140, 86, 75])
P["display"]["column_mark_colours"] = {"P1": [200, 40, 40], "P2": [40, 120, 200], "P3": [40, 170, 170],
"P4": [90, 90, 220], "P5": [140, 60, 160]}
P["display"]["src"] = "R8 팔레트(2026-10-07) + 울산 확장 H22 (23,190,207), H13 (140,86,75) [2026-10-13]; 숨김 없음"
P["scope"] = sorted(set(P["scope"]) | {"G2"})
P["builders"]["G2"] = "column_rebar_ring.py"
E["rebar_palette"] = dict(E["rebar_palette"], **{"22": [23, 190, 207], "13": [140, 86, 75]})
E["checkers"]["G2"] = "g2_ring.py"
E["negative"]["G2"] = [{"mark": "P1", "d": [5, 0, 0]}, {"mark": "P2", "d": [0, 0, 5]}]
E["G2"] = {
"schedule_L": {m: L(m) for m in ("P1", "P2", "P3", "P4", "P5")},
"schedule_n": {m: int(ROWS[m]["n"]) for m in ("P1", "P2", "P3", "P4", "P5")},
"dia": {m: int(ROWS[m]["dia"][1:]) for m in ("P1", "P2", "P3", "P4", "P5")},
"main": {"mark": "P1", "radius": 1125, "divisions": 68, "start_deg": 0.0, "bottom_above_footing": 200,
"top_parts": [540, 27510]},
"hoop_chain": hoop_chain, "hoop_zones": zones, "r_hoop": 1149,
"tie": {"mark": "P5", "chain": tie_chain, "per_level": 4, "offset": 17.5},
"no_fillet_marks": ["P1", "P3", "P4"],
"src": "재료표 L·수량·R; 단면 '125','1.125','1.125','125', DIVISION 68; 정면 사슬(띠철근 외측·크로스타이); P1 갈고리 작도 높이 200/540",
}
(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("hoop levels", len(levels), levels[0], levels[-1], "ties", len(P["column_rebar"]["ties"]["levels"]),
P["column_rebar"]["ties"]["levels"][-1])
print("schedule L", E["G2"]["schedule_L"], "scope", P["scope"])
if __name__ == "__main__":
main()
+111
View File
@@ -0,0 +1,111 @@
"""R3 (footing rebar) reading of the Ulsan P1 drawing -> data/산외교울산P1 params.footing_rebar, expected.G3;
adds G3 to the pier scope (builder footing_rebar_mats.py, checker g3_mats.py).
배근도(1) front view (CX 10473.9, FB y -40253.3) and side view (CX 24604.3); footing 7,500 x 7,500 x 2,500.
- position chains: top '100','150','28@250=7.000','50','100(상면)'; bottom '100','150','56@125=7.000','50','100(하면)';
middle '100','400','13@500=6.500','400','100(중앙)'. The side-view top chain ends with '150','100' -> B4 last
bar at 3,650 (front view: 3,600) - drawing inconsistency, modelled as drawn.
- Y-direction (front): bottom z 127.5 = B2 (U, legs up 2,250, on the top-row positions, 31) + B3 (other 28);
top z 2,422.5 = B1 (31). X-direction (side): bottom z 172.5 = B5 (U) + B6; top z 2,377.5 = B4.
The B5 positions follow the front top row (bottom chain has no 3,650) [추론].
- B8 perimeter hoops centreline ±3,672.5, z 375..2,175 @300 (7); B9 (X) / B10 (Y) mid layer z 1,275 at the
drawn positions, legs 100 down; both at the same z (drawn) -> cross at the intersections (recorded).
- B7 verticals on the 14 x 14 grid -3,250..3,250 @500, checkerboard (i+j even) = 98 [추론]; drawn z 150..2,400,
A 2,218 centred -> z0 166 [추론]; legs 100 along +Y (avoids the X-direction bottom bars) [추론].
"""
import json
import shutil
import time
from pathlib import Path
HERE = Path(__file__).resolve().parent
APP = HERE.parent / "교각모델링앱"
PIER = APP / "data" / "산외교울산P1"
S = json.loads((HERE / "판독" / "schedule.json").read_text(encoding="utf-8"))
ROWS = {r["mark"]: r for t in S.values() for r in t["rows"]}
MARKS = [f"B{i}" for i in range(1, 11)]
ROW_DEF = {
"bottom": {"first": [-3650], "start": -3500, "pitch": 125, "n": 57, "last": [3600]},
"top_front": {"first": [-3650], "start": -3500, "pitch": 250, "n": 29, "last": [3600]},
"top_side": {"first": [-3650], "start": -3500, "pitch": 250, "n": 29, "last": [3650]},
"grid": {"start": -3250, "pitch": 500, "n": 14},
}
MID = [-3250, -2250, -1250, -250, 750, 1750, 2750]
def row(spec):
return sorted(spec.get("first", []) + [spec["start"] + spec["pitch"] * i for i in range(spec["n"])] + spec.get("last", []))
def mm(v):
return round(float(v) * 1000) if "." in v else int(v)
def L(m):
return round(float(ROWS[m]["_right"][0][1]) * 1000) # first value right of the J column = L
def main():
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")
bottom, tf, ts = row(ROW_DEF["bottom"]), row(ROW_DEF["top_front"]), row(ROW_DEF["top_side"])
on = [v for v in bottom if v in tf]
off = [v for v in bottom if v not in tf]
a = mm(ROWS["B1"]["A"])
leg_u = mm(ROWS["B2"]["B"])
lap = mm(ROWS["B2"]["J"])
hook = mm(ROWS["B9"]["B"])
src_f, src_s = "배근도(1) 정면도 기초", "배근도(1) 측면도 기초"
groups = [
dict(mark="B1", axis="Y", z=2422.5, pos=tf, a=a, leg=0, src=f"{src_f} 상면 사슬 '28@250' (끝 3,600)"),
dict(mark="B2", axis="Y", z=127.5, pos=on, a=a, leg=leg_u, lap=lap, src=f"{src_f} 하면 U형 (상면 위치), 이음 J {lap} 길이만"),
dict(mark="B3", axis="Y", z=127.5, pos=off, a=a, leg=0, src=f"{src_f} 하면 '56@125' 중 B2 외"),
dict(mark="B4", axis="X", z=2377.5, pos=ts, a=a, leg=0, src=f"{src_s} 상면 사슬 (끝 '150','100' -> 3,650, 정면과 불일치)"),
dict(mark="B5", axis="X", z=172.5, pos=on, a=a, leg=leg_u, lap=lap, src=f"{src_s} 하면 U형 (정면 상면 위치) [추론]"),
dict(mark="B6", axis="X", z=172.5, pos=off, a=a, leg=0, src=f"{src_s} 하면 B5 외"),
dict(mark="B9", axis="X", z=1275, pos=MID, a=a, leg=-hook, src=f"{src_s} 중앙 (작도 위치, 비대칭)"),
dict(mark="B10", axis="Y", z=1275, pos=MID, a=a, leg=-hook, src=f"{src_f} 중앙 (작도 위치, 비대칭; B9와 같은 높이)"),
]
hoop = dict(mark="B8", half=3672.5, levels=[375 + 300 * i for i in range(7)],
design_length=2 * mm(ROWS["B8"]["A"]) + 2 * mm(ROWS["B8"]["B"]) + 4 * mm(ROWS["B8"]["J"]),
src="정면·측면 둘레 띠 ±3,672.5, z 375~2,175 @300; 길이 2A+2B+4J")
grid = row(ROW_DEF["grid"])
vert = dict(mark="B7", grid_x=grid, grid_y=grid, parity=0, z0=150 + (2250 - mm(ROWS["B7"]["A"])) / 2,
a=mm(ROWS["B7"]["A"]), leg=mm(ROWS["B7"]["B"]), leg_axis="Y",
src="14x14 격자 @500 중 체크무늬 98 [추론]; 작도 z 150~2,400, A 중앙 배치 [추론]; 갈고리 +Y [추론]")
P["footing_rebar"] = {"form": "mats", "groups": groups, "hoops": hoop, "verticals": vert,
"src": "배근도(1) 정면·측면 기초 배근 + 배근도(3) 재료표 B1~B10"}
P["scope"] = [g for g in ("G1", "G2", "G3", "G4", "G5") if g in set(P["scope"]) | {"G3"}]
P["builders"]["G3"] = "footing_rebar_mats.py"
E["checkers"]["G3"] = "g3_mats.py"
E["negative"]["G3"] = [{"mark": "B3", "d": [5, 0, 0]}, {"mark": "B7", "d": [0, 0, 5]}]
E["G3"] = {
"schedule": {m: [L(m), int(ROWS[m]["n"])] for m in MARKS},
"dia": {m: int(ROWS[m]["dia"][1:]) for m in MARKS},
"rows": ROW_DEF,
"layers": {
"B1": {"axis": "Y", "z": 2422.5, "row": "top_front"},
"B2": {"axis": "Y", "z": 127.5, "row": "bottom", "subset": "on", "of": "top_front"},
"B3": {"axis": "Y", "z": 127.5, "row": "bottom", "subset": "off", "of": "top_front"},
"B4": {"axis": "X", "z": 2377.5, "row": "top_side"},
"B5": {"axis": "X", "z": 172.5, "row": "bottom", "subset": "on", "of": "top_front"},
"B6": {"axis": "X", "z": 172.5, "row": "bottom", "subset": "off", "of": "top_front"},
"B9": {"axis": "X", "z": 1275, "pos": MID, "leg": -hook},
"B10": {"axis": "Y", "z": 1275, "pos": MID, "leg": -hook},
},
"hoops": {"mark": "B8", "half": 3672.5, "chain": {"start": [375], "groups": [[6, 300]]}},
"verticals": {"mark": "B7", "grid_x": "grid", "grid_y": "grid", "parity": 0, "z0": 166, "a": 2218},
"src": "재료표 L·수량; 정면·측면 위치 사슬(상면·하면·중앙); 층 높이는 작도값 [derived]",
}
(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", {g["mark"]: len(g["pos"]) for g in groups}, "B7", sum(1 for i in range(14) for j in range(14) if (i + j) % 2 == 0))
print("scope", P["scope"], "B8 len", hoop["design_length"], "B7 z0", vert["z0"], "palette", sorted(P["display"]["rebar_palette"]))
if __name__ == "__main__":
main()
+288
View File
@@ -0,0 +1,288 @@
"""R4 (coping rebar C1~C15, bearing-seat reinforcement S1~S4) reading of the Ulsan P1 drawing ->
data/산외교울산P1 params.coping_rebar (explicit centreline polylines), expected.G4; adds G4 to the scope.
Sources (배근도(1) front view CX 10473.9, side view CX 24604.3; 배근도(2) sections A-A / B-B, 받침부 보강 상세 1·3,
F-F / G-G; 배근도(3) schedule and shape table). Front-view drawing y -> EL: z = y + 99715.8 (bottom bars
-31753.3 = 67962.5 = coping bottom + 100; layer 1 -28752.8 = right top - 100).
- C1/C3 layer 1 (z 70962.5), C2/C4 layer 2 (z 70862.5): drawn lines 9,258.6 / 9,297 (= A); end legs drawn
(C1 left 1,364 / right 1,369 along the end faces; C2 102); y 24@125 (25 per layer) - C1/C2 even, C3/C4 odd [추론]
- C15 left top (z 71092.5): 4,500 + legs 510 (left leg along the end face [추론], right leg at x -100); y 12@250
- C5/C6 bottom: drawn polyline (650 / 4,018 / 2,457 / 4,016 / 650); y 12@250, C5 even (7) / C6 odd (6) [추론]
- stirrups C7 (x -4,600..-1,400 @200, 17) / C8 (-1,200 -1,000 -500 0 500 1,000 1,200) / C9 (1,400..4,600):
3 per position, legs y (-1,500,-250) (-1,000,1,000) (250,1,500) (A-A; shape table II note a = (1,250x2 +
2,000)/3 + 54); centreline height b = drawn height + 54 (schedule B range reproduced to 1 mm): top = layer-1
(x >= 0) or C15 level (x <= -500) + 27, bottom = drawn bottom bar line - 27
- side bars 13 levels z 70,562.5 - 200k (side view / A-A '530','13@200'), drawn ends per level; y +-977.5 and
+-272.5 = C13 (levels 1-5, 20) / C11 (levels 6-13, 32), a = drawn + 44 (schedule range reproduced);
180-deg hooks (b 165, c 140) in plan towards y = 0 inside the drawn ends [추론]
- perimeter hoops y +-1,477.5: C12 (XII, plan corners R400, levels 1-6) / C10 (III, levels 7-13); counts kept,
schedule ranges suggest 5 / 8 levels (C10 a max 9,570 = level 6) -> drawing inconsistency recorded
- C14 (H16, 3,000 + 300) at the drawn section marks (5 levels, 8+4+4+3+1); legs along X towards the column and
x offset 19 from the stirrup plane [추론]
- S1/S2 (front bearings 1,2) S3/S4 (rear 3,4): 11 bars per direction (50,100,'8@125',100,50) in the 1,300 pedestal,
50 below the pedestal top, legs 700 down; S1/S3 along Y on top, S2/S4 along X below [추론]
"""
import json
import shutil
import time
from pathlib import Path
HERE = Path(__file__).resolve().parent
APP = HERE.parent / "교각모델링앱"
PIER = APP / "data" / "산외교울산P1"
S = json.loads((HERE / "판독" / "schedule.json").read_text(encoding="utf-8"))
ROWS = {r["mark"]: r for t in S.values() for r in t["rows"]}
MARKS = [f"C{i}" for i in range(1, 16)] + ["S1", "S2", "S3", "S4"]
Z0 = 99715.8 # z = drawing y + Z0 (front / side views)
DIA = {"H32": 32, "H22": 22, "H16": 16, "H13": 13}
def z(y):
return round(y + Z0, 1)
def mm(v):
return round(float(v) * 1000) if "." in v else int(v)
def L(m):
"""Schedule length: the value in the L column (sheet x 111,000..112,500)."""
return round(float(next(v for x, v in ROWS[m]["_right"] if 111000 < x < 112500)) * 1000)
def rmin(dia):
d = DIA[dia]
return ((2 * d if d <= 16 else 3.5 * d) + d) / 2
# ---- drawn data (front view, x relative to CX) ----
LAYER1 = dict(z=z(-28752.8), pts=[(-4887.5, z(-30094.5)), (-4640.6, z(-28752.8)), (4618.0, z(-28752.8)), (4886.4, z(-30095.0))])
LAYER2 = dict(z=z(-28852.8), pts=[(-4677.4, z(-28952.8)), (-4659.0, z(-28852.8)), (4638.0, z(-28852.8)), (4658.0, z(-28952.8))])
BOTTOM = [(-4769.8, z(-29455.0)), (-4887.5, z(-30094.5)), (-1228.4, z(-31753.3)), (1228.4, z(-31753.3)),
(4886.4, z(-30095.0)), (4758.9, z(-29457.4))]
C15_Z = z(-28623.3)
C15_X = (-4616.7, -100.0)
LEVELS = [(z(y), a, b) for y, a, b in (
(-29153.3, -4714.3, 4698.1), (-29353.3, -4751.1, 4738.1), (-29553.3, -4787.9, 4778.1), (-29753.3, -4824.7, 4818.0),
(-29953.3, -4861.5, 4858.0), (-30153.3, -4757.8, 4757.8), (-30353.3, -4316.6, 4316.6), (-30553.3, -3875.4, 3875.5),
(-30753.3, -3434.3, 3434.3), (-30953.3, -2993.1, 2993.1), (-31153.3, -2551.9, 2551.9), (-31353.3, -2110.7, 2110.7),
(-31553.3, -1669.6, 1669.6))]
STIR_X = {"C7": [-4600 + 200 * i for i in range(17)], "C8": [-1200, -1000, -500, 0, 500, 1000, 1200],
"C9": [1400 + 200 * i for i in range(17)]}
STIR_Y = [(-1500, -250), (-1000, 1000), (250, 1500)]
C14_PTS = [(x, z(-28875.3)) for x in (-4600, -3600, -2600, -1600, 1600, 2600, 3600, 4600)] + \
[(x, z(-29353.3)) for x in (-4600, -2600, 1600, 3600)] + [(x, z(-29553.3)) for x in (-3600, -1600, 2600, 4600)] + \
[(x, z(-30553.3)) for x in (-2600, 1600, 3600)] + [(-1600, z(-31553.3))]
SEAT_OFFS = [-600] + [-500 + 125 * i for i in range(9)] + [600]
ZTL, ZTR, ZTIP = 71193.0, 71063.0, 69563.0
def x_face(z, x):
"""End face |x| of the coping at level z (batter 300 above the tip; vertical tip below)."""
if z < ZTIP:
return 5000.0
return 4700 + 300 * ((ZTL - z) / 1630 if x < 0 else (ZTR - z) / 1500)
def lim_x(y, z, x):
"""Largest |x| of a bar centreline at (y, z) inside the R500 plan corner with 100 clearance (R400 arc)."""
dy = abs(y) - 1100
if dy <= 0:
return 1e9
return x_face(z, x) - 500 + (400 ** 2 - min(dy, 400) ** 2) ** 0.5
def lim_y(x, z):
dx = abs(x) - (x_face(z, x) - 500)
if dx <= 0:
return 1e9
return 1100 + (400 ** 2 - min(dx, 400) ** 2) ** 0.5
def clip_end(pts, y):
"""Shift the first / last straight run ends inward to the corner limit; legs (first / last point) move along."""
pts = [list(p) for p in pts]
for i_end, i_leg in ((1, 0), (-2, -1)):
x, zz = pts[i_end]
lim = lim_x(y, zz, x)
if abs(x) > lim:
d = (abs(x) - lim) * (1 if x > 0 else -1)
pts[i_end][0] -= d
pts[i_leg][0] -= d
return [tuple(p) for p in pts]
def drawn_bottom(x):
"""Drawn bottom-bar line (front view) at x: flat 67,962.5 inside +-1,228.4, slope 1,658.8 / 3,659.1 outside."""
zf = z(-31753.3)
return zf if abs(x) <= 1228.4 else zf + (abs(x) - 1228.4) * 1658.8 / 3659.1
def stir_top_drawn(x):
return C15_Z if x <= -500 else LAYER1["z"]
def hook_bar(xl, xr, y, zz, r, tail):
"""Straight bar with 180-deg plan hooks towards y = 0; the hook extremes sit at xl / xr."""
s = -1 if y > 0 else 1
yy = y + s * 2 * r
return [(xl + r + tail, yy, zz), (xl, yy, zz), (xl, y, zz), (xr, y, zz), (xr, yy, zz), (xr - r - tail, yy, zz)]
def main():
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")
R = {m: ROWS[m] for m in MARKS}
dia = {m: R[m]["dia"] for m in MARKS}
bars = []
def add(mark, occ, pts, design, src, r=None):
bars.append(dict(mark=mark, occ=occ, pts=[[round(c, 2) for c in p] for p in pts],
r=rmin(dia[mark]) if r is None else r, design_length=round(design, 1), src=src))
# top layers C1~C4
for lay, (ma, mb), keys in ((LAYER1, ("C1", "C3"), ("A", "B", "C", "J")), (LAYER2, ("C2", "C4"), ("A", "B", "C", "J"))):
for i in range(25):
y = -1500 + 125 * i
m = ma if i % 2 == 0 else mb
add(m, f"y{y:+.0f}", [(x, y, zz) for x, zz in clip_end(lay["pts"], y)], sum(mm(R[m][k]) for k in keys),
f"정면 {'1' if lay is LAYER1 else '2'}단 작도선; 측면 '24@125'; 교번 배치 [추론]")
# C15 left top
dx, dz = -300 / 1657.4, -1630 / 1657.4
leg = mm(R["C15"]["B"])
for i in range(13):
y = -1500 + 250 * i
x0, x1 = C15_X
x0 = max(x0, -lim_x(y, C15_Z, x0))
pts = [(x0 + dx * leg, y, C15_Z + dz * leg), (x0, y, C15_Z), (x1, y, C15_Z), (x1, y, C15_Z - leg)]
add("C15", f"y{y:+.0f}", pts, mm(R["C15"]["A"]) + 2 * leg, "정면 좌측 상면 작도선 4,516.7; 단면 A-A '12@250'; 좌측 다리 단부면 평행 [추론]")
# bottom C5/C6
for i in range(13):
y = -1500 + 250 * i
m = "C5" if i % 2 == 0 else "C6"
pts = [list(p) for p in BOTTOM]
for i_end, i_leg, i_in in ((1, 0, 2), (4, 5, 3)):
(xe, ze), (xi, zi) = pts[i_end], pts[i_in]
lim = lim_x(y, ze, xe)
if abs(xe) > lim:
t = (lim - abs(xi)) / (abs(xe) - abs(xi))
nx, nz = xi + t * (xe - xi), zi + t * (ze - zi)
pts[i_leg] = [pts[i_leg][0] + nx - xe, pts[i_leg][1] + nz - ze]
pts[i_end] = [nx, nz]
add(m, f"y{y:+.0f}", [(x, y, zz) for x, zz in pts], sum(mm(R[m][k]) for k in "ABCDEJ"),
"정면 하면 작도선 (650/4,018/2,457/4,016/650); 단면 '12@250'; 교번 [추론]")
# stirrups C7~C9
stir_exp, clipped = {}, set()
for m, xs in STIR_X.items():
for x in xs:
zt = stir_top_drawn(x) + 27
zb = drawn_bottom(x) - 27
stir_exp[f"{x:.0f}"] = round(zt - zb, 1)
ly = lim_y(x, zt)
for k, (y0, y1) in enumerate(STIR_Y):
y0, y1 = max(y0, -ly), min(y1, ly)
if (y0, y1) != STIR_Y[k]:
clipped.add(x)
ym = (y0 + y1) / 2
pts = [(x, ym, zt), (x, y1, zt), (x, y1, zb), (x, y0, zb), (x, y0, zt), (x, ym, zt)]
design = 2 * (y1 - y0 + 54) + 2 * (zt - zb) + 2 * mm(R[m]["C"])
add(m, f"x{x:+.0f}_{k}", pts, design, "정면 스터럽 작도 위치·높이 (+54); 단면 A-A 3조; 형상표 II 주기")
# side bars C13 / C11 and hoops C12 / C10
hr = (mm(R["C11"]["B"]) - DIA["H22"]) / 2 # hook centreline radius 71.5
tail = mm(R["C11"]["C"])
for k, (zz, xl, xr) in enumerate(LEVELS):
m = "C13" if k < 5 else "C11"
a = xr - xl + 44
hooks = 2 * mm(R[m]["B"]) + 2 * mm(R[m]["C"])
for y in (-977.5, -272.5, 272.5, 977.5):
add(m, f"L{k + 1:02d}y{y:+.0f}", hook_bar(xl, xr, y, zz, hr, tail),
a + hooks + (mm(R[m]["J"]) if "J" in R[m] else 0),
f"측면 단 {k + 1} (z {zz}); 정면 작도 끝 {xl}/{xr}; a = 작도 + 44; 평면 갈고리 [추론]", r=hr - 0.5)
hm = "C12" if k < 6 else "C10"
yh = 1477.5
pts = [(0, -yh, zz), (xr, -yh, zz), (xr, yh, zz), (xl, yh, zz), (xl, -yh, zz), (0, -yh, zz)]
if hm == "C12":
design = 2 * (a - 790) + 2 * mm(R[hm]["B"]) + 4 * mm(R[hm]["C"]) + 4 * mm(R[hm]["J"])
add(hm, f"L{k + 1:02d}", pts, design, f"둘레 띠 단 {k + 1}; 모서리 R400; 길이 2a+2b+4c+4j", r=400)
else:
design = 2 * (xr - xl + 54) + 2 * mm(R[hm]["B"]) + 4 * mm(R[hm]["J"])
add(hm, f"L{k + 1:02d}", pts, design, f"둘레 띠 단 {k + 1}; 길이 2a+2b+4j (a = 작도 + 54)")
# C14 cross bars
c14 = []
for x, zz in C14_PTS:
s = 1 if x > 0 else -1
xx = x - s * 19
lg = mm(R["C14"]["B"])
yl = min(1500, lim_y(xx, zz), lim_y(xx - s * lg, zz) + 0)
if yl < 1500:
clipped.add(x)
add("C14", f"x{x:+.0f}z{zz:.0f}", [(xx - s * lg, -yl, zz), (xx, -yl, zz), (xx, yl, zz), (xx - s * lg, yl, zz)],
mm(R["C14"]["A"]) + 2 * lg, "정면 단면 표시 위치; 단면 A-A 3,000; 다리 방향·x 19 이격 [추론]")
c14.append([xx, zz])
# S1~S4
seats = {b["no"]: b for b in P["bearing_seats"]["bearings"]}
lg = mm(R["S1"]["B"])
s_exp = {}
for (my, mx), nos in ((("S1", "S2"), (1, 2)), (("S3", "S4"), (3, 4))):
for no in nos:
b = seats[no]
cx, cy = b["centre"]
top = b["seat_z"] + b["h1"]
z1, z2 = top - 50, top - 50 - DIA["H13"]
for o in SEAT_OFFS:
x = cx + o
add(my, f"B{no}x{o:+.0f}", [(x, cy - 600, z1 - lg), (x, cy - 600, z1), (x, cy + 600, z1), (x, cy + 600, z1 - lg)],
mm(R[my]["A"]) + 2 * lg, f"받침 {no} 보강 상세; '50','100','8@125','100','50'")
y = cy + o
add(mx, f"B{no}y{o:+.0f}", [(cx - 600, y, z2 - lg), (cx - 600, y, z2), (cx + 600, y, z2), (cx + 600, y, z2 - lg)],
mm(R[mx]["A"]) + 2 * lg, f"받침 {no} 보강 상세; S1/S3 아래 단 [추론]")
s_exp[str(no)] = dict(centre=[cx, cy], z_top=z1, marks=[my, mx])
P["coping_rebar"] = {"form": "polylines", "host": "CP", "group": "코핑", "bars": bars,
"src": "배근도(1) 정면·측면·평면, 배근도(2) 단면 A-A/B-B·받침부 보강 상세, 배근도(3) 재료표·형상표"}
P["scope"] = [g for g in ("G1", "G2", "G3", "G4", "G5") if g in set(P["scope"]) | {"G4"}]
P["builders"]["G4"] = "rebar_polylines.py"
E["checkers"]["G4"] = "g4_polylines.py"
E["negative"]["G4"] = [{"mark": "C7", "d": [5, 0, 0]}, {"mark": "C11", "d": [0, 0, 5]}]
E["G4"] = {
"schedule": {m: [L(m), int(R[m]["n"])] for m in MARKS},
"dia": {m: DIA[dia[m]] for m in MARKS},
"fixed_length": ["C1", "C2", "C3", "C4", "C5", "C6", "C14", "C15", "S1", "S2", "S3", "S4"],
"ranges": {"C7": ["B", 1656, 3106], "C8": ["B", 3054, 3184], "C9": ["B", 1526, 2977],
"C11": ["A", 3383, 9560], "C13": ["A", 9456, 9764], "C12": ["A", 8666, 8974], "C10": ["A", 3393, 9570]},
"layers": {"C1": {"z": LAYER1["z"], "y": "top125", "parity": 0}, "C3": {"z": LAYER1["z"], "y": "top125", "parity": 1},
"C2": {"z": LAYER2["z"], "y": "top125", "parity": 0}, "C4": {"z": LAYER2["z"], "y": "top125", "parity": 1},
"C15": {"z": C15_Z, "y": "y250", "parity": None},
"C5": {"z_min": z(-31753.3), "y": "y250", "parity": 0}, "C6": {"z_min": z(-31753.3), "y": "y250", "parity": 1}},
"x_extent": {"C1": [-4887.5, 4886.4], "C3": [-4887.5, 4886.4], "C2": [-4677.4, 4658.0], "C4": [-4677.4, 4658.0],
"C5": [-4887.5, 4886.4], "C6": [-4887.5, 4886.4]},
"rows": {"top125": {"start": -1500, "pitch": 125, "n": 25}, "y250": {"start": -1500, "pitch": 250, "n": 13}},
"stirrups": {"x": STIR_X, "y_pairs": STIR_Y, "height": stir_exp,
"rule": "높이 = 작도 높이 + 54 (상단 1단/C15 선 +27, 하단 하면선 -27)"},
"levels": [[zz, xl, xr] for zz, xl, xr in LEVELS],
"side": {"y": [-977.5, -272.5, 272.5, 977.5], "marks": [["C13", 5], ["C11", 8]]},
"hoops": {"y": 1477.5, "marks": [["C12", 6], ["C10", 7]]},
"c14": {"pts": c14, "y": [-1500, 1500]},
"corner": {"y_abs": 1100, "x_clipped": sorted(clipped),
"rule": "평면 모서리 R500: |y| > 1,100 철근은 R400 원호(중심선 이격 100)까지 단축 - 평면도 작도 [추론]"},
"seats": {"offsets": SEAT_OFFS, "half": 600, "leg": lg, "bearings": s_exp},
"src": "재료표 L·수량·범위; 정면·측면 작도 좌표 (z = y + 99,715.8); 단면 A-A/B-B; 받침부 보강 상세",
}
(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")
from collections import Counter
cnt = Counter(b["mark"] for b in bars)
print("bars", len(bars), {m: (cnt[m], E["G4"]["schedule"][m][1]) for m in MARKS if cnt[m] != E["G4"]["schedule"][m][1]} or "counts OK")
import statistics
for m in MARKS:
dl = [b["design_length"] for b in bars if b["mark"] == m]
print(m, "L", E["G4"]["schedule"][m][0], "mean", round(statistics.mean(dl), 1), "min", min(dl), "max", max(dl))
print("scope", P["scope"])
if __name__ == "__main__":
main()
+198
View File
@@ -0,0 +1,198 @@
"""S1 (shape) reading of RAG/교각배근도(울산P1).dwg -> app pier data/산외교울산P1 (params, expected, drawings).
Sheet: 일반도(1) (left part of the DWG, x -100000..-20000), drawn in mm.
Datums: front view column CL x -88384.7, footing bottom y -23989.8 (EL 42.763), column top / coping bottom
y -15389.8 (EL 67.863 = 42.763 + 2.500 + 22.600, coping drawn to scale above it); side view CL x -60315.3;
plan centre (-88384.7, -2498.5).
params = drawn entities (handles below) + ELEVATION / 솔플레이트 TABLE for bearing values.
expected = dimension / EL texts and tables (typed with their text), independent of params.
Scope of this stage: G1 (shape) and G5 (bearings, sole plates); rebar gates G2-G4 are out of scope.
"""
import json
import shutil
import sys
import time
from pathlib import Path
HERE = Path(__file__).resolve().parent
APP = HERE.parent / "교각모델링앱"
ROOT = HERE.parents[1]
PIER = APP / "data" / "산외교울산P1"
sys.path.insert(0, str(HERE))
sys.path.insert(0, str(APP))
import dxftools as T # noqa: E402
from engine import reader # noqa: E402
E1 = T.doc("D1").entitydb
FX, FB_Y, CB_Y = -88384.7, -23989.8, -15389.8
PLAN = (-88384.7, -2498.5)
EL_FB, FT_T, COL_H = 42763, 2500, 22600 # 'EL. 42.763', '2.500', '22.600'
Z_CB = EL_FB + FT_T + COL_H # 67863
def line(h):
e = E1[h]
return (e.dxf.start.x, e.dxf.start.y), (e.dxf.end.x, e.dxf.end.y)
def z(y):
return round(Z_CB + (y - CB_Y), 1)
def rx(x):
return round(x - FX, 1)
def tables(texts):
tabs = {t["key"]: t for t in reader.table_candidates(texts)}
# rows keyed by bearing number; keep only rows that carry the table's own columns (a wide window can also
# catch numeric cells of a neighbouring table)
el = {int(r["_key"]): r for _, r in reader.table_records(tabs["elevation"]["rows"], str.isdigit) if "EL.'X'" in r}
sp = {int(r["_key"]): r for _, r in reader.table_records(tabs["sole_plate"]["rows"], str.isdigit)
if "S(%)" in r and int(r["_key"]) in el}
return el, sp
def main():
template = json.loads((APP / "data" / "운곡교P1" / "params.json").read_text(encoding="utf-8"))
tmpl_e = json.loads((APP / "data" / "운곡교P1" / "expected.json").read_text(encoding="utf-8"))
if PIER.exists():
bk = PIER / "backup"
bk.mkdir(exist_ok=True)
stamp = time.strftime("%Y%m%d_%H%M%S")
for f in ("params.json", "expected.json"):
if (PIER / f).exists():
shutil.copy2(PIER / f, bk / f"{Path(f).stem}_before_S1_{stamp}.json")
(PIER / "drawings" / "dwg").mkdir(parents=True, exist_ok=True)
(PIER / "drawings" / "dxf").mkdir(parents=True, exist_ok=True)
src = ROOT / "RAG" / "교각배근도(울산P1).dwg"
shutil.copy2(src, PIER / "drawings" / "dwg" / src.name) # copy only; RAG original untouched
shutil.copy2(HERE / "dxf" / "교각배근도(울산P1).dxf", PIER / "drawings" / "dxf" / "교각배근도(울산P1).dxf")
audit = json.loads((HERE / "dxf" / "audit.json").read_text(encoding="utf-8"))
for a in audit:
a["label"] = "D1"
(PIER / "drawings" / "audit.json").write_text(json.dumps(audit, ensure_ascii=False, indent=1), encoding="utf-8")
shutil.copy2(HERE / "판독" / "texts.json", PIER / "drawings" / "texts.json")
texts = json.loads((HERE / "판독" / "texts.json").read_text(encoding="utf-8"))
el, sp = tables(texts)
# ---- params from drawn entities
ft, lc = line("FA9F"), line("FAA5") # footing / lean bottoms (front)
ft_side, lc_side = line("FC7E"), line("FC83")
col = (line("FA90")[0][0] - line("FA91")[0][0]) # column outline +-1250 (front)
tipL, tipR = line("FA67")[1], line("FA69")[0] # (-5000, 69563) / (+5000, 69563)
topL, topR = line("FA73")[0], line("FA6A")[0] # (-4700, 71193) / (+4700, 71063)
flat = line("FA68") # +-1250 at the coping bottom
zcb = z(flat[0][1])
profile = [[rx(flat[1][0]), zcb], [rx(flat[0][0]), zcb], [rx(tipR[0]), z(tipR[1])], [rx(topR[0]), z(topR[1])],
[0.0, z(topR[1])], [0.0, z(topL[1])], [rx(topL[0]), z(topL[1])], [rx(tipL[0]), z(tipL[1])]]
P = {
"_schema": "pier-T/1", "pier_id": "P1",
"_meta": {"structure": "산외교 울산 P1 교각 (T형, 직선 경사 코핑, 직접기초)",
"status": "S1 형상 판독 2026-10-13 (Agent 초안, 사용자 확정 전)",
"units": "mm; Z = EL x 1000", "frame": "X 교축직각(정면도 좌→우), Y 교축(평면도 아래→위 = 전열→후열), 원점 = 교각 중심",
"sources": {"D1": "RAG/교각배근도(울산P1).dwg — 일반도(1) + 배근도(1)~(3)"}},
"scope": ["G1", "G5"],
"builders": {"G1": "concrete_tapered.py"},
"lean_concrete": {"size_x": round(lc[0][0] - lc[1][0], 1), "size_y": round(lc_side[0][0] - lc_side[1][0], 1),
"z_bottom": EL_FB - 100, "z_top": EL_FB, "src": "일반도 정면 FAA5 / 측면 FC83 (7,700), 두께 100"},
"footing": {"size_x": round(ft[0][0] - ft[1][0], 1), "size_y": round(ft_side[0][0] - ft_side[1][0], 1),
"z_bottom": EL_FB, "thickness": round(line("FA9E")[1][1] - line("FA9E")[0][1], 1),
"src": "일반도 정면 FA9F / 측면 FC7E (7,500), FA9E (2,500); 'EL. 42.763'; 말뚝 없음(직접기초)"},
"column": {"shape": "circular", "diameter": round(col, 1), "height": COL_H,
"src": "일반도 정면 FA90/FA91 (+-1,250), 단면 A-A 원 r 1,250 (FDAA); 높이 '22.600' (파단 작도)"},
"coping": {"form": "tapered", "profile_xz": profile, "width_y": round(line("FC61")[0][0] - line("FC61")[1][0], 1),
"plan_length": round(tipR[0] - tipL[0], 1), "top_length": round(topR[0] - topL[0], 1),
"z_tip": z(tipL[1]), "z_top_left": z(topL[1]), "z_top_right": z(topR[1]),
"plan_corner_radius": 500,
"src": {"profile": "일반도 정면 FA68 (하면 평탄), FA67/FA69 (하면 경사), FA73/FA6A (끝면 300 경사), FA66/FA62 (상면, 중심 130 단차)",
"width": "일반도 측면 FC61 (3,200)", "plan": "일반도 평면 FDBC~FDBF: 하단 10,000·상단 9,400 모두 모서리 R500 ('R=500')",
"not_modelled": "기둥·코핑 내부 배수관(단면 A-A '300'), 측면 하단 모서리 소형 모따기 [범위 밖]"}},
"materials": {"fck": {"lean": "15MPa", "footing": "27MPa", "column": "40MPa", "coping": "40MPa", "seat": "40MPa"},
"src": "일반도 주기 'fck = 27, 40 MPa', 기초 'fck = 27 MPa', '버림 CON'C fck = 15 MPa'; 기둥·코핑·대좌 40 [추론]"},
}
bearings = []
for no in sorted(el):
r = el[no]
x = -3250.0 if no in (1, 3) else 3250.0 # plan dims '1.750','6.500','1.750'
s1 = int(r["S1"])
y = -(1600 - s1) if no in (1, 2) else (1600 - s1) # S1 from the -Y edge (전열 1,2) / +Y edge (후열 3,4)
bearings.append({"no": no, "type": r["교량받침"], "row": "front" if no in (1, 2) else "rear",
"centre": [x, float(y)], "rotation_deg": 0.0,
"seat_z": float(P["coping"]["z_top_left"] if x < 0 else P["coping"]["z_top_right"]),
"el_x": round(float(r["EL.'X'"]) * 1000), "h1": int(r["h1"]), "h2": int(r["h2"]),
"A": int(r["A"]), "B": int(r["B"])})
drawn = {}
for h, no in (("1025D", 2), ("10265", 1), ("1026D", 4), ("10271", 3)): # unused: drawn bearing CL crosses
pass
for hs, no in ((("1024D", "1024E"), 3), (("10245", "10246"), 4), (("10251", "10252"), 2), (("10259", "1025A"), 1)):
(x0, y0), (x1, y1) = line(hs[0])
(_, _), (x2, _) = line(hs[1])
drawn[no] = [round((x0 + x2) / 2 - PLAN[0], 1), round((y0 + y1) / 2 - PLAN[1], 1)]
P["bearing_seats"] = {
"_note": "pedestal = C3 x C6 box per bearing (h1); pad (h2) = frustum (A+200)x(B+200) -> (A+100)x(B+100)",
"pedestal": {"size_x": int(el[1]["C3"]), "size_y": int(el[1]["C6"])},
"pad_margin_bottom": 200, "pad_margin_top": 100,
"bearings": bearings, "drawn_pedestal_centres": drawn,
"src": {"table": "일반도 교량받침 ELEVATION TABLE (EL.'X', h1, h2, h3, h4, A, B, C1~C6, E, S1, S2)",
"pedestal": "교량받침 상세 C1+C2 = C3 (1,300), C4+C5 = C6 (1,300); 평면 작도 1,300 정사각",
"pad": "교량받침 상세 'h2','50','A','50','h2' -> 상면 A+100, 하면 A+100+2h2 = A+200 (h2 50)",
"position": "평면 '1.750','6.500','1.750' (X), S1 (Y); 작도 대좌 중심과 0.3 mm 이내 일치"},
}
rows = []
for no in sorted(sp):
r = sp[no]
rows.append({"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"]), "h3": int(el[no]["h3"])})
P["sole_plates"] = {"table": rows, "bearing_size": "AB", "bearing_shrink": 100,
"colours": {"bearing": [0, 0, 0], "sole_plate": [150, 150, 150]},
"sole_plate_src": "솔플레이트 상세 TABLE (S, L, W, T, T1, T2); L 교축 방향; S > 0 -> 두꺼운 쪽 +Y (T2 40)",
"src": "교량받침 = A x B (상세도: 받침 본체 A, 상판 L), h3 받침별(ELEVATION TABLE); 솔플레이트 두께 T = h4 31"}
P["display"] = dict(template["display"], hidden_ids=[], src="R8 팔레트(2026-10-07); 숨김 없음")
P["rebar_marks"] = template["rebar_marks"]
P["rebar_marks_src"] = "철근(G2~G4)은 이번 단계 범위 밖 — 운곡교 P1 템플릿 값(사용 안 함)"
# ---- expected from texts / tables
E = {"_schema": "pier-T-expected/1",
"_note": "독립 기대값: 일반도 치수 문자·EL 문자·표에서 옮긴 값. params와 별도.",
"pier_id": "P1", "tol_mm": 1.0, "checkers": {"G1": "g1_tapered.py"},
"negative": {"G1": [{"id": "BS02", "d": [3, 0, 0]}, {"id": "BP03", "d": [0, 0, 2]}],
"G5": [{"id": "BB04", "d": [5, 0, 0]}, {"id": "SP03", "d": [0, 0, 5]}]},
"rebar_palette": tmpl_e["rebar_palette"], "planned_fail": []}
E["G1"] = {
"footing": {"dx": 7500, "dy": 7500, "z0": EL_FB, "thickness": 2500, "src": "'7.500' (정면·측면·기초 평면), 'EL. 42.763', '2.500'"},
"lean": {"margin": 100, "thickness": 100, "src": "'100','7.500','100'; 두께 '100'"},
"column": {"d": 2500, "height": 22600, "src": "단면 A-A '2.500', '22.600'"},
"coping": {"bottom_flat_half": 1250, "tip_half": 5000, "top_half": 4700, "soffit_rise": 1700, "width_y": 3200,
"z_top_left": 71193, "z_top_right": 71063, "plan_corner_radius": 500,
"src": "'1.250','1.250','3.750' x2; '10.000'; '300','2@4.700=9.400','300'; '1.700'; '3.200'; 'EL. 71.193','EL. 71.063'; 'R=500'"},
"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()},
"pos": {str(n): [-3250 if n in (1, 3) else 3250,
-(1600 - int(r["S1"])) if n in (1, 2) else 1600 - int(r["S1"])] for n, r in el.items()},
"pedestal": [int(el[1]["C3"]), int(el[1]["C6"])], "pad_margin": [200, 100],
"src": "ELEVATION TABLE; 평면 '1.750','6.500','1.750', S1; 상세 C3·C6, h2·50"},
}
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": {str(r["no"]): r["L"] for r in rows}, "T": 31, "h3": {str(n): int(r["h3"]) for n, r in el.items()},
"bearing_size": {str(n): [int(r["A"]), int(r["B"])] for n, r in el.items()}, "bearing_shrink": 100,
"thick_end": "+Y", "colours": {"bearing": [0, 0, 0], "sole_plate": [150, 150, 150]},
"src": "ELEVATION TABLE (EL.'X', h3, A, B, h4=T); 솔플레이트 상세 TABLE (S, L, W, T1 22 / T2 40 -> 두꺼운 쪽 +Y)",
}
PIER.mkdir(parents=True, exist_ok=True)
if not (PIER / "pier.json").exists():
(PIER / "pier.json").write_text(json.dumps({"name": "산외교울산P1", "type": "T형", "created": time.strftime("%Y-%m-%d %H:%M:%S"),
"template": "판독(Code/울산P1판독)"}, ensure_ascii=False, indent=1), encoding="utf-8")
(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("profile", profile)
print("coping", {k: P["coping"][k] for k in ("width_y", "plan_length", "top_length", "z_tip", "z_top_left", "z_top_right")})
print("footing", P["footing"]["size_x"], P["footing"]["size_y"], "lean", P["lean_concrete"]["size_x"], P["lean_concrete"]["size_y"], "column", P["column"]["diameter"])
print("bearings", [(b["no"], b["centre"], b["seat_z"], b["el_x"], b["h1"]) for b in bearings])
print("drawn pedestal centres", drawn)
if __name__ == "__main__":
main()
+57
View File
@@ -0,0 +1,57 @@
"""Ulsan P1 rebar schedule (배근도(3) 철근재료표 SD400 / SD500) -> 판독/schedule.json.
The header row's column x positions (A, B, C, D, E, R, X1..X4, J, length, total) are taken from the drawing;
the first four columns (번호, 형식, 직경, 개수) are fixed left columns. Each data row (first cell = mark) is
mapped to the nearest header column. Ditto marks are resolved within a table. Values in m are kept as text.
"""
import json
import re
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent
T = json.loads((HERE / "판독" / "texts.json").read_text(encoding="utf-8"))
MARK = re.compile(r"^[A-Z]{1,2}\d{1,2}$")
def table(x0, x1, y_top, y_bot):
cells = [t for t in T if x0 <= t["x"] <= x1 and y_bot <= t["y"] <= y_top]
head = [t for t in cells if t["text"] in ("A", "B", "C", "D", "E", "R", "J")]
hy = max(round(t["y"]) for t in head) if head else None
cols = {t["text"]: t["x"] for t in head if abs(t["y"] - hy) < 100}
rows = {}
for t in cells:
rows.setdefault(round(t["y"] / 60), []).append(t)
out = []
for k in sorted(rows, reverse=True):
r = sorted(rows[k], key=lambda t: t["x"])
if not MARK.match(r[0]["text"]):
continue
rec = {"mark": r[0]["text"], "y": r[0]["y"]}
rest = r[1:]
for name, t in zip(("shape", "dia", "n"), rest[:3]):
rec[name] = t["text"]
for t in rest[3:]:
name = min(cols, key=lambda c: abs(cols[c] - t["x"]))
if abs(cols[name] - t["x"]) < 450 and name not in rec:
rec[name] = t["text"]
else:
rec.setdefault("_right", []).append((round(t["x"]), t["text"]))
out.append(rec)
return out, cols
if __name__ == "__main__":
import math
# locate the two tables by their titles
sd = {t["text"]: t for t in T if t["text"] in ("(SD400)", "(SD500)") and t["h"] < 300}
res = {}
for key, t in sd.items():
other = [o for o in sd.values() if o is not t and o["y"] < t["y"]]
y_bot = max(o["y"] for o in other) + 500 if other else t["y"] - 15000
recs, cols = table(t["x"] - 500, t["x"] + 22000, t["y"], y_bot)
res[key] = {"columns": cols, "rows": recs}
print(key, "columns", sorted(cols), "rows", len(recs))
for r in recs:
print(" ", {k: v for k, v in r.items() if k != "y"})
(HERE / "판독" / "schedule.json").write_text(json.dumps(res, ensure_ascii=False, indent=1), encoding="utf-8")
@@ -0,0 +1,29 @@
{
"lower": {
"valid": true,
"solid": true,
"orient": "Outward",
"vol": 33999999999.99997
},
"waste": {
"n": 1,
"valid": [
true
],
"solid": [
true
]
},
"low_minus_one": {
"n": 0
},
"low_and_one": {
"n": 0,
"vol": null
},
"brepbrep": {
"ok": true,
"curves": 1,
"pts": 0
}
}
+1
View File
@@ -0,0 +1 @@
{"model": "C:\\Users\\User\\Desktop\\바이브코딩\\pier_T\\Code\\교각모델링앱\\출력\\울산P1_S1\\G1.3dm", "units": "Millimeters", "tolerance": 0.001, "count": 11, "layers": {"P1::받침패드": [90, 160, 90, true], "P1::받침대좌": [190, 90, 90, true], "P1::기둥": [200, 140, 90, true], "P1::기초": [120, 150, 200, true], "P1::버림콘크리트": [160, 160, 160, true]}, "objects": {"P1-BP04": {"layer": "P1::받침패드", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [2850.0, 371.0, 71259.0, 3650.0, 1171.0, 71309.0], "user": {"fck": "-", "id": "P1-BP04", "role": "bearing pad h2 NO.4 4500 kN 일방향", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 28166666.7}, "P1-BS04": {"layer": "P1::받침대좌", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [2600.0, 121.0, 71063.0, 3900.0, 1421.0, 71259.0], "user": {"fck": "40MPa", "id": "P1-BS04", "role": "bearing pedestal h1 NO.4", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 331240000.0}, "P1-BP03": {"layer": "P1::받침패드", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3650.0, 399.0, 71390.0, -2850.0, 1199.0, 71440.0], "user": {"fck": "-", "id": "P1-BP03", "role": "bearing pad h2 NO.3 4500 kN 일방향", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 28166666.7}, "P1-BS03": {"layer": "P1::받침대좌", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3900.0, 149.0, 71193.0, -2600.0, 1449.0, 71390.0], "user": {"fck": "40MPa", "id": "P1-BS03", "role": "bearing pedestal h1 NO.3", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 332930000.0}, "P1-BP02": {"layer": "P1::받침패드", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [2860.0, -1164.0, 71238.0, 3640.0, -384.0, 71288.0], "user": {"fck": "-", "id": "P1-BP02", "role": "bearing pad h2 NO.2 4000 kN 일방향", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 26686666.7}, "P1-BS02": {"layer": "P1::받침대좌", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [2600.0, -1424.0, 71063.0, 3900.0, -124.0, 71238.0], "user": {"fck": "40MPa", "id": "P1-BS02", "role": "bearing pedestal h1 NO.2", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 295750000.0}, "P1-BP01": {"layer": "P1::받침패드", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3640.0, -1189.0, 71368.0, -2860.0, -409.0, 71418.0], "user": {"fck": "-", "id": "P1-BP01", "role": "bearing pad h2 NO.1 4000 kN 일방향", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 26686666.7}, "P1-BS01": {"layer": "P1::받침대좌", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3900.0, -1449.0, 71193.0, -2600.0, -149.0, 71368.0], "user": {"fck": "40MPa", "id": "P1-BS01", "role": "bearing pedestal h1 NO.1", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 295750000.0}, "P1-CL": {"layer": "P1::기둥", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-1250.0, -1250.0, 45263.0, 1250.0, 1250.0, 67863.0], "user": {"fck": "40MPa", "id": "P1-CL", "role": "column", "source_views": "일반도 정면도·단면도·단면 A-A"}, "faces": 3, "solid": true, "volume": 110937491036.2}, "P1-FT": {"layer": "P1::기초", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3750.0, -3750.0, 42763.0, 3750.0, 3750.0, 45263.0], "user": {"fck": "27MPa", "id": "P1-FT", "role": "spread footing (no piles)", "source_views": "일반도 정면도·단면도·기초 평면도"}, "faces": 6, "solid": true, "volume": 140625000000.0}, "P1-LC": {"layer": "P1::버림콘크리트", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3850.0, -3850.0, 42663.0, 3850.0, 3850.0, 42763.0], "user": {"fck": "15MPa", "id": "P1-LC", "role": "lean concrete", "source_views": "일반도 정면도·단면도"}, "faces": 6, "solid": true, "volume": 5929000000.0}}}
+1
View File
@@ -0,0 +1 @@
{"model": "C:\\Users\\User\\Desktop\\바이브코딩\\pier_T\\Code\\교각모델링앱\\출력\\울산P1_S1\\G5.3dm", "units": "Millimeters", "tolerance": 0.001, "count": 12, "layers": {"P1::받침패드": [90, 160, 90, true], "P1::받침대좌": [190, 90, 90, true], "P1::코핑": [210, 180, 80, true], "P1::기둥": [200, 140, 90, true], "P1::기초": [120, 150, 200, true], "P1::버림콘크리트": [160, 160, 160, true]}, "objects": {"P1-BP04": {"layer": "P1::받침패드", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [2850.0, 371.0, 71259.0, 3650.0, 1171.0, 71309.0], "user": {"fck": "-", "id": "P1-BP04", "role": "bearing pad h2 NO.4 4500 kN 일방향", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 28166666.7}, "P1-BS04": {"layer": "P1::받침대좌", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [2600.0, 121.0, 71063.0, 3900.0, 1421.0, 71259.0], "user": {"fck": "40MPa", "id": "P1-BS04", "role": "bearing pedestal h1 NO.4", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 331240000.0}, "P1-BP03": {"layer": "P1::받침패드", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3650.0, 399.0, 71390.0, -2850.0, 1199.0, 71440.0], "user": {"fck": "-", "id": "P1-BP03", "role": "bearing pad h2 NO.3 4500 kN 일방향", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 28166666.7}, "P1-BS03": {"layer": "P1::받침대좌", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3900.0, 149.0, 71193.0, -2600.0, 1449.0, 71390.0], "user": {"fck": "40MPa", "id": "P1-BS03", "role": "bearing pedestal h1 NO.3", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 332930000.0}, "P1-BP02": {"layer": "P1::받침패드", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [2860.0, -1164.0, 71238.0, 3640.0, -384.0, 71288.0], "user": {"fck": "-", "id": "P1-BP02", "role": "bearing pad h2 NO.2 4000 kN 일방향", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 26686666.7}, "P1-BS02": {"layer": "P1::받침대좌", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [2600.0, -1424.0, 71063.0, 3900.0, -124.0, 71238.0], "user": {"fck": "40MPa", "id": "P1-BS02", "role": "bearing pedestal h1 NO.2", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 295750000.0}, "P1-BP01": {"layer": "P1::받침패드", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3640.0, -1189.0, 71368.0, -2860.0, -409.0, 71418.0], "user": {"fck": "-", "id": "P1-BP01", "role": "bearing pad h2 NO.1 4000 kN 일방향", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 26686666.7}, "P1-BS01": {"layer": "P1::받침대좌", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3900.0, -1449.0, 71193.0, -2600.0, -149.0, 71368.0], "user": {"fck": "40MPa", "id": "P1-BS01", "role": "bearing pedestal h1 NO.1", "source_views": "일반도 교량받침 상세·ELEVATION TABLE"}, "faces": 6, "solid": true, "volume": 295750000.0}, "P1-CP": {"layer": "P1::코핑", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-5000.0, -1600.0, 67863.0, 5000.0, 1600.0, 71193.0], "user": {"fck": "40MPa", "id": "P1-CP", "role": "coping (tapered T)", "source_views": "일반도 평면도·정면도·단면도"}, "faces": 138, "solid": true, "volume": 82231356101.8}, "P1-CL": {"layer": "P1::기둥", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-1250.0, -1250.0, 45263.0, 1250.0, 1250.0, 67863.0], "user": {"fck": "40MPa", "id": "P1-CL", "role": "column", "source_views": "일반도 정면도·단면도·단면 A-A"}, "faces": 3, "solid": true, "volume": 110937491036.2}, "P1-FT": {"layer": "P1::기초", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3750.0, -3750.0, 42763.0, 3750.0, 3750.0, 45263.0], "user": {"fck": "27MPa", "id": "P1-FT", "role": "spread footing (no piles)", "source_views": "일반도 정면도·단면도·기초 평면도"}, "faces": 6, "solid": true, "volume": 140625000000.0}, "P1-LC": {"layer": "P1::버림콘크리트", "type": "Brep", "hidden": false, "locked": false, "colour_source": 0, "colour": [0, 0, 0], "bbox": [-3850.0, -3850.0, 42663.0, 3850.0, 3850.0, 42763.0], "user": {"fck": "15MPa", "id": "P1-LC", "role": "lean concrete", "source_views": "일반도 정면Line truncated
Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

+779
View File
@@ -0,0 +1,779 @@
{
"(SD400)": {
"columns": {
"A": 101056.8,
"B": 102294.8,
"C": 103532.8,
"D": 104770.8,
"E": 106008.8,
"R": 107119.8,
"J": 110523.8
},
"rows": [
{
"mark": "C1",
"y": -20474.6,
"shape": "IX",
"dia": "H32",
"n": "13",
"A": "9.259",
"B": "1.364",
"C": "1.369",
"_right": [
[
107744,
"100°"
],
[
108349,
"101°"
],
[
111723,
"13.551"
],
[
112875,
"176.163"
]
],
"J": "1.560"
},
{
"mark": "C2",
"y": -20744.6,
"shape": "IX",
"dia": "H32",
"n": "13",
"A": "9.297",
"B": "102",
"C": "102",
"_right": [
[
107744,
"100°"
],
[
108349,
"101°"
],
[
111723,
"11.061"
],
[
112875,
"143.793"
]
],
"J": "1.560"
},
{
"mark": "C3",
"y": -21014.6,
"shape": "IX",
"dia": "H32",
"n": "12",
"A": "9.259",
"B": "1.364",
"C": "1.369",
"_right": [
[
107744,
"100°"
],
[
108349,
"101°"
],
[
111723,
"13.551"
],
[
112875,
"162.612"
]
],
"J": "1.560"
},
{
"mark": "C4",
"y": -21284.6,
"shape": "IX",
"dia": "H32",
"n": "12",
"A": "9.297",
"B": "102",
"C": "102",
"_right": [
[
107744,
"100°"
],
[
108349,
"101°"
],
[
111723,
"11.061"
],
[
112875,
"132.732"
]
],
"J": "1.560"
},
{
"mark": "C5",
"y": -21554.6,
"shape": "IV",
"dia": "H32",
"n": "7",
"A": "650",
"B": "4.018",
"C": "2.457",
"D": "4.016",
"E": "650",
"_right": [
[
107744,
"104°"
],
[
108349,
"156°"
],
[
108954,
"156°"
],
[
109559,
"103°"
],
[
111723,
"12.731"
],
[
112961,
"89.117"
]
],
"J": "940"
},
{
"mark": "C6",
"y": -21824.6,
"shape": "IV",
"dia": "H32",
"n": "6",
"A": "650",
"B": "4.018",
"C": "2.457",
"D": "4.016",
"E": "650",
"_right": [
[
107744,
"104°"
],
[
108349,
"156°"
],
[
108954,
"156°"
],
[
109559,
"103°"
],
[
111723,
"12.731"
],
[
112961,
"76.386"
]
],
"J": "940"
},
{
"mark": "C7",
"y": -22364.6,
"shape": "II",
"dia": "H22",
"n": "51",
"A": "1.554",
"B": "3.106~1.656",
"C": "660",
"_right": [
[
111808,
"9.190"
],
[
112875,
"468.690"
]
]
},
{
"mark": "C8",
"y": -22634.6,
"shape": "II",
"dia": "H22",
"n": "21",
"A": "1.554",
"B": "3.184~3.054",
"C": "660",
"_right": [
[
111723,
"10.666"
],
[
112875,
"223.986"
]
]
},
{
"mark": "C9",
"y": -22904.6,
"shape": "II",
"dia": "H22",
"n": "51",
"A": "1.554",
"B": "2.977~1.526",
"C": "660",
"_right": [
[
111808,
"8.931"
],
[
112875,
"455.481"
]
]
},
{
"mark": "C10",
"y": -23174.6,
"shape": "III",
"dia": "H22",
"n": "7",
"A": "9.570~3.393",
"B": "3.054",
"J": "660",
"_right": [
[
111723,
"21.711"
],
[
112875,
"151.977"
]
]
},
{
"mark": "C11",
"y": -23444.6,
"shape": "VII",
"dia": "H22",
"n": "32",
"A": "9.560~3.383",
"B": "165",
"C": "140",
"R": "70",
"_right": [
[
111808,
"7.081"
],
[
112875,
"226.592"
]
]
},
{
"mark": "C12",
"y": -23714.6,
"shape": "XII",
"dia": "H22",
"n": "6",
"A": "8.974~8.666",
"B": "2.254",
"C": "628",
"R": "400",
"J": "660",
"_right": [
[
111723,
"27.300"
],
[
112875,
"163.800"
],
[
118713,
"IV"
]
]
},
{
"mark": "C13",
"y": -23984.6,
"shape": "VIII",
"dia": "H22",
"n": "20",
"A": "9.764~9.456",
"B": "165",
"C": "140",
"R": "70",
"J": "660",
"_right": [
[
111723,
"10.880"
],
[
112875,
"217.600"
]
]
},
{
"mark": "C15",
"y": -24254.6,
"shape": "I",
"dia": "H22",
"n": "13",
"A": "4.500",
"B": "510",
"_right": [
[
111808,
"5.520"
],
[
112961,
"71.760"
]
]
},
{
"mark": "P5",
"y": -24794.6,
"shape": "I",
"dia": "H19",
"n": "64",
"A": "2.295",
"B": "150",
"_right": [
[
111808,
"2.595"
],
[
112875,
"166.080"
]
]
},
{
"mark": "C14",
"y": -25334.6,
"shape": "I",
"dia": "H16",
"n": "20",
"A": "3.000",
"B": "300",
"_right": [
[
111808,
"3.600"
],
[
112961,
"72.000"
]
]
},
{
"mark": "P2",
"y": -25604.6,
"shape": "VI",
"dia": "H16",
"n": "70",
"A": "3.610",
"B": "200",
"R": "1.149",
"J": "380",
"_right": [
[
111808,
"8.779"
],
[
112875,
"614.530"
]
]
},
{
"mark": "P3",
"y": -25874.6,
"shape": "V",
"dia": "H16",
"n": "12",
"A": "3.555",
"B": "55",
"R": "1.149",
"_right": [
[
111808,
"7.219"
],
[
112961,
"86.628"
]
]
},
{
"mark": "P4",
"y": -26144.6,
"shape": "X",
"dia": "H16",
"n": "25",
"A": "7.164",
"B": "55",
"R": "1.149",
"_right": [
[
111808,
"7.219"
],
[
112875,
"180.475"
]
]
},
{
"mark": "B7",
"y": -26684.6,
"shape": "I",
"dia": "H13",
"n": "98",
"A": "2.218",
"B": "100",
"_right": [
[
111808,
"2.418"
],
[
112875,
"236.964"
],
[
118670,
"VII"
]
]
},
{
"mark": "S1",
"y": -26954.6,
"shape": "I",
"dia": "H13",
"n": "22",
"A": "1.200",
"B": "700",
"_right": [
[
111808,
"2.600"
],
[
112961,
"57.200"
]
]
},
{
"mark": "S2",
"y": -27224.6,
"shape": "I",
"dia": "H13",
"n": "22",
"A": "1.200",
"B": "700",
"_right": [
[
111808,
"2.600"
],
[
112961,
"57.200"
]
]
},
{
"mark": "S3",
"y": -27494.6,
"shape": "I",
"dia": "H13",
"n": "22",
"A": "1.200",
"B": "700",
"_right": [
[
111808,
"2.600"
],
[
112961,
"57.200"
]
]
},
{
"mark": "S4",
"y": -27764.6,
"shape": "I",
"dia": "H13",
"n": "22",
"A": "1.200",
"B": "700",
"_right": [
[
111808,
"2.600"
],
[
112961,
"57.200"
]
]
}
]
},
"(SD500)": {
"columns": {
"A": 101056.8,
"B": 102294.8,
"C": 103532.8,
"D": 104770.8,
"E": 106008.8,
"R": 107119.8,
"J": 110523.8
},
"rows": [
{
"mark": "P1",
"y": -30554.6,
"shape": "VI",
"dia": "H32",
"n": "68",
"A": "27.510",
"B": "534",
"C": "500",
"R": "340",
"_right": [
[
111723,
"28.545"
],
[
112790,
"1941.060"
]
]
},
{
"mark": "B2",
"y": -31094.6,
"shape": "IV",
"dia": "H22",
"n": "31",
"A": "7.300",
"B": "2.250",
"J": "1.000",
"_right": [
[
111723,
"12.800"
],
[
112875,
"396.800"
]
]
},
{
"mark": "B3",
"y": -31364.6,
"shape": "I",
"dia": "H22",
"n": "28",
"A": "7.300",
"_right": [
[
111808,
"7.300"
],
[
112875,
"204.400"
]
]
},
{
"mark": "B5",
"y": -31634.6,
"shape": "IV",
"dia": "H22",
"n": "31",
"A": "7.300",
"B": "2.250",
"J": "1.000",
"_right": [
[
111723,
"12.800"
],
[
112875,
"396.800"
]
]
},
{
"mark": "B6",
"y": -31904.6,
"shape": "I",
"dia": "H22",
"n": "28",
"A": "7.300",
"_right": [
[
111808,
"7.300"
],
[
112875,
"204.400"
]
]
},
{
"mark": "B1",
"y": -32444.6,
"shape": "I",
"dia": "H16",
"n": "31",
"A": "7.300",
"_right": [
[
111808,
"7.300"
],
[
112875,
"226.300"
]
]
},
{
"mark": "B4",
"y": -32714.6,
"shape": "I",
"dia": "H16",
"n": "31",
"A": "7.300",
"_right": [
[
111808,
"7.300"
],
[
112875,
"226.300"
]
]
},
{
"mark": "B8",
"y": -32984.6,
"shape": "V",
"dia": "H16",
"n": "7",
"A": "7.300",
"B": "7.350",
"J": "570",
"_right": [
[
111723,
"31.581"
],
[
112875,
"221.067"
]
]
},
{
"mark": "B9",
"y": -33254.6,
"shape": "III",
"dia": "H16",
"n": "7",
"A": "7.300",
"B": "100",
"_right": [
[
111808,
"7.500"
],
[
112961,
"52.500"
]
]
},
{
"mark": "B10",
"y": -33524.6,
"shape": "III",
"dia": "H16",
"n": "7",
"A": "7.300",
"B": "100",
"_right": [
[
111808,
"7.500"
],
[
112961,
"52.500"
]
]
}
]
}
}
+1
View File
@@ -0,0 +1 @@
[{"dwg": "D1", "layer": "CS-DIMT", "x": 4573.9, "y": -39918.6, "h": 125.0, "text": "625", "handle": "B046"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4573.9, "y": -39164.6, "h": 125.0, "text": "11@150=1.650", "handle": "B047"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4573.9, "y": -36677.1, "h": 125.0, "text": "25@150=3.750", "handle": "B048"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4573.9, "y": -29463.8, "h": 125.0, "text": "1.155", "handle": "B04A"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4573.9, "y": -28026.1, "h": 125.0, "text": "100", "handle": "B04B"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4798.9, "y": -28324.4, "h": 125.0, "text": "띠철근외측", "handle": "B04C"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 3573.9, "y": -34643.9, "h": 125.0, "text": "28.430", "handle": "B04D"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4298.9, "y": -28324.4, "h": 125.0, "text": "크로스타이", "handle": "B04E"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4073.9, "y": -28026.1, "h": 125.0, "text": "100", "handle": "B04F"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4073.9, "y": -29463.8, "h": 125.0, "text": "1.155", "handle": "B050"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4073.9, "y": -37544.7, "h": 125.0, "text": "3@1.800=5.400", "handle": "B053"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4073.9, "y": -39918.6, "h": 125.0, "text": "625", "handle": "B054"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16498.9, "y": -40118.6, "h": 125.0, "text": "225", "handle": "B055"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16273.9, "y": -39447.0, "h": 125.0, "text": "6@300=1.800", "handle": "B056"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16498.9, "y": -38093.6, "h": 125.0, "text": "225", "handle": "B057"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16273.9, "y": -37931.1, "h": 125.0, "text": "100", "handle": "B058"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16273.9, "y": -34758.9, "h": 125.0, "text": "22.600", "handle": "B059"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16498.9, "y": -31931.1, "h": 125.0, "text": "100", "handle": "B05A"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16273.9, "y": -31781.1, "h": 125.0, "text": "200", "handle": "B05B"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16273.9, "y": -31107.2, "h": 125.0, "text": "2@1.000=2.000", "handle": "B05C"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16498.9, "y": -29581.1, "h": 125.0, "text": "200", "handle": "B05D"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16273.9, "y": -29180.9, "h": 125.0, "text": "600", "handle": "B05E"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 16273.9, "y": -28530.7, "h": 125.0, "text": "100", "handle": "B05F"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4073.9, "y": -23638.7, "h": 125.0, "text": "12@250=3.000", "handle": "B061"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4058.9, "y": -21285.9, "h": 125.0, "text": "100(하면)", "handle": "B062"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 3573.9, "y": -23340.4, "h": 125.0, "text": "3.200", "handle": "B063"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4573.9, "y": -23638.7, "h": 125.0, "text": "24@125=3.000", "handle": "B064"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 4558.9, "y": -21285.9, "h": 125.0, "text": "100(상면)", "handle": "B065"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 24093.0, "y": -26752.8, "h": 125.0, "text": "24@125=3.000", "handle": "B078"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 26303.8, "y": -27518.3, "h": 125.0, "text": "(1단)", "handle": "B079"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 26303.8, "y": -27018.3, "h": 125.0, "text": "(2단)", "handle": "B07A"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 26389.0, "y": -26752.8, "h": 125.0, "text": "100", "handle": "B07B"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 21026.5, "y": -41852.5, "h": 125.0, "text": "400", "handle": "B07C"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 24093.0, "y": -41852.5, "h": 125.0, "text": "13@500=6.500", "handle": "B07D"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 27926.5, "y": -41852.5, "h": 125.0, "text": "400", "handle": "B07E"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 28595.9, "y": -41837.5, "h": 125.0, "text": "100(중앙)", "handle": "B07F"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 20901.5, "y": -42577.5, "h": 125.0, "text": "150", "handle": "B080"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 24093.0, "y": -42352.5, "h": 125.0, "text": "56@125=7.000", "handle": "B081"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 28026.5, "y": -42577.5, "h": 125.0, "text": "100", "handle": "B082"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 28144.1, "y": -42352.5, "h": 125.0, "text": "50", "handle": "B083"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 28595.9, "y": -42337.5, "h": 125.0, "text": "100(하면)", "handle": "B084"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 24391.3, "y": -42852.5, "h": 125.0, "text": "7.500", "handle": "B085"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 28595.9, "y": -41337.5, "h": 125.0, "text": "100(상면)", "handle": "B086"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 28051.5, "y": -41577.5, "h": 125.0, "text": "150", "handle": "B087"}, {"dwg": "D1", "layer": "CS-DIMT", "x": 24093.Line truncated
Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB