From c5b665157cf37b75691dcb335df52b1a3078ec25 Mon Sep 17 00:00:00 2001 From: zhaipx Date: Fri, 21 Mar 2025 10:25:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=89=E7=BB=B4=E4=BC=B4=E9=A3=9E=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/js/cesium-map/measureDistance.js | 14 +-- src/assets/js/websocketProtocol.ts | 60 ++++++++---- src/components/CollisionDetection.vue | 50 ++++++++++ src/components/toolbar.vue | 102 ++++++++++++++------ src/store/layerManagerStore.ts | 10 +- src/store/staticOptions.js | 4 + src/types/entityoptions.ts | 5 + src/utils/map/SpatialAnalysis.ts | 95 +++++++++++++----- 8 files changed, 260 insertions(+), 80 deletions(-) create mode 100644 src/components/CollisionDetection.vue diff --git a/src/assets/js/cesium-map/measureDistance.js b/src/assets/js/cesium-map/measureDistance.js index 12ede66..1788a91 100644 --- a/src/assets/js/cesium-map/measureDistance.js +++ b/src/assets/js/cesium-map/measureDistance.js @@ -304,15 +304,14 @@ export default class MeasureDistance { showAirLine(line){ let degreesArr = [] for (let i = 0; i < line.points.length; i++) { - degreesArr.push(line.points[i].lon) - degreesArr.push(line.points[i].lat) - degreesArr.push(line.points[i].alt) + let coord = new Cartesian3.fromDegrees(line.points[i].lon,line.points[i].lat,line.points[i].alt) + degreesArr.push(coord) } let airlineEntity = new Cesium.Entity({ name: line.name, id: line.name+line.totalDistance, polyline: { - positions:Cesium.Cartesian3.fromDegreesArray(degreesArr), + positions: degreesArr, width: 2, material: Cesium.Color.ORANGE, clampToGround: true, @@ -322,9 +321,11 @@ export default class MeasureDistance { } addAirplaneEntity(modelPath,StrUavTypeID){ + this.viewer.scene.globe.depthTestAgainstTerrain = true; + store.uav.ModelIDinMap = "ID: " + StrUavTypeID let entity = this.viewer.entities.add({ name: StrUavTypeID, - id: "ID: "+StrUavTypeID, + id: "ID: " + StrUavTypeID, position: new Cesium.CallbackProperty(() => { return new Cesium.Cartesian3.fromDegrees(this.dynamicData.lon, this.dynamicData.lat, this.dynamicData.alt) }, false), @@ -347,7 +348,8 @@ export default class MeasureDistance { clampAnimations: true, color: Cesium.Color.fromAlpha(Cesium.Color.RED, parseFloat(1.0)), colorBlendMode: Cesium.ColorBlendMode['MIX'], - colorBlendAmount: 0 + colorBlendAmount: 0, + clampToGround: true, } }); this.viewer.trackedEntity = entity; diff --git a/src/assets/js/websocketProtocol.ts b/src/assets/js/websocketProtocol.ts index b7a374f..0cebea0 100644 --- a/src/assets/js/websocketProtocol.ts +++ b/src/assets/js/websocketProtocol.ts @@ -1,4 +1,5 @@ import {Airline, AirlinePoint, UavDynamicInfo} from "@/types/entityoptions.ts"; +import {useLayerStore} from "@/store/layerManagerStore.ts"; /** * 处理来自中心指控websocket的数据,返回所需数据 @@ -39,32 +40,49 @@ function dataProcess_fromQT(websocketDataQT:any): UavDynamicInfo|null { let data:UavDynamicInfo = { alt: 0, groundSpeed: 0, heading: 0, lat: 0, lon: 0, uavId: "", uavType: "" } - data.uavId = websocketDataQT.uavId - data.uavType = websocketDataQT.uavType - data.heading = websocketDataQT.HeadAngle - data.lon = websocketDataQT.lon - data.lat = websocketDataQT.lat - data.alt = websocketDataQT.height - data.groundSpeed = websocketDataQT.groundSpeed //km/h + data.uavId = websocketDataQT.pos.uavId + data.uavType = websocketDataQT.pos.uavType + data.heading = websocketDataQT.pos.HeadAngle + data.lon = websocketDataQT.pos.lon + data.lat = websocketDataQT.pos.lat + data.alt = websocketDataQT.pos.height + data.groundSpeed = websocketDataQT.pos.groundSpeed //km/h + + useLayerStore().navi.currentRouteID = websocketDataQT.navi.currentRouteID + useLayerStore().navi.nextRouteID = websocketDataQT.navi.nextRouteID + useLayerStore().navi.nextPoint = websocketDataQT.navi.nextPoint + useLayerStore().navi.distonext = websocketDataQT.navi.distonext + + console.log(data.lon,data.lat, data.alt) return data.lon==0? null: data } -function getAirline(data: any): Airline | null { - let line: Airline = {totalDistance: 0, PtNum: 0, name: "", isClose: false, points: []} - line.PtNum = data.PtNum - line.name = data.Name - line.isClose = data.isClose - line.totalDistance = data.totalDistance - for (let i = 0; i < data.ListPoints.length; i++) { - let point: AirlinePoint = { - alt: 0, lat: 0, lon: 0 - } - line.points.push(point) +function dataProcess_fromQT_route(websocketDataQT:any): Airline|null { + let data: Airline = { + code: 0, PtNum: 0, isClose: false, name: "", points: [], totalDistance: 0 } - return line -} + if(!websocketDataQT.route) return null + data.PtNum = websocketDataQT.route.length + for (let i = 1; i < websocketDataQT.route.length; i++) { + let aPt: AirlinePoint = {alt: 0, ch1: 0, ch2: 0, lat: 0, lon: 0, nPt: 0, speed: 0} + aPt.lon = websocketDataQT.route[i].lon + aPt.lat = websocketDataQT.route[i].lat + aPt.alt = websocketDataQT.route[i].height + aPt.ch1 = websocketDataQT.route[i].ch1 + aPt.ch2 = websocketDataQT.route[i].ch2 + aPt.nPt = websocketDataQT.route[i].nPt + aPt.speed = websocketDataQT.route[i].nV + data.code = websocketDataQT.route[i].nL + data.points.push(aPt) + } + if(data.points[data.PtNum-2].ch1 ==2) + data.isClose = true + data.name = "lineID-" + data.code.toString() + console.log(data) + return data.PtNum==0? null: data +} function getUavTypeStr(type: number) : string{ switch (type) { @@ -73,4 +91,4 @@ function getUavTypeStr(type: number) : string{ default: return 'test' } } -export {dataProcess_fromQT,getAirline} \ No newline at end of file +export {dataProcess_fromQT,dataProcess_fromQT_route} \ No newline at end of file diff --git a/src/components/CollisionDetection.vue b/src/components/CollisionDetection.vue new file mode 100644 index 0000000..6c0cf9d --- /dev/null +++ b/src/components/CollisionDetection.vue @@ -0,0 +1,50 @@ + + + + + \ No newline at end of file diff --git a/src/components/toolbar.vue b/src/components/toolbar.vue index 0761401..d9dd4c4 100644 --- a/src/components/toolbar.vue +++ b/src/components/toolbar.vue @@ -9,22 +9,29 @@ import {RulerAlt} from '@vicons/carbon' import {TerrainSharp} from '@vicons/material' import {DrawPolygon} from '@vicons/fa' import {useMessage} from 'naive-ui' -import {ref} from "vue"; +import {nextTick, ref} from "vue"; import {useStaticStore} from "@/store/staticOptions.js"; -import {requestAirline} from "@/assets/js/request.js"; -import {dataProcess_fromQT, getAirline} from "@/assets/js/websocketProtocol.ts"; +import {dataProcess_fromQT, dataProcess_fromQT_route} from "@/assets/js/websocketProtocol.ts"; import SpatialAnalysis from "@/components/SpatialAnalysis.vue"; import LayerManager from "@/components/map/LayerManager.vue"; +import CollisionDetection from "@/components/CollisionDetection.vue"; +import {useLayerStore} from "@/store/layerManagerStore.ts"; +import {Cartesian3} from "cesium"; +import * as echarts from "echarts"; const message = useMessage(); let SceneValue; let showModal = ref(false); +let showDetection = ref(false); let hasPlane = ref(false); let store = useStaticStore(); +let lStore = useLayerStore(); -const spatialAnalyse= ref(null) -const layerManager= ref(null) +const spatialAnalyse = ref(null) +const layerManager = ref(null) +const collisionDetection = ref(null) SceneValue = ref('untrace'); +let frameCount = 0 function handleSceneSelect(key){ if(!hasPlane.value) return; @@ -32,7 +39,7 @@ function handleSceneSelect(key){ if(key === 'untrace') { window.measureViewer.setNoTrack() }else if(key === 'fallow') { - window.viewer.trackedEntity = window.viewer.entities.getById('websocket-flying-plane'); + window.viewer.trackedEntity = window.viewer.entities.getById(store.uav.ModelIDinMap); } } let layerValue = ref('layer1'); @@ -40,7 +47,7 @@ let barIsOpen = ref(true); function handleEditSelect(key) { if(key === 'requestLine') { - getUavAirline() + } else{ // 航线管理页面 @@ -151,16 +158,53 @@ async function connectWebSocket() { store.webskt.ws.onmessage = (event) => { //收到消息后的处理流程.... - let data = dataProcess_fromQT(JSON.parse(event.data)) - console.log(data); - // 添加飞机三维图标 - if (!hasPlane.value && data != null) { - window.measureViewer.addAirplaneEntity(store.models.defaultAirPlane, data.uavId + data.uavType) - SceneValue.value = 'fallow' - hasPlane.value = true; + let sktData = JSON.parse(event.data) + // console.log(sktData); + frameCount++ + if(sktData.type === 0){ + let ycData = dataProcess_fromQT(sktData) + if (ycData != null) { + // 更新遥测数据(飞机位置) + window.measureViewer.updateDynamicData(ycData) + // 添加飞机三维图标 + if(!hasPlane.value){ + window.measureViewer.addAirplaneEntity(store.models.defaultAirPlane, ycData.uavId + ycData.uavType) + SceneValue.value = 'fallow' + hasPlane.value = true; + } + /************************测试代码(以下)******************/ + // if(frameCount>50) { //(50帧更新一次) + // frameCount = 0 + // //TODO: 调用子组件函数、测试 + // let cartesianTarget = Cartesian3.fromDegrees(114.6, 37.8) + // let cartesianCurr = Cartesian3.fromDegrees(ycData.lon, ycData.lat, ycData.alt) + // collisionDetection.value?.drawDetection(ycData.alt, cartesianCurr, cartesianTarget) + // } + + /************************测试代码(以上)******************/ + // 加载和更新碰撞检测图(20帧更新一次) + if(lStore.navi.airlines.length>0 && frameCount>50){ + frameCount = 0 + lStore.navi.airlines.forEach(airline => { + if(airline.code === lStore.navi.currentRouteID){ + let targetPos = airline.points[lStore.navi.nextPoint] + //TODO: 调用子组件函数、测试 + let cartesianTarget = Cartesian3.fromDegrees(targetPos.lon, targetPos.lat,targetPos.alt) + let cartesianCurr = Cartesian3.fromDegrees(ycData.lon, ycData.lat,ycData.alt) + collisionDetection.value?.drawDetection(ycData.alt, cartesianCurr, cartesianTarget) + + } + }) + } + } } - if (data != null) { - window.measureViewer.updateDynamicData(data) + if(sktData.type === 1){ + let routeData = dataProcess_fromQT_route(sktData) + lStore.navi.airlines.push(routeData) + console.log(routeData) + if(routeData != null){ + window.measureViewer.showAirLine(routeData) + } } }; } @@ -174,20 +218,6 @@ function closeWS(){ } } -/** - * 请求航线接口 - */ -function getUavAirline() { - if(sessionStorage.getItem('uavId')){ - requestAirline(sessionStorage.getItem('uavId')).then(rsp => { - console.log(rsp.data) - window.measureViewer.showAirLine(getAirline(rsp.data)) - }) - }else { - message.warning('当前未连接飞机') - } -} - function manageLayer(){ layerManager.value?.open_closeSidebar() } @@ -273,6 +303,9 @@ function manageLayer(){ + + + diff --git a/src/store/layerManagerStore.ts b/src/store/layerManagerStore.ts index bbf7a6d..e241b3a 100644 --- a/src/store/layerManagerStore.ts +++ b/src/store/layerManagerStore.ts @@ -1,4 +1,5 @@ import {defineStore} from "pinia"; +import {Airline} from "@/types/entityoptions.ts"; type layer = { lName: string lId: string @@ -10,7 +11,14 @@ type layer = { export const useLayerStore = defineStore('LayerStore', { state: ()=>{ return { - Layers: [] as layer[] + Layers: [] as layer[], + navi: { + airlines: [] as Airline[], + currentRouteID: undefined, //当前航线号 + nextRouteID: undefined, //下一航线号 + nextPoint: undefined, //下一航点号 + distonext: undefined, //待飞距离 + }, } }, actions: { diff --git a/src/store/staticOptions.js b/src/store/staticOptions.js index 2f50462..e2593a9 100644 --- a/src/store/staticOptions.js +++ b/src/store/staticOptions.js @@ -53,6 +53,10 @@ export const useStaticStore = defineStore('staticOptions',{ defaultAirPlane: cesiumAirPlane, }, hasPlane: false, + uav: { + ModelIDinMap: '', //地图中的飞机entity ID + }, + analysisVars: { //当前的空间分析类型,剖面1 通视2 analysisType: -1, diff --git a/src/types/entityoptions.ts b/src/types/entityoptions.ts index 633eca9..91c33a6 100644 --- a/src/types/entityoptions.ts +++ b/src/types/entityoptions.ts @@ -39,10 +39,15 @@ export type AirlinePoint = { lon:number, lat:number, alt:number, + ch2:number, + ch1:number, //任务特征字, 2为闭合航线 0为开航线 + speed:number, //航点特征字 + nPt:number, //航点号 } export type Airline = { name: string, + code: number, //航线编号 PtNum: number, isClose: boolean, totalDistance: number, diff --git a/src/utils/map/SpatialAnalysis.ts b/src/utils/map/SpatialAnalysis.ts index 9070274..458d175 100644 --- a/src/utils/map/SpatialAnalysis.ts +++ b/src/utils/map/SpatialAnalysis.ts @@ -7,6 +7,7 @@ import {getDistance, getElevation} from "@/utils/map/geocomputation.ts"; import {Cartesian3, Viewer} from "cesium"; import * as echarts from "echarts"; +import {EChartsType} from "echarts"; type ProfileResult = { distanceArray:number[], elevationArray:number[], @@ -245,30 +246,37 @@ export function drawEchartsProfileAnalyse(xData:number[], yData:number[]) { /** - * 绘制折线图(航线碰撞检测) + * 绘制地形碰撞检测剖面图 + * @param myChart ECharts对象 * @param xData x数组 * @param yData y数组,以面积线绘制 - * @param yData2 y数组,以折线绘制 + * @param height 水平辅助线的高度 */ -export const drawEchartsAirlineDetect = (xData:number[],yData:number[],yData2:number[]) => { - let myChart = echarts.init(document.getElementById('profileEChart')) +export function drawEcharts_CollisionDetection(myChart: EChartsType, xData:number[], yData:number[], height:number) { // 绘制图表 myChart.setOption({ - legend:{ + legend: { show: true, type: 'plain', - top: '7%', + top: '5%', data:[ { - name: 'groundLine', + name: '地形', itemStyle: 'inherit', lineStyle: 'inherit', }, - { - name: 'airLine', - itemStyle: 'inherit', - lineStyle: 'inherit', - }] + { //视线图例 + name: '飞机高度', + lineStyle: { + type: 'dotted', + width: 3, + color: '#f8364d' + }, + itemStyle: { + fontSize: 18 + } + } + ] }, tooltip: { show: true, @@ -276,11 +284,11 @@ export const drawEchartsAirlineDetect = (xData:number[],yData:number[],yData2:nu axisPointer: { type: 'cross' }, - formatter:'地表高度: {c0}
航线高度: {c1}' + formatter:'地表高度: {c0}' }, xAxis: { data: xData, - name: '距离', + name: '距离/米', nameTextStyle: { fontWeight:'bolder', fontSize: 14 @@ -293,7 +301,7 @@ export const drawEchartsAirlineDetect = (xData:number[],yData:number[],yData2:nu symbolSize: [7, 10] }, axisLabel: { - formatter: '{value} m', + formatter: '{value}', margin: 5, }, axisTick: { @@ -308,7 +316,7 @@ export const drawEchartsAirlineDetect = (xData:number[],yData:number[],yData2:nu }, yAxis: { type: 'value', - name: '高度', + name: '高度/米', nameTextStyle: { fontWeight:'bolder', fontSize: 14 @@ -316,7 +324,7 @@ export const drawEchartsAirlineDetect = (xData:number[],yData:number[],yData2:nu nameLocation: 'end', position: 'left', axisLabel: { - formatter: '{value} m' + formatter: '{value}' }, axisLine: { show: true, @@ -324,23 +332,66 @@ export const drawEchartsAirlineDetect = (xData:number[],yData:number[],yData2:nu symbolSize: [7, 10] } }, + visualMap: { + type: 'piecewise', + show: false, + dimension: 1, + // seriesIndex: [0, 1], // 虽然可以指定多个series,但是线的颜色只能设置一条 + seriesIndex: [0, 1], + pieces: [{ + gt: height, + color: 'red' + }, { + lt: 0, + color: 'blue' + }], + outOfRange: { // 在选中范围外 的视觉元素,这里设置在正常范围内的图形颜色 + color: 'blue', + }, + }, series: [ { - name:'groundLine', + name:'地形', type: 'line', data: yData, areaStyle: { color: '#37a5fb', opacity: 0.5 - } + }, + markLine: { + name: "飞机高度", + data: [ + { + yAxis: height, + itemStyle: { + normal: { color: '#c60c30' } + } + } + ], + symbol:['circle', 'arrow'], + label:{ + formatter: "飞机高度", + show: true, + position: 'middle', + fontSize: 15, + fontWeight: 'bold', + color: '#e73d3d', + }, + lineStyle: { //标注线样式 + type: 'dashed', + color: 'red', + with: 10 + } + }, }, { - name:'airLine', type: 'line', - data: yData2, + symbol: 'none', + name: '飞机高度', + color: 'transparent' } ] - }); + }, false); }