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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -473,9 +473,11 @@ export function createCrossSectionCard(
|
||||
toggleArea,
|
||||
);
|
||||
// 배수관 세트 기하 계산 + 이동량 되받기(토스트) — 분리 파일(Wire, 700줄 제한).
|
||||
// 계산은 **표시 반폭으로 자르지 않은 전체 샘플**로 한다(2026-08-22 사용자 확정) —
|
||||
// 표시 반폭은 보기용이고, 사면 끝·지반 교차 판정은 계산용 전 구간이 필요하다.
|
||||
const culvertLayout = computeCardCulvert(
|
||||
section,
|
||||
sourceSamples,
|
||||
section.samples,
|
||||
activeRevet,
|
||||
revetOffset,
|
||||
inletStructure,
|
||||
|
||||
Reference in New Issue
Block a user