feature: 实时飞行高度与地形高度折线图绘制

devzpx
zhaipx 2 months ago
parent c5b665157c
commit 5548c7e57e

@ -298,7 +298,7 @@ export default class MeasureDistance {
} }
/** /**
* 显示飞行航线 * 显示航线
* @param line Airline * @param line Airline
*/ */
showAirLine(line){ showAirLine(line){
@ -307,17 +307,34 @@ export default class MeasureDistance {
let coord = new Cartesian3.fromDegrees(line.points[i].lon,line.points[i].lat,line.points[i].alt) let coord = new Cartesian3.fromDegrees(line.points[i].lon,line.points[i].lat,line.points[i].alt)
degreesArr.push(coord) degreesArr.push(coord)
} }
if(line.isClose)
degreesArr.push(new Cartesian3.fromDegrees(line.points[0].lon,line.points[0].lat,line.points[0].alt))
let airlineEntity = new Cesium.Entity({ let airlineEntity = new Cesium.Entity({
name: line.name, name: line.name,
id: line.name+line.totalDistance, id: line.name + line.totalDistance,
polyline: { polyline: {
positions: degreesArr, positions: degreesArr,
width: 2, width: 3,
material: Cesium.Color.ORANGE, material: Cesium.Color.ORANGE,
clampToGround: true, clampToGround: false,
}, }
}) })
this.viewer.entities.add(airlineEntity) this.viewer.entities.add(airlineEntity)
for (let pt in degreesArr) {
let vertexEntity = new Cesium.Entity({
// id: "航点" + ,
position: pt,
point: {
color: Cesium.Color.FUCHSIA,
pixelSize: 6,
disableDepthTestDistance:99000000,
// heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,
}
});
this.viewer.entities.add(vertexEntity)
}
} }
addAirplaneEntity(modelPath,StrUavTypeID){ addAirplaneEntity(modelPath,StrUavTypeID){
@ -334,7 +351,7 @@ export default class MeasureDistance {
return new Cesium.Transforms.headingPitchRollQuaternion( return new Cesium.Transforms.headingPitchRollQuaternion(
new Cesium.Cartesian3.fromDegrees(this.dynamicData.lon, this.dynamicData.lat, this.dynamicData.alt), new Cesium.Cartesian3.fromDegrees(this.dynamicData.lon, this.dynamicData.lat, this.dynamicData.alt),
new Cesium.HeadingPitchRoll( new Cesium.HeadingPitchRoll(
Cesium.Math.toRadians(this.dynamicData.heading-90), // 0是正东顺时针增加 Cesium.Math.toRadians(this.dynamicData.heading-0), // 0调整该值不同模型的正方向不同
Cesium.Math.toRadians(0), Cesium.Math.toRadians(0),
Cesium.Math.toRadians(0) Cesium.Math.toRadians(0)
)) ))
@ -342,8 +359,9 @@ export default class MeasureDistance {
model: { model: {
uri: modelPath, uri: modelPath,
scale: 0.001,
minimumPixelSize: 100, minimumPixelSize: 100,
maximumScale: 2000, maximumScale: 1,
runAnimations: true, runAnimations: true,
clampAnimations: true, clampAnimations: true,
color: Cesium.Color.fromAlpha(Cesium.Color.RED, parseFloat(1.0)), color: Cesium.Color.fromAlpha(Cesium.Color.RED, parseFloat(1.0)),

@ -45,7 +45,7 @@ function dataProcess_fromQT(websocketDataQT:any): UavDynamicInfo|null {
data.heading = websocketDataQT.pos.HeadAngle data.heading = websocketDataQT.pos.HeadAngle
data.lon = websocketDataQT.pos.lon data.lon = websocketDataQT.pos.lon
data.lat = websocketDataQT.pos.lat data.lat = websocketDataQT.pos.lat
data.alt = websocketDataQT.pos.height data.alt = Number(websocketDataQT.pos.height) + useLayerStore().navi.hFactor
data.groundSpeed = websocketDataQT.pos.groundSpeed //km/h data.groundSpeed = websocketDataQT.pos.groundSpeed //km/h
useLayerStore().navi.currentRouteID = websocketDataQT.navi.currentRouteID useLayerStore().navi.currentRouteID = websocketDataQT.navi.currentRouteID
@ -53,8 +53,8 @@ function dataProcess_fromQT(websocketDataQT:any): UavDynamicInfo|null {
useLayerStore().navi.nextPoint = websocketDataQT.navi.nextPoint useLayerStore().navi.nextPoint = websocketDataQT.navi.nextPoint
useLayerStore().navi.distonext = websocketDataQT.navi.distonext useLayerStore().navi.distonext = websocketDataQT.navi.distonext
console.log(data.lon,data.lat, data.alt) // console.log(data.lon,data.lat, data.alt)
//
return data.lon==0? null: data return data.lon==0? null: data
} }
@ -63,24 +63,23 @@ function dataProcess_fromQT_route(websocketDataQT:any): Airline|null {
code: 0, PtNum: 0, isClose: false, name: "", points: [], totalDistance: 0 code: 0, PtNum: 0, isClose: false, name: "", points: [], totalDistance: 0
} }
if(!websocketDataQT.route) return null if(!websocketDataQT.route) return null
data.PtNum = websocketDataQT.route.length data.PtNum = websocketDataQT.route.points.length
for (let i = 1; i < websocketDataQT.route.length; i++) { data.isClose = websocketDataQT.route.isClose
for (let i = 1; i < websocketDataQT.route.points.length; i++) {
let aPt: AirlinePoint = {alt: 0, ch1: 0, ch2: 0, lat: 0, lon: 0, nPt: 0, speed: 0} let aPt: AirlinePoint = {alt: 0, ch1: 0, ch2: 0, lat: 0, lon: 0, nPt: 0, speed: 0}
aPt.lon = websocketDataQT.route[i].lon aPt.lon = websocketDataQT.route.points[i].lon
aPt.lat = websocketDataQT.route[i].lat aPt.lat = websocketDataQT.route.points[i].lat
aPt.alt = websocketDataQT.route[i].height aPt.alt = websocketDataQT.route.points[i].height
aPt.ch1 = websocketDataQT.route[i].ch1 aPt.ch1 = websocketDataQT.route.points[i].ch1
aPt.ch2 = websocketDataQT.route[i].ch2 aPt.ch2 = websocketDataQT.route.points[i].ch2
aPt.nPt = websocketDataQT.route[i].nPt aPt.nPt = websocketDataQT.route.points[i].nPt
aPt.speed = websocketDataQT.route[i].nV aPt.speed = websocketDataQT.route.points[i].nV
data.code = websocketDataQT.route[i].nL data.code = websocketDataQT.route.points[i].nL
data.points.push(aPt) data.points.push(aPt)
} }
if(data.points[data.PtNum-2].ch1 ==2)
data.isClose = true
data.name = "lineID-" + data.code.toString() data.name = "lineID-" + data.code.toString()
console.log(data) console.log(data)
return data.PtNum==0? null: data return data.PtNum==0? null: data
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,21 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import { import {
drawEcharts_CollisionDetection, drawEcharts_CollisionDetection,
drawEcharts_CollisionDetection2,
profileAnalyse profileAnalyse
} from "@/utils/map/SpatialAnalysis.ts"; } from "@/utils/map/SpatialAnalysis.ts";
import {Cartesian3} from "cesium"; import {Cartesian3} from "cesium";
import {nextTick, onMounted} from "vue"; import {onMounted} from "vue";
import * as echarts from "echarts"; import * as echarts from "echarts";
import {EChartsType} from "echarts"; import {EChartsType} from "echarts";
import {useLayerStore} from "@/store/layerManagerStore.ts";
let l_store = useLayerStore()
let myChart: EChartsType = undefined let myChart: EChartsType = undefined
let uavDisArr: number[] = []
let uavHeightArr: number[] = []
let terrainArr: number[] = []
onMounted(()=>{ onMounted(()=>{
myChart = echarts.init(document.getElementById('detection-chart')) myChart = echarts.init(document.getElementById('detection-chart'))
// nextTick(()=>{
//
// })
}) })
const props = defineProps(['groundHeight'])
/** /**
* 绘制地形碰撞检测折线图 * 绘制地形碰撞检测折线图
* @param height 飞机高度作为检测线 * @param height 飞机高度作为检测线
@ -26,19 +29,46 @@ const drawDetection = (height: number, currentPos:Cartesian3, nextPos: Cartesian
// //
let res = profileAnalyse(window.viewer, [currentPos, nextPos], 10) let res = profileAnalyse(window.viewer, [currentPos, nextPos], 10)
// //
nextTick(()=>{ drawEcharts_CollisionDetection(myChart, res.distanceArray, res.elevationArray, height)
drawEcharts_CollisionDetection(myChart, res.distanceArray, res.elevationArray, height)
}) }
/**
* 绘制地形碰撞检测折线图
* @param uavH 飞机高度
* @param uavDis 飞机当前位置与上一位置的距离
* @param terrainH 飞机当前地面投影点的地形高度
*/
const drawDetection2 = (uavH: number, uavDis:number, terrainH: number) => {
if(uavDisArr.length == 0){
uavDisArr.push(Math.round(uavDis))
}
else{
uavDisArr.push(Math.round(uavDis + uavDisArr[uavDisArr.length - 1]))
}
uavHeightArr.push(Math.round(uavH))
terrainArr.push(Math.round(terrainH))
// ECharts
drawEcharts_CollisionDetection2(myChart, uavDisArr, terrainArr, uavHeightArr)
} }
defineExpose({ defineExpose({
drawDetection, drawDetection,
drawDetection2,
}) })
</script> </script>
<template> <template>
<div id="detection-chart"></div> <n-space>
<span style="font-weight: bolder">
飞机对地高度{{props.groundHeight}}
</span>
<div id="detection-chart"></div>
</n-space>
</template> </template>
<style scoped> <style scoped>

@ -9,7 +9,7 @@ import {RulerAlt} from '@vicons/carbon'
import {TerrainSharp} from '@vicons/material' import {TerrainSharp} from '@vicons/material'
import {DrawPolygon} from '@vicons/fa' import {DrawPolygon} from '@vicons/fa'
import {useMessage} from 'naive-ui' import {useMessage} from 'naive-ui'
import {nextTick, ref} from "vue"; import {ref} from "vue";
import {useStaticStore} from "@/store/staticOptions.js"; import {useStaticStore} from "@/store/staticOptions.js";
import {dataProcess_fromQT, dataProcess_fromQT_route} from "@/assets/js/websocketProtocol.ts"; import {dataProcess_fromQT, dataProcess_fromQT_route} from "@/assets/js/websocketProtocol.ts";
import SpatialAnalysis from "@/components/SpatialAnalysis.vue"; import SpatialAnalysis from "@/components/SpatialAnalysis.vue";
@ -17,7 +17,7 @@ import LayerManager from "@/components/map/LayerManager.vue";
import CollisionDetection from "@/components/CollisionDetection.vue"; import CollisionDetection from "@/components/CollisionDetection.vue";
import {useLayerStore} from "@/store/layerManagerStore.ts"; import {useLayerStore} from "@/store/layerManagerStore.ts";
import {Cartesian3} from "cesium"; import {Cartesian3} from "cesium";
import * as echarts from "echarts"; import {getDistance, getElevation} from "@/utils/map/geocomputation.ts";
const message = useMessage(); const message = useMessage();
let SceneValue; let SceneValue;
@ -26,13 +26,13 @@ let showDetection = ref(false);
let hasPlane = ref(false); let hasPlane = ref(false);
let store = useStaticStore(); let store = useStaticStore();
let lStore = useLayerStore(); let lStore = useLayerStore();
let groundHeight = ref(-1)
const spatialAnalyse = ref(null) const spatialAnalyse = ref(null)
const layerManager = ref(null) const layerManager = ref(null)
const collisionDetection = ref(null) const collisionDetection = ref(null)
SceneValue = ref('untrace'); SceneValue = ref('untrace');
let frameCount = 0 let frameCount = 0
let lastPos = undefined; //
function handleSceneSelect(key){ function handleSceneSelect(key){
if(!hasPlane.value) return; if(!hasPlane.value) return;
@ -168,43 +168,54 @@ async function connectWebSocket() {
window.measureViewer.updateDynamicData(ycData) window.measureViewer.updateDynamicData(ycData)
// //
if(!hasPlane.value){ if(!hasPlane.value){
window.measureViewer.addAirplaneEntity(store.models.defaultAirPlane, ycData.uavId + ycData.uavType) window.measureViewer.addAirplaneEntity(store.models.fp98, ycData.uavId + ycData.uavType)
SceneValue.value = 'fallow' SceneValue.value = 'fallow'
hasPlane.value = true; hasPlane.value = true;
} }
/************************测试代码(以下)******************/ console.log(frameCount)
// if(frameCount>50) { //(50) // (50)
// frameCount = 0 if(frameCount>50){
// //TODO: showDetection.value = true
// 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 frameCount = 0
lStore.navi.airlines.forEach(airline => { let currentPos = Cartesian3.fromDegrees(ycData.lon, ycData.lat,ycData.alt)
if(airline.code === lStore.navi.currentRouteID){ new Promise(resolve => {
let targetPos = airline.points[lStore.navi.nextPoint] // m
//TODO: groundHeight.value = ycData.alt - getElevation(window.viewer, currentPos)
let cartesianTarget = Cartesian3.fromDegrees(targetPos.lon, targetPos.lat,targetPos.alt) //
let cartesianCurr = Cartesian3.fromDegrees(ycData.lon, ycData.lat,ycData.alt) if(lastPos===undefined){
collisionDetection.value?.drawDetection(ycData.alt, cartesianCurr, cartesianTarget) lastPos = currentPos;
} }
let dis = getDistance(currentPos, lastPos) * 1000
lastPos = currentPos
resolve(dis)
}).then(res=>{
collisionDetection.value.drawDetection2(ycData.alt, res, ycData.alt-groundHeight.value)
}) })
} }
} }
} }
if(sktData.type === 1){ if(sktData.type === 1){
let routeData = dataProcess_fromQT_route(sktData) let routeData = dataProcess_fromQT_route(sktData)
lStore.navi.airlines.push(routeData)
console.log(routeData)
if(routeData != null){ if(routeData != null){
lStore.navi.airlines.push(routeData)
lStore.navi.currentRouteID = routeData.code
console.log(routeData)
window.measureViewer.showAirLine(routeData) window.measureViewer.showAirLine(routeData)
//线store
// FIXME:
/*
profileAnalyse_promise(window.viewer, routeData,100).then((result) => {
let routeTerr = {}
routeTerr.routeID = routeData.code
routeTerr.distanceArray = result.distanceArray
routeTerr.elevationArray = result.elevationArray
lStore.routesTerrain.push(routeTerr)
})
*/
} }
} }
}; };
} }
@ -304,7 +315,7 @@ function manageLayer(){
</n-row> </n-row>
</n-space> </n-space>
<n-space id="detectionGraph" v-show="showDetection"> <n-space id="detectionGraph" v-show="showDetection">
<CollisionDetection ref="collisionDetection"></CollisionDetection> <CollisionDetection ref="collisionDetection" :groundHeight="groundHeight"></CollisionDetection>
</n-space> </n-space>
<n-modal v-model:show="showModal" <n-modal v-model:show="showModal"
@ -356,6 +367,6 @@ function manageLayer(){
width: 100rem; width: 100rem;
height: 15rem; height: 15rem;
border-radius: 7px; border-radius: 7px;
background: rgba(21, 21, 21, 0.94); background: rgba(255, 255, 255, 0.94);
} }
</style> </style>

@ -1,5 +1,5 @@
import {defineStore} from "pinia"; import {defineStore} from "pinia";
import {Airline} from "@/types/entityoptions.ts"; import {Airline, routeTerrain} from "@/types/entityoptions.ts";
type layer = { type layer = {
lName: string lName: string
lId: string lId: string
@ -14,11 +14,13 @@ export const useLayerStore = defineStore('LayerStore', {
Layers: [] as layer[], Layers: [] as layer[],
navi: { navi: {
airlines: [] as Airline[], airlines: [] as Airline[],
currentRouteID: undefined, //当前航线号 currentRouteID: -1, //当前航线号
nextRouteID: undefined, //下一航线号 nextRouteID: -1, //下一航线号
nextPoint: undefined, //下一航点号 nextPoint: -1, //下一航点号
distonext: undefined, //待飞距离 distonext: -1, //待飞距离
hFactor: 3 //高度修正数
}, },
routesTerrain: [] as routeTerrain[]
} }
}, },
actions: { actions: {

@ -1,5 +1,7 @@
import {defineStore} from "pinia"; import {defineStore} from "pinia";
import cesiumAirPlane from "@/assets/models/Cesium_Air.glb"; import cesiumAirPlane from "@/assets/models/Cesium_Air.glb";
import fp985Plane from "@/assets/models/FP-985.gltf";
import fp98Plane from "@/assets/models/fp-98.gltf";
export const useStaticStore = defineStore('staticOptions',{ export const useStaticStore = defineStore('staticOptions',{
state: ()=>{ state: ()=>{
@ -51,6 +53,8 @@ export const useStaticStore = defineStore('staticOptions',{
}, },
models: { models: {
defaultAirPlane: cesiumAirPlane, defaultAirPlane: cesiumAirPlane,
fp985: fp985Plane,
fp98: fp98Plane
}, },
hasPlane: false, hasPlane: false,
uav: { uav: {

@ -53,3 +53,9 @@ export type Airline = {
totalDistance: number, totalDistance: number,
points: AirlinePoint[], points: AirlinePoint[],
} }
export type routeTerrain = {
routeID: number,
distanceArray: number[],
elevationArray: number[],
}

@ -8,10 +8,12 @@ import {getDistance, getElevation} from "@/utils/map/geocomputation.ts";
import {Cartesian3, Viewer} from "cesium"; import {Cartesian3, Viewer} from "cesium";
import * as echarts from "echarts"; import * as echarts from "echarts";
import {EChartsType} from "echarts"; import {EChartsType} from "echarts";
import {Airline, AirlinePoint} from "@/types/entityoptions.ts";
type ProfileResult = { type ProfileResult = {
distanceArray:number[], distanceArray:number[],
elevationArray:number[], elevationArray:number[],
} }
/** /**
* *
* @param viewer Viewer * @param viewer Viewer
@ -74,6 +76,36 @@ export function profileAnalyse(viewer: Viewer, polyline:Cartesian3[], interval:
return result return result
} }
/**
* 线
* @param viewer Viewer
* @param route 线
* @param interval 线 m
* @return 线线
*/
export function profileAnalyse_promise(viewer: Viewer, route: Airline, interval: number){
return new Promise((resolve, reject) => {
let result: ProfileResult = { distanceArray:[], elevationArray:[] }
let polyline = []
//航线转为坐标点数组
route.points.forEach(point => {
polyline.push(Cartesian3.fromDegrees(point.lon, point.lat,point.alt))
})
let temp_dis = 0 //每两点之间的距离
for (let i = 0; i <= polyline.length - 2; i++) {
let temp = elevationProfile(viewer, polyline[i], polyline[i+1], interval)
result.elevationArray = result.elevationArray.concat(temp.elevationArray)
temp.distanceArray.forEach(distance => {
result.distanceArray.push(distance+temp_dis)
})
if(temp.distanceArray.length > 0){
temp_dis += temp.distanceArray[temp.distanceArray.length-1]
}
}
resolve(result)
})
}
/** /**
* <br> * <br>
* truefalseundefined * truefalseundefined
@ -394,6 +426,120 @@ export function drawEcharts_CollisionDetection(myChart: EChartsType, xData:numbe
}, false); }, false);
} }
/**
*
* @param myChart ECharts
* @param xData x
* @param yData y线
* @param yData2 y2线
*/
export function drawEcharts_CollisionDetection2(myChart: EChartsType, xData:number[], yData:number[], yData2: number[]) {
// 绘制图表
myChart.setOption({
legend: {
show: true,
type: 'plain',
top: '5%',
data:[
{
name: '地表高度',
itemStyle: 'inherit',
lineStyle: 'inherit',
},
{
name: '飞机高度',
lineStyle: {
type: 'dotted',
width: 3,
color: '#f8364d'
},
itemStyle: {
fontSize: 18
}
}
]
},
tooltip: {
show: true,
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter:'地表高度: {c0}<br>飞机高度: {c1}'
},
xAxis: {
data: xData,
name: '距离/米',
nameTextStyle: {
fontWeight:'bolder',
fontSize: 14
},
nameLocation: 'end',
axisLine:{
onZero: false,
show: true, // 是否显示坐标轴轴线
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
},
axisLabel: {
formatter: '{value}',
margin: 5,
},
axisTick: {
show: true, // 是否显示坐标轴刻度
inside: true, // 坐标轴刻度是否朝内,默认朝外
alignWithLabel: true,
lineStyle: {
color: '#000000', //刻度线的颜色
type: 'solid', //坐标轴线线的类型solid实线类型dashed虚线类型dotted点状类型
},
}
},
yAxis: {
max: (value:any)=>{
return Math.floor(value.max * 1.01)
},
min: (value:any)=>{
return Math.floor(value.min * 0.99)
},
type: 'value',
name: '高度/米',
nameTextStyle: {
fontWeight:'bolder',
fontSize: 14
},
nameLocation: 'end',
position: 'left',
axisLabel: {
formatter: '{value}'
},
axisLine: {
show: true,
symbol: ['none', 'arrow'],
symbolSize: [7, 10]
}
},
series: [
{
name:'地表高度',
type: 'line',
data: yData,
areaStyle: {
color: '#37a5fb',
opacity: 0.5
},
},
{
name: '飞机高度',
type: 'line',
symbol: 'none',
color: 'red',
data: yData2,
}
]
}, false);
}
/** /**
* 线线 * 线线

Loading…
Cancel
Save