서버 Node 가 기준벽 역할별 넓이를 design.wall_fill_overlap 에 남기고 B08 이 다단 목록 통(base 표시 칸)으로 읽어 기준벽 줄 비고에 붙임 · 호출부(Router_Material) 안 늘림 · 936be972 빈 저장: 관 9 곳 유출 벽 258.12 1.417 · 720 1.403 · 804.18 1.166 · 982.64 0.807 · 620 0.136 · 440 0.046 · 533.98 0.004 · 85.05/900 0㎡ · 이 프로젝트 기준벽은 모두 미확정(금액 밖)이라 비고 안 뜸 · 벽 칸을 적으면 「1.42㎡ × 10m ≈ 14.2㎥」 · 금액 변화 0 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
171 lines
7.2 KiB
Python
171 lines
7.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""다단 추가 기슭막이도 수량이 섬 — ④ (2026-09-14 브레인 판정 「수량이 통째로 빠지는 것」).
|
|
|
|
앞서 B06 횡단도는 다단 벽(`design.extra_wall_counts` · `revet_adjust.extra*` · `extra_spans`)을
|
|
그리고 면적에도 넣었는데, B08 전개는 관 유입·유출 기준벽만 셈 → 다단 벽 돌쌓기·터파기가 한 줄도 안 섬.
|
|
|
|
길 — 실제로 **선** 단 수·높이는 지형이 정하므로(요청보다 적게 설 수 있음) 서버 Node 재계산이
|
|
관 연장처럼 「선 다단 벽 목록」(`design.extra_walls`)을 소유 측점에 남기고, B08 이 그 목록으로 줄을 세움.
|
|
값이 없는 다단(높이를 안 적어 기본 1.5m 로 지반에 맞춰 그린 단)은 **미확정·금액 밖** 규칙 그대로.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
if str(ROOT) not in sys.path:
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from B08_Quantity.B08_Quantity_Engine_Pipe import ( # noqa: E402
|
|
extra_walls_from_designs,
|
|
facility_structures,
|
|
)
|
|
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import build_table # noqa: E402
|
|
|
|
LAYOUTS = (ROOT / "B06_Section" / "B06_Section_Structure_Layouts.ts").read_text(encoding="utf-8")
|
|
NODE = (ROOT / "B06_Section" / "B06_Section_Server_Calc_Node.ts").read_text(encoding="utf-8")
|
|
PREBUILD = (ROOT / "B06_Section" / "B06_Section_Server_Calc_Prebuild.py").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
|
|
WALLS = [
|
|
{
|
|
"key": "extra0",
|
|
"side": "outlet",
|
|
"form": "돌쌓기(메)",
|
|
"height_m": 1.8,
|
|
"height_set": True,
|
|
"form_set": True,
|
|
"before_m": 4.0,
|
|
"after_m": 4.0,
|
|
},
|
|
{
|
|
"key": "extra1",
|
|
"side": "outlet",
|
|
"form": "돌쌓기(메)",
|
|
"height_m": 1.3,
|
|
"height_set": False,
|
|
"form_set": False,
|
|
"before_m": 5.0,
|
|
"after_m": 5.0,
|
|
},
|
|
]
|
|
POINT = {
|
|
"chainage_m": 85.05,
|
|
"options": {
|
|
"pipe_diameter_mm": 1000,
|
|
"outlet_revet_form": "돌쌓기(메)",
|
|
"outlet_revet_height_m": 2.0,
|
|
"outlet_revet_length_m": 10,
|
|
"inlet_revet_form": "돌쌓기(찰)",
|
|
"inlet_revet_height_m": 2.0,
|
|
"inlet_revet_length_m": 10,
|
|
"revet_foundation": "기초유",
|
|
},
|
|
}
|
|
|
|
|
|
def _tiers(rows: list[dict]) -> list[dict]:
|
|
return [row for row in rows if "다단" in str(row.get("attachment_label") or "")]
|
|
|
|
|
|
def test_설계에서_다단_목록을_측점별로_읽는다() -> None:
|
|
designs = [
|
|
{"chainage_m": 85.0, "design": {"extra_walls": WALLS}},
|
|
{"chainage_m": 140.0, "design": {"cut_area_m2": 1.0}},
|
|
]
|
|
assert extra_walls_from_designs(designs) == {85.0: WALLS}
|
|
|
|
|
|
def test_선_다단_벽마다_기슭막이_줄이_선다() -> None:
|
|
rows = facility_structures([POINT], {85.0: WALLS})
|
|
tiers = _tiers(rows)
|
|
assert [row["attachment_label"] for row in tiers] == [
|
|
"유출측 다단 기슭막이 1단",
|
|
"유출측 다단 기슭막이 2단",
|
|
]
|
|
first, second = tiers
|
|
assert first["type_id"] == "revetment"
|
|
assert first["options"]["height_m"] == 1.8 and first["options"]["form"] == "돌쌓기(메)"
|
|
assert (first["start_m"], first["end_m"]) == (85.05 - 4.0, 85.05 + 4.0)
|
|
assert first["options"]["foundation"] == "기초유" # 기준벽과 같은 기초
|
|
assert first["unconfirmed"] == ""
|
|
# 높이를 안 적은 단 — 줄은 서되 미확정
|
|
assert "다단 높이를 안 적음" in second["unconfirmed"]
|
|
|
|
|
|
def test_다단_줄이_원단위와_금액_합에_든다() -> None:
|
|
table = build_table(facility_structures([POINT], {85.0: WALLS}), {"revetment": "기슭막이"}, {})
|
|
tiers = [s for s in table["structures"] if "다단" in s["name"]]
|
|
assert len(tiers) == 2
|
|
assert tiers[0]["components"] and not tiers[0]["unconfirmed"]
|
|
assert tiers[1]["unconfirmed"]
|
|
|
|
|
|
def test_윗단이_미확정이면_아랫단도_미확정() -> None:
|
|
"""면적은 첫 미확정 단부터 아래를 없는 것으로 봄(B06) — B08 도 같은 선에서 끊어야 성토·벽이 함께 움직임."""
|
|
walls = [
|
|
dict(WALLS[1], key="extra0"),
|
|
dict(WALLS[0], key="extra1"),
|
|
] # 1단 미확정 · 2단 높이 적음
|
|
tiers = _tiers(facility_structures([POINT], {85.0: walls}))
|
|
assert "다단 높이를 안 적음" in tiers[0]["unconfirmed"]
|
|
assert "윗단(1단)이 미확정" in tiers[1]["unconfirmed"]
|
|
|
|
|
|
def test_미확정_단은_성토를_안_깎는다() -> None:
|
|
"""2026-09-14 브레인 판정 — 미확정 벽이 성토만 깎으면 「벽도 성토도 없는 빈 자리」가 생김."""
|
|
geom = (ROOT / "B06_Section" / "B06_Section_UI_Cross_Culvert_Geom.ts").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
assert "extendTrimSlope(drawnFillPoints(extrasForArea)" in geom
|
|
assert "extendTrimSlope(drawnFillPoints(basinExtrasForArea)" in geom
|
|
assert "applied.h == null" in geom
|
|
|
|
|
|
def test_벽_몸이_성토에도_든_겹침을_사유로_드러냄() -> None:
|
|
"""2026-09-14 브레인 — 폐회로는 구조물 면적을 안 뺌(2026-09-06 확정)이라 벽 몸이 성토에도 셈.
|
|
고치지 않고 사유로: 258.12 실측 1단 벽 몸 1.335㎡ 가 성토 폐회로 안."""
|
|
walls = [dict(WALLS[0], fill_overlap_m2=1.336, before_m=5.0, after_m=5.0)]
|
|
note = " ".join(_tiers(facility_structures([POINT], {85.0: walls}))[0]["notes"])
|
|
assert "성토 면적에도" in note and "1.34㎡" in note and "13.4㎥" in note
|
|
bare = " ".join(_tiers(facility_structures([POINT], {85.0: WALLS[:1]}))[0]["notes"])
|
|
assert "성토 면적에도" not in bare # 값이 없으면(옛 저장본) 지어내지 않음
|
|
|
|
|
|
def test_서버가_벽_몸_겹침을_잰다() -> None:
|
|
assert "wallBodyInFillM2(" in LAYOUTS and "fill_overlap_m2" in LAYOUTS
|
|
|
|
|
|
def test_관_기준벽도_겹침_사유가_뜬다() -> None:
|
|
"""2026-09-14 브레인 ㉡ — 같은 겹침이 관 기준벽에도 있음. 다단에만 뜨면 「다단만 문제」로 읽힘.
|
|
258.12 실측 유출 벽 몸 1.417㎡ 가 성토 폐회로 안."""
|
|
designs = [
|
|
{"chainage_m": 85.0, "design": {"extra_walls": [], "wall_fill_overlap": {"outlet": 1.417}}}
|
|
]
|
|
rows = facility_structures([POINT], extra_walls_from_designs(designs))
|
|
by_label = {
|
|
row["attachment_label"]: " ".join(row["notes"])
|
|
for row in rows
|
|
if row.get("notes") is not None
|
|
}
|
|
outlet = next(text for label, text in by_label.items() if "유출" in label)
|
|
inlet = next(text for label, text in by_label.items() if "유입" in label)
|
|
assert "성토 면적에도" in outlet and "1.42㎡" in outlet and "14.2㎥" in outlet
|
|
assert "성토 면적에도" not in inlet # 잰 값이 없는 벽엔 지어내지 않음
|
|
assert not _tiers(rows) # 기준벽 값이 다단 줄로 새지 않음
|
|
assert "wall_fill_overlap" in LAYOUTS and '"wall_fill_overlap"' in PREBUILD
|
|
|
|
|
|
def test_목록이_없으면_종전과_같다() -> None:
|
|
assert not _tiers(facility_structures([POINT]))
|
|
assert not _tiers(facility_structures([POINT], {}))
|
|
|
|
|
|
def test_서버_재계산이_선_다단_목록을_남긴다() -> None:
|
|
assert "export function extraWallRows" in LAYOUTS
|
|
assert "extraWallRows(sections)" in NODE and "extra_walls" in NODE
|
|
assert '"extra_walls"' in PREBUILD
|