조정창에서 좌·우 끝을 따로 잡는다 — ◀▶는 구체 길이, ▲▼는 그 끝의 구체 표고를 0.1m씩 움직인다. 좌·우 표고가 달라지면 구체가 기울고, 날개벽 구간 바닥(에이프런)은 각 끝 표고에서 수평을 지킨다(2026-08-25 사용자). - `computeBoxLayout`이 좌·우를 따로 푼다: 끝 표고·길이·성토선·에이프런 - 성토선은 그쪽 표고 기준으로 물매 1:1.2를 지키므로 표고를 내리면 구체가 길어진다 - 조정창 `_Cross_Box_Panel.ts` + 제어 `createBoxControls` + `design.box_adjust` 저장 (세션 → 캐시 → 확정 payload, 세월교와 같은 체계) - 3D: 구체 밖(날개벽 구간)에 서 있던 벽을 없앴다 — 천장 없는 통로가 생기던 자리는 날개벽 몫이다. 이제 상판·구체 저판·측벽 2매·에이프런 2매 + 날개벽 4매로 나뉜다 - 카드 렌더러의 구체 배선(선택 토글·강조·조정창)을 `_Cross_View_Bodies.ts`로 분리, 연동 플래그 세션은 `_Page_Link_Session.ts`로 분리(700줄 제한) 검증(10+0.9): 구체 5.34m·수평 → ◀ 1회 5.44m → ▼ 2회 표고 −0.2m·물매 1:28.4, 에이프런 두 장 모두 수평 유지, ↺ 원복. 3D 솔리드 10개(측벽 링 0.2m). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
64 lines
2.6 KiB
TypeScript
64 lines
2.6 KiB
TypeScript
/* =============================================================================
|
|
* B06_Section_UI_Cross_View_Box.ts
|
|
* 횡단 카드 ↔ **BOX암거 조정창** 배선과 구조물 선택 토글 — 카드 렌더러
|
|
* (`_UI_Cross_View.ts`)에서 700줄 제한으로 분리했다(2026-08-25).
|
|
* 기하나 그리기는 하지 않는다.
|
|
* ========================================================================== */
|
|
|
|
import type { BoxLayout } from "./B06_Section_UI_Cross_Box";
|
|
import type { BoxControl, BoxPanelDeps } from "./B06_Section_UI_Cross_Box_Panel";
|
|
|
|
export interface BoxPanelContext {
|
|
chainageM: number;
|
|
box: BoxControl;
|
|
/** 마지막 계산 결과 — 창이 길이·물매를 읽는다. */
|
|
layout: () => BoxLayout | null;
|
|
close: () => void;
|
|
}
|
|
|
|
export function boxPanelDeps(context: BoxPanelContext): BoxPanelDeps {
|
|
const { chainageM, box } = context;
|
|
return {
|
|
adjustFor: (role) => box.adjustFor(chainageM)[role],
|
|
// 화면 좌(◀) = offset 증가. 좌측 끝은 그대로, 우측 끝은 부호를 뒤집어야 바깥이 된다.
|
|
nudgeLength: (role, screenDeltaM) =>
|
|
box.update(chainageM, role, {
|
|
lengthM: box.adjustFor(chainageM)[role].lengthM + screenDeltaM * (role === "left" ? 1 : -1),
|
|
}),
|
|
nudgeRise: (role, deltaM) =>
|
|
box.update(chainageM, role, { riseM: box.adjustFor(chainageM)[role].riseM + deltaM }),
|
|
reset: (role) => box.reset(chainageM, role),
|
|
bodyLengthM: () => context.layout()?.bodyLengthM ?? 0,
|
|
slopeRatio: () => context.layout()?.slopeRatio ?? null,
|
|
close: context.close,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 구조물 선택 토글 한 벌 — 세월교 측벽·BOX암거 끝이 같은 규칙을 쓴다(2026-08-21 확정
|
|
* 규칙: 구조물 선택과 면적 강조는 배타, 고르면 그 측점 카드도 함께 선택된다).
|
|
*/
|
|
export function structureToggle<T>(deps: {
|
|
current: () => T | null;
|
|
setCurrent: (value: T | null) => void;
|
|
setActive: (value: T | null) => void;
|
|
showPanel: (visible: boolean) => void;
|
|
persist: (value: T | null) => void;
|
|
isCardSelected: () => boolean;
|
|
clearArea: () => void;
|
|
selectCard: () => void;
|
|
}): (value: T) => void {
|
|
return (value: T): void => {
|
|
const wasSelected = deps.isCardSelected();
|
|
const next = deps.current() === value ? null : value;
|
|
deps.setCurrent(next);
|
|
deps.setActive(next);
|
|
deps.showPanel(next !== null);
|
|
deps.persist(next);
|
|
if (next === null) return;
|
|
deps.clearArea();
|
|
// 미선택 카드는 카드 선택만 부른다 — 그 경로가 부모의 면적 강조를 이미 비운다.
|
|
if (!wasSelected) deps.selectCard();
|
|
};
|
|
}
|