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