perf: 障碍物添加和航线绘制、websocket发送后端
parent
6572ef649d
commit
a8701993b3
@ -0,0 +1,168 @@
|
||||
import {DataSource} from "cesium";
|
||||
import * as Cesium from 'cesium'
|
||||
|
||||
|
||||
export default class RouteManageViewer {
|
||||
constructor(viewer, isClose, height) {
|
||||
this.viewer = viewer
|
||||
this.scene = viewer.scene
|
||||
this.routeParams = {
|
||||
isClose: isClose,
|
||||
height: height,
|
||||
}
|
||||
this.positions = []
|
||||
this.temPositions = [] // 鼠标移动时产生的临时点
|
||||
this.vertexEntities = [] // 节点元素
|
||||
this.lineEntity = undefined // 折线元素
|
||||
this.lineEntitys = [] // 折线元素数组,每完成一次航线绘制,将折线元素加入此数组
|
||||
}
|
||||
|
||||
// -------------------------------------------//
|
||||
//开始绘制
|
||||
start() {
|
||||
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
|
||||
this.viewer.scene.globe.depthTestAgainstTerrain = true
|
||||
|
||||
//设置鼠标样式
|
||||
this.viewer._element.style.cursor = 'crosshair';
|
||||
this.viewer.enableCursorStyle = true;
|
||||
this.temPositions = [];
|
||||
this.positions = [];
|
||||
return new Promise((resolve,reject) => {
|
||||
//注册鼠标事件
|
||||
//单击鼠标左键画点点击事件
|
||||
this.handler.setInputAction(e => {
|
||||
let position = this.viewer.scene.pickPosition(e.position);
|
||||
if (!position) {
|
||||
const ellipsoid = this.viewer.scene.globe.ellipsoid;
|
||||
position = this.viewer.scene.camera.pickEllipsoid(e.position, ellipsoid);
|
||||
}
|
||||
//TODO: 海拔高度转Cartesain3 Z 值
|
||||
if (position){
|
||||
this.positions.push(position);
|
||||
}
|
||||
if (this.positions.length === 1) { //首次点击
|
||||
this.createLineEntity();
|
||||
}
|
||||
this.createVertex();
|
||||
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||||
|
||||
this.handler.setInputAction(e => {
|
||||
if (this.positions.length < 3) {
|
||||
this.endDraw();
|
||||
this.clearDisEntity()
|
||||
reject("航线不得少于三个航点!")
|
||||
}
|
||||
else {
|
||||
this.lineEntity.polyline = {
|
||||
positions: this.routeParams.isClose? this.positions.concat(this.positions[0]) : this.positions,
|
||||
width: 2,
|
||||
material: Cesium.Color.YELLOW,
|
||||
depthFailMaterial: Cesium.Color.YELLOW
|
||||
}
|
||||
this.endDraw();
|
||||
resolve(this._Cartesian_degrees(this.positions))
|
||||
}
|
||||
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
|
||||
|
||||
this.handler.setInputAction(e => {
|
||||
let position = this.viewer.scene.pickPosition(e.endPosition);
|
||||
if (!position) {
|
||||
position = this.viewer.scene.camera.pickEllipsoid(e.startPosition, this.viewer.scene.globe.ellipsoid);
|
||||
}
|
||||
if (this.positions.length >= 1){
|
||||
this.temPositions = this.positions.concat(position);
|
||||
}
|
||||
this.viewer.scene.requestRender()
|
||||
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||||
})
|
||||
}
|
||||
|
||||
//结束绘制
|
||||
endDraw() {
|
||||
this.unRegisterEvents();
|
||||
this.viewer._element.style.cursor = 'default';
|
||||
this.viewer.enableCursorStyle = true;
|
||||
this.lineEntitys.push(this.lineEntity)
|
||||
|
||||
}
|
||||
|
||||
//清空绘制
|
||||
clearDisEntity() {
|
||||
//清除折线
|
||||
this.lineEntitys.forEach(item => {
|
||||
this.viewer.entities.remove(item);
|
||||
});
|
||||
//清除节点
|
||||
this.vertexEntities.forEach(item => {
|
||||
this.viewer.entities.remove(item);
|
||||
});
|
||||
|
||||
this.positions = []
|
||||
this.temPositions = [] // 鼠标移动时产生的临时点
|
||||
this.vertexEntities = [] // 节点元素
|
||||
this.lineEntity = undefined // 折线元素
|
||||
this.lineEntitys = [] // 折线元素数组,每完成一次航线绘制,将折线元素加入此数组
|
||||
}
|
||||
|
||||
//创建线对象
|
||||
createLineEntity() {
|
||||
this.lineEntity = this.viewer.entities.add({
|
||||
polyline: {
|
||||
positions: new Cesium.CallbackProperty(e => {
|
||||
return this.temPositions;
|
||||
}, false),
|
||||
width: 2,
|
||||
material: Cesium.Color.YELLOW,
|
||||
clampToGround: true,
|
||||
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
},
|
||||
})
|
||||
this.viewer.scene.requestRender()
|
||||
}
|
||||
//创建线节点
|
||||
createVertex() {
|
||||
let vertexEntity = new Cesium.Entity({
|
||||
id: "Route" + this.positions[this.positions.length - 1],
|
||||
position: this.positions[this.positions.length - 1],
|
||||
point: {
|
||||
color: Cesium.Color.FUCHSIA,
|
||||
pixelSize: 8,
|
||||
outlineColor: Cesium.Color.WHITE,
|
||||
outlineWidth: 2,
|
||||
disableDepthTestDistance:99000000,
|
||||
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
},
|
||||
});
|
||||
this.vertexEntities.push(vertexEntity)
|
||||
this.viewer.entities.add(vertexEntity)
|
||||
}
|
||||
|
||||
//解除鼠标事件(测距)
|
||||
unRegisterEvents() {
|
||||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
|
||||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||||
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 笛卡尔坐标数组转为经纬度坐标数组
|
||||
* @param cartesian3Arr 笛卡尔坐标数组
|
||||
* @returns {*[]} 经纬度坐标数组
|
||||
* @private
|
||||
*/
|
||||
_Cartesian_degrees(cartesian3Arr){
|
||||
let coords = []
|
||||
cartesian3Arr.forEach((item) => {
|
||||
// 将 Cartesian3 转换为 Cartographic
|
||||
let cartographic = Cesium.Cartographic.fromCartesian(item, Cesium.Ellipsoid.WGS84);
|
||||
coords.push({
|
||||
lon: Cesium.Math.toDegrees(cartographic.longitude),
|
||||
lat: Cesium.Math.toDegrees(cartographic.latitude),
|
||||
alt: this.routeParams.height
|
||||
})
|
||||
})
|
||||
return coords
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
import { defineAsyncComponent, render, createVNode } from "vue";
|
||||
export class routeDialog {
|
||||
constructor() {
|
||||
this.component = defineAsyncComponent(
|
||||
() => import("@/components/RouteOptions.vue"));
|
||||
this.vnode = null;
|
||||
this.node = null;
|
||||
this.props = {
|
||||
width: "40%",
|
||||
height: "auto",
|
||||
};
|
||||
}
|
||||
installRouteDialog() {
|
||||
if (!this.vnode) {
|
||||
const dialog = createVNode(this.component, this.props);
|
||||
const container = document.createElement('div');
|
||||
render(dialog, container);
|
||||
this.vnode = dialog;
|
||||
this.node = container.childNodes[0];
|
||||
document.body.appendChild(this.node);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @returns {Promise<string>}
|
||||
* @param points 经纬度坐标点数组
|
||||
*/
|
||||
show(points) {
|
||||
// 发送信号,显示窗口
|
||||
const event = new CustomEvent('route-dialog-show', { detail:
|
||||
{ show: true, pts: points }
|
||||
});
|
||||
document.dispatchEvent(event);
|
||||
return new Promise((resolve,reject) => {
|
||||
document.addEventListener('route-dialog-confirm', event => {
|
||||
if(event.detail==='cancel'){
|
||||
reject('cancel')
|
||||
}else{
|
||||
resolve(event.detail);
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
const aDialog = new routeDialog();
|
||||
|
||||
/**
|
||||
* 展示一个阻塞式对话框
|
||||
* @returns {Promise<string>}
|
||||
* @param point 经纬度坐标点数组
|
||||
*/
|
||||
export async function showRouteDialog(point) {
|
||||
return aDialog.show(point);
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
<!--
|
||||
* @Author: zhaipx
|
||||
* @Date: 2024-04-01 13:36:35
|
||||
* @Description: 航线选项窗口
|
||||
-->
|
||||
<script setup lang="ts">
|
||||
import {defineEmits, ref} from "vue";
|
||||
|
||||
let emit = defineEmits(['routeDraw','cancelDraw'])
|
||||
let routeParams = ref({
|
||||
code: 0,
|
||||
isClose: false,
|
||||
height: 0,
|
||||
routePts: []
|
||||
})
|
||||
let routeCode = [
|
||||
{
|
||||
label: "任务航线1",
|
||||
value: 1,
|
||||
},{
|
||||
label: "任务航线2",
|
||||
value: 2,
|
||||
},{
|
||||
label: "任务航线3",
|
||||
value: 3,
|
||||
},{
|
||||
label: "任务航线4",
|
||||
value: 4,
|
||||
}
|
||||
]
|
||||
const done = ()=>{
|
||||
emit("routeDraw", routeParams.value)
|
||||
}
|
||||
const cancel = ()=>{
|
||||
emit("cancelDraw")
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-modal :mask-closable="false" preset="dialog" >
|
||||
<template #header>
|
||||
<div>航线参数设定</div>
|
||||
</template>
|
||||
<div>
|
||||
<n-space>
|
||||
<n-form ref="formRef" :model="routeParams"
|
||||
label-placement="left"
|
||||
label-width="auto"
|
||||
require-mark-placement="right-hanging">
|
||||
<n-form-item label="是否闭合">
|
||||
<n-switch v-model:value="routeParams.isClose">
|
||||
<template #checked>
|
||||
是
|
||||
</template>
|
||||
<template #unchecked>
|
||||
否
|
||||
</template>
|
||||
</n-switch>
|
||||
</n-form-item>
|
||||
<n-form-item label="航线名称">
|
||||
<n-select v-model:value="routeParams.code" :options="routeCode" />
|
||||
</n-form-item>
|
||||
<n-form-item label="航线高度/m">
|
||||
<n-input-number v-model:value="routeParams.height" placeholder=500 :step="100" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-space>
|
||||
<n-space justify="center">
|
||||
<n-button @click="done" type="primary" size="small">确定</n-button>
|
||||
<n-button @click="cancel" type="warning" size="small">取消</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
Loading…
Reference in New Issue