BOX암거를 세월교와 같은 계류 방향 절단면으로 그리고, 3D는 속이 빈 서피스 셸로 만든다. 관통 컷·중공 튜브는 배수관 세트와 세월교에도 함께 적용한다. B06 횡단도 - `_box_set()` — 내공 폭·높이(B05 옵션), 부재 두께 세월교 승계(측벽 0.2·상하판 0.3), 복토 0.5m(별표2 교차 참조), 날개벽 투영 저판 연장 - 상판 윗면 = 노면 − 복토, 구체는 수평 설치(교본 3장). 계류 하상과의 고저차는 툴팁 표기 - 구체가 노면 아래 묻히므로 계획선은 자르지 않는다(세월교와 다른 점) 3D - 로프트가 **링별 폴리곤**을 받는다 — 구조물을 위·아래 조각으로 갈라 링마다 틈을 벌려 빈 공간을 만든다. 틈 0이면 속 찬 단면 그대로라 토폴로지가 유지된다 - BOX = 내공 구간만 틈을 벌려 측벽이 저절로 생기는 셸 + 날개벽 4매(날개 축 프레임) - 관통 보어 = 링 y에서 틈 높이 2·√(r²−(y−y₀)²) → 배관 외측 기준 원형 구멍. 기슭막이·집수정·세월교 측벽에 적용 - 배관은 중공 튜브(바깥·안쪽 원통 + 양 끝 고리)로 내부 유로를 보인다 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
64 lines
2.8 KiB
TypeScript
64 lines
2.8 KiB
TypeScript
/* =============================================================================
|
|
* B06_Section_UI_Cross_View_Ford.ts
|
|
* 횡단 카드 ↔ **세월교 조정창** 배선 — 카드 렌더러(`_UI_Cross_View.ts`)에서 700줄
|
|
* 제한으로 분리했다(2026-08-25). 조정창이 부르는 동작을 제어기로 넘기는 얇은 층이고,
|
|
* 기하나 그리기는 하지 않는다.
|
|
* ========================================================================== */
|
|
|
|
import type { CrossSection } from "./B06_Section_Api_Fetch";
|
|
import type { FordPanelDeps, FordControl } from "./B06_Section_UI_Cross_Ford_Panel";
|
|
import type { FordLayout, FordWallRole } from "./B06_Section_UI_Cross_Ford";
|
|
|
|
/** 조정창 배선에 필요한 카드 상태. 계산 결과는 그릴 때마다 바뀌므로 함수로 받는다. */
|
|
export interface FordPanelContext {
|
|
section: CrossSection;
|
|
ford: FordControl;
|
|
/** 마지막 계산의 측벽 높이(m) — 높이 조작의 시작값. */
|
|
heightFor: (role: FordWallRole) => number;
|
|
/** 마지막 계산의 바닥판 길이(m). */
|
|
slabLengthM: () => number;
|
|
close: () => void;
|
|
}
|
|
|
|
/** 화면 좌(◀) 방향을 벽 기준 바깥 부호로 환산한다. 유입 = 상단측. */
|
|
function outwardOf(section: CrossSection, role: FordWallRole): number {
|
|
return ((section.uphill_side ?? "left") === "left") === (role === "inlet") ? 1 : -1;
|
|
}
|
|
|
|
export function fordPanelDeps(context: FordPanelContext): FordPanelDeps {
|
|
const { section, ford } = context;
|
|
const chainage = section.chainage_m;
|
|
return {
|
|
adjustFor: (role) => ford.adjustFor(chainage)[role],
|
|
heightFor: context.heightFor,
|
|
nudgeHeight: (role, deltaM) =>
|
|
ford.update(chainage, role, { heightM: context.heightFor(role) + deltaM }),
|
|
nudge: (role, screenDeltaM) =>
|
|
ford.update(chainage, role, {
|
|
lateralM: ford.adjustFor(chainage)[role].lateralM + screenDeltaM * outwardOf(section, role),
|
|
}),
|
|
nudgeSlope: (role, deltaM) =>
|
|
ford.update(chainage, role, {
|
|
slopeM: ford.adjustFor(chainage)[role].slopeM + deltaM,
|
|
}),
|
|
reset: (role) => ford.reset(chainage, role),
|
|
pipeDiameterMm: () => Math.round((section.ford?.diameter_m ?? 1) * 1000),
|
|
setPipeDiameterMm: (value) => ford.setPipe(chainage, { pipe_diameter_mm: value }),
|
|
pipeCount: () => section.ford?.pipe_count ?? 1,
|
|
setPipeCount: (value) => ford.setPipe(chainage, { pipe_count: value }),
|
|
slabLengthM: context.slabLengthM,
|
|
close: context.close,
|
|
};
|
|
}
|
|
|
|
/** 조정창이 쓸 세월교 카드 상태 — 마지막 기하 결과에서 뽑는다(카드 렌더러 700줄 분리). */
|
|
export function fordCardState(layout: FordLayout): {
|
|
slabLengthM: number;
|
|
heights: Map<FordWallRole, number>;
|
|
} {
|
|
return {
|
|
slabLengthM: layout.slabLengthM,
|
|
heights: new Map(layout.sides.map((side) => [side.role, side.heightM])),
|
|
};
|
|
}
|