Files
CMPlanning/3d-drawing/scripts/inventory_dxf.py
T

86 lines
3.2 KiB
Python

#!/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()