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