| | |
| | | * @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) |
| | | } |
| | | } |
| | | |