Files
GhiVideo/docs/DefVideo→GhiVideo_업그레이드_상세.md
b23042andClaude Opus 4.8 e0ff5dd6d0 feat: 지도 나침반(OSM/위성) 추가 + 측점 검색·마커 정확도 개선 + POI/영상 수정
- 지도 기반 나침반(노스업, 현재위치, 시야 역삼각형): 호버 확대·휠 줌·클릭 위성전환, OSM/Esri 타일 서버 프록시(/api/tile)
- 스테이션 검색: 실제 측점(chain) 기준 이동, 없으면 '측점 없음' 안내
- 역 마커: 직교 투영 측점 일치 시에만 표시, 미도착 종점은 추가 방식
- POI 팝업 겹침/재등장·라벨 정합 수정
- 영상 fps 데이터 기반 자동 산출
- 기술/발표/쉬운설명 문서 추가

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 18:03:30 +09:00

16 KiB
Raw Permalink Blame History

DefVideo → GhiVideo 업그레이드 상세 문서

작성일: 2026-06-30 비교 기준: b23042/DefVideo(구버전) → b23042/GhiVideo(신버전) 두 저장소는 git 히스토리가 분리된 별도 저장소이며, 동일 코드베이스에서 파생되었다. 본 문서는 실제 소스 트리(diff -r)를 직접 비교하여 작성되었다.


0. 한눈에 보기

영역 변경 규모 평가
서버 (server) app.ts +2줄, 신규 elevation.ts(69줄) 거의 동일 — 골격 유지
공유 타입 (shared) 변경 없음 동일
클라이언트 (client) +3,000줄 순증 대폭 발전

핵심 결론: 기반 골격(서버 스트리밍/HLS/업로드, 공유 타입)은 그대로 유지하면서, 측점(체이니지) 기반 주행영상 분석 도메인 기능이 본격적으로 구현된 한 단계 발전한 버전이다. 세 갈래로 요약하면:

  1. V2.0 데이터 형식 대응 — 영상 옆 KMZ/KML을 1순위로 POI·구조물 추출(없으면 building/ 5종 CSV 폴백), 측점 CSV 기반 중심선 생성, 자동 인코딩 감지, 방향전환점 추출
  2. 투영 정확도 개선 — 지오이드 보정, 지면고도(DEM) 적용, 역투영 기반 위치 보정
  3. 영상 오버레이/편집 UI 고도화 — 라벨 평활, 겹침 억제, 컴팩트 팝업, 드래그 편집, 나침반 미니맵

1. 파일 단위 변경 요약

변경된 기존 파일

파일 변경량 내용
client/src/components/overlay/StationOverlay.tsx +1,188 / 167 라벨 평활·겹침억제·구조물표출·컴팩트팝업·편집모드 (최대 변경)
client/src/utils/geoData.ts +660 / 111 V2.0 폴더 파싱·구조물·방향전환점·POI보정
client/src/stationbar/StationBar.tsx +340 / 87 이동거리축·시설등급필터·종점역 미도착
client/src/stationbar/components/Timeline/Timeline.tsx +248 / 27 구조물 겹침필터·라벨 그룹핑
client/src/components/player/VideoPlayer.tsx +168 / 40 영상컨트롤 UI 통합·smoothTimeRef·폴더 드롭
client/src/utils/geoProjection.ts +138 / 5 지오이드 보정·역투영 함수 3종
client/src/types/geo.ts +54 / 7 구조물/방향전환점/보정 타입
client/src/store/geoStore.ts +47 / 3 POI 보정 분리관리·구조물 상태
client/src/components/overlay/RoutePanel.tsx +27 / 5 구조물 필터·방향 우선순위
client/src/store/playerStore.ts +13 / 1 videoReady·영상 해상도 상태
client/src/hooks/useVideoPlayer.ts +8 / 0 영상 로드 이벤트 추적
server/src/app.ts +2 / 0 elevation 라우트 등록

신규 추가 파일 (DefVideo엔 없음)

파일 줄수 역할
client/src/components/overlay/Minimap.tsx 69 드론 방위각(heading-up) 나침반 미니맵
client/src/store/settingsStore.ts 90 사용자 표시 설정 중앙 관리(localStorage 영속)
client/src/utils/chainage.ts 64 측점값(체이니지) 계산·중심선 투영
server/src/routes/elevation.ts 69 DEM(표고) 데이터 프록시 API

2. 데이터 처리 — V2.0 형식 대응 (geoData.ts)

가장 많이 변경된 유틸. 구버전은 center.csv + 단일 POI CSV 중심이었으나, 신버전은 영상 옆(root)의 KMZ/KML을 1순위 소스로 POI·구조물을 직접 추출하고, building/ 하위 CSV는 KMZ가 없을 때의 폴백으로 둔다(loadFolderGeoDatauseKmz 분기). 측점만 KMZ에 없어 항상 CSV에서 읽되, 측점·역사 CSV는 building/ 또는 root 어디서든 찾는다(폴더 삭제 대비). 즉 현재 데이터는 KMZ(root) + 측점 CSV(root)만으로 동작하며 building 폴더가 필수는 아니다.

2.1 자동 인코딩 감지

  • 구버전: 파일별로 utf-8 / euc-kr를 코드에 하드코딩
  • 신버전: ArrayBuffer 앞 3바이트(BOM EF BB BF)를 검사해 UTF-8/EUC-KR 자동 선택 → 혼재된 인코딩 자동 처리

2.2 데이터 소스 우선순위 (KMZ 우선 · CSV 폴백)

1순위: 영상 옆(root) *.kml / *.kmz   → parseKmz → POI·구조물 직접 추출
       (KMZ에 POI/구조물 있으면 useKmz=true → 아래 building CSV 미사용)

측점:  01)측점.csv  (building/ 또는 root) → 측점 + 방향전환점 (KMZ에 없어 항상 CSV)
역사:  02)지장물_역사.csv (building/ 또는 root) → 스테이션바 전용

폴백(KMZ 없을 때만):
  building/02)지장물.csv     → POI(지장물)
  building/03)교량.csv        → 구조물(bridge)
  building/04)터널.csv        → 구조물(tunnel)
  building/05)출입문번호.csv  → POI(출입문)
  building/06)구교.csv        → 구조물(bridge, 구교 아이콘)
  • center.csv를 더 이상 찾지 않고, 측점(01)을 측점값 순으로 이어 중심선을 생성(buildCenterlineFromStations())
  • 지장물·교량·터널·구교·출입문 CSV는 building/ 안에서만 찾지만, KMZ가 있으면 통째로 무시되므로 KMZ 기반 데이터에서는 building 폴더가 없어도 정상 동작한다.

2.3 CSV 파싱 견고성 강화

  • makeFieldIndexer(): 헤더명 기반 인덱싱 실패 시 위치 인덱스로 폴백 → 깨진 EUC-KR 헤더도 안전
  • cell(): 음수/범위 초과 인덱스에서 빈 문자열 반환 → 크래시 방지
  • rowProps(): CSV 원본 속성을 {k, v}[] 쌍으로 추출 → UI 라벨 클릭 팝업에 그대로 표출

2.4 신규 파싱 항목

  • 측점 + 방향전환점(parseStations()): Z좌표_한국(정표고, EPSG:5186) 우선 사용, 비고 컬럼에서 방향전환점(상행->하행, 02:05) 정규식 추출 → DirectionChange 생성
  • 구조물(parseStructures()): 교량/터널/구교 3종 통합, 위경도 대한민국 범위(33–39°N, 124132°E) 검증, 연장(m)·시설종별·분류 채움
  • 역사: type='station'으로 변환 → 스테이션바에만 표시(영상 오버레이 제외)
  • KMZ 원본(parseKmz()): 구글 어스 KMZ가 있으면 직접 추출(CSV 중복 회피), 측점만 항상 CSV 사용
  • POI 위치 보정(parsePoiOverrides()/applyPoiOverrides()): 드래그 보정값을 <base>_poi_overrides.json({title: {lat,lon,z}})으로 저장/복원

3. 투영 정확도 개선 (geoProjection.ts, chainage.ts)

3.1 카메라 파라미터 신규 필드

  • geoidOffset(m): 정표고(EL) → 타원체고 변환. 드론 abs_alt(타원체고)와 datum 일치 (대전 기본 25.8m, KNGeoid18)
  • poiZOffset(m): POI 전용 표고 보정. 선로 지면 가정 오차를 패널에서 조절

3.2 카메라 좌표 신규 필드

  • distH: 수평 거리(m) — POI 거리필터용
  • fwd/side: 진행방향(yaw) 기준 앞쪽/옆쪽 거리(m) → 비등방 거리필터(앞은 멀리, 옆은 가깝게) 구현 가능

3.3 역투영 함수 3종 신규 (편집 기능의 수학적 기반)

  • worldFromPixel(px, py, range): 화면 픽셀 + 슬랜트거리 → 월드좌표(lat/lon/z). POI 드래그 보정(수평+수직 동시)
  • solveZForPixelY(...): 특정 화면 세로위치에 맞는 표고(z) 역산. "앞으로 밀려 보이는 슬라이드" 보정
  • groundPointFromPixel(px, py, zGround): 화면점과 특정 고도평면의 교차점(lat/lon). 지면 좌표 보정

3.4 측점/체이니지 계산 (chainage.ts, 신규)

  • kmFromTitle("157K970")157970(m), fmtKm10()"157k970"
  • buildChainLine(): 측점 → 평면투영 폴리라인
  • projectToChain(): 드론 GPS → 폴리라인 투영 → {km(측점값), offsetM(선로 수직이격)}
  • nearestChainPoint(): 최근접 측점 검색 → StationBar·VideoPlayer HUD 공유

4. 영상 오버레이 고도화 (StationOverlay.tsx)

4.1 라벨 평활 & 이상치 거부

  • 이상치 거부: 한 프레임에 화면폭 12%(REJECT_DIST) 이상 점프하면 노이즈로 보고 이전 위치 유지. 단 연속 8프레임(MAX_REJECT_FRAMES) 초과 시 수용 → 시크/재등장에서 멈추지 않음
  • 속도 적응형 평활(One Euro 방식): 떨림(방향 왕복)은 강하게 평활, 실제 이동(방향 일관)은 즉시 추종 → 1배속 떨림 제거 + 빠른 배속 지연 해소
  • 조절 파라미터: smoothMinAlpha(정지 시 최소 추종), smoothSpeedRef(즉시추종 기준속도)

4.2 POI 겹침 억제

  • 화면상 가로 10%·세로 3.5% 이내 마커는 겹침으로 판정 → 드론에 더 가까운 것만 표시
  • 같은 건물 여러 업체/시설 중 주요한 것만 노출 → 화면 정리

4.3 구조물 표출 & 컴팩트 팝업

  • 교량/터널/구교를 POI처럼 라벨로 표출(이모지 🌉 구교, 🚪 출입문 추가)
  • 컴팩트 필드: 라벨 옆 항상 표시(시설종별 → 구조형식 → 연장 → 폭 → 용도 → 준공연도 순)
  • 클릭 시 전체 팝업 확장, 다시 클릭 시 컴팩트로 토글. 다중 팝업 누적 가능, ESC로 정리

4.4 POI 높이 모드 & DEM 자동 적용

  • 드론 높이 기준: POI를 드론보다 N미터 아래 고정(droneHeightDrop)
  • 지면고도 기준: POI를 실제 지형고도에 고정 → 드론 오르내려도 지물에 붙음
  • 서버 elevation API(SRTM 30m DEM)로 모든 좌표의 실제 표고 일괄 적용 → 먼 곳에서 밀리는 현상 완화

4.5 드래그 편집 & 세로화각 보정

  • POI를 마우스로 드래그 → groundPointFromPixel로 위경도 역산
  • 표고 슬라이더로 높이 미세조정, 개별 리셋 가능
  • 세로화각 보정 모드: 라벨이 상하로 어긋날 때 POI를 실제 위치로 드래그 → 세로 화각(sensorH)만 역산 자동보정
  • 보정값 JSON 내보내기/가져오기, 일괄 초기화

4.6 좌표 정렬 (object-fit:cover 보정)

  • coverRef: 영상이 object-fit:cover로 크롭된 영역을 매 프레임 계산 → 정규좌표(0–1) ↔ 화면 px 정확 변환 → 포인터 히트테스트 정확

5. 나침반 미니맵 (Minimap.tsx, 신규)

  • 우측 상단 고정 150×150px 아날로그 나침반 위젯(heading-up)
  • 고정 프레임(배경원/외곽링) + 회전 카드(6° 간격 60눈금 + N 문자 + 빨강/흰 삼각형)
  • 부모의 --rot CSS 변수로 부드럽게 회전, StationOverlay RAF에서 매 프레임 갱신(360° 언랩)
  • 효과: 영상만으로 드론이 향하는 방향을 한눈에 파악

6. 하단 측점바 & 타임라인 (StationBar.tsx, Timeline.tsx)

6.1 측점 정확도 개선

  • 이동거리축 추가: 드론 실제 GPS 이동량을 시간축에 반영 → 호버(공중 대기) 구간 가시화, 전진/후진 색 리본(주황/하늘색) 구분
  • 영상 FPS 자동 적응: 고정 29.97 대신 마지막 프레임 / 재생시간으로 영상별 계산 → 측점 배지 정확도 향상
  • kmExists 플래그: 실제 측점값 존재 여부 구분 → 좌표 반경만으로 잡힌 통과는 라벨 제외

6.2 시설등급 필터 & 구조물 표시

  • 1종/2종/3종/기타 선택적 표시(settingsStore 연동, 체크박스 즉시 반영)
  • 긴 이름 2줄 분할(CJK 1.0/영문 0.55 가중치)
  • 상/하행 평행 변형은 영상 진행방향에 따라 하나만 표시
  • 동명 구조물 반복 통과 → 중앙 라벨 1개 + 통과점 점선 드롭 + 수평 브래킷

6.3 종점역 미도착 시각화

  • 영상이 종점역에 미도달 시 트랙 우측을 회색(재생불가)으로 표시(상한 15%)
  • 종점역 마커를 '속 빈 링' 스타일(미도착)로

7. 영상 플레이어 (VideoPlayer.tsx, useVideoPlayer.ts, playerStore.ts)

  • 영상제어 UI 수평 통합: 좌하단 컨트롤을 한 줄 가로 배열(영상제어 | 배속 | 프레임 | 좌측패널 | 선형 | 드론궤적 | GPS/고도 | 시설등급), flex-wrap 자동 줄바꿈
  • smoothTimeRef: 벽시계 기준 단조 보간 시간 → StationBar가 ref로 직접 읽어 React 리렌더 없이 transform 갱신 → 60fps 부드러운 커서, 시크 시 즉시 재동기화
  • videoReady 게이트: loadeddata 이후에만 오버레이 렌더 → 영상보다 먼저 그려지는 깜빡임 제거
  • 영상 해상도 추적: videoWidth/videoHeight로 object-fit:cover 정렬 정확화
  • 폴더 드롭 지원: webkitGetAsEntry() 디렉토리 재귀 순회 → 영상+측점/POI 폴더 통째 로드
  • 드론 정보 HUD: 현재 프레임 최근접 드론 GPS/고도 항상 표시
  • 버튼 정렬: min-w-[96px] 고정폭 + amber 활성색, 프레임번호 6자리 고정폭

8. 설정 중앙 관리 (settingsStore.ts, 신규)

Zustand + persist(localStorage: 'ghivideo.settings')로 다음 표시 설정을 영속화한다.

기본값 용도
gradeFilter {1종:T, 2종:T, 3종:F, 기타:T} 시설종별 표시 필터
poiOverlapExclude true 겹친 POI 숨김
showRoutePanel true 좌측 노선 패널
showStationDiag false 측점 진단 HUD
showCenterline true 선형(중심선) 오버레이
showDronePath true 드론 궤적 오버레이
  • 누락된 키는 기본값으로 자동 보충(스키마 진화 대비)
  • isGradeVisible() 공유 함수로 StationBar·RoutePanel·StationOverlay가 동일 규칙 적용

9. 서버: 고도 API 프록시 (elevation.ts, 신규)

  • 브라우저 COEP/CSP 제약으로 클라이언트가 외부 DEM API를 직접 호출 불가 → 서버 중계
  • GET /api/elevation?lat=36.4,36.5&lon=127.4,127.5 (배치, 콤마 구분)
  • 응답: { elevation: number[], source }
  • 폴백 전략: ① opentopodata SRTM 30m(정밀) → ② open-meteo 90m(폴백)
  • app.tsapp.use('/api/elevation', elevationRouter) 등록 (서버 변경은 이것 + 라우트 파일이 전부)

10. 타입/스토어 변경 요약

geo.ts 신규/확장

  • GeoPoint.props: CSV 원본 속성 {k,v}[] (팝업 표시)
  • RouteStructure: lengthM(연장) · category(교량/터널/구교/역사) · grade(시설종별) · props 추가
  • DirectionChange(신규): station · from/to · atSeconds
  • PoiOverride / PoiOverrideMap(신규): 드래그 보정값
  • RouteMeta.endStationGapMeters: 종점역 미도착 거리
  • FolderGeoData: structures · directionChanges · poiOverrides 추가

geoStore.ts

  • POI 보정 분리관리: basePois(원본) + poiOverrides(보정맵) → applyPoiOverrides() 결과가 pois
  • 신규 상태: structures, directionChanges
  • 신규 메서드: setPoiOverride(), clearPoiOverride(), setPoiOverrides()
  • loadFromFolder(): Promise.all 병렬 로딩으로 8개 파서 동시 실행

11. 사용자 체감 개선 총괄

항목 개선 효과
라벨 안정성 떨림/튐 제거 — 이상치 거부 + 속도적응 평활
화면 가독성 겹친 POI/구조물 자동 숨김
정보 탐색 다중 팝업 + 컴팩트/전체 토글 + ESC 정리
위치 정확도 지오이드 보정 + DEM 실제 표고 + 역투영 편집
편집 편의 드래그 + 표고 슬라이더 + 세로화각 자동보정 + JSON 저장
측점 정확도 이동거리축(호버 가시화) + 영상별 FPS 자동
커서 부드러움 smoothTimeRef 단조보간 → 60fps
작업 효율 폴더 통째 드롭 로드, 설정 localStorage 영속
방향 인지 나침반 미니맵으로 드론 방위각 실시간 표시
오버레이 안정 videoReady 게이트로 깜빡임 제거

본 문서는 DefVideoGhiVideo의 소스 트리 전체 비교(diff -r) 및 주요 변경 파일의 라인 단위 분석을 통해 작성되었다.