feat: add DXF inventory script for main-line (본선) drawings
Scans 21 main-line DXF files (02 평면·종단, 03 본선굴착, 04 본선기타) for header, layers, entity counts, extents, 3D flag and text samples. Strict load failures fall back to ezdxf recover mode and are recorded. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A5Cun3RHQKna9qxE6ybZ4A
This commit is contained in:
commit
cc381b9d50
3 files changed
+1618
No files matched your search
@@ -0,0 +1,3 @@
|
||||
data/*.tmp
|
||||
__pycache__/
|
||||
*.pyc
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,85 @@
|
||||
#!/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()
|
||||
Reference in new issue
Block a user