fix(B06): 관 끝점 기준 = 실제 바닥+0.5 · 추가 벽 매몰 이동 차단 · 기본 높이 2.0 통일
- 유출 관 하단 끝점·다음 단 성토선 시작점의 기준을 기준선(anchor)이 아니라 **실제 바닥(전면 근입 심화 반영) +0.5m**로 통일 — 가파른 지반에서 바닥만 깊어지고 관이 벽 위쪽에 떠 보이던 문제 해소(2026-08-22 사용자 지적) - 추가 기슭막이 이동 한계 = 원지반 매몰 자리 금지: 이음선 상단이 지반 아래 (통째 매몰)이거나 자기 성토선 시작점이 지반 아래 0.05m 이상이면 그 앞에서 멈춤(상하 먼저, 다음 좌우 되돌림) — 자동 자리조차 매몰이면 그 단은 불가 - 배관 기슭막이 기본 높이 = 재질 무관 2.0m(찰·콘크리트 기본 2.5 → 2.0 정정) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -112,8 +112,8 @@ export function materialFromForm(form: string | null | undefined): RevetMaterial
|
||||
|
||||
/** 배관 기슭막이 높이 조작 하한(m) — 2~3m 구간 지시(2026-08-22)의 하한. */
|
||||
export const PIPE_WALL_MIN_HEIGHT_M = 2.0;
|
||||
/** 배관 기슭막이 기본 높이(m, 2026-08-22 지시 2.5) — 재질 한계로 잘린다(메→2.0). */
|
||||
export const PIPE_WALL_DEFAULT_HEIGHT_M = 2.5;
|
||||
/** 배관 기슭막이 기본 높이(m) — 재질과 무관하게 2.0(2026-08-22 사용자 정정). */
|
||||
export const PIPE_WALL_DEFAULT_HEIGHT_M = 2.0;
|
||||
/** 일반(추가) 기슭막이 높이 조작 하한(m). */
|
||||
export const EXTRA_WALL_MIN_HEIGHT_M = 0.5;
|
||||
/** 일반(추가) 기슭막이 기본 높이(m). */
|
||||
|
||||
@@ -217,8 +217,52 @@ export function buildOutletExtras(input: OutletExtrasInput): OutletExtrasResult
|
||||
// 관통 금지: 상단 ≤ 윗단 하단 → 성토선 수평거리(경사부) ≥ 1.2×(시작−윗단하단).
|
||||
const autoJointRun = (autoOffset - src.offset) * outward - jointRunOf(height);
|
||||
const minJointRun = FILL_SLOPE_RATIO_MIN * Math.max(src.elevation - prevBottom, 0);
|
||||
const appliedD = Math.max(adjust.d, Math.ceil((minJointRun - autoJointRun) * 10) / 10);
|
||||
const appliedX = Math.max(adjust.x, 0);
|
||||
const minD = Math.ceil((minJointRun - autoJointRun) * 10) / 10;
|
||||
/** 후보 자리의 바닥(전면 근입 심화 반영) — buildExtraWall과 같은 계산. */
|
||||
const bottomAt = (anchorX: number, baseElevation: number): number => {
|
||||
const baseWidth = REVET_THICKNESS_M * 1.5 + REVET_LEAN_RATIO * height;
|
||||
const jointX = anchorX - outward * (baseWidth / 2 - REVET_THICKNESS_M / 2);
|
||||
const topFrontX = jointX + outward * REVET_THICKNESS_M;
|
||||
const topElevation2 = baseElevation + height;
|
||||
const frontXAt = (e: number): number =>
|
||||
topFrontX + outward * REVET_LEAN_RATIO * (topElevation2 - e);
|
||||
let bottom = baseElevation - REVET_EMBED_DEPTH_M;
|
||||
if (baseElevation - groundAt(anchorX) <= 1e-6) {
|
||||
for (let pass = 0; pass < 6; pass += 1) {
|
||||
const toe = Math.min(groundAt(frontXAt(bottom)), baseElevation);
|
||||
if (toe - REVET_EMBED_DEPTH_M >= bottom - 1e-6) break;
|
||||
bottom = toe - REVET_EMBED_DEPTH_M;
|
||||
}
|
||||
}
|
||||
return bottom;
|
||||
};
|
||||
// 이동 한계 = 원지반 매몰 자리 금지(2026-08-22 사용자 확정): ① 이음선 상단이
|
||||
// 지반 아래(벽이 통째로 묻힘) ② 자기 성토선 시작점(실바닥+0.5 전면 교차점)이
|
||||
// 지반 아래 0.05m 이상(= 0.5m 이상 매몰 → 성토 불필요 자리).
|
||||
const placeable = (xShift: number, dShift: number): boolean => {
|
||||
const topE = src.elevation - (autoJointRun + dShift) / FILL_SLOPE_RATIO_MIN;
|
||||
const aX = autoOffset + outward * (xShift + dShift);
|
||||
const jointX = aX - outward * jointRunOf(height);
|
||||
if (Math.max(groundAt(jointX), groundAt(jointX + outward * REVET_THICKNESS_M)) >= topE - 0.01)
|
||||
return false;
|
||||
const baseE = topE - height;
|
||||
const bottom = bottomAt(aX, baseE);
|
||||
const startE = bottom + REVET_EMBED_DEPTH_M;
|
||||
const topFrontX = jointX + outward * REVET_THICKNESS_M;
|
||||
const startX = topFrontX + outward * REVET_LEAN_RATIO * (topE - startE);
|
||||
return groundAt(startX) < startE + 0.05;
|
||||
};
|
||||
let appliedD = Math.max(adjust.d, minD);
|
||||
let appliedX = Math.max(adjust.x, 0);
|
||||
for (let pass = 0; pass < 400 && !placeable(appliedX, appliedD); pass += 1) {
|
||||
// 매몰 자리 — 요청을 자동 자리 쪽으로 0.05m씩 되돌린다(상하 먼저, 다음 좌우).
|
||||
if (appliedD > minD + 1e-9) appliedD = Math.max(minD, appliedD - 0.05);
|
||||
else if (appliedX > 1e-9) appliedX = Math.max(0, appliedX - 0.05);
|
||||
else break;
|
||||
}
|
||||
if (!placeable(appliedX, appliedD)) break; // 자동 자리조차 매몰 — 이 단은 불가.
|
||||
appliedD = Math.round(appliedD * 10) / 10;
|
||||
appliedX = Math.round(appliedX * 10) / 10;
|
||||
appliedAdjusts.push({
|
||||
x: appliedX,
|
||||
d: appliedD,
|
||||
@@ -254,10 +298,14 @@ export function buildOutletExtras(input: OutletExtrasInput): OutletExtrasResult
|
||||
ratio: rise > 1e-9 ? run / rise : FILL_SLOPE_RATIO_MIN,
|
||||
overLimit: Math.hypot(run, rise) >= FILL_SLOPE_MAX_LENGTH_M - 1e-6,
|
||||
});
|
||||
// 다음 단 시작점 = 이 벽 하단 +0.5m(기준선) 수평선과 전면 경사선(1:0.3)의 교차점.
|
||||
// 다음 단 시작점 = 이 벽 **실제 바닥**(근입 심화 반영) +0.5m 수평선과 전면
|
||||
// 경사선(1:0.3)의 교차점(2026-08-22 사용자 — 관 끝점 규칙과 동일 기준).
|
||||
const startElevation = wall.bottomBack.elevation + REVET_EMBED_DEPTH_M;
|
||||
src = {
|
||||
offset: wall.points[2].offset + outward * REVET_LEAN_RATIO * height,
|
||||
elevation: base,
|
||||
offset:
|
||||
wall.points[2].offset +
|
||||
outward * REVET_LEAN_RATIO * (wall.topJoint.elevation - startElevation),
|
||||
elevation: startElevation,
|
||||
};
|
||||
prevBottom = wall.bottomBack.elevation;
|
||||
}
|
||||
|
||||
@@ -461,12 +461,17 @@ export function computeCulvertLayout(
|
||||
const pipeStart = basinPipeEnd ?? inlet;
|
||||
/** 유출 관 하단 끝점 목표 = 벽 바닥 기준 0.5m 상단(기준선)과 **전면 경사선의
|
||||
* 교차점**(2026-08-22 사용자 ① — 성토부선 시작 규칙과 같은 자리). */
|
||||
const outletPipeEnd = (wall: WallLayout): OffsetPoint => ({
|
||||
offset:
|
||||
wall.points[2].offset +
|
||||
wall.outward * REVET_LEAN_RATIO * (wall.topJoint.elevation - wall.base),
|
||||
elevation: wall.base,
|
||||
});
|
||||
const outletPipeEnd = (wall: WallLayout): OffsetPoint => {
|
||||
// 기준은 **실제 바닥**(전면 근입으로 깊어진 값) +0.5 — 기준선(anchor)을 쓰면
|
||||
// 가파른 지반에서 바닥만 내려가고 관이 벽 위쪽에 떠 보인다(2026-08-22 사용자 ②).
|
||||
const reference = wall.bottomBack.elevation + REVET_EMBED_DEPTH_M;
|
||||
return {
|
||||
offset:
|
||||
wall.points[2].offset +
|
||||
wall.outward * REVET_LEAN_RATIO * (wall.topJoint.elevation - reference),
|
||||
elevation: reference,
|
||||
};
|
||||
};
|
||||
// 유출 벽이 사면 끝과 다른 자리면 관 끝도 그 자리 기준으로 맞춘다(올림 연장분은
|
||||
// 유출 쪽 — 2026-08-20 확정). 관 하단선은 전면 기준선 교차점을 지나 정수 길이로.
|
||||
if (outletWall) {
|
||||
|
||||
Reference in New Issue
Block a user