|
|
<template>
|
|
|
<mars-map :options="options" @onload="mapLoad"></mars-map>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import marsMap from "@/components/marsMap";
|
|
|
import PointJson from "./point.json";
|
|
|
import { onMounted,nextTick } from "vue";
|
|
|
const { proxy } = getCurrentInstance();
|
|
|
let options = {
|
|
|
scene: {
|
|
|
center: {
|
|
|
lat: 31.035216,
|
|
|
lng: 120.656763,
|
|
|
alt: 652.5,
|
|
|
heading: 6.3,
|
|
|
pitch: -23,
|
|
|
},
|
|
|
showSun: false,
|
|
|
showMoon: false,
|
|
|
showSkyBox: true,
|
|
|
showSkyAtmosphere: true,
|
|
|
fog: false,
|
|
|
clock: {
|
|
|
currentTime: "2023-11-01 12:00:00", // 固定光照时间
|
|
|
},
|
|
|
cameraController: {
|
|
|
zoomFactor: 1.5,
|
|
|
minimumZoomDistance: 0.1,
|
|
|
maximumZoomDistance: 200000,
|
|
|
enableCollisionDetection: false, // 允许进入地下
|
|
|
},
|
|
|
},
|
|
|
terrain: {
|
|
|
show: false,
|
|
|
},
|
|
|
basemaps: [
|
|
|
{
|
|
|
id: 2021,
|
|
|
pid: 10,
|
|
|
name: "天地图影像",
|
|
|
icon: "https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png",
|
|
|
type: "group",
|
|
|
layers: [
|
|
|
{
|
|
|
name: "底图",
|
|
|
type: "tdt",
|
|
|
layer: "img_d",
|
|
|
},
|
|
|
{
|
|
|
name: "注记",
|
|
|
type: "tdt",
|
|
|
layer: "img_z",
|
|
|
},
|
|
|
],
|
|
|
show: true,
|
|
|
},
|
|
|
],
|
|
|
};
|
|
|
const params = reactive({
|
|
|
lat: 31.162232,
|
|
|
lng: 120.734077,
|
|
|
altitude: 100,
|
|
|
heading: 0, //当前朝向
|
|
|
pitch: 0, //保当前俯仰角
|
|
|
roll: 0, //当前翻滚角
|
|
|
correction: 1,
|
|
|
speed: 500,
|
|
|
});
|
|
|
|
|
|
// 使用 import.meta.glob 动态导入本地图片
|
|
|
const imageModules = import.meta.glob('@/assets/images/*.png', { eager: true });
|
|
|
|
|
|
// 获取图片路径
|
|
|
const imageUrls = Object.values(imageModules).map((module) => module.default);
|
|
|
|
|
|
let isGamepad = false;
|
|
|
let map = null;
|
|
|
let list = [];
|
|
|
let uav = null;
|
|
|
const mapLayer = {};
|
|
|
const mapLoad = (mapInstance) => {
|
|
|
map = mapInstance;
|
|
|
//创建marker图层
|
|
|
mapLayer.markerLayer = new mars3d.layer.GraphicLayer({
|
|
|
allowDrillPick: true, // 如果存在坐标完全相同的图标点,可以打开该属性,click事件通过graphics判断
|
|
|
});
|
|
|
map.addLayer(mapLayer.markerLayer);
|
|
|
//创建无人机图层
|
|
|
mapLayer.uav = new mars3d.layer.GraphicLayer()
|
|
|
map.addLayer(mapLayer.uav);
|
|
|
|
|
|
map.on(mars3d.EventType.load, function (event) {
|
|
|
boostrapUav();
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
onMounted(()=>{
|
|
|
onAddGamepadboardListener();
|
|
|
})
|
|
|
|
|
|
/**
|
|
|
* 监听游戏手柄
|
|
|
*/
|
|
|
const onAddGamepadboardListener = () => {
|
|
|
window.addEventListener("gamepadconnected", function (e) {
|
|
|
// var gp = navigator.getGamepads()[e.gamepad.index];
|
|
|
proxy.$modal.msgSuccess("手柄控制已启动");
|
|
|
// 获取无人机固定航线最后的信息
|
|
|
const uavItem = mapLayer.uav.getGraphicById('uav1');
|
|
|
const {heading,pitch,roll,position } = uavItem
|
|
|
const cartographic = mars3d.LngLatPoint.fromCartesian(position)
|
|
|
params.lat =cartographic._lat
|
|
|
params.lng=cartographic._lng
|
|
|
params.heading=heading
|
|
|
params.pitch=pitch
|
|
|
params.roll=roll
|
|
|
|
|
|
// 开始手柄操作
|
|
|
const renderer = () => {
|
|
|
startgamepad();
|
|
|
onAdjustAttitude();
|
|
|
requestAnimationFrame(renderer);
|
|
|
};
|
|
|
renderer();
|
|
|
|
|
|
|
|
|
});
|
|
|
// 监听游戏手柄拔出
|
|
|
window.addEventListener("gamepaddisconnected", function (e) {
|
|
|
clearInterval(interval);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
const boostrapUav = () => {
|
|
|
// 绘制停机场矩形
|
|
|
initRectangle();
|
|
|
//渲染所有图标点
|
|
|
initMarker();
|
|
|
//渲染无人机
|
|
|
initUav();
|
|
|
};
|
|
|
|
|
|
const startgamepad = () => {
|
|
|
var gamepad = navigator.getGamepads()[0];
|
|
|
if (gamepad) {
|
|
|
//手柄方向按键
|
|
|
pressKey(gamepad.buttons);
|
|
|
// 手柄方向遥感
|
|
|
rocker(gamepad.axes);
|
|
|
}
|
|
|
};
|
|
|
// 手柄左方向遥感
|
|
|
const rocker = (axes) => {
|
|
|
const deadZone = 0.5;
|
|
|
const x = axes[0];
|
|
|
const y = axes[1];
|
|
|
// //机体左转
|
|
|
if (x < -deadZone) {
|
|
|
//机体左转
|
|
|
params.heading -= 0.115;
|
|
|
if (params.roll > -10) {
|
|
|
params.roll -= 0.115;
|
|
|
}
|
|
|
} else if (x > deadZone) {
|
|
|
//机体右转
|
|
|
params.heading += 0.115;
|
|
|
if (params.roll < 10) {
|
|
|
params.roll += 0.115;
|
|
|
}
|
|
|
}
|
|
|
// 检测垂直方向机体爬升
|
|
|
if (y < -deadZone && params.pitch <= 0.3) {
|
|
|
params.pitch += 0.015;
|
|
|
if (params.pitch > 0) {
|
|
|
const { speed, pitch } = params;
|
|
|
const temp = (params.speed / 60 / 60 / 60) * 110;
|
|
|
//1经纬度约等于110km
|
|
|
params.altitude += temp * Math.sin(pitch);
|
|
|
}
|
|
|
} else if (y > deadZone && params.pitch >= -0.3) {
|
|
|
//机体俯冲
|
|
|
params.pitch -= 0.016;
|
|
|
if (params.pitch < 0) {
|
|
|
const { speed, pitch } = params;
|
|
|
//1经纬度约等于110km
|
|
|
const temp = (params.speed / 60 / 60 / 60) * 110;
|
|
|
params.altitude += temp * Math.sin(pitch);
|
|
|
}
|
|
|
}
|
|
|
reset();
|
|
|
};
|
|
|
//左侧方向按键上下键
|
|
|
const pressKey = (buttons) => {
|
|
|
// 加速
|
|
|
if (buttons[12] && buttons[12].pressed) {
|
|
|
params.speed += 100;
|
|
|
}
|
|
|
// 减速
|
|
|
if (buttons[13] && buttons[13].pressed) {
|
|
|
if (params.speed >= 500) {
|
|
|
params.speed -= 100;
|
|
|
}
|
|
|
}
|
|
|
reset()
|
|
|
};
|
|
|
|
|
|
const reset = () => {
|
|
|
const { heading, pitch, roll } = params;
|
|
|
const { abs, cos } = Math;
|
|
|
params.correction = abs(cos(heading) * cos(pitch));
|
|
|
if (abs(heading) < 0.001) params.heading = 0;
|
|
|
if (abs(roll) < 0.001) params.roll = 0;
|
|
|
if (abs(pitch) < 0.001) params.pitch = 0;
|
|
|
//方向自动回正
|
|
|
// if (params.heading > 0) params.heading -= 0.0025
|
|
|
// if (params.heading < 0) params.heading += 0.0025
|
|
|
if (params.roll > 0) params.roll -= 0.003;
|
|
|
if (params.roll < 0) params.roll += 0.003;
|
|
|
if (params.pitch < 0) params.pitch += 0.005;
|
|
|
if (params.pitch > 0) params.pitch -= 0.003;
|
|
|
};
|
|
|
|
|
|
// 开启飞行姿态调整/
|
|
|
const onAdjustAttitude = () => {
|
|
|
const temp = params.speed / 60 / 60 / 60 / 110;
|
|
|
params.lng += temp * Math.cos(Cesium.Math.toRadians(params.heading));
|
|
|
params.lat -= temp * Math.sin(Cesium.Math.toRadians(params.heading));
|
|
|
const { lng, lat, altitude, heading, pitch, roll } = params;
|
|
|
params.altitude += temp * Math.sin(pitch) * 110 * 1000 * 10;
|
|
|
const position = Cesium.Cartesian3.fromDegrees(lng, lat, altitude);
|
|
|
uav.model.setStyle({
|
|
|
heading,
|
|
|
pitch,
|
|
|
roll,
|
|
|
});
|
|
|
uav.addTimePosition(position);
|
|
|
};
|
|
|
|
|
|
const initUav = () => {
|
|
|
if (list.length == 0 && !isGamepad ) {
|
|
|
list = PointJson.map((item) => item.wz);
|
|
|
}
|
|
|
uav = new mars3d.graphic.FixedRoute({
|
|
|
id: "uav1",
|
|
|
name: "无人机模型",
|
|
|
position: {
|
|
|
type: "time", // 时序动态坐标
|
|
|
speed: 100,
|
|
|
list: list,
|
|
|
},
|
|
|
clockLoop: true, //是否循环播放
|
|
|
model: {
|
|
|
url: "https://data.mars3d.cn/gltf/mars/wrj.glb",
|
|
|
scale: 0.1,
|
|
|
minimumPixelSize: 0.1,
|
|
|
runAnimations: true,
|
|
|
// mergeOrientation: true,
|
|
|
},
|
|
|
polyline:{
|
|
|
materialType: mars3d.MaterialType.PolylineDash,//虚线
|
|
|
materialOptions:{
|
|
|
color: 'rgba(34, 232, 174, 1)',
|
|
|
dashLength: 8.0
|
|
|
}
|
|
|
},
|
|
|
camera: {
|
|
|
type: "gs",
|
|
|
},
|
|
|
});
|
|
|
mapLayer.uav.addGraphic(uav);
|
|
|
uav.start()
|
|
|
};
|
|
|
|
|
|
const initRectangle = () => {
|
|
|
const graphic = new mars3d.graphic.RectanglePrimitive({
|
|
|
positions: [
|
|
|
[120.657821, 31.048952],
|
|
|
[120.657318, 31.047691],
|
|
|
[120.658122, 31.047505],
|
|
|
[120.658591, 31.04872],
|
|
|
],
|
|
|
style: {
|
|
|
color: "#22E8AE",
|
|
|
opacity: 0.4,
|
|
|
outline: true,
|
|
|
outlineColor: "#22E8AE",
|
|
|
},
|
|
|
});
|
|
|
mapLayer.markerLayer.addGraphic(graphic);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 渲染所有点位
|
|
|
*/
|
|
|
const initMarker = () => {
|
|
|
console.log(imageModules)
|
|
|
PointJson.map((item, index) => {
|
|
|
|
|
|
//绘制名字图标
|
|
|
lablePoint(item, index);
|
|
|
// 绘制水波浪圆
|
|
|
circlePoint(item, index);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
*文字图标
|
|
|
*/
|
|
|
const lablePoint = (item, index) => {
|
|
|
const markerDiv = new mars3d.graphic.DivGraphic({
|
|
|
position: item.wz,
|
|
|
id: `marker${index}`,
|
|
|
name: item.name,
|
|
|
style: {
|
|
|
html: `
|
|
|
<div class="div-marker">
|
|
|
<div class="marker-name ${item.type == 'school' ? 'color-school' : item.type == 'park' ? 'color-park' :'color-uav' } ">${item.name}</div>
|
|
|
<img class="marker-icon" src="${item.type == 'school' ? imageUrls[5] : item.type == 'park' ? imageUrls[4] :imageUrls[6] }" />
|
|
|
</div>
|
|
|
`,
|
|
|
offsetY: -73,
|
|
|
clampToGround:true,
|
|
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
|
|
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
|
|
distanceDisplayCondition: true, // 按视距距离显示
|
|
|
},
|
|
|
});
|
|
|
mapLayer.markerLayer.addGraphic(markerDiv);
|
|
|
};
|
|
|
/**
|
|
|
* 点位底部圆特效
|
|
|
* @param item
|
|
|
* @param index
|
|
|
*/
|
|
|
const circlePoint = (item, index) => {
|
|
|
const graphic = new mars3d.graphic.CircleEntity({
|
|
|
position: item.wz,
|
|
|
style: {
|
|
|
radius: 50,
|
|
|
height: 0,
|
|
|
materialType: mars3d.MaterialType.CircleWave,
|
|
|
materialOptions: {
|
|
|
color: item.type == 'school' ? '#59F9FF' : item.type == 'park' ? '#33E064' : '#22E8AE',
|
|
|
count: 2,
|
|
|
speed: 6,
|
|
|
},
|
|
|
distanceDisplayCondition: true, // 按视距距离显示
|
|
|
},
|
|
|
});
|
|
|
mapLayer.markerLayer.addGraphic(graphic);
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
.mars3d-container {
|
|
|
position: fixed;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
height: 100%;
|
|
|
width: 100%;
|
|
|
}
|
|
|
</style>
|