初步实现无人机固定定位巡航

main
许宏杰 1 day ago
parent 15e025bc95
commit 677a4e0182

@ -19,6 +19,7 @@
"@element-plus/icons-vue": "2.3.1",
"@vueup/vue-quill": "1.2.0",
"@vueuse/core": "10.11.0",
"autofit.js": "^3.2.5",
"axios": "0.28.1",
"clipboard": "2.0.11",
"echarts": "5.5.1",

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

@ -5,8 +5,10 @@
@import './sidebar.scss';
@import './btn.scss';
@import './ruoyi.scss';
@import './marsMap.scss';
body {
width: 100%;
height: 100%;
margin: 0;
-moz-osx-font-smoothing: grayscale;

@ -0,0 +1,33 @@
.div-marker {
.marker-name {
font-size: 16px;
color: #ffffff;
font-weight: 600;
text-shadow: 1px 1px 0px #000000;
background: linear - gradient(to bottom, rgba(135, 206, 235, 0.1), rgba(89, 249, 255, 1));
border: 1px solid #59F9FF;
padding: 3px 13px;
letter-spacing: 2px;
border-radius: 14px;
}
.marker-icon{
margin: auto;
margin-top:5px;
width: 40px;
height: 60px;
background: url('../images/default-icon.png');
background-size: 100% 100%;
}
}
.div-marker:after{
content: "";
position: absolute;
bottom: -73px;
left: calc(50% - 2px);
display: block;
width: 3px;
height: 70px;
border-right: 3px solid #2bcdbb;
}

@ -0,0 +1,31 @@
<template>
<div class="map-container" id="mapContainer">
<slot></slot>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
import autofit from 'autofit.js'
onMounted(()=>{
//
autofit.init({
el:"#mapContainer",
dh: 1080,
dw: 1920,
resize:true,
})
})
</script>
<style lang="scss" scoped>
.map-container{
position: relative;
z-index: 100;
height: 100%;
width: 100%;
}
</style>

@ -0,0 +1,4 @@
export { default as MapContainer } from './container.vue'
export { default as PanelLeft } from './panelLeft.vue'
export { default as PanelRight } from './panelRight.vue'
export { default as MarsMap } from './marsMap.vue'

@ -0,0 +1,197 @@
<template>
<mars-map :options="options" @onload="mapLoad"></mars-map>
</template>
<script setup>
import marsMap from "@/components/marsMap";
import PointJson from "./point.json";
let options = {
scene: {
center: {
lat: 31.035216,
lng: 120.656763,
alt: 652.5,
heading: 6.3,
pitch: -23,
},
showSun: false,
showMoon: false,
showSkyBox: false,
showSkyAtmosphere: false,
fog: false,
// backgroundColor: "#363635", //
globe: {
baseColor: "#363635", //
showGroundAtmosphere: false,
enableLighting: 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,
},
],
};
let map = null;
const mapLayer = {};
const mapLoad = (mapInstance) => {
map = mapInstance;
//marker
mapLayer.markerLayer = new mars3d.layer.GraphicLayer({
allowDrillPick: true, // clickgraphics
});
map.addLayer(mapLayer.markerLayer);
//
initUav()
//
initRectangle();
initMarker();
};
const initUav = ()=>{
let list = []
PointJson.map(item=>{
list.push(item.wz.split(",").map(Number))
})
const uav = new mars3d.graphic.Route({
id: "uav",
name: "无人机模型",
position: {
type: "time", //
speed: 100,
list: list
},
model: {
url: "https://data.mars3d.cn/gltf/mars/wrj.glb",
scale: 0.1,
minimumPixelSize: 0.1,
runAnimations: true,
mergeOrientation: true,
},
camera: {
type: "gs",
}
})
mapLayer.markerLayer.addGraphic(uav);
}
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 = () => {
PointJson.map((item, index) => {
item.point = item.wz.split(",").map(Number);
//
circlePoint(item, index);
//
lablePoint(item, index);
});
};
/**
*文字图标
*/
const lablePoint = (item, index) => {
const markerDiv = new mars3d.graphic.DivGraphic({
position: item.wz.split(",").map(Number),
id: `marker${index}`,
name: item.name,
style: {
html: `
<div class="div-marker">
<div class="marker-name">${item.name}</div>
<div class="marker-icon"></div>
</div>
`,
offsetY: -73,
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.point,
style: {
radius: 50,
height: 0,
materialType: mars3d.MaterialType.CircleWave,
materialOptions: {
color: "#59F9FF",
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>

@ -0,0 +1,14 @@
<template>
<div class="panel-box panel-left">
</div>
</template>
<script setup>
</script>
<style scoped>
.panel-left{
left: 46px;
}
</style>

@ -0,0 +1,14 @@
<template>
<div class="panel-box panel-right">
</div>
</template>
<script setup>
</script>
<style scoped>
.panel-right{
right: 46px;
}
</style>

@ -0,0 +1,211 @@
[
{
"name": "云航低空研训基地",
"wz": "120.657967,31.048193"
},
{
"name": "吴江公园",
"wz": "120.634741,31.155611"
},
{
"name": "江苏同里国家湿地公园",
"wz": "120.806956,31.157053"
},
{
"name": "胜地生态公园",
"wz": "120.650494,31.082684"
},
{
"name": "新湖郁金香公园",
"wz": "120.634291,31.183498"
},
{
"name": "潜龙渠公园",
"wz": "120.612246,30.909961"
},
{
"name": "芦墟大渠荡生态公园",
"wz": "120.852208,31.028415"
},
{
"name": "镜湖公园",
"wz": "120.675721,30.919475"
},
{
"name": "七都湿地公园",
"wz": "120.384969,30.953492"
},
{
"name": "芦荡湖湿地公园",
"wz": "120.640464,31.117824"
},
{
"name": "苏州湾体育公园",
"wz": "120.601284,31.115582"
},
{
"name": "震泽公园",
"wz": "120.500364,30.913989"
},
{
"name": "东太湖生态园",
"wz": "120.598503,31.148862"
},
{
"name": "汾湖公园",
"wz": "120.833018,31.009082"
},
{
"name": "黎里古镇公园",
"wz": "120.711281,30.988861"
},
{
"name": "平望文体活动中心",
"wz": "120.624934,30.972651"
},
{
"name": "同里古镇公园",
"wz": "120.723765,31.154999"
},
{
"name": "吴江实验小学教育集团太湖校区",
"wz": "120.629232,31.138336"
},
{
"name": "吴江实验小学教育集团爱德校区",
"wz": "120.63353,31.149451"
},
{
"name": "吴江实验小学教育集团城中校区",
"wz": "120.641363,31.163391"
},
{
"name": "吴江实验小学教育集团长安实验小学",
"wz": "120.65505,31.125751"
},
{
"name": "鲈乡实验小学教育集团仲英校区",
"wz": "120.631532,31.164911"
},
{
"name": "鲈乡实验小学教育集团越秀校区",
"wz": "120.628219,31.170382"
},
{
"name": "鲈乡实验小学教育集团流虹校区",
"wz": "120.635097,31.161342"
},
{
"name": "思贤实验小学",
"wz": "120.636957,31.127222"
},
{
"name": "苏大附属吴江学校",
"wz": "120.642029,31.092945"
},
{
"name": "松陵小学",
"wz": "120.644365,31.155881"
},
{
"name": "北门小学",
"wz": "120.648293,31.164774"
},
{
"name": "绣湖东路小学",
"wz": "120.696411,31.155009"
},
{
"name": "淞南路小学",
"wz": "120.666246,31.187018"
},
{
"name": "三淞路小学",
"wz": "120.665384,31.184736"
},
{
"name": "吉市路小学",
"wz": "120.671435,31.175657"
},
{
"name": "云龙实验学校",
"wz": "120.668912,31.148545"
},
{
"name": "苏州湾外国语学校",
"wz": "120.615709,31.113141"
},
{
"name": "实验初级中学",
"wz": "120.632518,31.14779"
},
{
"name": "青云实验中学",
"wz": "120.502819,30.827075"
},
{
"name": "苏州湾实验初级中学",
"wz": "120.60238,31.142594"
},
{
"name": "松陵第一中学",
"wz": "120.630625,31.167276"
},
{
"name": "金家坝中学",
"wz": "120.783595,31.089252"
},
{
"name": "平望中学",
"wz": "120.646572,30.981293"
},
{
"name": "桃源中学",
"wz": "120.48338,30.794556"
},
{
"name": "震泽中学",
"wz": "120.638371,31.124036"
},
{
"name": "吴江中学",
"wz": "120.606418,31.14296"
},
{
"name": "吴江盛泽中学",
"wz": "120.681466,30.891258"
},
{
"name": "吴江汾湖高级中学",
"wz": "120.850662,31.009218"
},
{
"name": "震泽中学育英学校",
"wz": "120.496718,30.909832"
},
{
"name": "苏州枫华学校",
"wz": "120.882975,31.052381"
},
{
"name": "苏州中学苏州湾学校",
"wz": "120.645367,31.076471"
},
{
"name": "吴江新教育学校",
"wz": "120.693969,31.157251"
},
{
"name": "苏州大学未来校区",
"wz": "120.666188,31.068729"
},
{
"name": "苏州信息职业技术学院",
"wz": "120.632702,31.135007"
},
{
"name": "吴江高级中学",
"wz": "120.645829,31.175176"
}
]

@ -0,0 +1,257 @@
<template>
<div class="map-container">
<mars-map :options="options" @onload="mapLoad"></mars-map>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import marsMap from "@/components/marsMap";
let options = {
scene: {
center: {
lat: 30.647679,
lng: 120.691682,
alt: 37478.2,
heading: 2.7,
pitch: -36.9,
},
showSun: false,
showMoon: false,
showSkyBox: false,
showSkyAtmosphere: false,
fog: false,
// backgroundColor: "#363635", //
globe: {
baseColor: "#363635", //
showGroundAtmosphere: false,
enableLighting: 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: 2017,
pid: 10,
name: "蓝色底图",
icon: "https://data.mars3d.cn/img/thumbnail/basemap/my_blue.png",
type: "gaode",
layer: "vec",
chinaCRS: "GCJ02",
invertColor: true,
filterColor: "#015CB3",
brightness: 0.6,
contrast: 1.8,
gamma: 0.3,
hue: 1,
saturation: 0,
show: true,
},
],
};
const DIRECTION = {
UP: "w",
DOWN: "s",
LEFT: "a",
RIGHT: "d",
SPEED_UP: "q",
SPEED_DOWN: "e",
};
const keyboardMap = {
[DIRECTION.UP]: false,
[DIRECTION.DOWN]: false,
[DIRECTION.LEFT]: false,
[DIRECTION.RIGHT]: false,
[DIRECTION.SPEED_UP]: false,
[DIRECTION.SPEED_DOWN]: false,
};
let map = null;
let Cesium = {};
let mapLayer = {};
let uav = null;
const params = reactive({
lat: 31.162232,
lng: 120.734077,
altitude: 3000,
heading: 0, //
pitch: 0, //
roll: 0, //
correction: 1,
speed: 800,
gamepad: true,
});
/**
* 地图渲染完毕
* @param mapInstance 当前地图对象
*/
const mapLoad = (mapInstance) => {
map = mapInstance;
Cesium = mars3d.Cesium;
//marker
mapLayer.markerLayer = new mars3d.layer.GraphicLayer({
allowDrillPick: true, // clickgraphics
});
map.addLayer(mapLayer.markerLayer);
boostrapUav();
};
/**
* 创建模型对象
*/
const initModel = () => {
uav = new mars3d.graphic.Route({
id: "uav",
name: "无人机模型",
model: {
url: "https://data.mars3d.cn/gltf/mars/wrj.glb",
scale: 5,
minimumPixelSize: 50,
runAnimations: true,
mergeOrientation: true,
},
camera: {
type: "gs",
radius: 25000,
heading: 25,
pitch: -35,
},
});
mapLayer.markerLayer.addGraphic(uav);
};
const boostrapUav = () => {
initModel();
onAddKeyboardListener();
const renderer = () => {
onAdjustParams();
onAdjustAttitude();
requestAnimationFrame(renderer);
};
renderer();
};
//
const onAddKeyboardListener = () => {
document.addEventListener("keydown", (e) => {
if (Object.keys(keyboardMap).includes(e.key)) {
keyboardMap[e.key] = true;
}
});
document.addEventListener("keyup", (e) => {
if (Object.keys(keyboardMap).includes(e.key)) {
keyboardMap[e.key] = false;
}
});
};
//
const onAdjustParams = () => {
if (keyboardMap[DIRECTION.SPEED_UP]) {
params.speed += 100;
}
if (keyboardMap[DIRECTION.SPEED_DOWN]) {
if (params.speed >= 500) {
params.speed -= 100;
}
}
//
if (keyboardMap[DIRECTION.UP] && params.pitch <= 0.3) {
params.pitch += 0.005;
if (params.pitch > 0) {
const { speed, pitch } = params;
const temp = (params.speed / 60 / 60 / 60) * 110;
//1110km
params.altitude += temp * Math.sin(pitch);
}
}
//
if (keyboardMap[DIRECTION.DOWN] && params.pitch >= -0.3) {
params.pitch -= 0.006;
if (params.pitch < 0) {
const { speed, pitch } = params;
//1110km
const temp = (params.speed / 60 / 60 / 60) * 110;
params.altitude += temp * Math.sin(pitch);
}
}
//
if (keyboardMap[DIRECTION.LEFT]) {
params.heading -= 0.115;
if (params.roll > -10) {
params.roll -= 0.115;
}
}
//
if (keyboardMap[DIRECTION.RIGHT]) {
params.heading += 0.115;
if (params.roll < 10) {
params.roll += 0.115;
}
}
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(params.heading);
params.lat -= temp * Math.sin(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);
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
const orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr
);
uav.model.setStyle({
heading,
pitch,
roll
});
// uav.model.orientation= orientation //,
uav.addTimePosition(position);
};
</script>
<style lang="scss" scoped>
.map-container {
height: 100%;
}
</style>

@ -1,257 +1,32 @@
<template>
<div class="map-container">
<mars-map :options="options" @onload="mapLoad"></mars-map>
<div>
<map-container>
<!-- <panel-left></panel-left>
<panel-right></panel-right> -->
<mars-map></mars-map>
</map-container>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import marsMap from "@/components/marsMap";
let options = {
scene: {
center: {
lat: 30.647679,
lng: 120.691682,
alt: 37478.2,
heading: 2.7,
pitch: -36.9,
},
showSun: false,
showMoon: false,
showSkyBox: false,
showSkyAtmosphere: false,
fog: false,
// backgroundColor: "#363635", //
globe: {
baseColor: "#363635", //
showGroundAtmosphere: false,
enableLighting: 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: 2017,
pid: 10,
name: "蓝色底图",
icon: "https://data.mars3d.cn/img/thumbnail/basemap/my_blue.png",
type: "gaode",
layer: "vec",
chinaCRS: "GCJ02",
invertColor: true,
filterColor: "#015CB3",
brightness: 0.6,
contrast: 1.8,
gamma: 0.3,
hue: 1,
saturation: 0,
show: true,
},
],
};
const DIRECTION = {
UP: "w",
DOWN: "s",
LEFT: "a",
RIGHT: "d",
SPEED_UP: "q",
SPEED_DOWN: "e",
};
const keyboardMap = {
[DIRECTION.UP]: false,
[DIRECTION.DOWN]: false,
[DIRECTION.LEFT]: false,
[DIRECTION.RIGHT]: false,
[DIRECTION.SPEED_UP]: false,
[DIRECTION.SPEED_DOWN]: false,
};
let map = null;
let Cesium = {};
let mapLayer = {};
let uav = null;
const params = reactive({
lat: 31.162232,
lng: 120.734077,
altitude: 3000,
heading: 0, //
pitch: 0, //
roll: 0, //
correction: 1,
speed: 800,
gamepad: true,
});
/**
* 地图渲染完毕
* @param mapInstance 当前地图对象
*/
const mapLoad = (mapInstance) => {
map = mapInstance;
Cesium = mars3d.Cesium;
//marker
mapLayer.markerLayer = new mars3d.layer.GraphicLayer({
allowDrillPick: true, // clickgraphics
});
map.addLayer(mapLayer.markerLayer);
boostrapUav();
};
/**
* 创建模型对象
*/
const initModel = () => {
uav = new mars3d.graphic.Route({
id: "uav",
name: "无人机模型",
model: {
url: "https://data.mars3d.cn/gltf/mars/wrj.glb",
scale: 5,
minimumPixelSize: 50,
runAnimations: true,
mergeOrientation: true,
},
camera: {
type: "gs",
radius: 25000,
heading: 25,
pitch: -35,
},
});
mapLayer.markerLayer.addGraphic(uav);
};
const boostrapUav = () => {
initModel();
onAddKeyboardListener();
const renderer = () => {
onAdjustParams();
onAdjustAttitude();
requestAnimationFrame(renderer);
};
renderer();
};
//
const onAddKeyboardListener = () => {
document.addEventListener("keydown", (e) => {
if (Object.keys(keyboardMap).includes(e.key)) {
keyboardMap[e.key] = true;
}
});
document.addEventListener("keyup", (e) => {
if (Object.keys(keyboardMap).includes(e.key)) {
keyboardMap[e.key] = false;
}
});
};
//
const onAdjustParams = () => {
if (keyboardMap[DIRECTION.SPEED_UP]) {
params.speed += 100;
}
if (keyboardMap[DIRECTION.SPEED_DOWN]) {
if (params.speed >= 500) {
params.speed -= 100;
}
}
//
if (keyboardMap[DIRECTION.UP] && params.pitch <= 0.3) {
params.pitch += 0.005;
if (params.pitch > 0) {
const { speed, pitch } = params;
const temp = (params.speed / 60 / 60 / 60) * 110;
//1110km
params.altitude += temp * Math.sin(pitch);
}
}
//
if (keyboardMap[DIRECTION.DOWN] && params.pitch >= -0.3) {
params.pitch -= 0.006;
if (params.pitch < 0) {
const { speed, pitch } = params;
//1110km
const temp = (params.speed / 60 / 60 / 60) * 110;
params.altitude += temp * Math.sin(pitch);
}
}
//
if (keyboardMap[DIRECTION.LEFT]) {
params.heading -= 0.115;
if (params.roll > -10) {
params.roll -= 0.115;
}
}
//
if (keyboardMap[DIRECTION.RIGHT]) {
params.heading += 0.115;
if (params.roll < 10) {
params.roll += 0.115;
}
}
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(params.heading);
params.lat -= temp * Math.sin(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);
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
const orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr
);
uav.model.setStyle({
heading,
pitch,
roll
});
// uav.model.orientation= orientation //,
uav.addTimePosition(position);
};
import {
MapContainer,
PanelLeft,
PanelRight,
MarsMap,
} from "@/views/components/map";
</script>
<style lang="scss" scoped>
.map-container {
height: 100%;
.panel-box {
position: absolute;
top: 50%;
z-index: 100;
transform: translateY(-50%);
height: calc(100% - 175px);
width: 390px;
background: url("../assets/images/panel-bg.png");
background-size: 100% 100%;
}
</style>

Loading…
Cancel
Save