Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYJJRCfHfdCGNhmXTjQKV7
93 lines
3.9 KiB
Python
93 lines
3.9 KiB
Python
"""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)
|
||
# 유입 집수정 끝 절토 = 암 1:0.4 → 토사 1:1.0 복합경사(91-4 · 옛 한 줄 −10.4371 · 16.9505)
|
||
assert x_min == pytest.approx(-11.6239, abs=1e-3)
|
||
assert y_max - y_min == pytest.approx(17.7502, abs=1e-3)
|
||
# 0 m: 노폭 글자(2 mm, 세로 가운데 정렬)가 맨 위 — 글자 반높이 0.1 m 까지
|
||
assert extents[0][3] == pytest.approx(879.8831, abs=1e-3)
|