fix(B06): 유입 하강을 유출 수용 가능 여부로 제한 + 계산은 전체 샘플 사용

- 유입이 유출보다 높아야 하므로 유입을 내리면 유출도 따라 내려간다. 유출이
  원지반에 묻히고 3도 절토선이 지반과 다시 못 만나는 높이면 **유입도 그만큼
  못 내려간다**(placeInletWall의 outletGuard, 아래 방향만 되돌림)
- 횡단 카드의 배수관 기하 계산 입력을 표시 반폭으로 자른 샘플 → **전체 샘플**로
  변경(2026-08-22 사용자 확정: 표시 반폭은 보기용, 계산은 계산용 전 구간)
- 유입 배치 로직을 placeInletWall(Solve)로 이전

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-22 16:00:40 +09:00
co-authored by Claude Opus 5
parent 8be67485be
commit 7cbfa475a6
3 changed files with 92 additions and 3 deletions
@@ -63,6 +63,7 @@ import {
designInterpolator,
intersect,
slopeToeOffset,
placeInletWall,
placePipeWall,
slopeLengthAlong,
STRAY_LIMIT_M,
@@ -205,7 +206,8 @@ export function computeCulvertLayout(
inletAutoOffset = inletOptions.revetAutoOffset;
// 4축 배치는 공용 풀이(placePipeWall — Solve, 700줄 제한): 좌우 = 노견 연장
// 평행이동, 상하 = 성토선 대각, 위 한계 = 최소 성토고·토피 상한.
const placed = placePipeWall({
// 유입을 내리면 유출도 따라 내려간다 — 유출이 못 받으면 유입도 못 내려간다(가드).
const placed = placeInletWall({
autoOffset: inletAutoOffset,
outward: inletInfo.outward,
height: inletWallSpec.height,
@@ -215,7 +217,13 @@ export function computeCulvertLayout(
adjust: adjInlet,
groundAt,
limitOffset: inletInfo.limit,
requireCrossing: false,
outletGuard: {
edge: outletInfo.edge,
outward: outletInfo.outward,
height: outletWallSpec.height,
toeOffset: slopeToeOffset(designAt, groundAt, outletInfo.edge.offset_m, outletInfo.limit),
limitOffset: outletInfo.limit,
},
});
appliedAdjust.inlet.x = placed.x;
appliedAdjust.inlet.d = placed.d;
@@ -413,3 +413,82 @@ export function placePipeWall(input: {
invert: topElevation - input.height,
};
}
/**
* 유입 invert를 그 높이로 내렸을 때 **유출 벽이 성립하는가**(2026-08-22 사용자 확정).
* 유입이 유출보다 높아야 하므로 유입을 내리면 유출도 따라 내려간다 — 그런데 유출이
* 원지반에 묻히고 3도 절토선이 지반과 다시 만나지 못하면 그 자리는 둘 수 없다.
* 이 경우 **유입도 더 내려가면 안 된다**(종전에는 유입만 내려가 유출이 깨졌다).
*/
export function outletReceivable(input: {
inletElevation: number;
edge: { offset_m: number; elevation_m: number };
outward: number;
height: number;
toeOffset: number;
limitOffset: number;
groundAt: (offset: number) => number;
}): boolean {
const invertAt = (offset: number): number =>
Math.min(input.groundAt(offset), input.inletElevation);
const auto =
minShoulderWallOffset(
input.edge,
input.outward,
input.height,
invertAt,
input.toeOffset,
input.limitOffset,
) ?? input.toeOffset;
const invert = invertAt(auto);
if (invert >= input.groundAt(auto) - 0.01) return true;
return (
slopedCrossing(
{ offset: auto, elevation: invert },
input.outward,
-PIPE_CONNECT_GRADE,
input.groundAt,
input.limitOffset,
) !== null
);
}
/**
* 유입 기슭막이 4축 배치 — placePipeWall에 **유출 수용 가능성 가드**를 얹은 것.
* 유입을 내리면 유출도 따라 내려가므로(유입 > 유출 조건), 유출이 못 받는 높이면
* 유입도 그만큼 못 내려간다(2026-08-22 사용자 확정).
*/
export function placeInletWall(input: {
autoOffset: number;
outward: number;
height: number;
baseElevation0: number;
edgeElevation: number;
invertCap: number;
adjust: WallAdjust;
groundAt: (offset: number) => number;
limitOffset: number;
/** 유출 쪽 수용 검사 인자 — 없으면 가드 없이 배치한다. */
outletGuard?: {
edge: { offset_m: number; elevation_m: number };
outward: number;
height: number;
toeOffset: number;
limitOffset: number;
};
}): PipeWallPlacement {
const place = (adjust: WallAdjust): PipeWallPlacement =>
placePipeWall({ ...input, adjust, requireCrossing: false });
let placed = place(input.adjust);
const guard = input.outletGuard;
if (!guard) return placed;
const receivable = (invert: number): boolean =>
outletReceivable({ inletElevation: invert, groundAt: input.groundAt, ...guard });
for (let pass = 0; pass < 400 && placed.d > 1e-9 && !receivable(placed.invert); pass += 1) {
placed = place({
...input.adjust,
d: Math.max(0, Math.round((placed.d - 0.05) * 100) / 100),
});
}
return placed;
}
+3 -1
View File
@@ -473,9 +473,11 @@ export function createCrossSectionCard(
toggleArea,
);
// 배수관 세트 기하 계산 + 이동량 되받기(토스트) — 분리 파일(Wire, 700줄 제한).
// 계산은 **표시 반폭으로 자르지 않은 전체 샘플**로 한다(2026-08-22 사용자 확정) —
// 표시 반폭은 보기용이고, 사면 끝·지반 교차 판정은 계산용 전 구간이 필요하다.
const culvertLayout = computeCardCulvert(
section,
sourceSamples,
section.samples,
activeRevet,
revetOffset,
inletStructure,