diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts index 19190abc..35b1261b 100644 --- a/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts +++ b/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts @@ -139,12 +139,18 @@ export interface CulvertLink { /** * 다단 한 단의 구간값 — 단별로 따로 잡은 값(`design.extra_spans`)이 있으면 그것, - * 없으면 고정 기본 10m(5/5). 기준벽 연장을 상속하지 않는다(2026-08-29 사용자). + * **없으면 소유 벽 연장을 상속**한다(2026-08-30 사용자: 손대기 전에는 기준벽과 같이 + * 옆 측점에 서야 한다). 고정 기본 10m(5/5)는 소유 벽 제원조차 없을 때의 마지막 값이다. + * 손으로 한 번 잡은 단은 그 값으로 고정된다 — 계곡부·능선부에서 단마다 연장이 다르다. */ export function tierSpanOf(section: CrossSection, key: string): StructureSpan { const stored = section.design?.extra_spans?.[key]; - if (!stored) return { ...EXTRA_SPAN_DEFAULT }; - return { beforeM: Math.max(stored.before_m, 0), afterM: Math.max(stored.after_m, 0) }; + if (stored) return { beforeM: Math.max(stored.before_m, 0), afterM: Math.max(stored.after_m, 0) }; + // 유출측 다단(extra…)은 유출 벽, 유입측 다단(bextra…)은 유입 벽(집수정이면 집수정) + // 연장을 따른다 — 그 벽에 딸린 성토부 계단이기 때문이다. + const spec = key.startsWith("bextra") ? section.culvert?.inlet : section.culvert?.outlet; + if (!spec) return { ...EXTRA_SPAN_DEFAULT }; + return spec.structure === "집수정" ? basinSpanOfSpec(spec) : revetSpanOfSpec(spec); } /** 구조물이 종방향으로 덮는 범위(기준측점 전/후 m) — 기슭막이·집수정·다단 중 큰 값. */ diff --git a/B06_Section/B06_Section_UI_Page_Station_Controls.ts b/B06_Section/B06_Section_UI_Page_Station_Controls.ts index 45f6927b..dbb6f0dd 100644 --- a/B06_Section/B06_Section_UI_Page_Station_Controls.ts +++ b/B06_Section/B06_Section_UI_Page_Station_Controls.ts @@ -24,7 +24,7 @@ import type { StructureSpanControl, } from "./B06_Section_UI_Cross_View"; import * as CulvertConst from "./B06_Section_UI_Cross_Culvert_Const"; -import { culvertOwnerFor } from "./B06_Section_UI_Cross_Culvert_Wire"; +import { culvertOwnerFor, tierSpanOf } from "./B06_Section_UI_Cross_Culvert_Wire"; import { createCulvertOptionWriter } from "./B06_Section_Api_Culvert_Options"; import { createBodyControls } from "./B06_Section_UI_Page_Ford_Controls"; import { createLinkFlagSession } from "./B06_Section_UI_Page_Link_Session"; @@ -552,14 +552,17 @@ export function createStationControls(deps: StationControlDeps): StationControls } } - /** 정본(design)에 남은 단별 구간값 — 세션에 없을 때의 다음 후보. */ - const storedTierSpan = (owner: CrossSection, wall: string): SpanValues | null => { - const stored = owner.design?.extra_spans?.[wall]; - if (!stored) return null; + /** + * 세션에 없을 때의 단별 구간값 — 정본(`design.extra_spans`) → **소유 벽 연장 상속** + * 순서다(2026-08-30 사용자: 손대기 전에는 기준벽과 같이 옆 측점에 서야 한다). + * 상속 규칙은 그리기·링크 판정이 쓰는 `tierSpanOf`와 같은 함수 하나로 맞춘다. + */ + const storedTierSpan = (owner: CrossSection, wall: string): SpanValues => { + const span = tierSpanOf(owner, wall); return { - lengthM: stored.length_m, - beforeM: stored.before_m, - afterM: stored.after_m, + lengthM: Math.round((span.beforeM + span.afterM) * 10) / 10, + beforeM: Math.round(span.beforeM * 10) / 10, + afterM: Math.round(span.afterM * 10) / 10, }; }; @@ -582,18 +585,13 @@ export function createStationControls(deps: StationControlDeps): StationControls ownerOf, tierValuesFor: (section, key) => { const owner = ownerOf(section) ?? section; - return ( - extraSpans.get(spanKeyOf(owner.chainage_m, key)) ?? - storedTierSpan(owner, key) ?? - CulvertConst.EXTRA_SPAN_DEFAULT - ); + return extraSpans.get(spanKeyOf(owner.chainage_m, key)) ?? storedTierSpan(owner, key); }, updateTier: (section, key, patch) => { const owner = ownerOf(section); if (!owner) return; const mapKey = spanKeyOf(owner.chainage_m, key); - const current = - extraSpans.get(mapKey) ?? storedTierSpan(owner, key) ?? CulvertConst.EXTRA_SPAN_DEFAULT; + const current = extraSpans.get(mapKey) ?? storedTierSpan(owner, key); const next = CulvertConst.applySpanPatch(current, patch); extraSpans.set(mapKey, next); persistExtraSpans();