218 lines
5.6 KiB
JavaScript
218 lines
5.6 KiB
JavaScript
import * as Cesium from "cesium";
|
||
|
||
|
||
Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3NjcxNWZiYy1mZjFiLTQzNGEtYmEwNy1hMmU0ZDg4NWI2ZGUiLCJpZCI6Mzc3NjU2LCJpYXQiOjE3NjgyMTk2NzJ9.D5DL5zrDi4yK6OPgq-ypC4hM5hfqYKODvppgakc7y3g";
|
||
|
||
const creditContainer = document.createElement('div');
|
||
creditContainer.style.display = 'none';
|
||
|
||
const viewer = new Cesium.Viewer("cesiumContainer", {
|
||
timeline: false,
|
||
animation: false,
|
||
sceneModePicker: false,
|
||
baseLayerPicker: false,
|
||
geocoder: false,
|
||
homeButton: false,
|
||
navigationHelpButton: false,
|
||
terrainProvider: await Cesium.createWorldTerrainAsync(),
|
||
creditContainer: creditContainer,
|
||
contextOptions: {
|
||
webgl: {
|
||
preserveDrawingBuffer: true
|
||
}
|
||
}
|
||
});
|
||
|
||
try {
|
||
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(2275207);
|
||
viewer.scene.primitives.add(tileset);
|
||
} catch (error) {
|
||
console.log(error);
|
||
}
|
||
|
||
/*
|
||
=================== Настройка отображения ===================
|
||
*/
|
||
|
||
const outputWidth = 512;
|
||
const outputHeight = 512;
|
||
|
||
viewer.scene.canvas.style.width = outputWidth + 'px';
|
||
viewer.scene.canvas.style.height = outputHeight + 'px';
|
||
viewer.container.style.width = outputWidth + 'px';
|
||
viewer.container.style.height = outputHeight + 'px';
|
||
|
||
viewer.resize(); // важно: обновляет внутренние размеры рендерера
|
||
|
||
/*
|
||
=================== Вспомагательные функции ===================
|
||
*/
|
||
|
||
function dmsToDecimal(dms) {
|
||
// Пример входа: "48°18'20\"N" или "16°24'41\"E"
|
||
const regex = /(\d+)°(\d+)'(\d+)"?([NSEW])/i;
|
||
const match = dms.match(regex);
|
||
if (!match) {
|
||
throw new Error("Неверный формат координат: " + dms);
|
||
}
|
||
|
||
const degrees = parseInt(match[1], 10);
|
||
const minutes = parseInt(match[2], 10);
|
||
const seconds = parseInt(match[3], 10);
|
||
const direction = match[4].toUpperCase();
|
||
|
||
let decimal = degrees + minutes / 60 + seconds / 3600;
|
||
|
||
// Южная и Западная широты — отрицательные
|
||
if (direction === "S" || direction === "W") {
|
||
decimal = -decimal;
|
||
}
|
||
|
||
return decimal;
|
||
}
|
||
|
||
function metersToLat(m) {
|
||
return m / METERS_PER_DEG_LAT;
|
||
}
|
||
|
||
function metersToLon(m, latDeg) {
|
||
return m / (METERS_PER_DEG_LAT * Math.cos(Cesium.Math.toRadians(latDeg)));
|
||
}
|
||
|
||
function saveImage(filename) {
|
||
const canvas = viewer.scene.canvas;
|
||
const image = canvas.toDataURL("image/png");
|
||
|
||
const link = document.createElement("a");
|
||
link.href = image;
|
||
link.download = filename;
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
document.body.removeChild(link);
|
||
}
|
||
|
||
function downloadFile(filename, content, mime = "text/plain") {
|
||
const blob = new Blob([content], { type: mime });
|
||
const url = URL.createObjectURL(blob);
|
||
|
||
const a = document.createElement("a");
|
||
a.href = url;
|
||
a.download = filename;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
|
||
document.body.removeChild(a);
|
||
URL.revokeObjectURL(url);
|
||
}
|
||
|
||
/*
|
||
=================== Константы и переменные ===================
|
||
*/
|
||
|
||
const METERS_PER_DEG_LAT = 111_320;
|
||
|
||
// ---- Параметры сетки ----
|
||
|
||
const GRID = 2;
|
||
const TILE_M = 50;
|
||
const CAMERA_HEIGHT = 450;
|
||
|
||
// ---- Координаты ----
|
||
|
||
const latDMS = "45°25'3\"N";
|
||
const lonDMS = "9°04'15\"E";
|
||
//45°25'35"N 9°04'15"E
|
||
|
||
const half = (GRID - 1) * TILE_M / 2;
|
||
|
||
const CENTER_LAT = dmsToDecimal(latDMS);
|
||
const CENTER_LON = dmsToDecimal(lonDMS);
|
||
const startLat = CENTER_LAT + metersToLat(half);
|
||
const startLon = CENTER_LON - metersToLon(half, CENTER_LAT);
|
||
|
||
|
||
let row = 0;
|
||
let col = 0;
|
||
let index = 0;
|
||
const offset = 0.0005;
|
||
|
||
/*
|
||
=================== Главный цикл сбора ===================
|
||
*/
|
||
|
||
var flag = false;
|
||
|
||
function captureNextTile() {
|
||
|
||
if (flag == false) {
|
||
setTimeout(() => {
|
||
flag = true;
|
||
}, 5000)
|
||
}
|
||
|
||
const lat = startLat - metersToLat(row * TILE_M);
|
||
const lon = startLon + metersToLon(col * TILE_M, lat);
|
||
|
||
downloadFile(
|
||
`tile_${index}_sat.json`,
|
||
JSON.stringify({ lat: lat, lon: lon }, null, 2),
|
||
"application/json"
|
||
);
|
||
|
||
// ---------- Спутник ----------
|
||
viewer.camera.setView({
|
||
destination: Cesium.Cartesian3.fromDegrees(lon, lat, CAMERA_HEIGHT),
|
||
orientation: {
|
||
heading: Cesium.Math.toRadians(0),
|
||
pitch: Cesium.Math.toRadians(-90),
|
||
roll: 0
|
||
}
|
||
});
|
||
|
||
viewer.scene.requestRender();
|
||
|
||
setTimeout(() => {
|
||
saveImage(`tile_${index}_sat.png`);
|
||
|
||
// ---------- Дрон ----------
|
||
viewer.camera.setView({
|
||
destination: Cesium.Cartesian3.fromDegrees(lon, lat - offset, CAMERA_HEIGHT),
|
||
orientation: {
|
||
heading: Cesium.Math.toRadians(0),
|
||
pitch: Cesium.Math.toRadians(-60),
|
||
roll: 0
|
||
}
|
||
});
|
||
|
||
viewer.scene.requestRender();
|
||
|
||
setTimeout(() => {
|
||
saveImage(`tile_${index}_drone.png`);
|
||
|
||
// ---- След. ячейка ----
|
||
col++;
|
||
if (col >= GRID) {
|
||
col = 0;
|
||
row++;
|
||
}
|
||
index++;
|
||
|
||
captureNextTile();
|
||
}, 2500); // Задержка дрон-рендера
|
||
|
||
}, 2500); // Задержка спутник-рендера
|
||
}
|
||
|
||
/*
|
||
=================== Запуск ===================
|
||
*/
|
||
|
||
viewer.scene.postRender.addEventListener(function once() {
|
||
viewer.scene.postRender.removeEventListener(once);
|
||
|
||
setTimeout(() => {
|
||
captureNextTile();
|
||
}, 9000);
|
||
});
|
||
|