# -*- coding: utf-8 -*- """신규 프로젝트에서 구조물이 안 보이는 원인 진단 — 읽기 전용. 실행: ./venv/Scripts/python.exe resources/tester/diag_structures.py [프로젝트UUID] 인자를 생략하면 storage 아래에서 **가장 최근에 만들어진** 프로젝트를 고른다. 자동설계 체인이 남겨야 할 것을 한 줄씩 대조한다: 1. 배관 정본(edits/pipe_points.json) — 관·세월교·BOX 지정 2. 종단 정본 stations[].structure — 구조물 측점 표식 3. 횡단 정본 cross_*.json 의 structure — 측점 파일 4. B06 읽기 경로(load_culvert_sets) — 실제로 세트가 붙는가 5. 초기값 스냅샷 — 체인 직후 상태가 떠졌는가 """ import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT)) def newest_project() -> Path | None: candidates = [p for p in (ROOT / "storage").glob("*/*/*") if (p / "project_manifest.json").is_file()] return max(candidates, key=lambda p: p.stat().st_mtime) if candidates else None def read_json(path: Path): try: return json.loads(path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError): return None def main() -> int: if len(sys.argv) > 1: matches = [p for p in (ROOT / "storage").glob(f"*/*/{sys.argv[1]}")] project = matches[0] if matches else None else: project = newest_project() if project is None or not project.is_dir(): print("프로젝트를 찾지 못했습니다.") return 1 print(f"프로젝트: {project}") # 1) 배관 정본 pipes_path = project / "B04_PreProcess" / "drainage" / "edits" / "pipe_points.json" pipes = read_json(pipes_path) points = (pipes or {}).get("points") or [] print(f"1) pipe_points.json 존재={pipes_path.is_file()} 관={len(points)}건") for point in points: print( f" - {point.get('chainage_m')}m facility={point.get('facility') or 'pipe'}" f" options={list((point.get('options') or {}).keys())}" ) if pipes: print(f" route_signature={str(pipes.get('route_signature'))[:16]}…") # 2) 종단 정본 구조물 표식 long_path = project / "B06_Section" / "longitudinal" / "longitudinal.json" longitudinal = read_json(long_path) or {} stations = longitudinal.get("stations") or [] marked = [s for s in stations if s.get("structure")] print(f"2) longitudinal.json 측점={len(stations)} 구조물 표식={len(marked)}건") for station in marked: print(f" - {station.get('chainage_m')}m {station.get('structure')} kind={station.get('kind')}") # 3) 횡단 정본 파일 cross_dir = project / "B06_Section" / "cross_sections" files = sorted(cross_dir.glob("cross_*.json")) if cross_dir.is_dir() else [] with_structure = [(p.name, read_json(p).get("structure")) for p in files if (read_json(p) or {}).get("structure")] print(f"3) cross_*.json 파일={len(files)}개 구조물 표식={len(with_structure)}건 {with_structure}") # 4) B06 읽기 경로 — 실제로 세트가 붙는가 from B06_Section.B06_Section_Engine_Culvert import load_culvert_sets sets = load_culvert_sets(project) print(f"4) load_culvert_sets 세트={len(sets)}건") for chainage, spec in sorted(sets.items()): print(f" - {chainage}m kind={spec.get('kind')}") # 측점과 붙을 수 있는가 (허용오차 0.02m) chainages = [float(s.get("chainage_m", -1)) for s in stations] for chainage in sorted(sets): hit = any(abs(chainage - c) <= 0.02 for c in chainages) if not hit: print(f" ⚠ {chainage}m 에 붙을 측점이 없다 — 횡단도에 구조물이 안 뜬다") # 5) 초기값 스냅샷 snapshot = project / "initial_snapshot" snap_pipes = read_json(snapshot / "B04_PreProcess__drainage__edits" / "pipe_points.json") print( f"5) initial_snapshot 존재={snapshot.is_dir()}" f" 스냅샷 관={len((snap_pipes or {}).get('points') or [])}건" ) lock = project / "initial_design.lock" print(f" initial_design.lock(체인 진행 중 표시)={lock.exists()}") return 0 if __name__ == "__main__": raise SystemExit(main())