"""B07 횡단면도 — 화면이 덧그리는 설계선·구조물까지 박스 안 1 mm (68-3). 서버가 화면과 같은 TS 를 Node 로 돌려 덧그림 범위를 재고(`_Cross_Extent_Node`), 장 배치 · 블록 테두리가 그 범위를 덮는다. """ import json from pathlib import Path import pytest from B07_DesignDetail.B07_DesignDetail_Engine_Cad import ( CROSS_MM, FRAME_LAYER_ID, build_cross_drawing, ) from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import section_block_size from B07_DesignDetail.B07_DesignDetail_Engine_Template import entities_bbox ROOT = Path(__file__).resolve().parents[2] FIXTURE = Path(__file__).parent / "fixtures" / "b07_cross_overlay_sections.json" NODE_MODULES = ROOT / "config" / "node_modules" _SOURCE = { "chainage_m": 0.0, "samples": [ {"valid": True, "offset_m": float(x), "elevation_m": 100.0 + 0.2 * x} for x in range(-10, 11) ], } _DESIGN_LINE = [ {"offset_m": -10.0, "elevation_m": 98.0}, {"offset_m": -2.0, "elevation_m": 99.6}, {"offset_m": 2.0, "elevation_m": 99.6}, {"offset_m": 10.0, "elevation_m": 102.0}, ] # 오른쪽으로 8 m 더 뻗고 위로 3 m 솟는 덧그림(관 · 날개벽 따위) _OVERLAY = (-3.0, 18.0, 97.0, 105.0) def _frame(drawing: dict) -> list[float]: return drawing["cross_placements"][0]["frame"] def test_frame_covers_overlay_by_one_mm() -> None: drawing = build_cross_drawing( _SOURCE, "cross_s00000m", _DESIGN_LINE, None, None, "", overlay=_OVERLAY ) placement = drawing["cross_placements"][0] left, bottom, right, top = _frame(drawing) to_x = lambda offset: offset * CROSS_MM + placement["ox"] # noqa: E731 to_y = lambda elev: (elev - placement["dy"]) * CROSS_MM + placement["oy"] # noqa: E731 assert right - to_x(_OVERLAY[1]) == pytest.approx(1.0) assert top - to_y(_OVERLAY[3]) == pytest.approx(1.0) # 왼쪽 · 아래는 서버 선(원지반 끝 · 설계선)이 더 바깥 — 그쪽에 1 mm lines = [e for e in drawing["entities"] if e.get("layerId") != FRAME_LAYER_ID] min_x, _min_y, _max_x, _max_y = entities_bbox(lines) assert min_x - left == pytest.approx(1.0) # 장 배치용 크기도 같은 규칙 width, height = section_block_size(_SOURCE, _DESIGN_LINE, with_table=False, overlay=_OVERLAY) assert width == pytest.approx(right - left) assert height == pytest.approx(top - bottom) def test_no_overlay_keeps_68_1_frame() -> None: plain = build_cross_drawing(_SOURCE, "cross_s00000m", _DESIGN_LINE, None, None, "") inside = build_cross_drawing( _SOURCE, "cross_s00000m", _DESIGN_LINE, None, None, "", overlay=(1.0, 3.0, 99.7, 99.8) ) assert _frame(plain) == pytest.approx(_frame(inside)) @pytest.mark.skipif(not NODE_MODULES.is_dir(), reason="프론트엔드 의존성 미설치") def test_node_bundle_measures_screen_overlay() -> None: """화면 코드를 Node 로 — 배수관 측점(85.052)은 서버 범위(+4.0 m)보다 13.8 m 까지 뻗는다.""" from B07_DesignDetail.B07_DesignDetail_Router_Support_Overlay import ( _NPM_SCRIPT, BUNDLE, _extents_from, ) from common_util.common_util_node_bundle import run_bundle_json detail = json.loads(FIXTURE.read_text(encoding="utf-8")) extents = _extents_from(run_bundle_json(BUNDLE, _NPM_SCRIPT, {"detail": detail})) assert set(extents) == {0, 85.05} # 측점 키는 0.01 m 로 끊는다(cross_station) x_min, x_max, y_min, y_max = extents[85.05] assert x_max == pytest.approx(13.8216, abs=1e-3) assert x_min == pytest.approx(-10.4371, abs=1e-3) assert y_max - y_min == pytest.approx(16.9505, abs=1e-3) # 0 m: 노폭 글자(2 mm, 세로 가운데 정렬)가 맨 위 — 글자 반높이 0.1 m 까지 assert extents[0][3] == pytest.approx(879.8831, abs=1e-3)