표고 체계 정비·설정 파일 단순화·선형 클리핑·시연 준비
- 타원체고 기준 자동 변환: route.json ellipsoidal_height 선언 시 드론 고도(CSV 정표고)를 영상 메타(djmd 6.6 타원체고)와의 차(지오이드고 자동 산출)만큼 보정, 세그먼트 전환에도 유지 - KML 표고 파이프라인: 좌표 고도(z) 사용(POI/측점), *_byDem.kml 자동 생성(DEM 조회·높이 속성 포함) + 로더의 _byDem 우선 규칙, 선형중심선(LineString) 로딩·경로표고 앵커 - 설정 파일: camera.json/display.json/route.json 단순 이름 인식, 화면표시 옵션 PC 저장/자동 적용, 초기화 버튼을 환경설정 파일 기준 복원으로 변경, 저장 파일명 단순화 - 선형 표시: 표출된 마지막 측점까지 클립(경계 세그먼트 절단 + 관통 현 처리 — 구간 실종 수정) - 스테이션바: 시점(0k000) 마크(실통과 위치), 노선밖 프레임 통과 오인 방지, 커서 배지 1m 단위, 배너 연장/소요 실측값(측점 체이니지·영상 길이 합) 우선 - 세그먼트 전환 라벨 깜빡임 구조 수정(캐시 초기화·최근접 키 조회·이중 재계산 제거) + 사전계산 프레임 불변값 호이스팅(재생 지연 해소) - UI: 슬라이더/값 입력칸 휠 조절, 패널 버튼 위치 정렬, 저장 버튼 중복 제거, dev_mode(route.json)로 영상제어 UI 표시 제어, 지오이드 최대 200, 이격거리 측점 동반 적용 - 시연: start-demo.bat + docs/DEMO.md - docs/history: 작업 이력 30건 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import { usePlayerStore } from '../../store/playerStore';
|
||||
import { useGeoStore } from '../../store/geoStore';
|
||||
import { useSettingsStore, KNOWN_GRADES } from '../../store/settingsStore';
|
||||
import { captureFrame, downloadDataUrl } from '../../utils/frameCapture';
|
||||
import { generateByDemKmls } from '../../utils/demKml';
|
||||
import { secondsToTimecode, secondsToFrame } from '../../utils/timecode';
|
||||
import { useCaptureStore } from '../../store/captureStore';
|
||||
import HlsConversionStatus from './HlsConversionStatus';
|
||||
@@ -125,6 +126,14 @@ const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
||||
const geoLoaded = useGeoStore((s) => s.loaded);
|
||||
// 드론 정보 — 하단바에 GPS/고도 항상 표시.
|
||||
const storeFrames = useGeoStore((s) => s.frames);
|
||||
// dev_mode (route.json) — 0 이면 '영상제어' 버튼과 제어 UI 전체를 숨김(뷰어 모드).
|
||||
// routeInfo.dev_mode 우선, 최상위 dev_mode 도 허용. 없으면 1(표시) — 기존 동작 유지.
|
||||
const storeRouteMeta = useGeoStore((s) => s.routeMeta);
|
||||
const devMode = (() => {
|
||||
const ri = storeRouteMeta?.routeInfo as Record<string, unknown> | undefined;
|
||||
const v = ri?.dev_mode ?? (storeRouteMeta as unknown as Record<string, unknown> | null)?.dev_mode;
|
||||
return v === 0 || v === '0' ? 0 : 1;
|
||||
})();
|
||||
// 분할 영상 재생목록 — 폴더 로드 시 이름 오름차순. 목록 클릭으로 세그먼트 직접 선택 재생.
|
||||
const videoFiles = useGeoStore((s) => s.videoFiles);
|
||||
const videoDurations = useGeoStore((s) => s.videoDurations);
|
||||
@@ -162,6 +171,18 @@ const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
||||
'(측점·드론 정보는 정상 로드되었습니다.)',
|
||||
);
|
||||
}
|
||||
// 표고(z) 없는 KML → DEM(SRTM 30m)으로 채운 <이름>_byDem.kml 자동 생성·다운로드.
|
||||
// 폴더에 _byDem 이 이미 있으면 건너뛰고, 로더는 _byDem 을 원본보다 우선 사용한다.
|
||||
void generateByDemKmls(files)
|
||||
.then((made) => {
|
||||
if (made.length) {
|
||||
alert(
|
||||
`표고 없는 KML을 발견해 DEM 표고를 채운 파일을 생성했습니다:\n${made.join(', ')}\n\n` +
|
||||
'다운로드된 파일을 영상 폴더에 넣어두면 다음 폴더 선택부터 자동으로 사용됩니다.',
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((e) => console.warn('[DEM] _byDem.kml 생성 실패(오프라인이면 정상):', e));
|
||||
} catch (err) {
|
||||
console.error('[geo] 폴더 로드 실패', err);
|
||||
}
|
||||
@@ -373,7 +394,8 @@ const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
||||
{/* 노선 정보 배너 — 영상 좌상단 (route.json routeInfo) */}
|
||||
<RouteInfoOverlay />
|
||||
{/* 좌하단 그룹(재생바 위) — 한 줄: 영상제어 → 배속 → 프레임정보 → 겹침제외 → 시설등급 */}
|
||||
{source && (
|
||||
{/* dev_mode=0(route.json) 이면 그룹 전체 숨김 — 뷰어 모드 */}
|
||||
{source && devMode !== 0 && (
|
||||
<div
|
||||
className="absolute left-2 z-30 flex items-center gap-2 flex-wrap pointer-events-auto"
|
||||
style={{ bottom: (barHeight || 130) + 8 }}
|
||||
@@ -561,7 +583,7 @@ const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
||||
videoWidth={videoWidth}
|
||||
videoHeight={videoHeight}
|
||||
onTogglePlay={handleTogglePlay}
|
||||
showPanel={showVideoControls && !!source}
|
||||
showPanel={devMode !== 0 && showVideoControls && !!source}
|
||||
topPx={paramTop}
|
||||
barHeight={barHeight}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user