fix(B05): 3D 코리도 구조물 — ringsAt 를 pushSwept 앞에 선언해 ReferenceError(TDZ)를 없앰 (PLAN 24-6a)

- 원인: e371c275(2026-08-28)부터 기슭막이 단 반복이 ringsAt 선언 전에 pushSwept 를 불러 기슭막이 있는 프로젝트의 3D 코리도가 서버 사전 생성 · 브라우저 폴백 모두 안 만들어짐
- 시험: 선언 차례(ringsAt · pushSwept · 기슭막이 단 반복)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019BVZd1M6WUf1YEy9gbAE1G
This commit is contained in:
2026-09-29 21:55:29 +09:00
co-authored by Claude Sonnet 5.5
parent 76676b78fc
commit a2340c4d6d
2 changed files with 50 additions and 14 deletions
@@ -302,6 +302,22 @@ export function buildCorridorStructures(
const count = Math.max(2, Math.ceil((to - from) / SWEEP_STEP_M) + 1);
return Array.from({ length: count }, (_unused, i) => from + ((to - from) * i) / (count - 1));
};
/** 링 누가거리 목록으로 프레임을 만든다(보어처럼 촘촘한 간격이 필요할 때). */
const ringsAt = (chainages: number[]): StructureFrame[] =>
chainages.map((at) => {
const frame = frameAt(at);
if (!frame) return stationFrame;
return {
cx: frame.cx,
cy: frame.cy,
leftX: frame.leftX,
leftY: frame.leftY,
dz: baseZ != null && frame.designZ != null ? frame.designZ - baseZ : 0,
};
});
// ⚠ `ringsAt` 는 `pushSwept` 보다 **먼저** 선언한다 — 아래 기슭막이 단 반복이 `pushSwept` 를 곧바로
// 부르므로 뒤에 두면 ReferenceError(TDZ)로 그 구간 3D 코리도가 통째로 안 만들어진다.
const pushSwept = (
kind: "revet" | "basin",
points: Array<{ offset: number; elevation: number }>,
@@ -348,20 +364,6 @@ export function buildCorridorStructures(
}
}
/** 링 누가거리 목록으로 프레임을 만든다(보어처럼 촘촘한 간격이 필요할 때). */
const ringsAt = (chainages: number[]): StructureFrame[] =>
chainages.map((at) => {
const frame = frameAt(at);
if (!frame) return stationFrame;
return {
cx: frame.cx,
cy: frame.cy,
leftX: frame.leftX,
leftY: frame.leftY,
dz: baseZ != null && frame.designZ != null ? frame.designZ - baseZ : 0,
};
});
/**
* 관이 뚫고 지나는 구조물 — 단면을 위·아래 조각으로 갈라 링마다 관 지름만큼
* 벌린다(2026-08-25 사용자: 배관 외측 서피스 기준 관통 컷). 관이 닿지 않는
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
"""3D 코리도 구조물 — 선언 차례(PLAN 24-6a).
`ringsAt` 를 `const` 로 `pushSwept` 뒤에 선언했더니, 그 사이 기슭막이 단 반복이 `pushSwept` 를 곧바로 불러
ReferenceError(TDZ)가 나 기슭막이 있는 구간의 3D 코리도가 통째로 안 만들어졌다(2026-08-28 e371c275 ~).
쓰는 `const` 는 그것을 부르는 첫 호출보다 앞에 선언돼야 한다.
"""
from pathlib import Path
SOURCE = (
Path(__file__).resolve().parents[2] / "B05_Profile" / "B05_Profile_UI_Corridor_Structures.ts"
)
def test_ringsAt_는_pushSwept_와_첫_호출보다_앞에_선언():
source = SOURCE.read_text(encoding="utf-8")
rings = source.index("const ringsAt = ")
swept = source.index("const pushSwept = (")
first_call = (
source.index("pushSwept(\n") if "pushSwept(\n" in source else source.index("pushSwept(")
)
assert rings < swept, "pushSwept 가 ringsAt 를 쓴다 — 뒤에 선언하면 TDZ"
# 선언(`const pushSwept = (`) 뒤에 나오는 첫 호출 자리
first_call = source.index("pushSwept(", swept + len("const pushSwept = ("))
assert rings < first_call
def test_스윕_쓰는_const_는_호출보다_앞():
"""pushSwept · pushPierced 가 쓰는 도우미 const 가 첫 호출(기슭막이 단 반복)보다 앞에 있다."""
source = SOURCE.read_text(encoding="utf-8")
first_revet_loop = source.index("for (const tier of revetLayout.tiers)")
for name in ("const ringChainagesOf = ", "const ringsAt = ", "const pushSwept = ("):
assert source.index(name) < first_revet_loop, name