feat(B06): 다단 기슭막이 규칙 재정립 — 정확한 1:1.2·매몰 종단·단 수 입력

- 벽 사이 성토사면 = 정확히 1:1.2 — 벽 높이를 자리에서 역산(닫힌식),
  0.1m 눈금 올림 제거(물매 정확 유지 우선)
- 아랫단 상단은 윗단 하단(수평 기초) 관통 금지 — 안쪽 이동 한계
- 다음 단 성토선 시작 = 윗단 하단 +0.5m 수평선 × 전면 경사선(1:0.3) 교차점
  (배관 벽의 관 하단 꼭짓점과 같은 자리)
- 시작점이 원지반 아래(벽 0.5m 이상 매몰)면 성토 불필요 — 다단 종료
- 추가 방식 = 유출 벽 조정창의 단 수 숫자 입력(+/- 버튼 대체),
  지형 허용 단 수 초과 시 토스트로 가능한 단 수 안내 후 되는 만큼만 반영

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-22 13:39:21 +09:00
co-authored by Claude Opus 5
parent 9a58e3b1bd
commit 8167dd23c3
9 changed files with 203 additions and 125 deletions
@@ -33,12 +33,11 @@ export interface StructurePanelDeps {
canNudge: (key: RevetKey) => boolean;
/** 상황에 안 맞는 선택지 숨김(2026-08-22 사용자) — 기하가 판정한 가용성. */
optionsFor: () => { revetAllowed: boolean; basinLUAllowed: boolean };
/** 추가 기슭막이 상태 — 끝 성토부 5m 이상(canAdd)일 때만 +를 보인다. */
/** 다단 기슭막이 상태 — 유출 벽 선택 시 개수 입력 행 표시 판단에 쓴다. */
extraState: () => { canAdd: boolean; count: number };
/** 추가 기슭막이 하나 추가(유출 성토부 끝 구간에). */
addExtra: () => void;
/** 마지막 추가 기슭막이 삭제 — 마지막 벽이 선택된 상태에서만 버튼이 보인다. */
removeExtra: () => void;
/** 다단 기슭막이 단 수 지정(2026-08-22 사용자 — 숫자 입력). 지형이 허락하는
* 단 수보다 크면 기하가 되는 만큼만 세우고 토스트로 알린다. */
setExtraCount: (count: number) => void;
}
export interface StructurePanelHandle {
@@ -86,10 +85,6 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
if (current) run(current);
};
// 추가 기슭막이 +/-(2026-08-22 사용자 — 성토부 5m 이상이면 계단식 추가).
const addButton = makeButton("+", L("B06_Cross_Extra_Add"), () => deps.addExtra());
const removeButton = makeButton("-", L("B06_Cross_Extra_Remove"), () => deps.removeExtra());
const buttons = document.createElement("div");
buttons.className = "b06-structure-panel__buttons";
buttons.append(
@@ -108,10 +103,26 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
L("B06_Cross_Revet_Reset"),
act((key) => deps.reset(key)),
),
addButton,
removeButton,
);
// 다단 기슭막이 단 수 입력(2026-08-22 사용자) — 유출 벽 기준 숫자 입력.
const extraRow = document.createElement("label");
extraRow.className = "b06-structure-panel__struct";
const extraLabel = document.createElement("span");
extraLabel.textContent = L("B06_Cross_Extra_Count");
const countInput = document.createElement("input");
countInput.type = "number";
countInput.min = "0";
countInput.max = "9";
countInput.step = "1";
countInput.className = "b06-structure-panel__count";
countInput.addEventListener("change", () => {
const requested = Math.max(0, Math.min(9, Math.round(Number(countInput.value) || 0)));
countInput.value = String(requested);
deps.setExtraCount(requested);
});
extraRow.append(extraLabel, countInput);
// 유입측 구조물 형식 드롭다운(2026-08-22 사용자) — 자동/기슭막이/집수정 I·ㄴ·ㄷ.
const structureRow = document.createElement("label");
structureRow.className = "b06-structure-panel__struct";
@@ -143,7 +154,7 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
const head = document.createElement("div");
head.className = "b06-structure-panel__head";
head.append(title, closeButton);
root.append(head, value, structureRow, buttons);
root.append(head, value, structureRow, extraRow, buttons);
return {
root,
@@ -176,10 +187,13 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
select.value = current;
}
buttons.classList.toggle("is-hidden", !deps.canNudge(key));
// +는 유출·추가 벽에서 끝 성토부가 5m 이상일 때, -는 마지막 추가 벽에서만.
// 단 수 입력은 **유출 벽에서만** — 성토부가 5m 이상(의무)이거나 이미 단이 있을 때.
const extra = deps.extraState();
addButton.classList.toggle("is-hidden", !(extra.canAdd && (key === "outlet" || isExtra)));
removeButton.classList.toggle("is-hidden", !(isExtra && key === `extra${extra.count - 1}`));
extraRow.classList.toggle(
"is-hidden",
!(key === "outlet" && (extra.canAdd || extra.count > 0)),
);
countInput.value = String(extra.count);
const shift = deps.shiftFor(key);
// 자동 자리 기준 이동량 — 0이면 "자동"으로 적어 손을 안 댔음을 바로 알린다.
// 부호(+/−)만 적으면 좌·우 벽에서 어느 쪽인지 읽히지 않아 **안/바깥**으로 적는다.