# SandCastle Инструмент для массового захвата Google Photorealistic 3D Tiles в формате датасета **UAV-GeoLoc**. Через Cesium снимает ортофото-кропы сцены (DB) и «дроновые» кадры (query) по сетке, формирует JSON траектории камеры и сохраняет всё в дерево папок, совместимое с UAV-GeoLoc. ## Быстрый старт 1. Установите Node.js 14+. 2. Запустите `start.bat`: - `start.bat` — запуск на порту `3000` - `start.bat 3001` — запуск на указанном порту 3. Откройте `http://localhost:<порт>` если браузер не открылся сам. ## Рабочий процесс 1. **Панель управления** ([index.html](index.html)) — задайте имена сцены и параметры: - `Dataset / Country / City / Region` — 4 уровня дерева в `output/` - `Точка 1 / Точка 2` — противоположные углы прямоугольника в формате DMS - `Шаг сетки (метры)` — размер одного тайла - `Прореживание` — 1 = все точки, 2 = каждая вторая - `DB crop sizes` — ровно 11 уникальных размеров PNG-кропов (через запятую) - `Разрешение query кадра` — размер итогового JPEG (по умолчанию 512) - `FOV вертикальный` — параметр съёмки query-камеры - `Pitch query` — фиксирован в `-90` (top-down) - `Высоты (3 слота)` — чекбоксы + редактируемые значения высот - `Абсолютная высота` — выкл = над рельефом - `Предзагрузка тайлов` — прогрев Cesium перед съёмкой - `Пропускать пустые зоны` — не сохранять области без 3D-контента 2. **Сохранить настройки** → `settings.json`. 3. **Создать папки** → дерево сцены и `{region}.txt` с углами прямоугольника. 4. **Запустить захват** — откроется два окна: - **Карта зоны** ([mapview.html](mapview.html)) — чистый canvas без внешних тайлов, красный прямоугольник зоны, синие точки тайлов, жёлтая активная точка, зелёный след пройденного - **Окно захвата** ([capture.html](capture.html)) — Cesium Viewer, прогресс и лог ## Структура проекта ``` SandCastle/ ├── start.bat Запуск (проверяет Node, принимает порт, стартует сервер) ├── package.json ├── server.js Express backend + API ├── index.html Панель управления ├── ui.js UI-контроллер панели ├── style.css ├── capture.html Окно захвата (Cesium) ├── mapview.html Окно карты (canvas, без внешних тайлов) ├── settings.json Последние настройки (создаётся автоматически) └── output/ Результаты (создаётся автоматически) └── {dataset}/{country}/{city}/{region}/ ├── {region}.txt Углы зоны: maxLat minLon / minLat maxLon ├── DB/ │ ├── merge.tif Базовый TIFF сцены (для внешней нарезки) │ ├── db_postion.txt Строки: filename lon lat res_x res_y │ └── img/ │ └── crop_{col}_{row}_{size}.png Ортофото по сетке (X=col, Y=row, size=px) ├── positive.json Соответствия query -> точный DB crop ├── semi_positive.json Соответствия query -> соседние DB crop └── query/ └── height{H}_rot{R}/ ├── height{H}_rot{R}.json Траектория камеры └── footage/ └── height{H}_rot{R}_{NN}.jpeg Дроновые кадры ``` ## Формат траектории (UAV-GeoLoc) `query/height100_rot0/height100_rot0.json`: ```json { "name": "height100_rot0", "width": 512, "height": 512, "frameRate": 30, "numFrames": 75, "durationSeconds": 2.5, "cameraFrames": [ { "position": { "x": 3843512.1, "y": 604821.7, "z": 5095123.4 }, "rotation": { "x": -60, "y": 0, "z": 0 }, "coordinate": { "latitude": 52.41, "longitude": 9.65, "altitude": 100 }, "fovVertical": 30 } ] } ``` `numFrames` и `durationSeconds` вычисляются автоматически по фактическому числу сохранённых кадров. - `position` — ECEF (Earth-Centered Earth-Fixed) в метрах, получено через `Cesium.Cartesian3.fromDegrees` - `rotation` — `x` = pitch, `y` = heading (yaw), `z` = roll, все в градусах (pitch задаётся в UI) - `coordinate` — геодезические координаты точки съёмки - `fovVertical` — вертикальный FOV камеры Cesium в градусах (задаётся в UI) ## API сервера | Метод | Путь | Назначение | |---|---|---| | GET | `/api/get-settings` | Текущие настройки (или дефолты) | | POST | `/api/save-settings` | Сохранить настройки в `settings.json` | | POST | `/api/create-folders` | Создать дерево сцены и `{region}.txt` | | POST | `/api/start-capture` | Сохранить настройки и вернуть URL `capture.html` | | POST | `/api/save-db-crop` | Сохранить `crop_{col}_{row}_{size}.png` + строку в `db_postion.txt` | | POST | `/api/save-merge-tif` | Сохранить `DB/merge.tif` | | POST | `/api/save-drone-frame`| Сохранить кадр `height{H}_rot{R}_{NN}.jpeg` | | POST | `/api/save-trajectory` | Сохранить `height{H}_rot{R}.json` | | POST | `/api/save-annotations` | Сохранить `positive.json` и `semi_positive.json` | ## Координаты DMS Формат: `52°25'10.28"N 9°39'10.04"E`. Точки 1 и 2 — противоположные углы прямоугольника; их порядок не важен, сервер сам вычисляет `minLat/maxLat/minLon/maxLon`. ## Параметры съёмки (актуально) - `DB crop sizes` — обязательный список из **11 уникальных** положительных размеров (px) - стандартная кнопка в UI подставляет: - `100,150,200,250,300,400,500,512,600,800,1000` - для каждого тайла сохраняется 11 PNG-кропов: - `crop_{col}_{row}_{size}.png` - `Query`: - `drone_size` — размер JPEG кадра - `query_fov_deg` — вертикальный FOV - `query_pitch_deg` — зафиксирован на `-90` (top-down) - высоты query задаются тремя редактируемыми слотами (`height_100_value`, `height_125_value`, `height_150_value`) и включаются соответствующими чекбоксами - при завершении захвата сохраняются: - `DB/merge.tif` - `positive.json` - `semi_positive.json` ## Обмен окнами `capture.html` ↔ `mapview.html` общаются через `BroadcastChannel('sandcastle-map')`. Сообщения: - `{type: 'init', bounds, tiles}` — одноразово после генерации сетки - `{type: 'position', index, total, lat, lon}` — перед съёмкой каждого тайла - `{type: 'done', total}` — по завершении - `{type: 'request-init'}` — карта запрашивает реплей при позднем открытии ## Требования - Node.js 14+ - Cesium Ion token (Google Photorealistic 3D Tiles, asset `2275207`) — вшит в `capture.html` - Интернет для Cesium CDN и Google 3D Tiles (карта зоны работает офлайн) ## Версия 1.0.0 — Мороз Е.С. Павленко Б. В. / ЛИСАД