diff --git a/B05_Profile/B05_Profile_UI_Corridor.ts b/B05_Profile/B05_Profile_UI_Corridor.ts index e9ff7a21..63dbb273 100644 --- a/B05_Profile/B05_Profile_UI_Corridor.ts +++ b/B05_Profile/B05_Profile_UI_Corridor.ts @@ -157,7 +157,12 @@ function fnv1a(text: string): string { // 지우고 걸친 셀은 안쪽 조각만 남긴다(`patchClip`). 행 단위 바깥선 트림은 폐기 — // 비스듬한 사다리꼴 경계를 행 끝 하나로는 못 맞춰 74셀이 삐져나왔다(실측). // 지우는 면과 채우는 면이 같은 경계를 공유한다(2026-08-27 사용자). -const BUILD_VERSION = 79; +// 80 = 배수관 세트(기슭막이) **노견 → 벽 이음선 상단 성토 사면**을 되메움 리본 배열 +// (`fillRuns`)에도 담는다 — 78/79의 포켓은 노견까지 파는데 79까지의 배열에는 +// 벽 아래 다단·집수정 성토선만 있어 **기슭막이 상단부가 통째로 비었다** +// (2026-08-27 사용자). 새 면이 아니라 실루엣이 이미 쓰던 `designTrim` 사면선 +// 그대로다. 벽 루프·집수정 분기가 같은 선을 담으므로 측당 한 번만 등록한다. +const BUILD_VERSION = 80; /** 종횡단 정본에서 코리도에 영향을 주는 입력만 요약해 해시 — 갱신 감지 기준. */ export function corridorHash(detail: SectionDetailResponse, routePoints: RoutePoint[]): string { diff --git a/B05_Profile/B05_Profile_UI_Corridor_Station_Structure.ts b/B05_Profile/B05_Profile_UI_Corridor_Station_Structure.ts index 0929a29a..35cf6600 100644 --- a/B05_Profile/B05_Profile_UI_Corridor_Station_Structure.ts +++ b/B05_Profile/B05_Profile_UI_Corridor_Station_Structure.ts @@ -258,11 +258,31 @@ export function culvertSilhouettes(section: CrossSection): StructureSilhouette[] }; const trimSlopeOf = (side: "left" | "right") => side === "left" ? layout.designTrim?.maxSlope : layout.designTrim?.minSlope; + /** + * 노견 → 구조물 상단 성토 사면선을 이미 담은 측. 벽 루프와 집수정 분기가 **같은** + * `designTrim` 사면선을 각각 담으므로 표시가 없으면 리본이 두 장 겹친다. + */ + const topSlopeSides = new Set<"left" | "right">(); + /** + * 노견 → 구조물 상단 성토 사면 — 실루엣과 **되메움 리본에 함께** 담는다 + * (2026-08-27 사용자: "기슭막이 상단부 성토면이 비어 있다"). `fillRuns` 도입 + * (`4a5a98fe`) 때 이 줄만 `addRun`에서 빠져 포켓이 그 자리만 안 메워졌다. + * 벽 전면과 달리 구조물 솔리드가 덮지 않는 자리라 리본이 있어야 한다. + */ + const pushTopSlope = ( + side: "left" | "right", + points: ReadonlyArray<{ offset: number; elevation: number }>, + ): void => { + push(side, points); + if (topSlopeSides.has(side)) return; + topSlopeSides.add(side); + addRun(side, points); + }; for (const wall of layout.walls) { const side: "left" | "right" = wall.outward > 0 ? "left" : "right"; const slope = trimSlopeOf(side); - if (slope) push(side, slope.points); + if (slope) pushTopSlope(side, slope.points); // 구조물 전면 실루엣 — 이음선 상단에서 전면 발끝까지 내려온다. push(side, [wall.topJoint, wall.bottomFront]); spans[side] = wallSpanOf(section, wall.role === "inlet" ? "inlet" : "outlet"); @@ -292,10 +312,10 @@ export function culvertSilhouettes(section: CrossSection): StructureSilhouette[] const trimElevation = inletSide === "left" ? layout.designTrim?.maxElevation : layout.designTrim?.minElevation; if (slope) { - push(inletSide, slope.points); + pushTopSlope(inletSide, slope.points); } else if (trimOffset != null && trimElevation != null && Number.isFinite(trimOffset)) { const edge = inletSide === "left" ? edges.left : edges.right; - push(inletSide, [ + pushTopSlope(inletSide, [ { offset: edge.offset_m, elevation: edge.elevation_m }, { offset: trimOffset, elevation: trimElevation }, ]);