"""90-2 도수로 · 돌붙임 띠 — 윗면 = 유출 성토사면 선 · 사면 안쪽(아래)으로 두께만큼 · 안에 돌. 화면 TS(`appendChuteBand`)를 그 자리에서 돌린 값(`helper_90_chute_band.cjs`). """ import json import math import subprocess from pathlib import Path import pytest HERE = Path(__file__).parent ROOT = HERE.parents[1] pytestmark = pytest.mark.skipif( not (ROOT / "config" / "node_modules").is_dir(), reason="프론트엔드 의존성 미설치" ) @pytest.fixture(scope="module") def out() -> dict: done = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", str(HERE / "helper_90_chute_band.cjs")], capture_output=True, text=True, encoding="utf-8", ) assert done.returncode == 0, done.stderr return json.loads(done.stdout) def _distance(p: dict, a: dict, b: dict) -> float: dx, dz = b["offset"] - a["offset"], b["elevation"] - a["elevation"] cross = (p["offset"] - a["offset"]) * dz - (p["elevation"] - a["elevation"]) * dx return abs(cross) / math.hypot(dx, dz) @pytest.mark.parametrize("case", ["left", "right"]) def test_띠_두께는_사면에서_직각으로_0_30m_아래(out: dict, case: str) -> None: points = out[case]["points"] n = len(points) // 2 top, bottom = points[:n], points[n:][::-1] for i, low in enumerate(bottom): # 꼭짓점마다 붙은 변(앞 · 뒤)까지 직각 거리 = 두께 for j in {max(i - 1, 0), min(i, n - 2)}: assert _distance(low, top[j], top[j + 1]) == pytest.approx(0.3, abs=1e-6) assert low["elevation"] < top[i]["elevation"] # 사면 안쪽 = 아래 def test_안에_돌_윗면은_사면선(out: dict) -> None: for case in out.values(): assert case["stones"] >= 2 and case["clipped"] assert "돌붙임" in case["title"] and "0.30m" in case["title"] assert out["left"]["points"][:4] == [ {"offset": 5, "elevation": 10}, {"offset": 7.4, "elevation": 8}, {"offset": 8.4, "elevation": 8}, {"offset": 10.8, "elevation": 6}, ]