/*
|
* @Author: shuishen 1109946754@qq.com
|
* @Date: 2025-04-19 14:24:34
|
* @LastEditors: shuishen 1109946754@qq.com
|
* @LastEditTime: 2025-04-20 17:53:08
|
* @FilePath: \command-center-dashboard\src\hooks\useTaskWayline\useTaskWayline.js
|
* @Description:
|
*
|
* Copyright (c) 2025 by shuishen, All Rights Reserved.
|
*/
|
import lineImg from '@/assets/images/arrow-right-blue.png'
|
import rwqfdImg from '@/assets/images/signMachineNest/rwqfd.png'
|
import endPointImg from '@/assets/images/EndPointicon.png'
|
|
import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz'
|
import { flyVisual } from '@/utils/cesium/mapUtil'
|
import ImageTrailMaterial from '@/utils/cesium/ImageTrailMaterial'
|
|
import * as Cesium from 'cesium'
|
import { Cartesian3 } from 'cesium'
|
import aircraftGltf from '@/assets/gltf/aircraft.gltf'
|
import CreateFrustum from '@/utils/cesium/frustum/CreateFrustum'
|
|
export function useTaskWayline () {
|
let viewer = null
|
let deviceOsdInfo = null
|
let flighttaskProgressInfo = null
|
|
// watch
|
let taskWatch = null
|
let flighttaskWatch = null
|
let deviceWatch = null
|
|
// 航线位置
|
let currentWaylinePostions = []
|
// 当前航点 下标
|
let currentWaypointIndex = null
|
let droneSpeedArr = []
|
|
// 解析kmz文件
|
const parsingFiles = async url => {
|
const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`)
|
const waylinesXML = await res.fileInfoObj['wpmz/waylines.wpml']
|
const waylinesXMLJSON = XMLToJSON(waylinesXML)?.['Document']
|
const waylinesXMLObj = removeTextKey(waylinesXMLJSON.Folder)
|
if (!waylinesXMLObj.Placemark.length) return
|
// const allPoint = waylinesXMLObj.Placemark.map(item => item.Point.coordinates.split(','))
|
// flyVisual(allPoint, viewer)
|
drawWayline(waylinesXMLObj)
|
}
|
|
const drawWayline = lineObj => {
|
currentWaylinePostions = lineObj.Placemark.map(item => {
|
const [lon, lat] = item.Point.coordinates.split(',')
|
return Cartesian3.fromDegrees(Number(lon), Number(lat))
|
})
|
|
removeEntitys()
|
|
// 起点
|
viewer.entities.add({
|
id: 'drone-job-wayline-start',
|
position: currentWaylinePostions[0],
|
billboard: {
|
image: new Cesium.ConstantProperty(rwqfdImg),
|
width: 70,
|
height: 70,
|
},
|
})
|
|
// 终点
|
viewer.entities.add({
|
id: 'drone-job-wayline-end',
|
position: currentWaylinePostions[currentWaylinePostions.length - 1],
|
billboard: {
|
image: new Cesium.ConstantProperty(endPointImg),
|
width: 30,
|
height: 30,
|
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 底部对齐
|
},
|
})
|
|
// 路径线
|
let polylineEntity = viewer.entities.add({
|
id: 'drone-job-wayline-polyline',
|
polyline: {
|
width: 4,
|
positions: currentWaylinePostions,
|
material: new ImageTrailMaterial({
|
color: { alpha: 1, blue: 1, green: 1, red: 1 },
|
speed: 20,
|
image: lineImg,
|
repeat: { x: Math.floor(40), y: 1 },
|
}),
|
clampToGround: false,
|
},
|
})
|
|
viewer.flyTo(polylineEntity, {
|
offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0),
|
duration: 0.5,
|
})
|
}
|
|
let viewInfoFrustum
|
// 设置视椎
|
const setCreateFrustum = (host) => {
|
if (!host) return
|
viewInfoFrustum?.clear()
|
|
const attitude_head = 180 + host?.attitude_head
|
const gimbal_pitch = 90 - Number(host?.payloads[0]?.gimbal_pitch) || 0
|
|
viewInfoFrustum = new CreateFrustum(viewer, {
|
position: {
|
longitude: host?.longitude,
|
latitude: host?.latitude,
|
altitude: host?.height,
|
},
|
width: 30,
|
height: 30,
|
fov: 20.0,
|
near: 3.0,
|
far: 250.0,
|
roll: gimbal_pitch,
|
pitch: 0,
|
heading: attitude_head,
|
})
|
}
|
|
function setAircraftGltf () {
|
const host = deviceOsdInfo.value?.data?.host
|
|
const aircraftEntity = viewer?.entities.getById('aircraftGltf')
|
const position = Cesium.Cartesian3.fromDegrees(host?.longitude, host?.latitude, host?.height)
|
|
if (aircraftEntity) {
|
aircraftEntity.position = new Cesium.ConstantPositionProperty(position)
|
|
const homeDistance = Math.floor(host?.home_distance) || 0
|
|
// 距离下一个航点
|
const nextPoint = currentWaylinePostions[currentWaypointIndex]
|
|
if (!nextPoint) {
|
aircraftEntity.label = {}
|
return
|
}
|
|
const devicePosition = Cesium.Cartesian3.fromDegrees(
|
Number(host.longitude),
|
Number(host.latitude),
|
0,
|
)
|
|
// 距离下个点位的距离
|
let distance = Cesium.Cartesian3.distance(
|
devicePosition,
|
nextPoint,
|
)
|
|
// 本次航线平面里程
|
let totalDistance = 0
|
currentWaylinePostions.map((cartesian3, index) => {
|
// 两点之间的距离
|
let deviceCurPosition = null
|
if (index === 0) {
|
deviceCurPosition = devicePosition
|
} else {
|
deviceCurPosition = currentWaylinePostions[index - 1]
|
}
|
|
let distance = Cesium.Cartesian3.distance(
|
deviceCurPosition,
|
cartesian3,
|
)
|
totalDistance += distance
|
return Math.round(distance)
|
})
|
|
// 速度
|
let horizontalSpeed = host.horizontal_speed || 0
|
if (
|
!droneSpeedArr.includes(horizontalSpeed) &&
|
horizontalSpeed > 1
|
) {
|
droneSpeedArr.push(horizontalSpeed)
|
}
|
if (horizontalSpeed < 5) {
|
horizontalSpeed = 10
|
}
|
|
// 预计到达下一个航点时间
|
let arrivalTime = distance / horizontalSpeed
|
if (arrivalTime === Infinity || isNaN(arrivalTime)) {
|
arrivalTime = 0
|
}
|
if (arrivalTime > 60) {
|
const minute = Math.floor(arrivalTime / 60)
|
const second = Math.round(arrivalTime % 60)
|
arrivalTime = `${minute}m${second}s`
|
} else {
|
arrivalTime = Math.round(arrivalTime) + 's'
|
}
|
|
aircraftEntity.label = new Cesium.LabelGraphics({
|
text: `距离机场水平距离:${homeDistance}m\n距离下一个航点:${Math.round(distance)}m\n预计到达下一航点时间:${arrivalTime}\n本次航线平面里程:${Math.round(totalDistance)}m`,
|
font: '13px monospace',
|
showBackground: true,
|
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
pixelOffset: new Cesium.Cartesian2(0, -40),
|
show: true,
|
})
|
|
return
|
}
|
|
viewer?.entities.add({
|
id: 'aircraftGltf',
|
position,
|
label: {},
|
model: {
|
uri: aircraftGltf, // 或 .glb
|
scale: 1.0, // 缩放比例
|
minimumPixelSize: 64, // 最小像素尺寸(保证模型远处可见)
|
maximumScale: 128, // 最大缩放(可选)
|
},
|
})
|
}
|
|
const mapEntityRemove = () => {
|
viewInfoFrustum?.clear()
|
|
viewer?.entities.removeById('aircraftGltf')
|
}
|
|
const removeEntitys = () => {
|
const entitiesIDs = viewer?.entities.values.map(i => i.id)
|
|
Array.isArray(entitiesIDs) && entitiesIDs.forEach(item => {
|
item.includes('drone-job-wayline-') && viewer?.entities.removeById(item)
|
})
|
}
|
|
const removeWatchs = () => {
|
taskWatch?.()
|
flighttaskWatch?.()
|
deviceWatch?.()
|
}
|
|
const init = (v, wsInfo, taskDetails) => {
|
viewer = v
|
deviceOsdInfo = computed(() => wsInfo.value?.device_osd)
|
flighttaskProgressInfo = computed(() => wsInfo.value?.flighttask_progress)
|
|
removeWatchs()
|
|
taskWatch = watch(taskDetails,
|
() => {
|
if (taskDetails.value?.way_lines?.length) {
|
parsingFiles(taskDetails.value.way_lines[0].url)
|
}
|
},
|
{ immediate: true }
|
)
|
|
flighttaskWatch = watch(flighttaskProgressInfo, async () => {
|
const output = flighttaskProgressInfo.value?.data?.output
|
|
currentWaypointIndex = output.ext['current_waypoint_index']
|
})
|
|
deviceWatch = watch(deviceOsdInfo, () => {
|
const host = deviceOsdInfo.value?.data?.host
|
|
if (!host) return
|
|
if ([14, 0].includes(host?.mode_code)) {
|
mapEntityRemove()
|
return
|
}
|
|
setCreateFrustum(host)
|
setAircraftGltf()
|
}
|
)
|
}
|
|
onBeforeUnmount(() => {
|
mapEntityRemove()
|
removeEntitys()
|
|
removeWatchs()
|
})
|
|
return {
|
init,
|
removeEntitys,
|
mapEntityRemove,
|
}
|
}
|