Files
GhiVideo/docs/history/2026-07-02_지도나침반-OSM-노스업-추가.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

4.4 KiB
Raw Permalink Blame History

지도 기반 나침반(OSM, 노스업) 추가 + 타입 전환

소요 시간: 약 30분 Context 사용량: input ~340k / output ~9k tokens

요구

우측 상단 나침반을 2종 중 선택. 새 '지도 기반 나침반' = 나침반 안에 지도 + 실시간 위치. 사용자 선택: OSM 온라인 타일 · 노스업(북쪽 고정) · 화면표시 옵션에 전환 버튼.

구현

클라이언트

  • store/settingsStore.ts: compassType: 'analog'|'map' + setter (persist).
  • components/overlay/MapCompass.tsx (신규):
    • OSM 타일을 Web Mercator 로 배치, 원형 클립. 노스업(지도 고정) + 현재위치 중심 점 + 진행방향 화살표(yaw 회전) + 상단 N.
    • poseRef(부모 RAF 갱신 {lat,lon,yaw}) 를 내부 RAF 로 읽어: 화살표 즉시 회전 + 지도 팬(transform) + 임계 이동 시 타일 재배치(setState).
    • 타일 URL = 서버 프록시 /api/tile/{z}/{x}/{y}.png (외부 직접 로드는 CSP/COEP 로 차단됨).
  • components/overlay/StationOverlay.tsx:
    • mapPoseRef 추가, RAF 나침반 블록에서 headingDeg 항상 계산해 기록(아날로그 회전은 렌더 중일 때만).
    • 렌더: compassType 에 따라 <MapCompass> / <Minimap> 선택.
    • 화면표시 옵션 '표시 토글'에 나침반 [눈금|지도] 버튼 추가.

서버 (프록시 필수)

  • CSP img-src 'self' + COEP require-corp 라 외부 타일 <img> 직접 로드 불가(elevation.ts 와 동일 제약).
  • server/src/routes/tile.ts (신규): GET /api/tile/:z/:x/:y → OSM 타일 fetch(식별 User-Agent) 후 같은 출처로 중계. Cross-Origin-Resource-Policy: same-origin, 7일 캐시, 좌표 검증(범위 밖 400).
  • server/src/app.ts: app.use('/api/tile', tileRouter).

배포

  • server/client 빌드 + PM2 restart ghiVideo(서버 라우트 반영 필수) 완료.
  • 검증: /api/tile/16/x/y.png → 200 image/png, CORP same-origin, 7일 캐시. 범위 밖 → 400. 클라 index-BS7bYMJ3.js.

추가: 줌 + 호버 확대 + 휠 줌

  • settingsStore compassZoom(12~19, 기본16) + setter(persist). MapCompass 에서 project(z 동적) 사용.
  • 나침반 하단 /z/+ 버튼(pointer-events auto). 줌 변경 시 현재위치 기준 타일 재배치.
  • 마우스 오버 → 2배 확대(transform scale, 우상단 고정 origin, 140ms), 벗어나면 원복.
  • 휠 줌: 컨테이너 native wheel 리스너(passive:false) → deltaY 로 compassZoom ±1(위=확대).
  • 호버/휠 위해 컨테이너 pointer-events auto(해당 영역만 이벤트 캡처).

개선(사용자 피드백)

  • 확대: CSS scale(흐릿) → 위젯 지름 자체 확대(BASE_D 150 → HOVER_D 300, 타일 재배치) → 더 넓은 영역을 선명하게. 마우스 오버 시 확대, 벗어나면 기본 크기+기본 줌(16) 복귀.
  • 방향 표시: 빨간 화살표 → 반투명 역삼각형(▽) = 드론 시야(중심에서 촬영방향으로 벌어짐, yaw 회전).
  • 줌 +/ 버튼·z값 표시 삭제. 줌은 휠만(오버 중), 벗어나면 기본값.
  • 상단 N: SVG text 로(위젯 크기에 맞춰 스케일) 크게·붉은색·반투명.
  • settingsStore 의 compassZoom 제거(줌은 MapCompass 로컬 상태로 이동, 세션 임시).

추가: 위성지도 옵션

  • 타일 프록시를 소스별로 확장: server/routes/tile.ts GET /api/tile/:source/:z/:x/:y
    • source=osm → OpenStreetMap 일반, source=sat → Esri World Imagery 위성(z/row/col 순서, jpeg).
  • settingsStore compassMapStyle: 'street'|'sat'(persist). MapCompass 타일 URL /api/tile/${src}/....
  • 화면표시 옵션에 지도 [일반|위성] 토글(지도 타입일 때만 노출).
  • server 재빌드 + PM2 restart. 검증: osm→200 png, sat→200 jpeg.
  • 주의: Esri World Imagery 는 출처표기 필요(내부 도구, 저부하). 대량이면 라이선스 검토.

주의/추후

  • OSM 타일 사용 정책: 저부하 유지(줌16 고정 + 클라 96px 이동 시에만 재배치 + 서버 7일 캐시). 대량이면 자체 타일/유료 서비스 검토.
  • 인터넷 없으면 타일 미표시(테두리/점/화살표만). 오프라인 필요 시 '노선 개요도(데이터 기반)' 타입 추가 검토.