From 521fb89c30adf479708944983786a23bbf7ea9d5 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 27 Aug 2026 21:02:28 +0900 Subject: [PATCH] =?UTF-8?q?fix(B05):=20=EA=B8=B0=EC=8A=AD=EB=A7=89?= =?UTF-8?q?=EC=9D=B4=20=EC=83=81=EB=8B=A8=20=EC=84=B1=ED=86=A0=EB=A9=B4?= =?UTF-8?q?=EC=9D=84=20=EB=90=98=EB=A9=94=EC=9B=80=20=EB=A6=AC=EB=B3=B8=20?= =?UTF-8?q?=EB=B0=B0=EC=97=B4=EC=97=90=20=EB=8B=B4=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 배수관 세트(기슭막이) 구간에서 노견 → 벽 이음선 상단 성토 사면이 3D에서 통째로 비어 있었다. 포켓(FILL_CUT_APPLY)은 노견까지 파는데, 되메움 배열(fillRuns, 4a5a98fe)에는 벽 아래 다단 성토선·집수정 성토선만 담겨 그 위가 안 메워졌다. culvertSilhouettes가 designTrim 사면선을 push(실루엣)만 하고 addRun(리본)은 하지 않은 게 원인 — 세월교·BOX암거는 각각 fillSegments·fillLine으로 담고 있어 무관하다. 새 면을 만들지 않는다. 실루엣이 이미 쓰던 designTrim.min/maxSlope 점 배열을 리본 배열에도 등록할 뿐이다. - Station_Structure: pushTopSlope() 추가 — push + addRun을 함께 하되 측당 한 번만. 벽 루프와 집수정 분기가 같은 designTrim 사면선을 각각 담으므로 표시가 없으면 리본이 두 장 겹친다. 호출 3곳(벽 루프, 집수정 slope, 집수정 2점 폴백). - Corridor: BUILD_VERSION 79 -> 80. 실측(공용 브라우저 A/B, git stash로 코드만 교체): - 패치 리본 6 -> 10장. 늘어난 4장 전부 기슭막이 세트(측점 84.3·275.71). - 275.71 좌측: 기존 z 531.11~535.93 바로 위에 536.85~539.92가 새로 앉았다. 사이 0.92m는 벽 전면 — 구조물 솔리드 몫이라 원래 비는 자리. - 84.3은 수정 전 양측 0장 — 포켓만 파고 되메움이 통째로 없었다. - 날개형 구조물(149.73·200.92) 리본 수·z 범위 소수점까지 불변 = 무회귀. - tsc --noEmit 0. 화면 검증은 사용자가 직접 수행(2026-08-27 사용자 지시). Co-Authored-By: Claude Opus 5 (1M context) --- B05_Profile/B05_Profile_UI_Corridor.ts | 7 ++++- ...5_Profile_UI_Corridor_Station_Structure.ts | 26 ++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) 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 }, ]);