From 96be8fe2336899226bb4352ada1201a15be6ca08 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Wed, 26 Aug 2026 18:20:41 +0900 Subject: [PATCH] =?UTF-8?q?fix(B05):=20=EB=82=A0=EA=B0=9C=EB=B2=BD=20?= =?UTF-8?q?=EB=B0=94=EA=B9=A5=20=EC=84=B8=EB=A1=9C=EC=84=A0=EC=9D=84=20?= =?UTF-8?q?=EA=B5=AC=EC=B2=B4=20=EC=B8=A1=EB=A9=B4=EC=97=90=20=EB=B6=99?= =?UTF-8?q?=EC=97=AC=20=EB=8B=A8=EC=9D=84=20=EC=97=86=EC=95=A4=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 날개 판이 축 위에 가운데 정렬이라, 뿌리를 구체 측면에 놓으면 절반(두께/2)이 측면 밖으로 삐져나와 투영 커브에 단이 졌다. 각도 틸팅 방식은 그대로 두고 판을 축을 따라 뒤로 민다 — 바깥쪽 세로선이 측면에 닿는 데 필요한 양은 (두께/2) × |cos각| / sin각 = (두께/2) × cot각이다. 각이 아주 작으면 cot이 발산하므로 날개 길이의 절반으로 자른다. 세월교·BOX암거 둘 다 적용한다(사용자가 둘 다 지목). 에이프런도 새 뿌리를 따른다. `BUILD_VERSION` 36 → 37. 실측: 뿌리 링의 바깥 세로선이 구체 측면 평면에서 떨어진 거리가 세월교 4장·BOX 4장 전부 0.0000m. 안쪽 세로선은 0.1414m 안으로 박힌다(= 두께 0.2 × cos45°). 회귀 없음 — 아령 벌어짐 유지(149.73 좌 10.73 → 14.02m, 우 8.63 → 10.81m, 200.92 2.26 → 5.08m), 성토끝 박스 4/4·4/4, 에이프런 4장·0장, 기준 직선 이탈 0. Co-Authored-By: Claude Opus 5 (1M context) --- B05_Profile/B05_Profile_UI_Corridor.ts | 2 +- ...B05_Profile_UI_Corridor_Structures_Wing.ts | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/B05_Profile/B05_Profile_UI_Corridor.ts b/B05_Profile/B05_Profile_UI_Corridor.ts index d3eb0c0b..42b919c1 100644 --- a/B05_Profile/B05_Profile_UI_Corridor.ts +++ b/B05_Profile/B05_Profile_UI_Corridor.ts @@ -84,7 +84,7 @@ function fnv1a(text: string): string { * (2026-08-23 사용자 보고: "원복이 안 된 것 같다가 갑자기 반영됨"). 판번호를 해시에 * 섞어 두면 배포와 동시에 저장본이 만료된다. */ -const BUILD_VERSION = 36; // 세월교 날개 투영 커브를 노선 흐름에 맞춤(2026-08-26). +const BUILD_VERSION = 37; // 날개벽 바깥 세로선을 구체 측면에 붙임(2026-08-26). /** 종횡단 정본에서 코리도에 영향을 주는 입력만 요약해 해시 — 갱신 감지 기준. */ export function corridorHash(detail: SectionDetailResponse, routePoints: RoutePoint[]): string { diff --git a/B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts b/B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts index 08abbefa..558bfefc 100644 --- a/B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts +++ b/B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts @@ -129,12 +129,25 @@ export function buildWingSolids( const wingNorm = Math.hypot(wingX, wingY) || 1; const ux = wingX / wingNorm; const uy = wingY / wingNorm; + // 판을 축 방향으로 **밀어넣는 양**(2026-08-26 사용자: 커브에 단이 진다). + // + // 판은 축 위에 가운데 정렬이라 뿌리를 구체 측면에 놓으면 절반(두께/2)이 측면 + // 밖으로 삐져나와 단이 생긴다. **바깥쪽 세로선이 측면에 닿도록** 축을 따라 + // 뒤로 민다 — 측면(법선 = 진행 방향)까지의 거리를 0으로 만드는 양은 + // (두께/2) × |cos각| / sin각 = (두께/2) × cot각이다. 각도 틸팅은 그대로 둔다. + const alongDot = ux * dirX * along + uy * dirY * along; // = sin(각) + const edgeDot = -uy * dirX * along + ux * dirY * along; // = ±cos(각) + const push = alongDot > 1e-6 ? ((thicknessM / 2) * Math.abs(edgeDot)) / alongDot : 0; + // 날개 길이의 절반을 넘겨 밀지 않는다 — 각이 아주 작으면 cot이 발산한다. + const inset = Math.min(push, length / 2); + const rootX = startX - ux * inset; + const rootY = startY - uy * inset; const rings: StructureFrame[] = []; const polygons: SectionPolygon[] = []; for (let i = 0; i <= WING_STEPS; i += 1) { const t = (length * i) / WING_STEPS; // 패널 두께 방향 = 날개 축의 법선. - rings.push({ cx: startX + ux * t, cy: startY + uy * t, leftX: -uy, leftY: ux, dz: 0 }); + rings.push({ cx: rootX + ux * t, cy: rootY + uy * t, leftX: -uy, leftY: ux, dz: 0 }); const top = anchor.bottomElevation + height0 + ((height1 - height0) * i) / WING_STEPS; polygons.push([ [-thicknessM / 2, top], @@ -160,8 +173,8 @@ export function buildWingSolids( const t = i / WING_STEPS; // 링 좌향 = 뿌리→바닥판 끝 방향. 폭을 |P0P2| → 0으로 좁히면 P0·P2·P1 삼각형이다. apronRings.push({ - cx: startX + ux * length * t, - cy: startY + uy * length * t, + cx: rootX + ux * length * t, + cy: rootY + uy * length * t, leftX: base.leftX * spread, leftY: base.leftY * spread, dz: 0,