- 지도 기반 나침반(노스업, 현재위치, 시야 역삼각형): 호버 확대·휠 줌·클릭 위성전환, OSM/Esri 타일 서버 프록시(/api/tile) - 스테이션 검색: 실제 측점(chain) 기준 이동, 없으면 '측점 없음' 안내 - 역 마커: 직교 투영 측점 일치 시에만 표시, 미도착 종점은 추가 방식 - POI 팝업 겹침/재등장·라벨 정합 수정 - 영상 fps 데이터 기반 자동 산출 - 기술/발표/쉬운설명 문서 추가 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
16 KiB
16 KiB
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/업로드, 공유 타입)은 그대로 유지하면서, 측점(체이니지) 기반 주행영상 분석 도메인 기능이 본격적으로 구현된 한 단계 발전한 버전이다. 세 갈래로 요약하면:
- V2.0 데이터 형식 대응 — 영상 옆 KMZ/KML을 1순위로 POI·구조물 추출(없으면
building/5종 CSV 폴백), 측점 CSV 기반 중심선 생성, 자동 인코딩 감지, 방향전환점 추출 - 투영 정확도 개선 — 지오이드 보정, 지면고도(DEM) 적용, 역투영 기반 위치 보정
- 영상 오버레이/편집 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가 없을 때의 폴백으로 둔다(loadFolderGeoData의 useKmz 분기). 측점만 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, 124–132°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 문자 + 빨강/흰 삼각형)
- 부모의
--rotCSS 변수로 부드럽게 회전, 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.ts에app.use('/api/elevation', elevationRouter)등록 (서버 변경은 이것 + 라우트 파일이 전부)
10. 타입/스토어 변경 요약
geo.ts 신규/확장
GeoPoint.props: CSV 원본 속성{k,v}[](팝업 표시)RouteStructure:lengthM(연장) ·category(교량/터널/구교/역사) ·grade(시설종별) ·props추가DirectionChange(신규):station·from/to·atSecondsPoiOverride/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 게이트로 깜빡임 제거 |
본 문서는 DefVideo와 GhiVideo의 소스 트리 전체 비교(diff -r) 및 주요 변경 파일의 라인 단위 분석을 통해 작성되었다.