| | |
| | | * @Author: shuishen 1109946754@qq.com |
| | | * @Date: 2025-04-19 14:24:34 |
| | | * @LastEditors: shuishen 1109946754@qq.com |
| | | * @LastEditTime: 2025-04-19 15:23:57 |
| | | * @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. |
| | | * @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 * 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 (viewer, taskDetails) { |
| | | const newViewer = unref(viewer) |
| | | 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 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, newViewer) |
| | | // const allPoint = waylinesXMLObj.Placemark.map(item => item.Point.coordinates.split(',')) |
| | | // flyVisual(allPoint, viewer) |
| | | drawWayline(waylinesXMLObj) |
| | | } |
| | | |
| | | const drawWayline = lineObj => { |
| | | const positions = lineObj.Placemark.map(item => { |
| | | currentWaylinePostions = lineObj.Placemark.map(item => { |
| | | const [lon, lat] = item.Point.coordinates.split(',') |
| | | return Cartesian3.fromDegrees(Number(lon), Number(lat)) |
| | | }) |
| | | |
| | | removeEntitys() |
| | | |
| | | // 起点 |
| | | newViewer.entities.add({ |
| | | viewer.entities.add({ |
| | | id: 'drone-job-wayline-start', |
| | | position: positions[0], |
| | | position: currentWaylinePostions[0], |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(rwqfdImg), |
| | | width: 70, |
| | |
| | | }) |
| | | |
| | | // 终点 |
| | | newViewer.entities.add({ |
| | | viewer.entities.add({ |
| | | id: 'drone-job-wayline-end', |
| | | position: positions[positions.length - 1], |
| | | position: currentWaylinePostions[currentWaylinePostions.length - 1], |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(endPointImg), |
| | | width: 30, |
| | |
| | | }) |
| | | |
| | | // 路径线 |
| | | newViewer.entities.add({ |
| | | let polylineEntity = viewer.entities.add({ |
| | | id: 'drone-job-wayline-polyline', |
| | | polyline: { |
| | | width: 4, |
| | | positions: positions, |
| | | positions: currentWaylinePostions, |
| | | material: new ImageTrailMaterial({ |
| | | color: { alpha: 1, blue: 1, green: 1, red: 1 }, |
| | | speed: 20, |
| | |
| | | clampToGround: false, |
| | | }, |
| | | }) |
| | | } |
| | | |
| | | watch(taskDetails, () => { |
| | | if (taskDetails.value?.way_lines?.length) { |
| | | parsingFiles(taskDetails.value.way_lines[0].url) |
| | | } |
| | | }, { immediate: true }) |
| | | |
| | | const removeEntitys = () => { |
| | | const entitiesIDs = newViewer?.entities.values.map(i => i.id) |
| | | |
| | | entitiesIDs.forEach(item => { |
| | | item.includes('drone-job-wayline-') && newViewer?.entities.removeById(item) |
| | | 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 { |
| | | removeEntitys |
| | | init, |
| | | removeEntitys, |
| | | mapEntityRemove, |
| | | } |
| | | } |
| | | } |