#!/usr/bin/env python3 """Inventory the main-line (본선) DXF drawings: header, layers, entity counts, extents, 3D flag and text samples. Read-only on the source RAG folder.""" import collections import glob import json import os import sys import ezdxf from ezdxf import bbox, recover RAG_DIR = sys.argv[1] OUT_JSON = sys.argv[2] # 본선 scope (approved 2026-10-21): 02 평면·종단, 03 본선굴착, 04 본선기타 SUBDIRS = ["02_평면 및 종단면도", "03_본선터널굴착", "04_본선터널기타"] def inventory(path): rec = {"file": os.path.basename(path), "ok": False} rec["recovered"] = False try: doc = ezdxf.readfile(path) except Exception as exc: # strict load failed: retry in recover mode and record it strict_error = f"{type(exc).__name__}: {exc}" try: doc, _auditor = recover.readfile(path) rec["recovered"] = True rec["strict_error"] = strict_error except Exception as exc2: rec["error"] = f"{strict_error} | recover: {type(exc2).__name__}: {exc2}" return rec hdr = doc.header rec["dxfversion"] = doc.dxfversion rec["insunits"] = hdr.get("$INSUNITS") rec["codepage"] = hdr.get("$DWGCODEPAGE") rec["layers"] = len(doc.layers) msp = doc.modelspace() counts = collections.Counter(e.dxftype() for e in msp) rec["entity_counts"] = dict(counts.most_common()) rec["blocks"] = len([b for b in doc.blocks if not b.name.startswith("*")]) z_vals = [] texts = [] for e in msp: t = e.dxftype() if t == "LINE": z_vals += [e.dxf.start.z, e.dxf.end.z] elif t in ("TEXT", "MTEXT"): s = e.dxf.text if t == "TEXT" else e.plain_text() if s and len(texts) < 40: texts.append(s.strip()[:80]) elif t in ("POINT", "INSERT", "CIRCLE", "ARC"): z_vals.append(e.dxf.location.z if t == "POINT" else e.dxf.insert.z if t == "INSERT" else e.dxf.center.z) rec["z_min"] = round(min(z_vals), 3) if z_vals else None rec["z_max"] = round(max(z_vals), 3) if z_vals else None rec["has_3d_geometry"] = bool(z_vals) and (max(z_vals) - min(z_vals)) > 1e-6 try: ext = bbox.extents(msp) rec["extents_min"] = [round(v, 2) for v in ext.extmin] rec["extents_max"] = [round(v, 2) for v in ext.extmax] except Exception as exc: rec["extents_error"] = str(exc) rec["text_sample"] = texts rec["ok"] = True return rec def main(): paths = [] for sub in SUBDIRS: paths += sorted(glob.glob(os.path.join(RAG_DIR, sub, "*.dxf"))) results = [inventory(p) for p in paths] os.makedirs(os.path.dirname(OUT_JSON), exist_ok=True) with open(OUT_JSON, "w", encoding="utf-8") as fh: json.dump(results, fh, ensure_ascii=False, indent=2) ok = sum(r["ok"] for r in results) print(f"files={len(results)} ok={ok} failed={len(results) - ok}") for r in results: status = "OK " if r["ok"] else "ERR" detail = r.get("error") or f"ents={sum(r['entity_counts'].values())} 3D={r['has_3d_geometry']} units={r['insunits']} cp={r['codepage']} recovered={r['recovered']}" print(f"{status} {r['file'][:60]:60s} {detail}") if __name__ == "__main__": main()