feat(B06): 관 접속 절·성토선 3도 물매 + 교차점 보간 + 절성토 교차 기준 자동 줌아웃

- 관 유도 접속선을 0도 → **3도**로: 유입측은 계류 쪽 오름(물이 관으로),
  유출측 매몰 절토선은 계류 쪽 내림(물이 밖으로). 집수정 I형 되메움선도 동일
- 모든 유도선·성토부선 끝점을 격자점이 아니라 **선형 보간 교차점**에 붙여
  선이 원지반을 미세하게 벗어나던 문제 해소(2026-08-22 사용자 지적)
- 카드 자동 줌아웃: **구조물 없는 상태**의 설계 절·성토선이 원지반과 만나는
  지점(+0.5m)이 표시 반폭 밖이면 그 카드만 반폭을 넓혀 그린다. 보유 샘플
  범위를 넘는 경우는 기존 전역 반폭 재생성 경로(applyPanelToAll)가 담당

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-22 15:44:10 +09:00
co-authored by Claude Opus 5
parent de78feabde
commit cd855e32d3
7 changed files with 154 additions and 38 deletions
@@ -13,6 +13,7 @@
* ========================================================================== */
import {
PIPE_CONNECT_GRADE,
BASIN_INNER_HEIGHT_M,
BASIN_MEMBER_THICKNESS_M,
REVET_FREEBOARD_M,
@@ -262,12 +263,26 @@ export function applyBasinPipeFill(
outward: number,
groundAt: (offset: number) => number,
): void {
// 되메움선 물매 3도(2026-08-22 사용자) — 유입측이라 계류 쪽이 높다(물이 관으로).
if (basin.shape !== "I" || corner.elevation <= groundAt(corner.offset) + 0.02) return;
let previousGap = corner.elevation - groundAt(corner.offset); // 선 − 지반
for (let run = 0.05; run <= 30; run += 0.05) {
const probe = corner.offset + outward * run;
if (groundAt(probe) >= corner.elevation) {
basin.fillLine = { from: corner, to: { offset: probe, elevation: corner.elevation } };
const elevation = corner.elevation + PIPE_CONNECT_GRADE * run;
const gap = elevation - groundAt(probe);
if (gap <= 0) {
// 끝점은 보간 교차점 — 격자점이면 지반을 미세하게 벗어난다(2026-08-22 사용자).
const fraction = previousGap > 1e-12 ? previousGap / (previousGap - gap) : 1;
const runCross = run - 0.05 * (1 - fraction);
basin.fillLine = {
from: corner,
to: {
offset: corner.offset + outward * runCross,
elevation: corner.elevation + PIPE_CONNECT_GRADE * runCross,
},
};
return;
}
previousGap = gap;
}
}