diff --git a/B06_Section/B06_Section_Section_Store.ts b/B06_Section/B06_Section_Section_Store.ts index 38e54977..41ce275e 100644 --- a/B06_Section/B06_Section_Section_Store.ts +++ b/B06_Section/B06_Section_Section_Store.ts @@ -52,7 +52,10 @@ async function withDraftWalls( projectId: string, ): Promise { const drafts = readPendingStructures(projectId); - if (!drafts) return withStructureAreas(detail); + // ⚠ **빈 목록도 「초안 없음」이다**(2026-09-09). 예전에는 `[]` 가 「초안이 있는데 벽이 + // 하나도 없다」로 읽혀 **아래에서 서버 저장분을 통째로 지웠다** — 구조물을 놓아도 + // 횡단도에 아무것도 안 보이던 결함의 원인이다(창 둘에서 같은 증상, 실측 확인). + if (!drafts || !drafts.length) return withStructureAreas(detail); const types = await fetchStructureTypes().catch(() => []); const names = new Map( types diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts index 27c1484b..e4ccee55 100644 --- a/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts +++ b/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts @@ -256,6 +256,27 @@ export function wallStandsAt(owner: CrossSection, section: CrossSection, key: st return spanCovers(revetSpanOfSpec(side), deltaM); } +/** + * 링크된 관의 벽이 **이 카드에 실제로 서는가**. 하나도 안 서면 그 링크는 이 측점의 + * 그림을 막을 이유가 없다 — 독립 벽(D경로)이 그려져야 한다. + * + * 왜 있나(2026-09-09) — 「관이 없는 측점인데도 구조물을 놓으면 아무것도 안 보인다」가 + * 사용자에게 보이던 결함이었다. 겹침 방지 가드가 **링크가 있기만 하면** 막고 있었는데, + * 관이 아홉·열하나인 노선에서는 링크가 거의 모든 측점을 덮어 D경로가 통째로 죽었다. + * 가드를 없애지 않고 **좁힌다** — 벽이 실제로 서는 카드에서만 막는다. + */ +export function culvertWallsStandAt(owner: CrossSection, section: CrossSection): boolean { + const keys = ["inlet", "outlet"]; + const counts = owner.design?.extra_wall_counts ?? {}; + for (const [side, count] of Object.entries(counts)) { + const total = Math.max(Math.trunc(Number(count) || 0), 0); + for (let index = 0; index < total; index += 1) { + keys.push(side === "basin" ? `bextra${index}` : `extra${index}`); + } + } + return keys.some((key) => wallStandsAt(owner, section, key)); +} + export function culvertLinkFor( section: CrossSection, sections: readonly CrossSection[], diff --git a/B06_Section/B06_Section_UI_Cross_View.ts b/B06_Section/B06_Section_UI_Cross_View.ts index b5c18b79..061fd070 100644 --- a/B06_Section/B06_Section_UI_Cross_View.ts +++ b/B06_Section/B06_Section_UI_Cross_View.ts @@ -18,6 +18,7 @@ import { appendFordPavementOverlay, appendFordSurfaceDropPlan, } from "./B06_Section_UI_Cross_Ford_Pavement"; +import { culvertWallsStandAt } from "./B06_Section_UI_Cross_Culvert_Wire"; import { appendRevetmentOverlay, computeRevetmentLayout } from "./B06_Section_UI_Cross_Revetment"; import { appendCrossDesignOverlay, @@ -422,7 +423,12 @@ export function createCrossSectionCard( // 이 측점에 배관/숨김 기슭막이 세트가 직접 붙었거나(section.culvert) **연동으로 // 옆에서 이어져 온**(culvertLink) 경우엔 배관 경로가 그린다 — 옛 D경로는 건너뛴다 // (둘 다 그리면 이웃 카드에 벽이 겹친다 — 2026-08-28 이관 이중그리기 방지). - if (!section.culvert && !culvertLink) { + // ⚠ 가드를 **좁혔다**(2026-09-09) — 예전에는 링크가 **있기만 하면** 막았는데, + // 관이 아홉·열하나인 노선에서는 링크가 거의 모든 측점을 덮어 **구조물을 놓아도 + // 횡단도에 아무것도 안 보였다**(사용자에게 보이던 결함). 겹침 방지라는 까닭은 + // 그대로 두고, **그 링크의 벽이 이 카드에 실제로 설 때만** 막는다. + const linkedWallsHere = !!culvertLink && culvertWallsStandAt(culvertLink.source, section); + if (!section.culvert && !linkedWallsHere) { const ownAdjust = revetOffset?.adjustFor(section, "own"); const ownLayout = computeRevetmentLayout(section, ownAdjust); ownDesignTrim = ownLayout?.designTrim; diff --git a/common_util/common_util_structure_walls.ts b/common_util/common_util_structure_walls.ts index 1047ed46..5cd7c2e8 100644 --- a/common_util/common_util_structure_walls.ts +++ b/common_util/common_util_structure_walls.ts @@ -32,6 +32,8 @@ export interface WallSpec { form: string | null; height_m: number | null; side: string | null; + /** 기초 축 — "기초유" | "기초버림". 저장 칸과 같은 글자(터파기 그림이 이 값으로 갈린다). */ + foundation: string | null; tiers: number | null; lift_m: number | null; shift_m: number | null; @@ -78,6 +80,8 @@ export function wallSpecsFrom( form: (options.form as string) || FORM_BY_TYPE[structure.type_id] || null, height_m: num(options.height_m), side: (options.side as string) ?? null, + // 기초 축 — 저장 칸과 **같은 글자**. 초안 경로에서 빠지면 터파기가 안 그려진다. + foundation: (options.foundation as string) ?? null, tiers: num(options.tiers), lift_m: num(options.lift_m), shift_m: num(options.shift_m),