From a8793819af11697fc0d4283967e2bfd5403ad5dd Mon Sep 17 00:00:00 2001 From: umsangdon Date: Wed, 26 Aug 2026 18:13:29 +0900 Subject: [PATCH] =?UTF-8?q?feat(B05):=20=EC=84=B8=EC=9B=94=EA=B5=90=20?= =?UTF-8?q?=EB=82=A0=EA=B0=9C=20=ED=88=AC=EC=98=81=20=EC=BB=A4=EB=B8=8C?= =?UTF-8?q?=EB=A5=BC=20=EB=85=B8=EC=84=A0=20=ED=9D=90=EB=A6=84=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EC=B6=B0=20=EA=B8=8B=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 성토끝 박스 옆선이 날개 4장 전부 기준 측점의 고정 좌향을 쓰고 있었다. 세월교는 날개가 저마다 다른 자리의 노선 프레임에 붙는데 커브만 한 방향이라 흐름과 어긋난다. 박스암거는 그 고정 방향이 맞으므로 유지한다(사용자). 방향을 구조물에 실어 보낸다 — `CorridorStructure.wingAxis`(단위벡터). 세월교 날개를 만들 때 그 자리 노선 프레임의 좌향을 담고, `wingBoxLoops`가 `structure.wingAxis ?? 측점 좌향`으로 고른다. Plan 쪽에 새 배관이 없다. `wing` 표식은 `true` → `"station" | "route"`로 바꿔 어느 규칙으로 만든 날개인지 남긴다(문자열이라 기존 truthy 검사는 그대로 통한다). `BUILD_VERSION` 35 → 36. 실측: 149.73 날개 4장 모두 route, 실어 보낸 축이 기준 측점 좌향과 −20.45°/+2.57° 어긋난다. 박스 옆선 각도가 그 값과 정확히 일치(좌 −20.45°·2.57°, 우 159.55°· −177.43° = 같은 축 반대 방향). 200.92는 4장 모두 station, 옆선 0°·−180°로 무변화. 박스 4/4·4/4, 에이프런 4장·0장, 기준 직선 이탈 0.0000m. Co-Authored-By: Claude Opus 5 (1M context) --- B05_Profile/B05_Profile_UI_Corridor.ts | 2 +- .../B05_Profile_UI_Corridor_Plan_Footprint.ts | 7 +++++-- B05_Profile/B05_Profile_UI_Corridor_Structures.ts | 12 +++++++++++- .../B05_Profile_UI_Corridor_Structures_Wing.ts | 8 ++++++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/B05_Profile/B05_Profile_UI_Corridor.ts b/B05_Profile/B05_Profile_UI_Corridor.ts index 43cc3bfd..d3eb0c0b 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 = 35; // 세월교 날개벽 벌어짐 방향 정정(2026-08-26). +const BUILD_VERSION = 36; // 세월교 날개 투영 커브를 노선 흐름에 맞춤(2026-08-26). /** 종횡단 정본에서 코리도에 영향을 주는 입력만 요약해 해시 — 갱신 감지 기준. */ export function corridorHash(detail: SectionDetailResponse, routePoints: RoutePoint[]): string { diff --git a/B05_Profile/B05_Profile_UI_Corridor_Plan_Footprint.ts b/B05_Profile/B05_Profile_UI_Corridor_Plan_Footprint.ts index 5b3035fa..3b2ecd6e 100644 --- a/B05_Profile/B05_Profile_UI_Corridor_Plan_Footprint.ts +++ b/B05_Profile/B05_Profile_UI_Corridor_Plan_Footprint.ts @@ -209,14 +209,17 @@ export function wingBoxLoops( ): Array> { if (toe.length < 2) return []; const sign = side === "left" ? 1 : -1; - const dx = axis.leftX * sign; - const dy = axis.leftY * sign; const loops: Array> = []; for (const structure of set) { const rings = structure.rings; // 날개벽(revet)만 — 세월교 바닥 에이프런(basin)도 `wing` 표식을 달지만 박스는 없다. if (!structure.wing || structure.kind !== "revet" || !rings || rings.length < 2) continue; if (wingSide(rings, axis) !== side) continue; + // 옆선 방향 — 세월교는 그 날개가 붙은 자리의 노선 좌향(구조물이 실어 보낸다), + // BOX암거는 기준 측점의 좌향 그대로다(2026-08-26 사용자: "박스 암거는 유지"). + const [ax, ay] = structure.wingAxis ?? [axis.leftX, axis.leftY]; + const dx = ax * sign; + const dy = ay * sign; const start = rings[0]; const end = rings[rings.length - 1]; const startHit = castToToe(start.cx, start.cy, dx, dy, toe); diff --git a/B05_Profile/B05_Profile_UI_Corridor_Structures.ts b/B05_Profile/B05_Profile_UI_Corridor_Structures.ts index 9137ceb5..11854805 100644 --- a/B05_Profile/B05_Profile_UI_Corridor_Structures.ts +++ b/B05_Profile/B05_Profile_UI_Corridor_Structures.ts @@ -77,8 +77,18 @@ export interface CorridorStructure { * 날개벽 표식 — 링이 **노선이 아니라 날개 축**을 탄다(2026-08-26). 그래서 링 * 폴리곤의 편거리는 노선 편거리가 아니라 **패널 두께**다. 탑뷰 투영에서 도로부 * 클립을 적용하면 안 되고(링이 이미 노견 밖), 성토끝 박스를 하나 더 그린다. + * + * `"station"` = 기준 측점 프레임에서 직선으로 뻗은 날개(BOX암거). + * `"route"` = 측벽 끝단부 자리의 노선 프레임을 탄 날개(세월교). */ - wing?: true; + wing?: "station" | "route"; + /** + * 성토끝 박스 옆선을 그을 **바깥 방향**(단위벡터, 좌향 기준) — 세월교 전용. + * 없으면 기준 측점의 좌향을 쓴다(BOX암거 현행 — 2026-08-26 사용자 "박스 암거는 + * 유지"). 세월교는 날개마다 그 자리 노선 프레임의 좌향이 들어와 커브가 노선 + * 흐름을 탄다. + */ + wingAxis?: [number, number]; /** 배관 전용 — 관 하단 시·끝점(offset/표고)과 관경(m), 관벽 두께(m·중공 튜브). */ pipe?: { start: [number, number]; diff --git a/B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts b/B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts index 84ee9c78..08abbefa 100644 --- a/B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts +++ b/B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts @@ -143,7 +143,11 @@ export function buildWingSolids( [-thicknessM / 2, anchor.bottomElevation], ]); } - solids.push({ chainage_m: chainageM, kind, polygons, rings, wing: true }); + // 노선 프레임을 탄 날개(세월교)는 그 프레임 좌향을 투영 축으로 실어 보낸다 — + // 성토끝 박스 옆선이 노선 흐름을 타게 된다(2026-08-26 사용자). BOX는 안 싣는다. + const wingMode = end ? "route" : "station"; + const wingAxis: [number, number] | undefined = end ? [base.leftX, base.leftY] : undefined; + solids.push({ chainage_m: chainageM, kind, polygons, rings, wing: wingMode, wingAxis }); const apron = anchor.apron; if (!apron) continue; // 바닥판 종방향 끝의 계류측 모서리까지의 폭 — 뿌리에서 그만큼 벌어져 있다. @@ -175,7 +179,7 @@ export function buildWingSolids( kind: "basin", polygons: apronPolygons, rings: apronRings, - wing: true, + wing: wingMode, }); } }