Files
CMPlanning/scripts/extract_lining_spec.py
T
Claude fe6fe26655 feat: read concrete-lining drawings 04-004..009 and link lining spec to model (Task 6)
Extracted per-sheet pattern groups (입출구부 50 m / 온도미고려), note-5 scope,
fck 27 MPa, SD400, aggregate 25 mm, rebar label counts and printed radii.
Model keeps R1 = 6,982 mm; lining sheets print 6.892 m -> [CONFLICT DETECTED]
for user check. Sheet-to-station and pattern-name mapping left [미확정].
Viewer shows the lining spec on click.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A5Cun3RHQKna9qxE6ybZ4A
2026-10-21 06:30:45 +00:00

99 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""Extract structured lining-reinforcement data from the concrete-lining
structure drawings 04-004..009 (read-only on RAG).
Per sheet: pattern groups and their detail kind (입출구부 50 m / 온도미고려),
note-5 scope sentence, concrete and rebar grade, rebar sizes present,
radius and lap dimensions as printed, EL datum texts.
Output: data/lining_spec.json (+ printed summary).
Usage: extract_lining_spec.py <RAG_04_DIR> <OUT_JSON>
"""
import glob
import json
import os
import re
import sys
import ezdxf
from ezdxf import recover
RAG_04, OUT = sys.argv[1], sys.argv[2]
BAR_RE = re.compile(r"^0?H(\d{2})$")
PAT_RE = re.compile(r"\(([^()]*?)\s*패턴\)")
GROUP_RE = re.compile(r"주철근 조립도\(([^()]*?)\s*패턴\)")
def load(path):
try:
return ezdxf.readfile(path)
except Exception:
doc, _ = recover.readfile(path)
return doc
def texts_of(doc):
out = []
for e in doc.modelspace():
if e.dxftype() == "TEXT":
s = e.dxf.text
elif e.dxftype() == "MTEXT":
s = e.plain_text()
else:
continue
if s and s.strip():
out.append((e.dxf.layer, round(e.dxf.insert.x, 1), round(e.dxf.insert.y, 1), s.strip()))
return out
def sheet_no(name):
return int(re.search(r"C0060304-(\d{3})", name).group(1))
def main():
files = sorted(glob.glob(os.path.join(RAG_04, "C0060304-00[4-9]*.dxf")))
sheets = []
for f in files:
doc = load(f)
tx = texts_of(doc)
rec = {"sheet": sheet_no(f), "file": os.path.basename(f)}
# pattern groups: detail kind from the text itself
groups = []
for layer, x, y, s in tx:
if layer != "CS-TABL-TEX1":
continue
if "패턴" in s:
kind = "입출구부 50m" if "입출구부" in s else ("온도미고려" if "온도미고려" in s else "기타")
m = PAT_RE.search(s)
groups.append({"group": m.group(1) if m else None, "kind": kind, "raw": s})
rec["pattern_details"] = groups
# scope note 5 (full line, joined with the continuation line)
note5 = [s for _, _, _, s in tx if s.startswith("5. 본 콘크리트 라이닝 구조도")]
cont = [s for _, _, _, s in tx if s.startswith("설계조건과 상이할 경우")]
rec["note5"] = (note5[0] + " " + (cont[0] if cont else "")).strip() if note5 else None
rec["concrete"] = sorted({s for _, _, _, s in tx if "fck" in s})
rec["rebar_grade"] = sorted({s for _, _, _, s in tx if "fy=" in s})
rec["aggregate"] = sorted({s for _, _, _, s in tx if "최대치수" in s})
bars = {}
for layer, x, y, s in tx:
m = BAR_RE.match(s)
if m:
bars[f"H{m.group(1)}"] = bars.get(f"H{m.group(1)}", 0) + 1
rec["rebar_sizes_label_count"] = dict(sorted(bars.items()))
rec["radius_dims"] = sorted({s for layer, _, _, s in tx if layer == "CS-DIMT" and re.match(r"R\d?'?=", s)})
rec["lap_dims"] = sorted({s for layer, _, _, s in tx if layer == "CS-DIMT" and "mm" in s and "이음장" not in s and "600" in s})
rec["el_texts"] = sorted({s for _, _, _, s in tx if s.startswith("EL")})
rec["entrance_exit_50m"] = any("입출구부 50m" in s for _, _, _, s in tx)
sheets.append(rec)
with open(OUT, "w", encoding="utf-8") as fh:
json.dump({"source": "C0060304-004..009 (콘크리트라이닝구조도)", "sheets": sheets},
fh, ensure_ascii=False, indent=1)
for r in sheets:
print("==", r["sheet"], "| groups:", [(g["group"], g["kind"]) for g in r["pattern_details"]])
print(" note5:", (r["note5"] or "")[:140])
print(" concrete:", r["concrete"], "| rebar:", r["rebar_grade"], "| agg:", r["aggregate"])
print(" bars:", r["rebar_sizes_label_count"], "| R:", r["radius_dims"], "| EL:", r["el_texts"])
if __name__ == "__main__":
main()