- 벽 사이 성토사면 = 정확히 1:1.2 — 벽 높이를 자리에서 역산(닫힌식), 0.1m 눈금 올림 제거(물매 정확 유지 우선) - 아랫단 상단은 윗단 하단(수평 기초) 관통 금지 — 안쪽 이동 한계 - 다음 단 성토선 시작 = 윗단 하단 +0.5m 수평선 × 전면 경사선(1:0.3) 교차점 (배관 벽의 관 하단 꼭짓점과 같은 자리) - 시작점이 원지반 아래(벽 0.5m 이상 매몰)면 성토 불필요 — 다단 종료 - 추가 방식 = 유출 벽 조정창의 단 수 숫자 입력(+/- 버튼 대체), 지형 허용 단 수 초과 시 토스트로 가능한 단 수 안내 후 되는 만큼만 반영 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
83 lines
3.7 KiB
TypeScript
83 lines
3.7 KiB
TypeScript
/* =============================================================================
|
|
* B06_Section_UI_Cross_Culvert_Wire.ts
|
|
* 횡단 카드의 배수관 세트 **계산 호출 + 이동량 되받기(토스트)** — Cross_View에서
|
|
* 분리(700줄 제한). 카드가 다시 그려질 때마다 한 번 불린다.
|
|
* ========================================================================== */
|
|
|
|
import type { CrossSection, SectionSample } from "./B06_Section_Api_Fetch";
|
|
import { computeCulvertLayout } from "./B06_Section_UI_Cross_Culvert";
|
|
import type { CulvertLayout, RevetKey } from "./B06_Section_UI_Cross_Culvert";
|
|
import type {
|
|
ExtraWallControl,
|
|
InletStructureControl,
|
|
RevetOffsetControl,
|
|
} from "./B06_Section_UI_Cross_View";
|
|
import { showToast } from "@ui/ui_template_elements";
|
|
import { L } from "./B06_Section_UI_Section_Common";
|
|
|
|
/**
|
|
* 배수관 세트 기하 계산 + 제어 상태 동기화.
|
|
*
|
|
* ① 세션의 이동량(기슭막이·추가 벽)·유입 구조물 선택을 모아 기하를 계산하고,
|
|
* ② 성토부가 짧아져 못 세운 추가 벽은 개수를 잘라 동기화하며(고아 이동량 방지),
|
|
* ③ 요청 이동량이 한계에 잘렸으면 실제 적용값으로 되돌려 담는다 — 안 그러면 눌러도
|
|
* 안 움직이는데 창의 숫자만 계속 커진다(2026-08-21 사용자 지적). 잘린 순간에는
|
|
* **왜 안 움직였는지 토스트**로 알린다(2026-08-22 사용자 — 13+15.7처럼 자동
|
|
* 자리가 이미 안쪽 한계라 ◀가 그대로 먹히지 않는 경우). 조작 중(그 벽이 선택된
|
|
* 상태)일 때만 띄운다 — 리로드로 복원된 옛 세션 값에는 침묵.
|
|
*/
|
|
export function computeCardCulvert(
|
|
section: CrossSection,
|
|
sourceSamples: SectionSample[],
|
|
activeRevet: RevetKey | null,
|
|
revetOffset?: RevetOffsetControl,
|
|
inletStructure?: InletStructureControl,
|
|
extraWalls?: ExtraWallControl,
|
|
): CulvertLayout | null {
|
|
const layout = computeCulvertLayout(
|
|
section,
|
|
sourceSamples,
|
|
revetOffset
|
|
? {
|
|
inlet: revetOffset.shiftFor(section, "inlet"),
|
|
outlet: revetOffset.shiftFor(section, "outlet"),
|
|
extras: Array.from({ length: extraWalls?.countFor(section) ?? 0 }, (_, i) =>
|
|
revetOffset.shiftFor(section, `extra${i}`),
|
|
),
|
|
}
|
|
: undefined,
|
|
inletStructure?.valueFor(section),
|
|
);
|
|
if (!layout) return null;
|
|
if (extraWalls && extraWalls.countFor(section) > layout.extraWalls.length) {
|
|
// 요청 단 수보다 지형이 허락하는 단이 적다(벽이 원지반에 0.5m 이상 묻히면 성토
|
|
// 불필요 — 그 아래 단은 못 세운다). 조작 중일 때만 가능한 단 수를 토스트로 알린다.
|
|
if (activeRevet === "outlet" || activeRevet?.startsWith("extra")) {
|
|
showToast(
|
|
L("B06_Cross_Extra_Limit").replace("{n}", String(layout.extraWalls.length)),
|
|
"info",
|
|
);
|
|
}
|
|
extraWalls.syncCount(section.chainage_m, layout.extraWalls.length);
|
|
}
|
|
if (revetOffset) {
|
|
const roles: Array<[RevetKey, number]> = [
|
|
["inlet", layout.revetShift.inlet],
|
|
["outlet", layout.revetShift.outlet],
|
|
...layout.revetShift.extras.map((applied, i): [RevetKey, number] => [`extra${i}`, applied]),
|
|
];
|
|
for (const [role, applied] of roles) {
|
|
const requested = revetOffset.shiftFor(section, role);
|
|
if (activeRevet === role && Math.abs(requested - applied) > 0.05) {
|
|
// 이동량 부호: + = 계류측 바깥. 요청이 적용보다 작으면 안쪽 요청이 잘린 것.
|
|
showToast(
|
|
L(requested < applied ? "B06_Cross_Revet_Limit_Inward" : "B06_Cross_Revet_Limit_Outward"),
|
|
"info",
|
|
);
|
|
}
|
|
revetOffset.syncShift(section.chainage_m, role, applied);
|
|
}
|
|
}
|
|
return layout;
|
|
}
|