feat(B06): BOX암거 좌측 폼을 세월교와 같은 규칙으로 연결한다

세월교와 같은 문제가 BOX암거에도 있었다 — 좌측 「구조물 배치」의 본체 규격·날개벽을
바꿔도 도면이 그대로였고, 폼 기본값이 스펙에서 오지 않았으며, 구체를 골라도 좌측
칸이 서지 않았다. `applyPipeOptionsToCache`가 `section.box`를 모르고 즉시 return하던
것이 뿌리다(세월교와 동일).

- `applyBoxFormOptions()` — 폼 옵션(`body_*`·`wing_*`)을 제어기로 보낸다.
  `BoxControl`에 `setBody`·`setWing`을 더했다: 캐시(`section.box`)를 먼저 고치고
  (`span_m`은 백엔드 `_box_set`과 같은 식으로 다시 잡는다) 정본 예약 + 카드 갱신.
- 날개벽 옵션 조립·해석을 `wingOptions()`·`wingPatchFrom()`으로 묶어 세월교와 나눠
  쓴다 — 세월교 쪽 중복 코드가 사라졌다.
- `withBoxSpec()` — 폼 기본값을 `section.box`(내공 폭·높이, 날개벽)에서 읽는다.
- 좌·우 끝을 고르면 폼의 **날개벽(유입)/(유출)** 칸이 선다. 좌·우 ↔ 유입/유출
  매핑은 기하가 날개벽을 고르는 기준(`uphill_side`)과 같다. 조정창은 결국 지우고
  폼 이름(유입/유출)만 쓰기로 한 사용자 확정(2026-08-30)을 따랐다.

구체 길이·표고는 폼에 대응 칸이 없어 조정창 축으로 남는다(본체 높이는 규격이 이미
정한다 — 2026-08-30 사용자).

자체검증(공용 브라우저 5174 + 워크트리 백엔드 8001, 측점 10+0.9 BOX암거):
- tsc --noEmit 통과.
- 구체 선택 시 좌측 `날개벽(유입) (BOX암거)` 칸 강조(수정 전 강조 없음).
- 본체 규격 2.0×2.0 → 3.0×3.0 → 도면 라벨 `BOX 3.0×3.0`, 다시 2.0×2.0 → `BOX
  2.0×2.0`. 한 번 고른 상태에서 연속 조작도 그대로 먹는다. 수정 전에는 라벨이
  5.34m 구체와 함께 전혀 움직이지 않았다.
- 회귀: 세월교 날개 길이 2→4→2에서 조정창 표시가 4.0m→2.0m로 따라온다
  (`wingOptions`/`wingPatchFrom` 공용화 뒤에도 동일).
- 조작값은 원래대로(BOX 2.0×2.0 · 세월교 날개 길이 2m) 되돌려 놓았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-30 13:37:43 +09:00
co-authored by Claude Opus 5
parent 8106b1ed9b
commit 1c9ff90dfd
6 changed files with 157 additions and 17 deletions
+7 -1
View File
@@ -31,7 +31,7 @@ import {
} from "./B06_Section_Api_Fetch";
import { flushPendingStructures } from "../B05_Profile/B05_Profile_Api_Structures";
import { createStationControls } from "./B06_Section_UI_Page_Station_Controls";
import { applyFordFormOptions } from "./B06_Section_UI_Page_Ford_Controls";
import { applyBoxFormOptions, applyFordFormOptions } from "./B06_Section_UI_Page_Ford_Controls";
import { buildCrossPatches } from "./B06_Section_UI_Page_Patches";
import { maxToeFitHalfWidth } from "./B06_Section_UI_Cross_Fit";
import { readAlignmentDraft } from "../B05_Profile/B05_Profile_UI_Profile_Edit";
@@ -202,6 +202,12 @@ export async function renderB06ProfileCross(root: HTMLElement): Promise<void> {
applyFordFormOptions(stationControls.ford, owner.chainage_m, patch);
return;
}
// BOX암거도 스펙 자리가 따로다(`section.box`) — 같은 규칙으로 제어기에 보낸다
// (2026-08-30 사용자: 세월교와 같은 문제).
if (owner.box) {
applyBoxFormOptions(stationControls.box, owner.chainage_m, patch);
return;
}
const culvert = owner.culvert;
if (!culvert) return;
const num = (key: string): number | undefined => {