143 lines
6.3 KiB
Python
143 lines
6.3 KiB
Python
"""79 흙막이 · 세월교 · 박스암거 형상 — 화면 TS 를 그 자리에서 돌린 값(`helper_79_guard_shape.cjs`).
|
||
|
||
픽스처 = 73-4 와 같은 검증_sub7 상세 일부(세월교 173.09 · 박스 352.14 유입 · 유출 흙막이).
|
||
- 79-5 관 보호공 · 독립 기슭막이(옹벽) 기본 자리 = 성토사면 제일 위(d 0 · 관은 m 단위 맞춤만큼 아래)
|
||
- 79-6 구간 연동 측점 벽 = 연동 표시
|
||
- 79-7 흙막이 윗면 = 본체 윗면 · 높이 빈 칸 = 본체 끝 높이 · 세월교 ㄴ형 측벽 걷음 · 박스 수평 ·
|
||
박스 날개벽 끝 절 · 성토선 · 끝 절토 = 수평공간(컨테이너 칸) 뒤 절토 경사
|
||
"""
|
||
|
||
import json
|
||
import math
|
||
import subprocess
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
if str(ROOT) not in sys.path:
|
||
sys.path.insert(0, str(ROOT))
|
||
|
||
HELPER = Path(__file__).parent / "helper_79_guard_shape.cjs"
|
||
NODE_MODULES = ROOT / "config" / "node_modules"
|
||
|
||
pytestmark = pytest.mark.skipif(not NODE_MODULES.is_dir(), reason="프론트엔드 의존성 미설치")
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def shape() -> dict:
|
||
done = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||
["node", str(HELPER)], cwd=str(ROOT), capture_output=True, text=True, encoding="utf-8"
|
||
)
|
||
assert done.returncode == 0, done.stderr
|
||
return json.loads(done.stdout)
|
||
|
||
|
||
def test_세월교_높이_빈칸은_본체_끝_높이_윗면은_본체_윗면(shape: dict) -> None:
|
||
walls = shape["fordAuto"]
|
||
assert {w["role"] for w in walls} == {"inlet", "outlet"}
|
||
for wall in walls:
|
||
assert wall["topGap"] == pytest.approx(0, abs=1e-3)
|
||
assert wall["bottomGap"] == pytest.approx(0, abs=1e-3)
|
||
assert wall["pureHeight"] == pytest.approx(wall["endHeight"], abs=1e-3)
|
||
|
||
|
||
def test_박스_높이_빈칸은_박스_높이_값_윗면은_본체_윗면(shape: dict) -> None:
|
||
# 2 m 박스 → 2 m(사용자 원문 숫자 · 79b) — 바닥 = 윗면 − 그 높이
|
||
walls = shape["boxAuto"]
|
||
assert {w["role"] for w in walls} == {"inlet", "outlet"}
|
||
for wall in walls:
|
||
assert wall["topGap"] == pytest.approx(0, abs=1e-3)
|
||
assert wall["pureHeight"] == pytest.approx(wall["autoHeight"], abs=1e-3)
|
||
assert wall["autoHeight"] < wall["endHeight"]
|
||
assert wall["bottomGap"] == pytest.approx(wall["endHeight"] - wall["autoHeight"], abs=1e-3)
|
||
|
||
|
||
def test_높이를_적으면_윗면은_그대로_바닥이_따라감(shape: dict) -> None:
|
||
for wall in shape["boxSet"]:
|
||
assert wall["topGap"] == pytest.approx(0, abs=1e-3)
|
||
assert wall["bottomGap"] == pytest.approx(wall["endHeight"] - wall["pureHeight"], abs=1e-3)
|
||
|
||
|
||
def test_세월교_흙막이_쪽_ㄴ형_측벽은_사라짐(shape: dict) -> None:
|
||
assert all(side["parts"] == 0 for side in shape["fordParts"])
|
||
one = {side["role"]: side["parts"] for side in shape["fordOneGuardParts"]}
|
||
assert one == {"inlet": 0, "outlet": 2}
|
||
|
||
|
||
def test_박스_본체는_늘_수평(shape: dict) -> None:
|
||
level = shape["boxLevel"]
|
||
assert level["left"] == pytest.approx(level["right"], abs=1e-6)
|
||
assert level["slope"] is None
|
||
|
||
|
||
def test_박스_날개벽_끝_절성토선(shape: dict) -> None:
|
||
for side in shape["boxWing"]:
|
||
assert side["cut"] + side["fill"] >= 1
|
||
|
||
|
||
def test_흙막이_끝_절토는_수평공간_뒤(shape: dict) -> None:
|
||
tails = [tail for group in shape["cutDefault"] for tail in group]
|
||
assert tails, "절토 끝선이 없음"
|
||
assert any(tail["role"] == "inlet" for tail in tails)
|
||
for tail in tails:
|
||
# 시작 · 수평공간 끝 · (암 무릎 · 소단) · 원지반 교점 — 본선 절토와 같은 복합경사(91-4)
|
||
assert tail["points"] >= 2
|
||
if tail["role"] == "inlet":
|
||
assert tail["flat"] == pytest.approx(0, abs=1e-6)
|
||
assert tail["berm"] == pytest.approx(1.0, abs=1e-3)
|
||
else:
|
||
# 유출 = 묻히면 3도 내림 절토선 하나로 원지반까지(139-4)
|
||
assert tail["points"] == 2
|
||
assert tail["flat"] == pytest.approx(
|
||
-tail["berm"] * math.tan(math.radians(3)), abs=2e-3
|
||
)
|
||
for tail in shape["cutBerm2"]:
|
||
if tail["role"] == "inlet":
|
||
assert tail["berm"] == pytest.approx(2.0, abs=1e-3)
|
||
else:
|
||
assert tail["points"] == 2 and tail["flat"] < 0 # 유출 수평공간 칸 무시 · 3도 선
|
||
|
||
|
||
def test_유입_수평공간_시작은_본체_바닥(shape: dict) -> None:
|
||
"""89-3 — 박스 저판 상면 · 세월교 바닥판 상면 높이에서 수평 → 절토."""
|
||
for case in shape["inletFloor"]:
|
||
assert case["start"] == pytest.approx(case["floor"], abs=1e-3)
|
||
|
||
|
||
def test_관_보호공_기본_자리는_제일_위(shape: dict) -> None:
|
||
pipe = shape["pipe"]
|
||
assert pipe is not None
|
||
# 벽 윗면 = 관 윗면(139-1) · 관 위 토피 0.5 → 유입 벽 윗면 = 노견 − 0.5 = 사면 d 0.6(1:1.2)
|
||
assert pipe["d"]["inlet"] == pytest.approx(0.6, abs=1e-6)
|
||
# 유출은 관 m 단위 맞춤이 사면 아래로 민 만큼만 내려감(종전 기본 = 경사길이 4 m · d 3.07)
|
||
assert pipe["d"]["outlet"] < 1.0
|
||
inlet = next(w for w in pipe["walls"] if w["role"] == "inlet")
|
||
assert inlet["topBelowEdge"] == pytest.approx(0.5, abs=0.05)
|
||
assert float(pipe["lengthM"]).is_integer()
|
||
|
||
|
||
def test_저장_x_있는_관_보호공은_종전_자리_그대로(shape: dict) -> None:
|
||
# d 빈 칸 기본 = 경사길이 4 m 지점(3.07) — x 원점 그대로라 절대 자리 안 바뀜(79b)
|
||
stored = shape["pipeStoredX"]
|
||
assert stored["x"] == pytest.approx(1.0)
|
||
assert stored["d"] == pytest.approx(4.0 * 1.2 / (1 + 1.2**2) ** 0.5, abs=0.05)
|
||
|
||
|
||
def test_저장_x_있는_독립_기슭막이_옹벽은_종전_자리_그대로(shape: dict) -> None:
|
||
stored = shape["revetStoredX"]
|
||
assert stored["x"] == pytest.approx(1.0)
|
||
assert stored["d"] == pytest.approx(2.6) # 종전 기본 하강(3.07 / 1.2 → 0.1 눈금)
|
||
run = 4.0 * 1.2 / (1 + 1.2**2) ** 0.5
|
||
assert stored["shift"] == pytest.approx(run + 1.0, abs=1e-3)
|
||
assert stored["shiftXD"] == pytest.approx(run + 1.0, abs=1e-3)
|
||
|
||
|
||
def test_독립_기슭막이_옹벽_기본_자리는_제일_위(shape: dict) -> None:
|
||
revet = shape["revet"]
|
||
assert revet["d"] == 0
|
||
assert revet["topBelowEdge"] == pytest.approx(0, abs=1e-3)
|
||
assert revet["linked"] is False
|
||
assert shape["revetLinked"] is True
|