- 관 유입·유출 흙막이 · 추가 흙막이 · 사면안정 흙막이 · 옹벽 모두 공용 buildRevetWallGeometry - 외곽 기울기 형태 무관(outlineLeanOf) — 형태는 안 무늬만 - 형태별 높이 한도(메 2.0 · 찰 3.0 · 콘크리트 5.0) 자르기 · 경고 삭제 — 입력 높이 그대로 - 추가 흙막이 원지반 맞춤 늘이기 삭제(돌쌓기(메) 원지반 따라 연장 흠) - 벽 윗면 노면 위 금지 — 넘으면 노면에서 멈춤 - 다단 묶음 _Cross_Culvert_Tiers 로 분리(Geom 700줄 이하) - 시험 test_b06_wall_shape_unified 추가 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYJJRCfHfdCGNhmXTjQKV7
99 lines
4.6 KiB
Python
99 lines
4.6 KiB
Python
"""횡단 벽 형상 한 벌 — 관 유입·유출 흙막이 · 추가 흙막이 · 사면안정 흙막이 · 옹벽.
|
|
|
|
규칙(10-6 사용자):
|
|
① 네 벽 모두 공용 `buildRevetWallGeometry` 로 선다 — 형태는 안 무늬만 바꿈(외곽 같음).
|
|
② 형태별 높이 한도(메 2.0 · 찰 3.0 · 콘크리트 5.0) · 원지반 맞춤 자동 자르기 없음.
|
|
③ 벽 윗면은 노면 위로 올라오지 않음(넘으면 노면에서 멈춤).
|
|
|
|
서버 면적은 같은 TS 를 Node 로 돌리므로(`B06_Section_Server_Calc_Node.ts`) 이 함수가 곧 서버 기하.
|
|
"""
|
|
|
|
import json
|
|
import re
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
B06 = PROJECT_ROOT / "B06_Section"
|
|
TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
|
|
|
|
_RUNNER = """
|
|
import { writeFileSync } from "node:fs";
|
|
import { buildRevetWallGeometry } from "./B06_Section_UI_Cross_Wall.js";
|
|
import { revetWallSpec, REVET_FORMS } from "./B06_Section_UI_Cross_Culvert_Const.js";
|
|
const anchor = { offset: 5, elevation: 100 };
|
|
const outline = (form, role, extra = {}) =>
|
|
buildRevetWallGeometry({ anchor, outward: 1, height: 2.5, material: "dry", role, form, ...extra })
|
|
.points.map((p) => [p.offset, p.elevation]);
|
|
writeFileSync(process.argv[2], JSON.stringify({
|
|
forms: REVET_FORMS.map((form) => outline(form, "outlet")),
|
|
roles: ["inlet", "outlet", "extra"].map((role) => outline("돌쌓기(메)", role)),
|
|
capped: buildRevetWallGeometry({
|
|
anchor, outward: 1, height: 5, material: "dry", role: "outlet", roadElevation: 103,
|
|
}).topJoint.elevation,
|
|
under: buildRevetWallGeometry({
|
|
anchor, outward: 1, height: 2, material: "dry", role: "outlet", roadElevation: 103,
|
|
}).topJoint.elevation,
|
|
dry: revetWallSpec({ revet_form: "돌쌓기(메)" }, { h: 3.0 }, true, 0.3).pureHeight,
|
|
concrete: revetWallSpec({ revet_form: "콘크리트" }, { h: 7.5 }, true, 0.3).pureHeight,
|
|
}));
|
|
"""
|
|
|
|
|
|
@pytest.mark.skipif(not TSC.is_file(), reason="프론트엔드 의존성 미설치")
|
|
def test_벽_외곽_한_벌_높이_입력_그대로_노면_멈춤(tmp_path: Path) -> None:
|
|
out = tmp_path / "js"
|
|
# 형(type) import 가 끌어오는 페이지 파일은 별칭을 못 풀어 오류를 내지만 산출물은 나옴.
|
|
subprocess.run( # noqa: S603 — 고정 실행 파일
|
|
[
|
|
"node",
|
|
str(TSC),
|
|
str(B06 / "B06_Section_UI_Cross_Wall.ts"),
|
|
"--outDir",
|
|
str(out),
|
|
"--module",
|
|
"esnext",
|
|
"--target",
|
|
"es2022",
|
|
"--moduleResolution",
|
|
"bundler",
|
|
"--skipLibCheck",
|
|
"--ignoreConfig",
|
|
],
|
|
cwd=str(PROJECT_ROOT),
|
|
capture_output=True,
|
|
)
|
|
for emitted in out.rglob("*.js"):
|
|
emitted.write_text(
|
|
re.sub(r'(from\s+"\./[^"]+)"', r'\1.js"', emitted.read_text(encoding="utf-8")),
|
|
encoding="utf-8",
|
|
)
|
|
base = next(path.parent for path in out.rglob("B06_Section_UI_Cross_Wall.js"))
|
|
(base / "runner.mjs").write_text(_RUNNER, encoding="utf-8")
|
|
result = tmp_path / "out.json"
|
|
subprocess.run( # noqa: S603
|
|
["node", str(base / "runner.mjs"), str(result)], check=True, capture_output=True
|
|
)
|
|
got = json.loads(result.read_text(encoding="utf-8"))
|
|
|
|
assert all(outline == got["forms"][0] for outline in got["forms"]), "형태마다 외곽이 다름"
|
|
assert all(outline == got["roles"][0] for outline in got["roles"]), "벽 갈래마다 외곽이 다름"
|
|
assert got["capped"] == pytest.approx(103.0), "노면 위로 올라옴"
|
|
assert got["under"] == pytest.approx(102.0), "노면 아래 벽이 잘림"
|
|
assert got["dry"] == pytest.approx(3.0), "돌쌓기(메) 3.0 이 잘림"
|
|
assert got["concrete"] == pytest.approx(7.5), "콘크리트 7.5 가 잘림"
|
|
|
|
|
|
def test_네_벽이_공용_함수로_서고_형태_한도가_없다() -> None:
|
|
for name in ("Culvert_Geom", "Culvert_Extra", "Revetment"):
|
|
source = (B06 / f"B06_Section_UI_Cross_{name}.ts").read_text(encoding="utf-8")
|
|
assert "buildRevetWallGeometry(" in source, f"{name} 가 공용 벽 함수를 안 씀"
|
|
for path in B06.glob("*.ts"):
|
|
source = path.read_text(encoding="utf-8")
|
|
assert "revetHeightLimit" not in source, f"{path.name} 에 형태 높이 한도가 남음"
|
|
assert "materialLimit" not in source, f"{path.name} 에 재질 높이 한도가 남음"
|
|
extra = (B06 / "B06_Section_UI_Cross_Culvert_Extra.ts").read_text(encoding="utf-8")
|
|
assert "fitted" not in extra, "추가 흙막이가 원지반에 맞춰 늘어남"
|