diff --git a/B05_Profile/B05_Profile_UI_Structures_Panel.ts b/B05_Profile/B05_Profile_UI_Structures_Panel.ts index fe1ab070..019232c4 100644 --- a/B05_Profile/B05_Profile_UI_Structures_Panel.ts +++ b/B05_Profile/B05_Profile_UI_Structures_Panel.ts @@ -354,6 +354,22 @@ export function createStructuresSection( read: () => (option.input === "number" ? Number(input.value) || 0 : input.value), isEmpty: () => input.value.trim() === "", }); + // 전면 기울기는 품셈 표준경사 표(0.20~0.50) 밖 값도 받는다 — 실무 도면이 S0.7·S0.8 을 + // 쓴다(2026-09-09 실무 DWG 확인). **막지 않고 알리기만** 한다: 막으면 실물이 안 들어간다. + if (option.key === "face_slope_ratio") { + const warn = (): void => { + const value = Number(input.value); + const outside = + input.value.trim() !== "" && Number.isFinite(value) && (value < 0.2 || value > 0.5); + input.title = outside + ? "품셈 표준경사 표 범위(0.20~0.50) 밖 값입니다 — 근거를 적어 두시기 바랍니다." + : "비워 두면 품셈 표대로 자동 판정합니다."; + input.classList.toggle("is-outside-standard", outside); + }; + warn(); + input.addEventListener("input", warn); + input.addEventListener("change", warn); + } // 길이·기준측점 전/후가 바뀌면 서로 연동하고 측점 범위 표시가 즉시 따라온다 // (범위 계산 타입, 2026-08-19). 전·후는 **나중에 고친 쪽**이 살아남고 반대쪽이 // 길이 − 그 값으로 맞춰진다. 길이를 고치면 나중에 고쳤던 쪽을 지키며 재배분. diff --git a/B05_Profile/B05_Profile_UI_Style_Structures.css b/B05_Profile/B05_Profile_UI_Style_Structures.css index 650db38c..6ddb3807 100644 --- a/B05_Profile/B05_Profile_UI_Style_Structures.css +++ b/B05_Profile/B05_Profile_UI_Style_Structures.css @@ -419,3 +419,9 @@ .b05-structure-section .b05-structure__position-row .b05-route__field { gap: 6px; } + +/* 전면 기울기가 품셈 표준경사 표(0.20~0.50) 밖일 때 — 실무가 S0.7 을 쓰므로 **막지 않고** + 테두리로만 알린다(2026-09-09). 말풍선에 까닭이 들어 있다. */ +.is-outside-standard { + border-color: var(--color-warning, #c98a00); +} diff --git a/common_util/common_util_structure_face_role.py b/common_util/common_util_structure_face_role.py new file mode 100644 index 00000000..85422a1e --- /dev/null +++ b/common_util/common_util_structure_face_role.py @@ -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}) — 성절토를 가를 근거 없음"