From b9938dfa18f145fdd48e2246c60e056f5072cfe5 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 27 Aug 2026 11:18:32 +0900 Subject: [PATCH] =?UTF-8?q?fix(B05):=20=EB=85=B8=EA=B2=AC=20=EC=AA=BD?= =?UTF-8?q?=C2=B7=EC=84=B1=ED=86=A0=20=EB=81=9D=EB=8B=A8=20=EC=AA=BD=20?= =?UTF-8?q?=EB=A6=AC=EB=B3=B8=20=EA=B2=BD=EA=B3=84=EC=97=90=EB=8A=94=20?= =?UTF-8?q?=EC=B8=A1=EB=B2=BD=EC=9D=84=20=EC=84=B8=EC=9A=B0=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 거기서 잘린 게 아니라 리본이 끝난 자리다(2026-08-27 사용자). - 통째로 지운 셀의 모서리 벽: 열 방향 이웃이 리본 밖이면 건너뛴다(`col > 0`, `col < cols - 2`). 행 방향(노선 앞뒤)은 종전대로. - 걸친 셀의 교점 직선: 두 교점이 모두 안쪽 끝(노견)이나 바깥 끝(성토 끝선) 위를 달리면 건너뛴다. 판정은 **열 좌표 기준 ±0.1열**(셀 폭의 10%) — 커브가 끝선과 나란히 지나면 교점이 가로 모서리에 걸려 열 좌표가 3~5mm 빗나간다(실측). - BUILD_VERSION 55 → 57. 검증(실빌드 데이터): - 벽 삼각형 1,450/1,358 → 852/824(우/좌). - 성토끝단선 위를 달리는 벽 구간 8/6 → **0**, 노견선 위 2/2 → **0** (구간 길이 3cm 이상, 선까지 거리 1cm 이내 기준). - 벽 ↔ 절단커브 거리는 그대로 중앙값 0.000m. 리본 조각 삼각형 814/787 불변. - npm run typecheck 통과, prettier 적용. Co-Authored-By: Claude Opus 5 (1M context) --- B05_Profile/B05_Profile_UI_Corridor.ts | 6 +++--- B05_Profile/B05_Profile_UI_Corridor_Cut.ts | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/B05_Profile/B05_Profile_UI_Corridor.ts b/B05_Profile/B05_Profile_UI_Corridor.ts index 2ff29dc0..5700382d 100644 --- a/B05_Profile/B05_Profile_UI_Corridor.ts +++ b/B05_Profile/B05_Profile_UI_Corridor.ts @@ -106,9 +106,9 @@ function fnv1a(text: string): string { // 투영 커브 안쪽 성토면 절단 — 커브 다각형 기준(2026-08-26). // ※ 40에 머물러 있는 동안 기하 수정 3회가 통째로 묻혔다 — 저장본이 그대로 // 복원되어 화면·데이터가 하나도 안 바뀌었다. 기하를 고치면 **반드시** 올릴 것. -// 55 = 측벽을 **실제로 잘린 선**(걸친 셀은 교점 직선, 통째 셀은 이웃 모서리)에 -// 세운다 — 종전 격자 계단은 면 경계와 최대 0.3m 어긋났다(2026-08-27 사용자). -const BUILD_VERSION = 55; +// 56 = 측벽에서 **노견 쪽·성토 끝단 쪽 리본 경계 벽을 뺀다** — 거기서 잘린 게 +// 아니라 리본이 끝난 자리다(2026-08-27 사용자). +const BUILD_VERSION = 57; /** 종횡단 정본에서 코리도에 영향을 주는 입력만 요약해 해시 — 갱신 감지 기준. */ export function corridorHash(detail: SectionDetailResponse, routePoints: RoutePoint[]): string { diff --git a/B05_Profile/B05_Profile_UI_Corridor_Cut.ts b/B05_Profile/B05_Profile_UI_Corridor_Cut.ts index 8ca98b01..8b4dedd6 100644 --- a/B05_Profile/B05_Profile_UI_Corridor_Cut.ts +++ b/B05_Profile/B05_Profile_UI_Corridor_Cut.ts @@ -334,6 +334,14 @@ class SkirtBuilder { /** 걸친 셀 — 그 셀을 자른 교점 직선에 벽을 세운다. */ addChord(row: number, col: number, chord: readonly [Corner, Corner]): void { const [h0, h1] = chord; + // 교점 직선이 리본 **안쪽 끝(노견)·바깥 끝(성토 끝선)** 위를 그대로 달리면 건너뛴다 — + // 투영 커브의 바깥 변이 곧 성토 끝선이라 거기서는 자른 게 아니다(2026-08-27 사용자). + // 판정은 **열 단위**로 한다 — 커브가 끝선과 나란히 지나면 교점이 가로 모서리에 + // 걸려 열 좌표가 끝값에서 조금 빗나간다(실측 3~5mm). 셀 폭의 10%를 여유로 둔다. + const last = this.ribbon.colCount - 1; + const TOL = 0.1; + if (h0.a < TOL && h1.a < TOL) return; + if (h0.a > last - TOL && h1.a > last - TOL) return; this.quad( h0.p[0], h0.p[1], @@ -478,8 +486,12 @@ export function maskFillByPlanCurves( if (!mask[i] || chorded[i]) continue; if (filled(row - 1, col)) skirt.addEdge(row, col, row, col + 1); if (filled(row + 1, col)) skirt.addEdge(row + 1, col + 1, row + 1, col); - if (filled(row, col - 1)) skirt.addEdge(row + 1, col, row, col); - if (filled(row, col + 1)) skirt.addEdge(row, col + 1, row + 1, col + 1); + // 리본의 **안쪽 끝(노견)·바깥 끝(성토 끝단)**에는 벽을 세우지 않는다 — + // 거기서 잘린 게 아니라 리본이 끝난 것이다(2026-08-27 사용자). + if (col > 0 && filled(row, col - 1)) skirt.addEdge(row + 1, col, row, col); + if (col < cols - 2 && filled(row, col + 1)) { + skirt.addEdge(row, col + 1, row + 1, col + 1); + } } } }