개발 취재 노트
격자 크기가 기록 안 된 좌표 데이터에서 원래 스냅 간격을 찾아내는 법
무용 연습 영상 위에 격자를 띄우고 시점마다 무용수 위치를 찍어 대형(포메이션)·동선을 편집하는 웹 앱(formation)에서, 댄서 12명·83개 키프레임짜리 안무 데이터를 격자에 맞춰 정리하려 했다. 그런데 좌표 파일에는 애초에 어떤 격자 크기로 찍었는지 기록이 없었다 — 저장 형식이 숫자 배열뿐인 구버전이라 격자 설정값 자체가 사라져 있었다.
결론
좌표가 격자에 "대략" 맞는데 완전히는 아니고, 그 격자 크기 자체가 파일에 안 남아 있다면 — 후보 격자 크기들을 하나씩 대보면서 각 점이 격자선에 얼마나 가까운지(적합률) 를 비교해 역산할 수 있다. 이때 "온전한 칸" 격자만 보지 말고 반 칸(half-cell, 선과 칸 중앙까지 포함하는 격자) 도 같이 검증해야 한다. 이 사건에서는 전체 칸 격자 적합률이 55%였지만 반 칸 격자는 91%였다 — 범위를 반으로 좁힌 격자가 실제 정답이었다 .
오차·적합률 계산법: 좌표를 후보 격자 간격(step)으로 나눈 나머지를 구해, 가장 가까운 격자선까지의
거리로 바꾼다(나머지가 step/2보다 크면 step에서 뺀 값을 쓴다). 이 거리를 step 대비 비율로 정규화한
게 "오차"(0~50%)다. 오차가 허용오차(예: step의 10% 이내) 안에 드는 점의 비율이 "적합률"이다 —
허용오차를 좁게 잡을수록 맞는 후보와 틀린 후보의 적합률 격차가 커져 구분이 쉬워진다.
격자 정의: cell = gridSize × (w/800)
화면 gridSize=50 기준 정규화 간격: 가로 0.0625 / 세로 0.1111 [S:dae2585f#24][S:dae2585f#25]
1차 실측(전체 칸 격자): x 중앙값 4% · y 중앙값 7% 벗어남 → 격자 기반은 맞는데 딱 맞진 않음 [S:dae2585f#27]
2차 실측(반 칸 격자): 91% 적합 (전체 칸은 55%) → 반 칸이 실제 격자 [S:dae2585f#28]
gridSize 20~100 전체 스캔 → stepX=0.03125, stepY=0.05556 (gridSize 50의 반 칸)에서 x 90%·y 91% 최적 [S:dae2585f#29][S:dae2585f#30]
상황
formation은 리더 한 명이 영상을 재생하면 나머지가 각자 폰으로 접속해 같은 지점의 영상과 대형을 함께 보는 라이브 기능도 갖고 있지만, 이 사건은 그 전 단계 — 에디터에서 찍은 좌표를 정리하는 작업에서 나왔다. 좌표는 x, y 모두 0~1로 정규화해 저장하고 , 격자는 화면 픽셀 기준 cell = gridSize × (w/800)으로 정의된다 . 영상 해상도가 1920×1080(16:9)이라, 화면에서 정사각형인 격자 칸도 정규화 좌표계에서는 가로 0.0625·세로 0.1111로 간격이 다르다 .
좌표 지터 제거·정렬 스냅 작업을 먼저 하던 중, "격자 사이즈도 확인돼? 격자에 맞춰서 배치를 하려고 하는데 지금은 격자에 맞춰지지 않고 좀 비뚤어"라는 요청이 나오면서 격자 조사가 시작됐다 .
증상
격자 간격을 계산해 좌표를 실측해보니, 완전히 벗어나 있지는 않았다(x 중앙값 4%, y 중앙값 7% 오차) — 격자 기반 배치인 건 맞는데, 그대로 전체 칸에 스냅하면 틀렸다. 일부 점들의 분포가 격자 중간(half-cell) 쪽에 몰려 있었다 . 전체 칸으로 밀어붙이면 애초에 중간에 찍으려던 의도된 위치가 뭉개질 상황이었다.
원인
- 격자 크기가 파일에 저장되지 않음: 저장 형식이
{gridSize, keyframes}가 아니라 좌표만 담은 bare array(구포맷)라, 실제 편집 당시 쓰던 gridSize 값이 사라져 있었다 . - 에디터에 드래그 스냅 기능이 없음: 격자 슬라이더(20~100, 기본 50)는 있지만 드래그할 때 격자에 달라붙는 기능 자체가 없어서, 안무가가 격자선·칸 중앙 근처에 눈대중으로 찍었다 . 그래서 좌표가 격자에 "거의" 맞지만 완전히는 안 맞았다.
- "전체 칸"이라는 가정이 틀림: 처음엔 화면 gridSize 그대로의 격자(온전한 칸)에 맞을 거라 가정했지만, 실제 배치 기준은 그 절반 — 선과 칸 중앙까지 모두 격자점으로 쓰는 반 칸 격자였다.
해결
가진 건 "격자 기반인 것 같다"는 심증과, 격자 크기를 모르는 좌표 숫자들뿐이었다. 그래서 후보 격자 크기를 넓게 스캔하며 통계적으로 역산했다.
- 전체 칸 격자로 먼저 실측한다. 각 좌표가 가장 가까운 격자선에서 얼마나 떨어져 있는지 오차를(위 계산법대로) 구해, 중앙값과 분포를 본다. 이 사건에서는 x 4%·y 7%로 "격자 기반은 맞다"는 신호는 나왔지만 완전히 맞진 않았다 .
- 오차 분포에서 반 칸 편향을 의심한다. 오차 값들이 0 근처가 아니라 칸의 중간(half-cell) 근처에 몰려 있으면, 격자 크기 자체를 반으로 잡고 다시 재야 한다. 재보니 반 칸 격자 적합률이 91%로 전체 칸(55%)을 크게 앞섰다 .
- 격자 크기 자체도 모른다면 범위를 정해 전부 스캔한다. 이 사건에서는 에디터 슬라이더 범위가 20~100이라는 걸 코드에서 확인했으므로, 그 전체 구간을 훑어 각 gridSize(및 그 반 칸)에 대해 위 계산법으로 x·y 적합률을 계산했다.
stepX=0.03125, stepY=0.05556(= gridSize 50의 반 칸 = gridSize 25 격자)에서 x 90%·y 91%로 가장 잘 맞았다 . - 역산한 격자로 모든 점을 가장 가까운 격자점에 스냅하고, 같은 칸에 두 점이 겹치면 가까운 빈 칸으로 옮긴다. 1034개 좌표 전부 격자점에 안착했고, 무대의 3%를 넘게 움직인 건 7개뿐(최대 3.6%), 충돌 6건은 빈 칸으로 정리됐다 .
- 뒤이어 "더 촘촘히 놓아보자"는 요청으로 격자를 gridSize 50→25로 좁혀(스냅 간격을 다시 절반으로) 재적용하니 최대 이동이 3.6%→1.7%로 줄고 3% 초과 이동은 0건이 됐다 . 같은 방식을 다른 안무 파일(927개 좌표)에도 적용했을 때도 같은 격자가 x 98%·y 93%로 들어맞아, 방법이 특정 파일 하나의 우연이 아님을 확인했다 .
핵심은 "격자에 맞는 것 같다"는 느낌을 적합률이라는 숫자로 바꾸고, 전체 칸뿐 아니라 그 배수·절반까지 후보에 넣어 스캔한 것이다. 격자 크기를 안다고 가정한 채 스냅만 돌리면, 이 사건처럼 틀린 칸에 억지로 밀어넣어 의도된 배치를 뭉개게 된다.
덤 — 구현 보고와 실제 확인은 별개다
이 작업 내내 "완료했습니다", "1034개 점 전부 격자점에 정확히 안착" 같은 보고가 단계마다 나왔지만 , 그 결과물(비교 뷰어)을 실제로 열어 격자 스냅이 맞는지 시각적으로 확인하는 명시적인 동의는 이 세션 안에는 없다. 원본 파일에 덮어쓸지 묻는 질문()에도 답 없이 세션이 다른 주제(모바일 네트워크 구성)로 넘어갔다 . 통계적으로 맞는 격자를 찾아내는 것과, 그 결과가 실제로 쓸 만한지 눈으로 보고 받는 확인은 별개의 단계라는 뜻이다.
취재 후기 — 격자가 반 칸씩 밀려 있던 이유
격자 스냅 작업 로그를 띄워 놓고 넷이 모였다.