feat(공용): 구조물 자리의 성토/절토 판정 한 벌 + 전면 기울기 범위 안내

품셈 표준경사 표가 높이 × 메/찰 × **성토/절토** 로 갈리는데 성절토만 없었다.
새 입력을 만들지 않고 이미 저장되는 두 값으로 가린다 —
`design.section_mode` + 구조물 `options.side`.

- `common_util_structure_face_role.structure_face_role()` — ("성토"|"절토"|None, 까닭 문구).
  ⚠ 못 가르면 **None**. 성토로 눅이지 않는다 — 받는 쪽이 근거 없음을 알아야 한다.
  예외 하나: `both_cut` + 「자동(성토 쪽)」은 세울 성토면이 없어 근거 없음.
  판정을 두 벌로 짜면 그 예외에서 갈리므로 여기 하나만 둔다(CLAUDE.md 5장).
  파이썬 단독 — 읽는 쪽이 B08 뿐이다. 화면이 쓰게 되면 그때 TS 짝·거울 시험을 붙일 것.
- 전면 기울기 칸: 표 범위(0.20~0.50) 밖이면 **막지 않고 알리기만** 한다.
  실무 도면이 S0.7·S0.8 을 쓴다 — 막으면 실물이 안 들어간다.

시험 14건(네 단면유형 × 좌/우 여덟 · 자동 셋 · 모르는 값 · 옛 영문 표기 · 문구).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-08 20:21:12 +09:00
co-authored by Claude Opus 5
parent ebdf2988e1
commit e29f55782e
3 changed files with 83 additions and 0 deletions
@@ -0,0 +1,61 @@
"""구조물이 선 자리가 **성토면인가 절토면인가** — 판정 한 벌.
왜 있나(2026-09-09) — 품셈 표준경사 표가 **높이 × 메/찰 × 성토/절토** 셋으로 갈리는데,
앞 둘은 구조물 제원에 있고 **성절토만 없었다**. 그 값은 횡단 설계가 아는 것이라 B06 이
내주기로 했고, **새 입력을 만들지 않고** 이미 저장되는 두 값으로 가린다:
design.section_mode left_cut · right_cut · both_cut · both_fill
구조물 options.side "자동(성토 쪽)" · "" · ""
판정이 두 곳에 두 벌로 짜이면 `both_cut` + 「자동」의 예외에서 갈린다 — 그래서 여기 하나만
둔다(CLAUDE.md 5장 「코드는 한 벌」). **파이썬 단독**이다: 읽는 쪽이 B08 수량뿐이고 브라우저는
이 판정을 쓰지 않는다. 화면이 쓰게 되면 그때 TS 짝을 만들고 거울 시험을 붙일 것.
⚠ **못 가르면 `None` 을 돌려준다.** 성토로 눅여 돌려주지 않는다 — 받는 쪽이 「근거가 없다」는
사실을 알아야 임의값이 금액으로 굳지 않는다(측구 토사/암 분리와 같은 태도).
"""
from __future__ import annotations
FILL = "성토"
CUT = "절토"
#: 단면유형 → (좌측 역할, 우측 역할). 좌 = +offset, 우 = offset (B06 규약).
_MODE_ROLES: dict[str, tuple[str, str]] = {
"left_cut": (CUT, FILL),
"right_cut": (FILL, CUT),
"both_cut": (CUT, CUT),
"both_fill": (FILL, FILL),
}
#: 설치 측 표기 — 레지스트리 선택지와 옛 저장분(영문)을 함께 받는다.
_LEFT = {"", "left", "L"}
_RIGHT = {"", "right", "R"}
_AUTO = {"자동(성토 쪽)", "자동", "auto", ""}
def structure_face_role(section_mode: str | None, side: str | None) -> tuple[str | None, str]:
"""(`"성토"` | `"절토"` | `None`, 까닭 문구)를 돌려준다.
까닭 문구는 화면 근거 줄에 그대로 실을 수 있는 한 줄이다
(예: `right_cut · 좌측 → 성토면`).
"""
mode = (section_mode or "").strip()
roles = _MODE_ROLES.get(mode)
if roles is None:
return None, f"단면유형을 알 수 없음({section_mode!r}) — 성절토를 가를 근거 없음"
left_role, right_role = roles
picked = (side or "").strip()
if picked in _LEFT:
return left_role, f"{mode} · 좌측 → {left_role}"
if picked in _RIGHT:
return right_role, f"{mode} · 우측 → {right_role}"
if picked in _AUTO:
# 「자동(성토 쪽)」은 성토면에 세운다는 뜻이다 — 그런데 양쪽이 다 절토면
# 세울 성토면이 없어 어느 쪽인지 정할 근거가 없다. 임의로 몰지 않는다.
if left_role == CUT and right_role == CUT:
return None, f"{mode} · 자동(성토 쪽)인데 성토면이 없음 — 가를 근거 없음"
return FILL, f"{mode} · 자동(성토 쪽) → 성토면"
return None, f"설치 측을 알 수 없음({side!r}) — 성절토를 가를 근거 없음"