forked from drone/command-center-dashboard

罗广辉
2025-04-21 2800fa4f32f3900509cb4d6eefaf2bfaf54efdd7
src/utils/cesium/common.js
@@ -6,189 +6,200 @@
 * @FilePath: /bigScreen/src/utils/cesium/common.js
 * @Description:
 */
import * as Cesium from 'cesium';
import JsZip from 'jszip';
import _ from 'lodash';
import axios from 'axios';
import { analyzeKmzFile, XMLToJSON } from './kmz';
import { getCenterPoint, getLnglatDist, getShortestDistance } from './mapUtil';
import * as Cesium from 'cesium'
import JsZip from 'jszip'
import _ from 'lodash'
import axios from 'axios'
import { analyzeKmzFile, XMLToJSON } from './kmz'
import { getCenterPoint, getLnglatDist, getShortestDistance } from './mapUtil'
// 图斑航线计算
export const polygonRoutePlanning = (polygonList, startPostion) => {
    // 起始点位
    const { longitude, latitude } = startPostion;
    // 计算中心点
    const polygonCenterArr = polygonList.map((polygon) => {
        const newPolygon = [
            ...new Set(polygon.map((lnglat) => lnglat.join(','))),
        ];
        return {
            center: getCenterPoint(polygon),
            polygon: newPolygon.map((item) => item.split(',')),
        };
    });
    // 机场到中心点的距离排序
    const airportDistanceArr = polygonCenterArr.sort((prev, next) => {
        const prevDistance = getLnglatDist(
            longitude,
            latitude,
            prev.center.lng,
            prev.center.lat,
        );
        const nextDistance = getLnglatDist(
            longitude,
            latitude,
            next.center.lng,
            next.center.lat,
        );
        return prevDistance - nextDistance;
    });
   // 起始点位
   const { longitude, latitude } = startPostion
   // 计算中心点
   const polygonCenterArr = polygonList.map(polygon => {
      const newPolygon = [...new Set(polygon.map(lnglat => lnglat.join(',')))]
      return {
         center: getCenterPoint(polygon),
         polygon: newPolygon.map(item => item.split(',')),
      }
   })
   // 机场到中心点的距离排序
   const airportDistanceArr = polygonCenterArr.sort((prev, next) => {
      const prevDistance = getLnglatDist(longitude, latitude, prev.center.lng, prev.center.lat)
      const nextDistance = getLnglatDist(longitude, latitude, next.center.lng, next.center.lat)
      return prevDistance - nextDistance
   })
    const sortPolygon = [];
    function getFirstPolygon(arr, start) {
        const { slongitude, slatitude } = start;
        // 机场到中心点的距离排序
        const airportDistanceArr = arr.sort((prev, next) => {
            const prevDistance = getLnglatDist(
                slongitude,
                slatitude,
                prev.center.lng,
                prev.center.lat,
            );
            const nextDistance = getLnglatDist(
                slongitude,
                slatitude,
                next.center.lng,
                next.center.lat,
            );
            return prevDistance - nextDistance;
        });
        const polygon = _.cloneDeep(airportDistanceArr[0]);
        if (polygon === void 0) return;
        sortPolygon.push(polygon);
        airportDistanceArr.splice(0, 1);
        if (airportDistanceArr.length > 0) {
            getFirstPolygon(airportDistanceArr, {
                slongitude: polygon.center.lng,
                slatitude: polygon.center.lat,
            });
        }
    }
    getFirstPolygon(polygonCenterArr, {
        slongitude: longitude,
        slatitude: latitude,
    });
    // 计算图斑内点位飞行顺序
    let result = [[longitude, latitude]];
    sortPolygon.forEach((item, index) => {
        const { polygon } = item;
        // 取出当前图斑之前最后一个点
        const prevPolygon = result[result.length - 1];
        const [slng, slat] = prevPolygon;
        const nextPolygon = airportDistanceArr[index + 1];
        // 求出距离上一个点最近的点,作为第一个点
        const sequence = polygon.sort((prev, next) => {
            const [prevLng, prevLat] = prev;
            const [nextLng, nextLat] = next;
            const prevDistance = getLnglatDist(slng, slat, prevLng, prevLat);
            const nextDistance = getLnglatDist(slng, slat, nextLng, nextLat);
            return prevDistance - nextDistance;
        });
        // 第一个点位
        const firstLnglat = [...sequence[0]];
        // 去除第一个点位
        const cloneSequence = _.cloneDeep(sequence);
        cloneSequence.splice(0, 1);
        if (nextPolygon) {
            // 获取两个经纬度组两个最近的点位
            const { index: lnglatIndex } = getShortestDistance(
                cloneSequence,
                nextPolygon.polygon,
            );
            const lastLnglat = _.cloneDeep(cloneSequence[lnglatIndex[0]]);
            // 删除飞行的最后一个点
            cloneSequence.splice(lnglatIndex[0], 1);
            const centerLnglatList = cloneSequence.sort((prev, next) => {
                const [prevLng, prevLat] = prev;
                const [nextLng, nextLat] = next;
                const prevDistance = getLnglatDist(
                    longitude,
                    latitude,
                    prevLng,
                    prevLat,
                );
                const nextDistance = getLnglatDist(
                    longitude,
                    latitude,
                    nextLng,
                    nextLat,
                );
                return prevDistance - nextDistance;
            });
            result = [...result, firstLnglat, ...centerLnglatList, lastLnglat];
        } else {
            // const last = polygon.sort((prev, next) => {
            //   const [prevLng, prevLat] = prev;
            //   const [nextLng, nextLat] = next;
            //   const prevDistance = getLnglatDist(longitude, latitude, prevLng, prevLat);
            //   const nextDistance = getLnglatDist(longitude, latitude, nextLng, nextLat);
            //   return prevDistance - nextDistance;
            // });
            result = [...result, ...sequence];
            // result = [...result, ...last]
        }
    });
    return result;
};
   const sortPolygon = []
   function getFirstPolygon(arr, start) {
      const { slongitude, slatitude } = start
      // 机场到中心点的距离排序
      const airportDistanceArr = arr.sort((prev, next) => {
         const prevDistance = getLnglatDist(slongitude, slatitude, prev.center.lng, prev.center.lat)
         const nextDistance = getLnglatDist(slongitude, slatitude, next.center.lng, next.center.lat)
         return prevDistance - nextDistance
      })
      const polygon = _.cloneDeep(airportDistanceArr[0])
      if (polygon === void 0) return
      sortPolygon.push(polygon)
      airportDistanceArr.splice(0, 1)
      if (airportDistanceArr.length > 0) {
         getFirstPolygon(airportDistanceArr, {
            slongitude: polygon.center.lng,
            slatitude: polygon.center.lat,
         })
      }
   }
   getFirstPolygon(polygonCenterArr, {
      slongitude: longitude,
      slatitude: latitude,
   })
   // 计算图斑内点位飞行顺序
   let result = [[longitude, latitude]]
   sortPolygon.forEach((item, index) => {
      const { polygon } = item
      // 取出当前图斑之前最后一个点
      const prevPolygon = result[result.length - 1]
      const [slng, slat] = prevPolygon
      const nextPolygon = airportDistanceArr[index + 1]
      // 求出距离上一个点最近的点,作为第一个点
      const sequence = polygon.sort((prev, next) => {
         const [prevLng, prevLat] = prev
         const [nextLng, nextLat] = next
         const prevDistance = getLnglatDist(slng, slat, prevLng, prevLat)
         const nextDistance = getLnglatDist(slng, slat, nextLng, nextLat)
         return prevDistance - nextDistance
      })
      // 第一个点位
      const firstLnglat = [...sequence[0]]
      // 去除第一个点位
      const cloneSequence = _.cloneDeep(sequence)
      cloneSequence.splice(0, 1)
      if (nextPolygon) {
         // 获取两个经纬度组两个最近的点位
         const { index: lnglatIndex } = getShortestDistance(cloneSequence, nextPolygon.polygon)
         const lastLnglat = _.cloneDeep(cloneSequence[lnglatIndex[0]])
         // 删除飞行的最后一个点
         cloneSequence.splice(lnglatIndex[0], 1)
         const centerLnglatList = cloneSequence.sort((prev, next) => {
            const [prevLng, prevLat] = prev
            const [nextLng, nextLat] = next
            const prevDistance = getLnglatDist(longitude, latitude, prevLng, prevLat)
            const nextDistance = getLnglatDist(longitude, latitude, nextLng, nextLat)
            return prevDistance - nextDistance
         })
         result = [...result, firstLnglat, ...centerLnglatList, lastLnglat]
      } else {
         // const last = polygon.sort((prev, next) => {
         //   const [prevLng, prevLat] = prev;
         //   const [nextLng, nextLat] = next;
         //   const prevDistance = getLnglatDist(longitude, latitude, prevLng, prevLat);
         //   const nextDistance = getLnglatDist(longitude, latitude, nextLng, nextLat);
         //   return prevDistance - nextDistance;
         // });
         result = [...result, ...sequence]
         // result = [...result, ...last]
      }
   })
   return result
}
export const getWaylineFilePoints = async (fileUrl) => {
    const fileRes = await analyzeKmzFile(fileUrl);
    const waylineContent = await fileRes['fileInfoObj']?.['wpmz/waylines.wpml'];
    const xml = XMLToJSON(waylineContent);
    const placemarkArr = xml?.Document?.Folder.Placemark;
    const points = placemarkArr.map((placemark) => {
        const lnglat = placemark.Point.coordinates?.['#text'].split(',');
        return {
            longitude: lnglat[0],
            latitude: lnglat[1],
        };
    });
    return points;
};
export const getWaylineFilePoints = async fileUrl => {
   const fileRes = await analyzeKmzFile(fileUrl)
   const waylineContent = await fileRes['fileInfoObj']?.['wpmz/waylines.wpml']
   const xml = XMLToJSON(waylineContent)
   const placemarkArr = xml?.Document?.Folder.Placemark
   const points = placemarkArr.map(placemark => {
      const lnglat = placemark.Point.coordinates?.['#text'].split(',')
      return {
         longitude: lnglat[0],
         latitude: lnglat[1],
      }
   })
   return points
}
// 传入方向,计算移动点位经纬度
export function movePosition(lon, lat, heading, direction) {
    // 计算朝向角度的弧度值(Cesium 是基于地理坐标系,heading=0 指向正北)
    const headingRad = Cesium.Math.toRadians(heading);
    const moveStep = 0.00005; // 移动步长
    let newLon = lon;
    let newLat = lat;
   // 计算朝向角度的弧度值(Cesium 是基于地理坐标系,heading=0 指向正北)
   const headingRad = Cesium.Math.toRadians(heading)
   const moveStep = 0.00005 // 移动步长
   let newLon = lon
   let newLat = lat
    switch (direction) {
        case "W": // 向前(heading 方向)
            newLon += moveStep * Math.sin(headingRad);
            newLat += moveStep * Math.cos(headingRad);
            break;
   switch (direction) {
      case 'W': // 向前(heading 方向)
         newLon += moveStep * Math.sin(headingRad)
         newLat += moveStep * Math.cos(headingRad)
         break
        case "S": // 向后(反方向)
            newLon -= moveStep * Math.sin(headingRad);
            newLat -= moveStep * Math.cos(headingRad);
            break;
      case 'S': // 向后(反方向)
         newLon -= moveStep * Math.sin(headingRad)
         newLat -= moveStep * Math.cos(headingRad)
         break
        case "D": // 向右(heading + 90°)
            newLon += moveStep * Math.cos(headingRad);
            newLat -= moveStep * Math.sin(headingRad);
            break;
      case 'D': // 向右(heading + 90°)
         newLon += moveStep * Math.cos(headingRad)
         newLat -= moveStep * Math.sin(headingRad)
         break
        case "A": // 向左(heading - 90°)
            newLon -= moveStep * Math.cos(headingRad);
            newLat += moveStep * Math.sin(headingRad);
            break;
      case 'A': // 向左(heading - 90°)
         newLon -= moveStep * Math.cos(headingRad)
         newLat += moveStep * Math.sin(headingRad)
         break
        default:
            console.warn("无效方向");
            return null;
    }
      default:
         console.warn('无效方向')
         return null
   }
    return { longitude: newLon, latitude: newLat };
   return { longitude: newLon, latitude: newLat }
}
/**
 * 添加蓝色滤镜
 * @param options
 * @param viewer
 * @param layer
 */
export const addBlueFilter = (options, viewer, layer) => {
   if (layer){
      layer.brightness = 0.6    // 亮度(默认值)
      layer.contrast = 1.8     // 对比度(负值降低对比度)
      layer.hue = 1           // 色相(弧度值,3.0可能导致紫色)
      layer.saturation = 0    // 增加饱和度强化蓝色
      layer.gamma = 0.3         // 伽马校正(小于1.0使颜色更鲜艳)
   }
   const { bInvertColor, bFilterColor, filterColor } = options
   const color = new Cesium.Color.fromCssColorString(filterColor)
   const filterRGB = [
      Math.round(color.red * 255),
      Math.round(color.green * 255),
      Math.round(color.blue * 255)
   ]
   let fragShader = viewer.scene.globe._surfaceShaderSet.baseFragmentShaderSource.sources
   for (let i = 0; i < fragShader.length; i++) {
      const strS = 'color = czm_saturation(color, textureSaturation);\n#endif\n'
      let strT = 'color = czm_saturation(color, textureSaturation);\n#endif\n'
      if (bInvertColor) {
         strT += `
          color.r = 1.0 - color.r;
          color.g = 1.0 - color.g;
          color.b = 1.0 - color.b;
        `
      }
      if (bFilterColor) {
         strT += `
          color.r = color.r * ${filterRGB[0]}.0/255.0;
          color.g = color.g * ${filterRGB[1]}.0/255.0;
          color.b = color.b * ${filterRGB[2]}.0/255.0;
        `
      }
      fragShader[i] = fragShader[i].replace(strS, strT)
   }
}