feat(B06): 기슭막이 높이·자리 체계 개편 + 조정창 방향키 조작

- 조정창 십자 키패드 키보드 방향키 조작(집수정 9키는 십자 축만)
- 배관 기슭막이 높이 = 순수 높이(바닥~상단), 하한·기본 = 관경+1.0m (고정 2.0m 폐기)
- 매몰 시 전면 발끝 지반 추적 바닥 심화 삭제 — 바닥 = invert-0.5 고정
- 상하(d) 0점 = 성토선 0 지점(벽 상단=노견), 기본 자리 = 성토사면 경사길이 4m 지점
  (d=null 자동, 저장·표시·정수맞춤 pinned 판정 연동, 구세션 d=0 호환)
- 유입 접속 절토선: 지반 교차 없으면 1m 공간 확보에서 끝
- 자동 집수정 기본 형상 L형 -> I형 (선택지 밖 구조물 그려지던 불일치)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 20:34:30 +09:00
co-authored by Claude Fable 5
parent 7217747e81
commit 5371534fc3
11 changed files with 209 additions and 126 deletions
+25 -4
View File
@@ -37,6 +37,7 @@ import type { CrossWidthActions, ZoomPanState } from "./B06_Section_UI_Cross_Vie
import { toeFitHalfWidth } from "./B06_Section_UI_Cross_Fit";
import { createCrossAxes, IDENTITY_VIEW } from "./B06_Section_UI_Cross_Axes";
import type { RevetHighlightSetter, RevetKey } from "./B06_Section_UI_Cross_Culvert";
import { REVET_EMBED_DEPTH_M } from "./B06_Section_UI_Cross_Culvert_Const";
import type { RevetMaterial } from "./B06_Section_UI_Cross_Culvert_Const";
import type { WallAdjust } from "./B06_Section_UI_Cross_Culvert_Types";
import {
@@ -164,8 +165,11 @@ export function createCrossSectionCard(
let culvertExtraState = { canAdd: false, count: 0 };
/** 집수정 계류측 다단 상태(2026-08-22) — 조정창의 집수정 단 수 행이 쓴다. */
let culvertBasinExtraState = { canAdd: false, count: 0 };
/** 마지막 계산의 벽 제원(높이·재질) — 조정창 표시·높이 조작 기준. */
/** 마지막 계산의 벽 제원(높이·재질) — 조정창 표시·높이 조작 기준.
* 배관(유입·유출) 벽 높이는 **순수 높이**(바닥~상단 — 2026-08-23 사용자). */
let culvertWallSpecs = new Map<RevetKey, { height: number; material: RevetMaterial }>();
/** 마지막 계산의 실제 적용 d(상하) — d 미지정(자동) 벽의 ▲▼ 시작값. */
let culvertAppliedD = new Map<RevetKey, number>();
/**
* 기슭막이를 고른다. 구조물 선택과 절·성토 면적 강조는 **같은 레벨**이라 하나를
* 고르면 다른 하나는 풀린다(2026-08-21 사용자). 또 구조물을 고르면 그 **측점 카드도
@@ -417,10 +421,23 @@ export function createCrossSectionCard(
};
culvertWallSpecs = new Map();
const specOf = (wall: (typeof culvertLayout.walls)[number], key: RevetKey) =>
culvertWallSpecs.set(key, { height: wall.height, material: wall.material });
culvertWallSpecs.set(key, {
// 배관 벽은 순수 높이(바닥~상단 = 계산용 + 근입 0.5 — 2026-08-23 사용자).
height: wall.role === "extra" ? wall.height : wall.height + REVET_EMBED_DEPTH_M,
material: wall.material,
});
for (const wall of culvertLayout.walls) specOf(wall, wall.role as RevetKey);
culvertLayout.extraWalls.forEach((wall, i) => specOf(wall, `extra${i}` as RevetKey));
culvertLayout.basinExtras.forEach((wall, i) => specOf(wall, `bextra${i}` as RevetKey));
culvertAppliedD = new Map();
culvertAppliedD.set("inlet", culvertLayout.revetShift.inlet.d ?? 0);
culvertAppliedD.set("outlet", culvertLayout.revetShift.outlet.d ?? 0);
culvertLayout.revetShift.extras.forEach((applied, i) =>
culvertAppliedD.set(`extra${i}` as RevetKey, applied.d ?? 0),
);
culvertLayout.revetShift.basinExtras.forEach((applied, i) =>
culvertAppliedD.set(`bextra${i}` as RevetKey, applied.d ?? 0),
);
}
if (culvertLayout) {
setRevetActive = appendCulvertOverlay(
@@ -534,15 +551,19 @@ export function createCrossSectionCard(
const materialOfWall = (key: RevetKey): RevetMaterial =>
culvertWallSpecs.get(key)?.material ?? "dry";
const adjustOf = (key: RevetKey): WallAdjust =>
revetOffset?.adjustFor(section, key) ?? { x: 0, d: 0, h: null, m: null };
revetOffset?.adjustFor(section, key) ?? { x: 0, d: null, h: null, m: null };
const panel = buildStructurePanel({
adjustFor: adjustOf,
nudge: (key, screenDeltaM) =>
revetOffset?.update(section.chainage_m, key, {
x: adjustOf(key).x + screenDeltaM * outwardOf(key),
}),
// d 미지정(자동)이면 실제 적용 자리에서부터 움직인다(2026-08-23 — d는 0점
// 기준 절대값이라 시작값이 필요하다).
nudgeSlope: (key, deltaM) =>
revetOffset?.update(section.chainage_m, key, { d: adjustOf(key).d + deltaM }),
revetOffset?.update(section.chainage_m, key, {
d: (adjustOf(key).d ?? culvertAppliedD.get(key) ?? 0) + deltaM,
}),
nudgeHeight: (key, deltaM) => {
const current = adjustOf(key);
const base = current.h ?? heightOfWall(key);