Files
Aislo/B06_Section/B06_Section_UI_Cross_Culvert_Tiers.ts
T
eomsangdonandClaude Opus 5.5 fb3b24f13f fix(section): 횡단 벽 형상 한 벌 · 형태별 높이 한도 · 원지반 맞춤 삭제 · 노면 위 금지(54-42)
- 관 유입·유출 흙막이 · 추가 흙막이 · 사면안정 흙막이 · 옹벽 모두 공용 buildRevetWallGeometry
- 외곽 기울기 형태 무관(outlineLeanOf) — 형태는 안 무늬만
- 형태별 높이 한도(메 2.0 · 찰 3.0 · 콘크리트 5.0) 자르기 · 경고 삭제 — 입력 높이 그대로
- 추가 흙막이 원지반 맞춤 늘이기 삭제(돌쌓기(메) 원지반 따라 연장 흠)
- 벽 윗면 노면 위 금지 — 넘으면 노면에서 멈춤
- 다단 묶음 _Cross_Culvert_Tiers 로 분리(Geom 700줄 이하)
- 시험 test_b06_wall_shape_unified 추가

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYJJRCfHfdCGNhmXTjQKV7
2026-10-06 14:48:53 +09:00

129 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =============================================================================
* B06_Section_UI_Cross_Culvert_Tiers.ts
* 배수관 세트 기하(`_Cross_Culvert_Geom`)에서 떼어 낸 **벽 자리 도우미 + 다단 흙막이** 층.
* 다단 벽은 `buildExtrasAt`(공용 `buildRevetWallGeometry`)이 세우고, 여기서는 유출측과
* 집수정 계류측 두 채널의 입력을 짜고 면적용(미확정 단 제외) 결과를 함께 돌려준다.
* ========================================================================== */
import type { CrossSection } from "./B06_Section_Api_Fetch";
import { 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";
// d의 0점 = **성토선 길이 0 지점**(벽 상단 = 노견 — 2026-08-23 사용자 확정).
// 그 자리(하단선 중점)는 이음선 상단점이 노견 끝에 오는 offset이고, 기본 자리는
// 성토선을 타고 경사길이 4m 내려간 지점(PIPE_WALL_DEFAULT_RUN_M)이다.
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` 갈래(벽이 원지반에 묻힌 자리)는 뺀다.
export const drawnFillPoints = (result: OutletExtrasResult): OffsetPoint[] =>
result.segments.filter((segment) => 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,
});
// 성토부선 + 다단 기슭막이(2026-08-22 — 보호공 삭제, 윗면 선만 성토부선으로).
// 유출측과 **집수정 계류측**이 같은 체계를 쓴다: 5m 넘으면 다단을 둘 수 있다.
const outletInput = {
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 = {
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),
};
}