forked from drone/command-center-dashboard

chenyao
2025-04-21 a7729ab954c949489fd6888fdecdd361d617c39e
src/hooks/useTaskWayline/useTaskWayline.js
@@ -2,11 +2,11 @@
 * @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'
@@ -18,9 +18,24 @@
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 => {
@@ -29,20 +44,23 @@
    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,
@@ -51,9 +69,9 @@
    })
    // 终点
    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,
@@ -63,11 +81,11 @@
    })
    // 路径线
    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,
@@ -77,27 +95,209 @@
        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,
  }
}
}