Files
Aislo/resources/tester/test_b06_spoil_fill_allocation.py
T
eomsangdonandClaude Opus 5.5 3898cb0019 refactor(380-1): 사토장 횡단 그림 · 사토 단면 셈 지움 — 부품 처음값 형상 · 3D 없음
- 부품 처음값 spoil_bank 형상 · 3D = none · 형상 부품 「사토(성토 채움)」 지움
- 사토 단면 셈 파이썬 · TS 짝 지움(Engine_SpoilFill · common_util_spoil_fill · spoil_fill 옵션 · fill_area_beyond)
- 카드 그림 · 면적표 줄 · 모달 띠 · 고름 선 · B07 표 「사토장」 칸 지움(빈 줄로 되돌림)
- B08 수량 · 유토 배분(haul-plan) 미사용 확인 · 남은 사토 값 = [저장] 서버 재계산 · 브라우저 단계 다시 셈으로 정리
- 시험 고쳐 씀: 322_1 · 349_0n · b06_spoil_fill_allocation(남은 값 정리) · spoil_fill_mirror(죽은 길) · 52_9 · cross_design_mirror · 150 · 164 · 179_4 · 316

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VmC34fsxxbweEG3RUjs3Mn
2026-10-17 14:56:42 +09:00

110 lines
4.0 KiB
Python

"""사토장 — 횡단 단면 셈 지움 · 남은 사토 값 정리 (PLAN 380-1 · 요구 241-8).
⚠ 잠그는 것
① 사토장이 놓여도 [저장]·[확정] 서버 재계산(`enforce_design_lines` → `_enforce_stored_designs`)이
사토 단면을 세우지 않는다 — 횡단도에 그림 없음 · 상세 CAD 글만.
② 옛 저장분에 남은 `spoil_fill_*` 값(노선 성토를 뺀 꼴)은 [저장] 한 번에 지워지고
노선 성토(`fill_area_m2`)가 사토장 없는 값으로 돌아온다.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[2]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from B06_Section.B06_Section_Engine_Design import compute_cross_design # noqa: E402
from B06_Section.B06_Section_Router_Design import enforce_design_lines # noqa: E402
from B06_Section.B06_Section_Server_Calc_Prebuild import _enforce_stored_designs # noqa: E402
def _samples() -> list[dict]:
"""우측(-offset)이 높고 좌측(+offset)이 낮은 지반 — 좌가 성토 쪽."""
return [
{"offset_m": round(offset, 3), "elevation_m": round(100.0 - 0.5 * offset, 4), "valid": True}
for offset in [x * 0.5 for x in range(-30, 31)]
]
def _plain() -> dict:
return compute_cross_design(
_samples(), 99.8, ground_type="soil", section_mode="right_cut", ditch_side="right"
)
_LONGITUDINAL = {
"design_profiles": [
{"samples": [{"chainage_m": float(c), "elevation_m": 99.8} for c in range(0, 201, 20)]}
]
}
def _write_site(root: Path) -> None:
(root / "B05_Profile" / "route").mkdir(parents=True, exist_ok=True)
(root / "B05_Profile" / "route" / "structures.json").write_text(
json.dumps(
{
"revision": 1,
"structures": [
{
"structure_id": "sp-1",
"type_id": "spoil_bank",
"placement": "site",
"chainage_m": 120.0,
"options": {"capacity_m3": 400.0, "side": "좌"},
}
],
},
ensure_ascii=False,
),
encoding="utf-8",
)
def _leftover() -> dict:
"""옛 저장분 꼴 — 사토장 몫 1 ㎡ 를 노선 성토에서 뺀 채 `spoil_fill_*` 가 남음."""
design = _plain()
return {
**design,
"fill_area_m2": round(design["fill_area_m2"] - 1.0, 4),
"spoil_fill_area_m2": 7.0,
"spoil_fill_side": "left",
"spoil_fill_width_m": 3.0,
"spoil_fill_line": [{"offset_m": 3.0, "elevation_m": 99.0}],
"spoil_fill_replaced_fill_m2": 1.0,
"spoil_fill_capacity_m3": 400.0,
"spoil_fill_structure_id": "sp-1",
}
def test_설계_결과에_사토_칸_없음() -> None:
assert not [key for key in _plain() if key.startswith("spoil_fill")]
def test_사토장이_놓여도_저장_재계산이_사토_단면을_안_세움(tmp_path: Path) -> None:
_write_site(tmp_path)
sections = [
{"chainage_m": c, "samples": _samples(), "design": _plain()} for c in (100.0, 120.0, 140.0)
]
enforce_design_lines(_LONGITUDINAL, sections, tmp_path)
_enforce_stored_designs(_LONGITUDINAL, sections, tmp_path, None)
for section in sections:
assert not [key for key in section["design"] if key.startswith("spoil_fill")]
def test_옛_사토_값은_저장_한_번에_지워지고_성토_돌아옴(tmp_path: Path) -> None:
_write_site(tmp_path)
plain_fill = _plain()["fill_area_m2"]
assert plain_fill > 1.0 # 성토가 실제로 서는 지반이라야 「돌아옴」이 뜻을 가짐
sections = [{"chainage_m": 120.0, "samples": _samples(), "design": _leftover()}]
assert enforce_design_lines(_LONGITUDINAL, sections, tmp_path) == 1
design = sections[0]["design"]
assert not [key for key in design if key.startswith("spoil_fill")]
assert design["fill_area_m2"] == pytest.approx(plain_fill, abs=1e-6)