# 지리정보 + 측점 + 프레임 맵핑 구조 분석 **작업일**: 2026-06-17 **작업명**: 지리정보·측점·프레임 맵핑 구조 소스 분석 + station 기준 재생 HTML 문서화 **소요 시간**: 18분 **Context 사용량**: input 60k / output 8k tokens **이슈**: #0 --- ## 목적 영상 프레임 ↔ 측점 ↔ 지리정보(POI/중심선)가 현재 소스에서 어떻게 맵핑되는지 코드 기반으로 파악. 추가로 "시간 기준이 아닌 station(측점) 기준 재생"을 위한 맵핑 구조를 HTML 문서로 출력. ## 분석 대상 파일 - [server/src/services/geoMatch.ts](../../server/src/services/geoMatch.ts) — 서버 투영/매칭 (평면근사 ENU) - [server/src/routes/geo.ts](../../server/src/routes/geo.ts) — geo API 엔드포인트 - [client/src/utils/geoProjection.ts](../../client/src/utils/geoProjection.ts) — 클라 투영 (EPSG:5186 TM, Python advanced_tuner_v2.py 동일) - [client/src/components/overlay/StationOverlay.tsx](../../client/src/components/overlay/StationOverlay.tsx) — 실시간 캔버스 오버레이 - [client/src/components/geo/StationVerify.tsx](../../client/src/components/geo/StationVerify.tsx) — 측점→프레임 점프 검증 패널 - [client/src/components/player/VideoPlayer.tsx](../../client/src/components/player/VideoPlayer.tsx) — frame↔time 변환 ## 핵심 결론 ### 맵핑 키 = 프레임 번호 - 드론 CSV의 `frame_cnt` = 영상 프레임 ↔ GPS+자세 연결고리 - `time = frame / fps` - **fps 불일치 발견**: 클라 `VIDEO_FPS = 30000/1001 = 29.97`, 서버 `DEFAULT_FPS = 30`. seek는 frame번호 기반이라 실害 적으나 서버 `FrameMatch.time` 부정확. ### 데이터 소스 (GEO_DATA_DIR 기본 samplevideo/) 1. `*회덕*.csv` — 드론 비행로그 (frame_cnt, lat, lon, alt, yaw, pitch, roll, focal_len) 2. `building/*POI*위경도*.csv` — 지장물 (타원체고 버전 우선) 3. `building/*측점*위경도*.csv` — 측점 4. `pythonsource/input/center.csv` — 선로 중심선 224점 (타원체고 col5) 5. `*.srt` — terrain offset (로드만, 거의 미사용) ### 투영 파이프라인 ``` geo(lat,lon,z) → ENU world(m) → 카메라 상대벡터 → 회전(yaw/pitch/roll) → 핀홀 투영 px,py(0~1) ``` - 월드 원점 = **첫 측점** (측량 기준점), 드론 frame[0] 아님 → 드론 GPS 오차 회피 - 서버/클라 투영 **구현 2벌** (서버=cos(lat) 평면근사, 클라=EPSG:5186 TM proj4) — 정밀도 차이 ### 두 방향 질의 - `findFramesForPoi(name)`: 측점명 → 전 프레임 투영 → FOV 안 → 연속구간 그룹화(GAP=30) → 구간별 중심 프레임. (StationVerify 점프) - `findPoisForFrame(n)`: 프레임 → 보이는 POI 목록. ### 클라 실시간 오버레이 - idle time에 `Map` 사전계산 - RAF 루프: Map 조회 + frameNum→+1 보간 + EMA 스무딩 → canvas - 측점은 투영 전 가장 가까운 중심선 점에 스냅 (nearestCL, z도 중심선값) - smoothFrame: 드론 자세 ±N프레임 이동평균으로 GPS/IMU 노이즈 제거 ### 측점 순서 - `stationOrder`: title `\d+K\d+` 파싱 = km측점 ("12K345" = 12.345km). 서버/클라 동일 함수. ## Station 기준 재생 관점 현재 구조는 "시간(프레임) → 지리정보" 단방향 표시 중심. station 기준 재생 = **측점 → 대표 프레임 → seek** 역방향이 핵심. - 이미 존재하는 빌딩블록: `findFramesForPoi` (측점→최적 프레임), `onSeekToFrame` (프레임→`currentTime(frame/fps)`). - station 기준 타임라인을 만들려면: 전 측점에 대해 `findFramesForPoi` 1회 일괄 호출 → 측점별 대표 프레임 테이블 구성 → km 순 정렬 → 측점 간 이동 = seek. - 산출물: 맵핑 구조 + station 기준 재생 설계를 정리한 HTML (`docs/geo-station-mapping.html`). ## 후속 참고 - fps 불일치(30 vs 29.97) 정리 검토 가치 있음 - 서버/클라 투영 알고리즘 통일 여부 결정 필요 (현재 클라가 정밀) - station 기준 재생용 측점→프레임 테이블 API(`/api/geo/station-index` 등) 신설 검토