충돌 풂 — Culvert_Tiers cutBerm = sub7 (lengthM) 꼴 + 91-4 복합경사 제원 · test_79 유출 끝 = 수평공간 없이 바로 절토(89-4) · Culvert_Geom 700줄 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013rJwJMVL4EE31y77TB11AP
144 lines
6.7 KiB
TypeScript
144 lines
6.7 KiB
TypeScript
/* =============================================================================
|
||
* B06_Section_UI_Cross_Culvert_Tiers.ts
|
||
* 배수관 세트 기하(`_Cross_Culvert_Geom`)에서 떼어 낸 **벽 자리 도우미 + 다단 흙막이** 층.
|
||
* 다단 벽은 `buildExtrasAt`(공용 `buildRevetWallGeometry`)이 세우고, 여기서는 유출측과
|
||
* 집수정 계류측 두 채널의 입력을 짜고 면적용(미확정 단 제외) 결과를 함께 돌려준다.
|
||
* ========================================================================== */
|
||
|
||
import type { CrossSection } from "./B06_Section_Api_Fetch";
|
||
import {
|
||
GUARD_CUT_BERM_M,
|
||
REVET_EMBED_DEPTH_M,
|
||
REVET_TRAP_TOP_M,
|
||
} from "./B06_Section_UI_Cross_Culvert_Const";
|
||
import type { OutletExtrasResult } from "./B06_Section_UI_Cross_Culvert_Extra";
|
||
import { buildExtrasAt } from "./B06_Section_UI_Cross_Culvert_Extra";
|
||
import { fillWallBaseWidth } from "./B06_Section_UI_Cross_Culvert_Solve";
|
||
import type { OffsetPoint, WallAdjust, WallLayout } from "./B06_Section_UI_Cross_Culvert_Types";
|
||
import { outlineLeanOf } from "./B06_Section_UI_Cross_Lean";
|
||
import { structureCutSpec } from "./B06_Section_UI_Cross_Structure_Cut";
|
||
|
||
// d의 0점 = **성토선 길이 0 지점**(벽 상단 = 노견 — 2026-08-23 사용자 확정).
|
||
// 그 자리(하단선 중점)는 이음선 상단점이 노견 끝에 오는 offset이고, 기본 자리는
|
||
// 그 점 자체다 · 손으로 x 를 넣은 벽만 경사길이 4m 지점(`pipeWallDefaultD` · 79-5 · 79b).
|
||
export const slopeZeroAnchor = (
|
||
edge: { offset_m: number },
|
||
outward: number,
|
||
wallHeight: number,
|
||
lean: number,
|
||
): number => edge.offset_m + outward * (fillWallBaseWidth(wallHeight, lean) / 2 - REVET_TRAP_TOP_M);
|
||
|
||
/** 유출 관 하단 끝점 목표 = 벽 바닥 기준 0.5m 상단(기준선)과 **전면 경사선의
|
||
* 교차점**(2026-08-22 사용자 ① — 성토부선 시작 규칙과 같은 자리). */
|
||
export const outletPipeEnd = (wall: WallLayout): OffsetPoint => {
|
||
// 기준 = 바닥 +0.5(= 관 invert 자리 — 2026-08-23부터 바닥은 invert−0.5 고정).
|
||
const reference = wall.bottomBack.elevation + REVET_EMBED_DEPTH_M;
|
||
return {
|
||
offset:
|
||
wall.points[2].offset + wall.outward * wall.lean * (wall.topJoint.elevation - reference),
|
||
elevation: reference,
|
||
};
|
||
};
|
||
|
||
// 다단 기슭막이의 성토부선까지 트림에 넣는다 — 넣지 않으면 단을 올려도 폐회로가 그대로라
|
||
// **물량이 안 바뀐다**(2026-09-07 사용자 확정). 화면이 그리는 선(`outletFill.segments`)과
|
||
// 같은 선을 면적도 보게 맞춘다 — 그리지 않는 `cut` 갈래(벽이 원지반에 묻힌 자리)는 뺀다.
|
||
// 세월교 · 박스 흙막이(`withCut`)는 수평공간 뒤 절토선을 그리므로 넣음(79-7).
|
||
export const drawnFillPoints = (result: OutletExtrasResult, withCut = false): OffsetPoint[] =>
|
||
result.segments
|
||
.filter((segment) => withCut || segment.kind !== "cut")
|
||
.flatMap((segment) => segment.points);
|
||
|
||
interface SideInfo {
|
||
outward: number;
|
||
limit: number;
|
||
}
|
||
|
||
/** 다단 흙막이 두 채널 — 유출측(`extras`)과 집수정 계류측·독립 기슭막이 유입측(`basinExtras`). */
|
||
export function buildCulvertTiers(input: {
|
||
section: CrossSection;
|
||
outletStart: OffsetPoint | null;
|
||
outletBottom: number;
|
||
basinStart: OffsetPoint | null;
|
||
basinBottom: number;
|
||
outletInfo: SideInfo;
|
||
inletInfo: SideInfo;
|
||
groundAt: (offset: number) => number;
|
||
extras: WallAdjust[];
|
||
basinExtras: WallAdjust[];
|
||
outletForm: string;
|
||
inletForm: string;
|
||
equalize: boolean;
|
||
}): {
|
||
extras: OutletExtrasResult;
|
||
basinExtras: OutletExtrasResult;
|
||
extrasForArea: OutletExtrasResult;
|
||
basinExtrasForArea: OutletExtrasResult;
|
||
} {
|
||
const { section, groundAt } = input;
|
||
const culvert = section.culvert;
|
||
// 다단 벽 기울기 — 같은 측점·같은 설치 측 규칙으로 높이마다 표준경사(형태 무관 · B08 은 다단을 안 셈).
|
||
const extraLean = (form: string, pureHeightM: number): number =>
|
||
outlineLeanOf({
|
||
form,
|
||
height_m: pureHeightM,
|
||
section_mode: section.design?.section_mode,
|
||
side: culvert?.hidden_pipe ? culvert.inlet.face_side : null,
|
||
});
|
||
// 세월교 · 박스 흙막이 끝 절토 = 컨테이너 수평공간 뒤 절토 경사(79-7) · 배관은 종전(3도 선).
|
||
const cutBerm = (lengthM: number) =>
|
||
culvert?.body
|
||
? { lengthM: Math.max(lengthM, 0), cut: structureCutSpec(section.design) }
|
||
: undefined;
|
||
// 성토부선 + 다단 기슭막이(2026-08-22 — 보호공 삭제, 윗면 선만 성토부선으로).
|
||
// 유출측과 **집수정 계류측**이 같은 체계를 쓴다: 5m 넘으면 다단을 둘 수 있다.
|
||
const outletInput = {
|
||
cutBerm: cutBerm(0), // 유출 수평공간 없음 — 끝이 원지반에 묻히면 바로 절토(89-4)
|
||
startBottomElevation: input.outletBottom,
|
||
outward: input.outletInfo.outward,
|
||
groundAt,
|
||
limitOffset: input.outletInfo.limit,
|
||
adjusts: input.extras,
|
||
ownerForm: input.outletForm,
|
||
equalize: input.equalize,
|
||
leanFor: extraLean,
|
||
};
|
||
const extras = buildExtrasAt(input.outletStart, outletInput);
|
||
// 독립 기슭막이(관 숨김)는 집수정이 없어 이 채널이 **유입측 벽의 성토부선·다단**이다 —
|
||
// 유출측(`extras`)과 같은 시작점(관 하단 꼭짓점)·같은 `bextra` 키(2026-08-29 사용자).
|
||
const basinInput = {
|
||
cutBerm: cutBerm(culvert?.inlet.revet_berm_m ?? GUARD_CUT_BERM_M),
|
||
startBottomElevation: input.basinBottom,
|
||
outward: input.inletInfo.outward,
|
||
groundAt,
|
||
limitOffset: input.inletInfo.limit,
|
||
adjusts: input.basinExtras,
|
||
ownerForm: input.inletForm,
|
||
equalize: false,
|
||
leanFor: extraLean,
|
||
};
|
||
const basinExtras = buildExtrasAt(input.basinStart, basinInput);
|
||
/** ⭐ 면적용 다단 — **미확정 단(높이 안 적음)부터 아래는 없는 것**으로 봄(2026-09-14 브레인 판정
|
||
* 「미확정 벽은 성토도 안 깎음 · 벽 금액과 성토 감소가 함께」). 그림은 그대로 다 그림.
|
||
* B08 도 첫 미확정 단 아래는 미확정으로 셈(`facility_structures`) — 두 곳이 같은 선에서 끊김. */
|
||
const confirmedOnly = (
|
||
built: OutletExtrasResult,
|
||
start: OffsetPoint | null,
|
||
channel: typeof outletInput,
|
||
): OutletExtrasResult => {
|
||
const firstUnset = built.appliedAdjusts.findIndex((applied) => applied.h == null);
|
||
if (firstUnset < 0) return built;
|
||
return buildExtrasAt(start, {
|
||
...channel,
|
||
adjusts: channel.adjusts.slice(0, firstUnset),
|
||
equalize: false,
|
||
});
|
||
};
|
||
return {
|
||
extras,
|
||
basinExtras,
|
||
extrasForArea: confirmedOnly(extras, input.outletStart, outletInput),
|
||
basinExtrasForArea: confirmedOnly(basinExtras, input.basinStart, basinInput),
|
||
};
|
||
}
|