refactor(B07): 도면 조립 지원 700줄 초과 분리 — 유역도·입출력
808줄 한 파일을 셋으로 나눔 (동작 불변, 순수 이동). - `B07_DesignDetail_Router_Support.py` 532줄 — 도면 목록·장 배치·확정 저장·재계산 - `B07_DesignDetail_Router_Support_Basin.py` 279줄 — 유역도 배경(GeoJSON·좌표 환산·도곽 클리핑) - `B07_DesignDetail_Router_Support_Io.py` 88줄 — 원본 JSON·매니페스트 입출력, 측점 대응표 떼어낸 `watershed_source`·`clip_line_to_box` 는 본체에서 `as` 로 다시 내보내 호출부(`B07_DesignDetail_Router.py`)의 import 경로가 그대로임. 검증: 라우트 7개 그대로, 공용 브라우저 `design-drawings` 200 · `frame-template` 200, ruff check 통과, tmp/tests 378 passed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
"""B07 도면 조립 지원 — 원본 JSON·매니페스트 읽기/쓰기와 측점 대응표.
|
||||
|
||||
지원 모듈이 700줄을 넘어 떼어냈다(2026-09-04). 유역도 조각과 본체가 함께 쓴다.
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from B05_Profile.B05_Profile_Engine_Sections import prune_stale_cross_files
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
_STAGE_DIR = "B07_DesignDetail"
|
||||
|
||||
_CROSS_ID = re.compile(r"^cross_(\d+)m$")
|
||||
_LONG_ID = re.compile(r"^longitudinal(?:_(\d+))?$")
|
||||
# 노선 전장에 한 장씩만 나오는 도면 — 라우터가 원본 자료를 따로 실어 넘긴다.
|
||||
MASS_HAUL_ID = "mass_haul"
|
||||
WATERSHED_ID = "watershed"
|
||||
COVER_ID = "cover"
|
||||
|
||||
# 아직 내용을 만들지 않은 도면 — 도각만 실어 연다(2026-09-01 사용자 지시).
|
||||
# 화면 순서(DRAWING_GROUPS)와 같은 이름을 쓴다.
|
||||
BLANK_DRAWINGS: tuple[tuple[str, str], ...] = (
|
||||
("blank_plan_terrain", "계획평면도(지형)"),
|
||||
("blank_plan_route", "계획평면도(노선배치도)"),
|
||||
("blank_plan_layout", "계획평면도(배치도)"),
|
||||
("blank_plan_lidar", "계획평면도(라이다)"),
|
||||
("blank_cross_standard", "표준 횡단면도"),
|
||||
("blank_standard", "표준도"),
|
||||
("blank_landuse", "용지도"),
|
||||
)
|
||||
BLANK_LABELS: dict[str, str] = dict(BLANK_DRAWINGS)
|
||||
|
||||
|
||||
def _read_json(path: Path) -> dict[str, Any]:
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
if not isinstance(payload, dict):
|
||||
raise ValueError("도면 원본 JSON 형식이 올바르지 않습니다.")
|
||||
return payload
|
||||
|
||||
|
||||
def _cross_files(longitudinal_path: Path, longitudinal: dict[str, Any]) -> list[Path]:
|
||||
cross_dir = longitudinal_path.parent.parent / "cross_sections"
|
||||
if not cross_dir.is_dir():
|
||||
raise FileNotFoundError("B06 횡단면 파일을 찾을 수 없습니다.")
|
||||
stations = longitudinal.get("stations")
|
||||
valid_names = prune_stale_cross_files(cross_dir, stations if isinstance(stations, list) else [])
|
||||
files = sorted(cross_dir.glob("cross_*.json"))
|
||||
if valid_names:
|
||||
files = [path for path in files if path.name in valid_names]
|
||||
return files
|
||||
|
||||
|
||||
def _station_map(longitudinal: dict[str, Any]) -> dict[int, dict[str, Any]]:
|
||||
stations = longitudinal.get("stations", [])
|
||||
if not isinstance(stations, list):
|
||||
return {}
|
||||
return {
|
||||
round(float(station.get("chainage_m", 0))): station
|
||||
for station in stations
|
||||
if isinstance(station, dict)
|
||||
}
|
||||
|
||||
|
||||
def _design_root(project_root: Path) -> Path:
|
||||
return project_root / _STAGE_DIR
|
||||
|
||||
|
||||
def _read_manifest(project_root: Path) -> dict[str, Any]:
|
||||
path = _design_root(project_root) / "manifest.json"
|
||||
if not path.is_file():
|
||||
return {"drawings": {}}
|
||||
payload = _read_json(path)
|
||||
return payload if isinstance(payload.get("drawings"), dict) else {"drawings": {}}
|
||||
|
||||
|
||||
def _write_manifest(project_root: Path, manifest: dict[str, Any]) -> None:
|
||||
stage_root = _design_root(project_root)
|
||||
stage_root.mkdir(parents=True, exist_ok=True)
|
||||
path = stage_root / "manifest.json"
|
||||
temporary = path.with_suffix(".tmp")
|
||||
temporary.write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
temporary.replace(path)
|
||||
Reference in New Issue
Block a user