fix(B05,B06): 계획고를 조절해도 횡단 기준 유토곡선이 안 따라오던 것 — 계산 캐시 제거

사용자 보고(2026-09-04) — 「종단 곡선 조절에 따라 횡단 기준 유토곡선 변경 안 됨」.
오늘 프레임을 아끼려고 넣은 곡선 계산 캐시가 원인. 횡단 설계는 `refreshCrossDesigns` 가
**같은 객체를 제자리에서 고치므로**(배열·요소 동일성 유지) 「입력 객체가 같으면 안 바뀐 것」
이라는 캐시 판정이 성립하지 않음. B06 은 `detail` 동일성으로 캐시해 **한 번 계산한 뒤로는
영원히 낡은 곡선**을 보였음.

- 두 곳(B05 패널·B06 조립기)의 캐시를 걷어내고 그릴 때마다 계산하게 되돌림.
- 왜 캐시하면 안 되는지 주석으로 못 박음.

자체검증(공용 브라우저 임시 탭):
① B06 — 횡단 지반 종류를 바꾸자 절토 4,500.3 → 4,500.7㎥, 토취 10,211.5 → 10,211.1㎥,
   곡선 경로도 바뀜(고치기 전에는 완전 동일)
② B05 — 계획고 6칸 올리자 계획선·유토곡선 둘 다 바뀜(성토 14,729 → 17,513㎥)
③ 휠 20칸 기준 최대 프레임 27.0ms, 33ms 초과 **0건**(캐시 없어도 예산 안)
④ 전체 시험 381 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 23:10:22 +09:00
co-authored by Claude Opus 5
parent 27751d76ad
commit 79dc0cc82d
2 changed files with 14 additions and 60 deletions
+8 -38
View File
@@ -308,41 +308,6 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa
bar.append(empty);
}
/** 곡선 계산 아낌 — 입력 객체가 그대로면 다시 계산하지 않는다. */
let seriesCache: {
longitudinal: RouteMassHaulDrawParams["longitudinal"];
crossSections: RouteMassHaulDrawParams["crossSections"];
context: RouteMassHaulContext;
series: MassHaulSeries[];
} | null = null;
function cachedSeries(
params: RouteMassHaulDrawParams,
current: RouteMassHaulContext,
): MassHaulSeries[] {
if (
seriesCache &&
seriesCache.longitudinal === params.longitudinal &&
seriesCache.crossSections === params.crossSections &&
seriesCache.context === current
) {
return seriesCache.series;
}
const series = computeMassHaulSeries(
params.longitudinal,
params.crossSections,
current.conversion,
current.naturalSpoilMinSlope,
);
seriesCache = {
longitudinal: params.longitudinal,
crossSections: params.crossSections,
context: current,
series,
};
return series;
}
// 세로창 버티기·부드러운 이동 상태 — 이 패널이 사는 동안 하나만 둔다(2026-09-04).
const windowState = createMassHaulWindowState();
/** 마지막으로 그린 입력 — 이동이 아직 안 끝났으면 다음 프레임에 이걸로 한 번 더 그린다. */
@@ -372,9 +337,14 @@ export function createRouteMassHaulPanel(onChanged: () => void): RouteMassHaulPa
}
pendingChip.hidden = true;
// B06과 같은 계산 — 횡단 기준(정식)과 종단 기준(개략 비교)을 함께 낸다.
// 가로로 스크롤할 때는 **입력이 그대로**인데 그릴 때마다 다시 계산하면 프레임을 잡아먹는다
// (2026-09-04 실측: 세로창 이동 중 33ms 넘는 프레임 다수). 같은 입력이면 아껴 둔 것을 쓴다.
const series: MassHaulSeries[] = cachedSeries(params, context);
// 결과를 아껴 두지 **않는다** — 횡단 설계가 제자리에서 갈리므로 객체 동일성으로는
// 바뀐 것을 못 잰다(2026-09-04 캐시를 넣었다가 곡선이 안 따라와 되돌림).
const series: MassHaulSeries[] = computeMassHaulSeries(
params.longitudinal,
params.crossSections,
context.conversion,
context.naturalSpoilMinSlope,
);
if (!series.length) {
note("횡단 설계가 아직 없어 유토곡선을 그릴 수 없습니다.");
return;