fix: 중심선 스무딩 적용 및 디버그 패널 제거
- renderCacheRef useEffect에서 CL 계산 시 smoothFrame 적용 (텍스트와 동일한 smooth 슬라이더 값 공유) - currentFrameIdxRef 추가로 smoothFrame 인덱스 전달 - 디버그 패널(frame/frac/mapSize) 캔버스에서 제거 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -114,6 +114,7 @@ export default function StationOverlay({ currentFrame, currentTime, fps, visible
|
||||
// 현재 상태 ref
|
||||
const currentDroneFrameRef = useRef<DroneFrameBasic | null>(null);
|
||||
const currentFrameNumRef = useRef<number>(0); // RAF에서 Map 조회용
|
||||
const currentFrameIdxRef = useRef<number>(0); // smoothFrame용 배열 인덱스
|
||||
const currentTimeSecRef = useRef<number>(0); // 마지막으로 알려진 재생 시간
|
||||
const timeUpdateWallRef = useRef<number>(performance.now()); // currentTime 갱신된 시각
|
||||
const paramsRef = useRef<CameraParams>(DEFAULT_CAMERA_PARAMS);
|
||||
@@ -298,13 +299,14 @@ export default function StationOverlay({ currentFrame, currentTime, fps, visible
|
||||
if (!visible || !droneFramesLoaded) return;
|
||||
const frames = allDroneFramesRef.current;
|
||||
if (!frames.length) return;
|
||||
let best = frames[0], bestD = Math.abs((best.frame ?? 0) / VIDEO_FPS - currentTime);
|
||||
for (const f of frames) {
|
||||
const d = Math.abs(f.frame / VIDEO_FPS - currentTime);
|
||||
if (d < bestD) { bestD = d; best = f; }
|
||||
let best = frames[0], bestIdx = 0, bestD = Math.abs((best.frame ?? 0) / VIDEO_FPS - currentTime);
|
||||
for (let i = 0; i < frames.length; i++) {
|
||||
const d = Math.abs(frames[i].frame / VIDEO_FPS - currentTime);
|
||||
if (d < bestD) { bestD = d; best = frames[i]; bestIdx = i; }
|
||||
if (bestD < 1 / VIDEO_FPS / 2) break;
|
||||
}
|
||||
currentFrameNumRef.current = best.frame;
|
||||
currentFrameIdxRef.current = bestIdx;
|
||||
currentTimeSecRef.current = currentTime;
|
||||
timeUpdateWallRef.current = performance.now();
|
||||
if (currentDroneFrameRef.current?.frame !== best.frame) {
|
||||
@@ -315,10 +317,14 @@ export default function StationOverlay({ currentFrame, currentTime, fps, visible
|
||||
|
||||
// 중심선 + 나침반 캐시 빌드 (per-frame, 텍스트 계산 없음)
|
||||
useEffect(() => {
|
||||
const drone = currentDroneFrameRef.current;
|
||||
if (!drone || !visible) { renderCacheRef.current = null; return; }
|
||||
if (!currentDroneFrameRef.current || !visible) { renderCacheRef.current = null; return; }
|
||||
|
||||
const t0 = performance.now();
|
||||
// 중심선도 smoothFrame 적용 (텍스트와 동일한 스무딩)
|
||||
const frames = allDroneFramesRef.current;
|
||||
const drone = frames.length
|
||||
? smoothFrame(frames, currentFrameIdxRef.current, smoothHalfRef.current)
|
||||
: currentDroneFrameRef.current;
|
||||
const params = paramsRef.current;
|
||||
const worldOrigin = worldOriginRef.current;
|
||||
const allCL = allCenterlinePointsRef.current;
|
||||
@@ -426,28 +432,12 @@ export default function StationOverlay({ currentFrame, currentTime, fps, visible
|
||||
const elapsed = (performance.now() - timeUpdateWallRef.current) / 1000;
|
||||
const estTime = currentTimeSecRef.current + elapsed;
|
||||
const frac = Math.min(0.999, (estTime * VIDEO_FPS) - frameNum); // 0~0.999
|
||||
const mapSize = labelMapRef.current.size;
|
||||
const labelsA = labelMapRef.current.get(frameNum);
|
||||
const labelsB = labelMapRef.current.get(frameNum + 1);
|
||||
|
||||
// 두 프레임 사이 픽셀 좌표 보간
|
||||
const interpY = (a: number, b: number | undefined) => b !== undefined ? a + (b - a) * frac : a;
|
||||
|
||||
// 디버그 표시 (좌하단)
|
||||
ctx.font = '11px monospace';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.6)';
|
||||
ctx.fillRect(6, H - 54, 300, 48);
|
||||
ctx.fillStyle = '#0f0';
|
||||
ctx.fillText(`frame: ${frameNum} frac: ${frac.toFixed(2)} mapSize: ${mapSize}`, 10, H - 50);
|
||||
const firstSt = labelsA?.stationLabels[0];
|
||||
const firstStB = labelsB?.stationLabels[0];
|
||||
const dispY = firstSt ? interpY(firstSt.sy, firstStB?.sy) * H : 0;
|
||||
ctx.fillText(`labels: ${labelsA?.stationLabels.length ?? '-'} firstY: ${firstSt ? dispY.toFixed(1) : '-'}px`, 10, H - 36);
|
||||
ctx.fillText(`smooth: ±${smoothHalfRef.current}fr interp: ${frac.toFixed(2)}`, 10, H - 22);
|
||||
ctx.textBaseline = 'alphabetic';
|
||||
|
||||
if (labelsA) {
|
||||
const α = emaAlphaRef.current;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user