/* * @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, } }