import * as Cesium from 'cesium'
|
import { Decimal } from 'decimal.js'
|
import _, { cloneDeep, throttle } from 'lodash'
|
import { v4 as uuidv4 } from 'uuid'
|
|
import { render } from 'vue'
|
|
import HistoryDronePopup from '@/components/DeviceJobDetails/HistoryDronePopup.vue'
|
|
import { getNewPolygonData } from '@/views/RoutePlan/PlanarAirLine/planarRouteUtils'
|
|
import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz'
|
|
import { ArrowLineMaterialProperty, LineTrailMaterial, PolylineGlowMaterial, } from '@/utils/cesium/Material'
|
|
import CreateFrustum from '@/utils/cesium/frustum/CreateFrustum'
|
import { ElMessage } from 'element-plus'
|
|
import rwqfdImg from '@/assets/images/signMachineNest/rwqfd.png'
|
import endingOnlineImg from '@/assets/images/aiNowFly/ending-online.png'
|
import newEndPointImg from '@/assets/images/newEndPointicon.png'
|
import endPointImg from '@/assets/images/EndPointicon.png'
|
import aircraftGltf from '@/assets/gltf/aircraft.gltf'
|
import newNumPoint from '@/assets/images/newStartPoint.png'
|
|
import {
|
getPolyLine,
|
} from '@/views/RoutePlan/PointAirLine/pointWayLineUtils'
|
import store from '@/store/index'
|
|
let arrowLineMaterialProperty = new ArrowLineMaterialProperty({
|
color: new Cesium.Color(128 / 255, 215 / 255, 255 / 255, 1),
|
directionColor: new Cesium.Color(1, 1, 1, 1),
|
outlineColor: new Cesium.Color(1, 1, 1, 1),
|
outlineWidth: 0,
|
speed: 5
|
})
|
|
let runningLineMaterial = new LineTrailMaterial({
|
color: Cesium.Color.fromCssColorString('#1FFF69'),
|
opacity: 1,
|
speed: 10,
|
})
|
let runningTextColor = Cesium.Color.fromCssColorString('#1FFF69')
|
let runningTextOffset = new Cesium.Cartesian2(0, -32)
|
|
let pendingLineMaterial = new PolylineGlowMaterial({
|
color: Cesium.Color.fromCssColorString('#FFB81D'),
|
})
|
let pendingTextColor = Cesium.Color.fromCssColorString('#FFB81D')
|
let pendingTextOffset = new Cesium.Cartesian2(0, 32)
|
|
let MapPopUpBox = HistoryDronePopup
|
|
function getZoomFactor (camerasInfo, type) {
|
let zoom_factor
|
const irLevel = camerasInfo?.ir_zoom_factor
|
const zoomLevel = camerasInfo?.zoom_factor
|
if (type === 'wide') {
|
zoom_factor = 1
|
} else if (type === 'ir') {
|
zoom_factor = irLevel
|
} else {
|
zoom_factor = zoomLevel
|
}
|
zoom_factor = _.round(zoom_factor, 1)
|
|
return zoom_factor
|
}
|
|
export default class CreateRouteLine {
|
/**
|
*
|
* @param {*} options 参数
|
*/
|
constructor(options) {
|
this.type = options?.type || 'single'
|
this.isShowVideoPlan = options?.isShowVideoPlan || false
|
|
this.viewer = null
|
this.currentWaypointIndex = null
|
this.droneSpeedArr = []
|
|
this.multiNestData = []
|
|
this.detailsMapPopupData = []
|
|
this.labelBoxRenderHandler = this.labelBoxRender.bind(this)
|
this.removeLabelHandler = this.removeLabel.bind(this)
|
}
|
|
/**
|
* 初始化viewer
|
* @param {*} viewer
|
*/
|
initCreateRoute (viewer) {
|
this.viewer = viewer
|
}
|
|
/**
|
* 设置当前所在点位
|
* @param {*} data flighttaskProgressInfo 信息
|
*/
|
setCurrentWaypointIndex (data) {
|
const output = data?.output
|
const sn = data?.sn
|
|
if (output?.ext) {
|
const currentWaypointIndex = output?.ext['current_waypoint_index']
|
|
this.updataMultiNestData(sn, {
|
currentWaypointIndex
|
})
|
}
|
}
|
|
/**
|
* 请求航线文件数据并解析处理
|
* @param {*} data 包含文件url等信息
|
* @param {*} dronePosition 无人机位置
|
* @returns
|
*/
|
async parsingFiles (data, dronePosition = null, isShowDock = false, isShowPointBillboard = true) {
|
const { url, wayline_type, device_sn } = data
|
|
if (!url) return dronePosition != null ? {
|
dronePosition: [{ lng: dronePosition.longitude, lat: dronePosition.latitude, alt: dronePosition.height }]
|
} : {}
|
|
this.updataMultiNestData(device_sn)
|
|
const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`)
|
|
const templateXML = await res.fileInfoObj['wpmz/template.kml']
|
const waylinesXML = await res.fileInfoObj['wpmz/waylines.wpml']
|
|
const templateXmlJson = XMLToJSON(templateXML)?.['Document']
|
const waylinesXmlJson = XMLToJSON(waylinesXML)?.['Document']
|
|
const templateXMLObj = removeTextKey(templateXmlJson.Folder)
|
const { takeOffRefPoint } = removeTextKey(templateXmlJson.missionConfig)
|
|
const [latitude, longitude, height] = takeOffRefPoint.split(',').map(item => _.round(item, 6))
|
|
const startPoint = { latitude, longitude, height: Number.isNaN(height) ? 0 : height }
|
|
const { templateType } = templateXMLObj
|
|
const missionConfig = removeTextKey(waylinesXmlJson.missionConfig)
|
const waylinesXMLObj = removeTextKey(waylinesXmlJson.Folder)
|
|
if (templateType === "mapping3d") {
|
if (!waylinesXMLObj[0].Placemark.length) return ElMessage.error('没有航线点位')
|
} else {
|
if (!waylinesXMLObj.Placemark.length) return ElMessage.error('没有航线点位')
|
}
|
|
if ([2, 4, 5].includes(Number(wayline_type))) {
|
if (templateType === "mapping3d") {
|
let morePolygonData = waylinesXMLObj.map(i => ({
|
data: i.Placemark
|
}))
|
|
let newPolygonData = getNewPolygonData(morePolygonData)
|
|
let newPolygonDisposePositions = newPolygonData.map(i =>
|
Cesium.Cartesian3.fromDegrees(Number(i[0]), Number(i[1]))
|
)
|
|
this.viewer.entities.add({
|
name: 'work-drone-route-planar-outer-polygon',
|
|
polygon: {
|
hierarchy: new Cesium.CallbackProperty(() => {
|
return new Cesium.PolygonHierarchy(newPolygonDisposePositions)
|
}, false),
|
material: Cesium.Color.fromBytes(255, 228, 22, 44),
|
outline: false,
|
outlineWidth: 2,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
},
|
})
|
|
return this.drawPlanarRoute(
|
waylinesXMLObj[0],
|
missionConfig,
|
templateXmlJson,
|
dronePosition,
|
data,
|
startPoint,
|
isShowDock,
|
isShowPointBillboard,
|
wayline_type
|
)
|
}
|
|
return this.drawPlanarRoute(
|
waylinesXMLObj,
|
missionConfig,
|
templateXmlJson,
|
dronePosition,
|
data,
|
startPoint,
|
isShowDock,
|
isShowPointBillboard,
|
wayline_type
|
)
|
} else {
|
return this.drawPointRoute(
|
waylinesXMLObj,
|
missionConfig,
|
dronePosition,
|
data,
|
startPoint,
|
isShowDock,
|
isShowPointBillboard,
|
wayline_type
|
)
|
}
|
}
|
|
/**
|
* 绘制面状航线
|
* @param {*} lineObj 航线文件中的
|
* @param {*} missionConfig 航线文件中的
|
* @param {*} templateXmlJson 航线文件中的
|
* @param {*} dronePosition 无人机位置
|
* @param {*} data
|
* @param {*} startPoint
|
* @param {*} isShowPointBillboard 是否显示,航线起飞点,终点等标注
|
* @returns
|
*/
|
async drawPlanarRoute (lineObj, missionConfig, templateXmlJson, dronePosition, data, startPoint, isShowDock, isShowPointBillboard, wayline_type) {
|
const { positionArray, filePositions } = this.disposeData(lineObj, missionConfig, dronePosition, data, startPoint, wayline_type)
|
const { device_sn } = data
|
|
const droneTransformPosition = Cesium.Cartesian3.fromDegrees(
|
Number(dronePosition.longitude),
|
Number(dronePosition.latitude),
|
Number(dronePosition.height),
|
)
|
|
let coordArr = null
|
|
const placemark = templateXmlJson.Folder?.Placemark
|
// 取出点位
|
const coordinates =
|
placemark.Polygon?.outerBoundaryIs.LinearRing.coordinates?.[
|
'#text'
|
]?.split('\n') || []
|
|
// 数组转换
|
coordArr = coordinates.map((coordinate) =>
|
coordinate
|
.replace(/\s+/g, '')
|
.split(',')
|
.map((v) => Number(v)),
|
)
|
|
// 获取当前经纬度绝对高度
|
let newCoordArr = coordArr.map(item => ([item[0], item[1], 0]))
|
|
let planarRouteEntity = this.viewer.entities.add({
|
name: 'work-drone-route-planar-polyline',
|
|
polyline: {
|
width: 3,
|
positions: positionArray,
|
material: Cesium.Color.CHARTREUSE,
|
zIndex: 1,
|
},
|
|
customData: {
|
data
|
}
|
})
|
|
let droppointPositions = (filePositions || [])?.map(i => ({
|
longitude: Number(i.lng),
|
latitude: Number(i.lat),
|
height: Number(i.alt),
|
}));
|
|
// 落点线
|
(droppointPositions || [])?.forEach((item, index) => {
|
const topPosition = Cesium.Cartesian3.fromDegrees(
|
Number(item.longitude),
|
Number(item.latitude),
|
Number(item.height)
|
)
|
let setting = {
|
name: 'work-drone-route-planar-polyline',
|
position: topPosition,
|
polyline: getPolyLine(this.viewer, { value: droppointPositions }, index),
|
}
|
this.viewer.entities.add(setting)
|
})
|
|
// 面状航线第一个点突出展示
|
isShowPointBillboard && this.startingIncreasePoint(positionArray)
|
|
// 面状判断当前点位数量
|
const cloneCoordArr = [...newCoordArr]
|
|
if (cloneCoordArr.length >= 3) {
|
cloneCoordArr.push(newCoordArr[0])
|
}
|
|
// 绘制面状边框线--------------------
|
this.viewer.entities.add({
|
name: 'work-drone-route-planar-border',
|
|
polyline: {
|
positions: Cesium.Cartesian3.fromDegreesArrayHeights(
|
cloneCoordArr.flat(),
|
),
|
width: 4,
|
material: new Cesium.PolylineOutlineMaterialProperty({
|
color: new Cesium.Color.fromBytes(74, 138, 233),
|
outlineWidth: 2,
|
outlineColor: Cesium.Color.WHITE,
|
}),
|
zIndex: -1,
|
clampToGround: true,
|
},
|
})
|
|
// 绘制面状地块--------------------
|
this.viewer.entities.add({
|
name: 'work-drone-route-planar-polygon',
|
|
polygon: {
|
hierarchy: Cesium.Cartesian3.fromDegreesArrayHeights(
|
newCoordArr.flat(),
|
),
|
material: new Cesium.Color.fromBytes(75, 159, 221, 100),
|
outline: true,
|
outlineColor: new Cesium.Color.fromBytes(35, 85, 216, 255),
|
zIndex: -1,
|
},
|
})
|
|
if (this.type === 'clusterScheduling') {
|
this.viewer.entities.add({
|
name: 'work-drone-route-point-start',
|
position: Cesium.Cartesian3.fromDegrees(filePositions[0].lng, filePositions[0].lat, filePositions[0].alt),
|
|
billboard: {
|
image: rwqfdImg,
|
outlineWidth: 0,
|
width: 50,
|
height: 50,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
|
label: {
|
text: data.job_name || '',
|
font: 'bold 16px YouSheBiaoTiHei',
|
fillColor: Cesium.Color.WHITE,
|
pixelOffset: new Cesium.Cartesian2(0, -50),
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
outlineWidth: 2,
|
outlineColor: Cesium.Color.BLACK,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
})
|
} else {
|
// 显示机巢位置
|
if (isShowDock) {
|
// 起点
|
this.viewer.entities.add({
|
name: 'work-drone-route-point-dock',
|
|
position: droneTransformPosition,
|
|
billboard: {
|
image: endingOnlineImg,
|
width: 50,
|
height: 50,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
|
customData: {
|
data
|
}
|
})
|
|
this.viewer.entities.add({
|
name: 'work-drone-route--point-polyline',
|
position: droneTransformPosition,
|
polyline: getPolyLine(this.viewer, { value: [dronePosition] }, 0),
|
})
|
}
|
|
const startPosition = Cesium.Cartesian3.fromDegrees(
|
Number(filePositions[0].lng),
|
Number(filePositions[0].lat),
|
Number(filePositions[0].alt)
|
)
|
|
// 起点
|
isShowPointBillboard && this.viewer.entities.add({
|
name: 'work-drone-route-point-start',
|
|
position: startPosition,
|
|
billboard: {
|
image: rwqfdImg,
|
width: 50,
|
height: 50,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
|
customData: {
|
data
|
}
|
})
|
}
|
|
return {
|
entity: planarRouteEntity,
|
routeLinePositions: positionArray,
|
filePositions: dronePosition != null ? [
|
{ lng: dronePosition.longitude, lat: dronePosition.latitude, alt: dronePosition.height },
|
...filePositions
|
] : filePositions
|
}
|
}
|
|
planarBillboard (color) {
|
const billboard = document.createElement('canvas')
|
const ctx = billboard.getContext('2d')
|
const radius = 4
|
ctx.beginPath()
|
ctx.arc(radius, radius, radius, 0, 2 * Math.PI, false)
|
ctx.fillStyle = color // 设置填充颜色
|
ctx.fill()
|
return billboard
|
}
|
|
startingIncreasePoint (wayData) {
|
let positions = wayData[3]
|
|
let setting = {
|
name: 'work-drone-route-planar-start',
|
|
position: positions,
|
|
billboard: {
|
image: this.planarBillboard('#2D8CF0'),
|
pixelOffset: new Cesium.Cartesian2(146, 72),
|
zIndex: 2,
|
},
|
}
|
|
this.viewer.entities.add(setting)
|
}
|
|
/**
|
* 绘制点航线
|
* @param {*} lineObj 航线文件中的
|
* @param {*} missionConfig 航线文件中的
|
* @param {*} dronePosition 无人机位置
|
* @param {*} data 任务信息,航线地址等
|
* @param {*} startPoint
|
* @param {*} isShowDock 是否显示机巢位置
|
* @param {*} isShowPointBillboard 是否显示,航线起飞点,终点等标注
|
* @returns
|
*/
|
async drawPointRoute (lineObj, missionConfig, dronePosition, data, startPoint, isShowDock, isShowPointBillboard, wayline_type) {
|
const { positionArray, filePositions } = this.disposeData(lineObj, missionConfig, dronePosition, data, startPoint, wayline_type)
|
|
const droneTransformPosition = Cesium.Cartesian3.fromDegrees(
|
Number(dronePosition.longitude),
|
Number(dronePosition.latitude),
|
Number(dronePosition.height),
|
)
|
|
// 路径线
|
let polyline
|
|
if (this.type === 'clusterScheduling') {
|
filePositions.forEach((item, index) => {
|
let position = Cesium.Cartesian3.fromDegrees(item.lng, item.lat, item.alt)
|
|
if (index === 0) {
|
this.viewer.entities.add({
|
name: 'work-drone-route-point-start',
|
position,
|
|
billboard: {
|
image: rwqfdImg,
|
outlineWidth: 0,
|
width: 50,
|
height: 50,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
|
label: {
|
text: data.job_name || '',
|
font: 'bold 16px YouSheBiaoTiHei',
|
fillColor: data.type === 2 ? runningTextColor : pendingTextColor,
|
pixelOffset: data.type === 2 ? runningTextOffset : pendingTextOffset,
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
outlineWidth: 2,
|
outlineColor: Cesium.Color.BLACK,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
})
|
} else if (index === filePositions.length - 1) {
|
this.viewer.entities.add({
|
name: 'work-drone-route-point-end',
|
|
position,
|
|
billboard: {
|
image: newEndPointImg,
|
outlineWidth: 0,
|
width: 40,
|
height: 40,
|
scale: 1.0,
|
verticalOrigin: Cesium.VerticalOrigin.TOP, // 添加这行确保图标正确显示
|
pixelOffset: new Cesium.Cartesian2(0, -20), // 根据需要调整偏移量
|
},
|
})
|
} else {
|
this.viewer.entities.add({
|
name: 'work-drone-route-point-approach',
|
|
position,
|
|
billboard: {
|
image: newNumPoint,
|
width: 50,
|
height: 50,
|
},
|
|
label: {
|
text: `${index}`,
|
font: 'bold 14px serif',
|
fillColor: Cesium.Color.WHITE,
|
pixelOffset: new Cesium.Cartesian2(1, 0), // 根据需要调整偏移量
|
eyeOffset: new Cesium.Cartesian3(0, 0, -10), // 使标签在点的上方
|
},
|
|
offset: new Cesium.Cartesian2(10, 30),
|
})
|
}
|
})
|
|
polyline = this.viewer.entities.add({
|
name: 'work-drone-route-point-polyline',
|
|
polyline: {
|
width: 4,
|
positions: positionArray,
|
material: data.type === 2 ? runningLineMaterial : pendingLineMaterial,
|
clampToGround: false,
|
}
|
})
|
} else {
|
// 显示机巢位置
|
if (isShowDock) {
|
// 起点
|
this.viewer.entities.add({
|
name: 'work-drone-route-point-dock',
|
|
position: droneTransformPosition,
|
|
billboard: {
|
image: endingOnlineImg,
|
width: 50,
|
height: 50,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
|
customData: {
|
data
|
}
|
})
|
|
this.viewer.entities.add({
|
name: 'work-drone-route--point-polyline',
|
position: droneTransformPosition,
|
polyline: getPolyLine(this.viewer, { value: [dronePosition] }, 0),
|
})
|
}
|
|
const startPosition = Cesium.Cartesian3.fromDegrees(
|
Number(filePositions[0].lng),
|
Number(filePositions[0].lat),
|
Number(filePositions[0].alt)
|
)
|
|
// 起点
|
isShowPointBillboard && this.viewer.entities.add({
|
name: 'work-drone-route-point-start',
|
|
position: startPosition,
|
|
billboard: {
|
image: rwqfdImg,
|
width: 50,
|
height: 50,
|
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
},
|
|
customData: {
|
data
|
}
|
})
|
|
// 终点
|
isShowPointBillboard && this.viewer.entities.add({
|
name: 'work-drone-route-point-end',
|
|
position: positionArray[positionArray.length - 1],
|
|
billboard: {
|
image: new Cesium.ConstantProperty(endPointImg),
|
width: 30,
|
height: 30,
|
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 底部对齐
|
},
|
})
|
|
polyline = this.viewer.entities.add({
|
name: 'work-drone-route-point-polyline',
|
|
polyline: {
|
width: 4,
|
positions: positionArray,
|
material: arrowLineMaterialProperty,
|
clampToGround: false,
|
},
|
|
customData: {
|
data
|
}
|
})
|
}
|
|
let droppointPositions = (filePositions || [])?.map(i => ({
|
longitude: Number(i.lng),
|
latitude: Number(i.lat),
|
height: Number(i.alt),
|
}));
|
|
// 落点线
|
(droppointPositions || [])?.forEach((item, index) => {
|
const topPosition = Cesium.Cartesian3.fromDegrees(
|
Number(item.longitude),
|
Number(item.latitude),
|
Number(item.height)
|
)
|
|
let setting = {
|
name: 'work-drone-route-point-polyline',
|
position: topPosition,
|
polyline: getPolyLine(this.viewer, { value: droppointPositions }, index),
|
}
|
this.viewer.entities.add(setting)
|
})
|
|
return {
|
entity: polyline,
|
routeLinePositions: positionArray,
|
filePositions: dronePosition != null ? [
|
{ lng: dronePosition.longitude, lat: dronePosition.latitude, alt: dronePosition.height },
|
...filePositions
|
] : filePositions,
|
}
|
}
|
|
/**
|
* 通用处理数据
|
* @param {*} lineObj
|
* @param {*} missionConfig
|
* @param {*} dronePosition
|
* @param {*} startPoint
|
* @returns {} {positionArray: 带拼接点位置, filePositions:光航线点位置}
|
*/
|
disposeData (lineObj, missionConfig, dronePosition, data, startPoint, wayline_type) {
|
const { device_sn } = data
|
|
const executeHeightMode = lineObj.executeHeightMode === "WGS84"
|
|
let filePositions = lineObj.Placemark.map(item => {
|
const [lng, lat] = item.Point.coordinates.split(',')
|
const height = item.executeHeight
|
|
return {
|
lng: Number(lng),
|
lat: Number(lat),
|
alt: Number(height),
|
}
|
})
|
|
let safetyHeight
|
|
if (executeHeightMode) {
|
let startHeight = new Decimal(missionConfig.takeOffSecurityHeight)
|
.plus(dronePosition.height).toNumber()
|
|
safetyHeight = startHeight < filePositions[0].alt ? filePositions[0].alt : startHeight
|
} else {
|
safetyHeight = missionConfig.takeOffSecurityHeight < filePositions[0].alt ? filePositions[0].alt : missionConfig.takeOffSecurityHeight
|
}
|
|
let safetyPositions = []
|
|
if (dronePosition != null) {
|
safetyPositions = [
|
{
|
lng: Number(dronePosition.longitude),
|
lat: Number(dronePosition.latitude),
|
alt: Number(dronePosition.height),
|
},
|
|
{
|
lng: Number(dronePosition.longitude),
|
lat: Number(dronePosition.latitude),
|
alt: Number(safetyHeight),
|
},
|
|
{
|
lng: filePositions[0].lng,
|
lat: filePositions[0].lat,
|
alt: Number(safetyHeight),
|
},
|
]
|
}
|
|
let pointAll = [...safetyPositions, ...filePositions]
|
|
const currentRoutePositions = pointAll.map((item, index) => {
|
let height = executeHeightMode ? item.alt : item.alt + (dronePosition != null ? dronePosition.height : 0)
|
|
if (index == 0) height = item.alt
|
|
return Cesium.Cartesian3.fromDegrees(item.lng, item.lat, height)
|
})
|
|
this.updataMultiNestData(device_sn, {
|
currentRoutePositions
|
})
|
|
if ([0].includes(wayline_type)) {
|
let startHeight = executeHeightMode ? filePositions[0].alt : filePositions[0].alt + (dronePosition != null ? dronePosition.height : 0)
|
let endHeight = executeHeightMode ? filePositions[1].alt : filePositions[1].alt + (dronePosition != null ? dronePosition.height : 0)
|
|
this.updataMultiNestData(device_sn, {
|
showPopupPosition: Cesium.Cartesian3.midpoint(
|
Cesium.Cartesian3.fromDegrees(filePositions[0].lng, filePositions[0].lat, startHeight),
|
Cesium.Cartesian3.fromDegrees(filePositions[1].lng, filePositions[1].lat, endHeight),
|
new Cesium.Cartesian3())
|
})
|
} else {
|
let startHeight = executeHeightMode ? safetyPositions[1].alt : safetyPositions[1].alt + (dronePosition != null ? dronePosition.height : 0)
|
let endHeight = executeHeightMode ? safetyPositions[2].alt : safetyPositions[2].alt + (dronePosition != null ? dronePosition.height : 0)
|
|
this.updataMultiNestData(device_sn, {
|
showPopupPosition: Cesium.Cartesian3.midpoint(
|
Cesium.Cartesian3.fromDegrees(safetyPositions[1].lng, safetyPositions[1].lat, startHeight),
|
Cesium.Cartesian3.fromDegrees(safetyPositions[2].lng, safetyPositions[2].lat, endHeight),
|
new Cesium.Cartesian3())
|
})
|
}
|
|
return {
|
positionArray: currentRoutePositions,
|
filePositions: filePositions.map(item => {
|
let height = executeHeightMode ? item.alt : item.alt + (dronePosition != null ? dronePosition.height : 0)
|
|
return {
|
...item,
|
alt: Number(height)
|
}
|
})
|
}
|
}
|
|
/**
|
* 删除entity
|
*/
|
removeAllRouteEntity () {
|
const entities = this.viewer?.entities.values.filter(i => {
|
return i?.name && i?.name.includes('work-drone-route-')
|
})
|
|
Array.isArray(entities) && entities.forEach(item => {
|
this.viewer?.entities.remove(item)
|
})
|
}
|
|
// 当前无人机视椎体相关
|
setCreateFrustum (host, zoomFactor = {}, cameraParams = {}) {
|
if (!host) return
|
|
const parent_sn = host?.parent_sn
|
|
if (parent_sn) {
|
const curDroneData = this.getCurDroneData(parent_sn)
|
|
curDroneData.viewInfoFrustum?.destroyed()
|
|
const attitude_head = 180 + host?.attitude_head
|
const gimbal_pitch = 90 - Number(host?.payloads[0]?.gimbal_pitch) || 0
|
|
let fov = 60
|
|
if (
|
zoomFactor?.value?.set === true &&
|
cameraParams?.value?.set === true &&
|
curDroneData?.camera_type &&
|
['wide', 'ir', 'zoom'].includes(curDroneData?.camera_type)
|
) {
|
if (curDroneData.camera_type === 'wide') {
|
fov = 60
|
} else {
|
const diffFocal = zoomFactor.value[curDroneData.camera_type].max - getZoomFactor(host?.cameras?.[0], curDroneData.camera_type)
|
|
fov = (60 / zoomFactor.value[curDroneData.camera_type].max) * (diffFocal === 0 ? 1 : diffFocal)
|
}
|
}
|
|
this.updataMultiNestData(parent_sn, {
|
viewInfoFrustum: new CreateFrustum(this.viewer, {
|
position: {
|
longitude: host?.longitude,
|
latitude: host?.latitude,
|
altitude: host?.height,
|
},
|
width: store.state.common.liveResolution.width || 960,
|
height: store.state.common.liveResolution.height || 720,
|
fov: fov,
|
near: 0.01,
|
far: 250,
|
roll: gimbal_pitch,
|
pitch: 0,
|
heading: attitude_head,
|
|
isShowVideoPlan: this.isShowVideoPlan
|
})
|
})
|
}
|
}
|
|
setLiveStatusWs (data) {
|
const { device_sn, live_status } = data
|
|
if (device_sn && live_status) {
|
this.updataMultiNestData(device_sn, {
|
camera_type: live_status?.[0].video_type || 'wide'
|
})
|
}
|
}
|
|
removeCreateFrustum (host) {
|
const parent_sn = host?.parent_sn
|
|
if (parent_sn) {
|
const curDroneData = this.getCurDroneData(parent_sn)
|
|
curDroneData.viewInfoFrustum?.clear()
|
}
|
}
|
|
setFrustumInfoDetails (data) {
|
const {
|
dock_sn,
|
distance_to_airport,
|
distance_to_next_point,
|
estimated_time_to_next_point,
|
plane_mileage
|
} = data
|
|
if (dock_sn) {
|
const aircraftEntity = this.viewer?.entities.values.find(i => {
|
return i?.name && i?.name.includes(`aircraft-glf-${dock_sn}`)
|
})
|
|
if (aircraftEntity) {
|
// 预计到达下一个航点时间
|
let arrivalTime = estimated_time_to_next_point
|
|
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: `离机场平面距离:${distance_to_airport}m\n离下个航点平面距离:${Math.round(distance_to_next_point)}m\n到达下个航点剩余时间:${arrivalTime}\n航线总平面里程:${Math.round(plane_mileage)}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
|
}
|
|
}
|
}
|
|
removeFrustumInfoDetails (host) {
|
const parent_sn = host?.parent_sn
|
|
if (parent_sn) {
|
const aircraftEntity = this.viewer?.entities.values.find(i => {
|
return i?.name && i?.name.includes(`aircraft-glf-${parent_sn}`)
|
})
|
|
if (aircraftEntity) {
|
aircraftEntity.label.show = false
|
}
|
}
|
}
|
|
setAircraftGltf (host) {
|
const parent_sn = host?.parent_sn
|
|
if (parent_sn) {
|
const aircraftEntity = this.viewer?.entities.values.find(i => {
|
return i?.name && i?.name.includes(`aircraft-glf-${parent_sn}`)
|
})
|
|
const position = Cesium.Cartesian3.fromDegrees(host?.longitude, host?.latitude, host?.height)
|
|
if (aircraftEntity) {
|
aircraftEntity.position = new Cesium.ConstantPositionProperty(position)
|
|
return
|
}
|
|
if (parent_sn) {
|
this.viewer?.entities.add({
|
name: `aircraft-glf-${parent_sn}`,
|
position,
|
label: {},
|
model: {
|
uri: aircraftGltf, // 或 .glb
|
scale: 1.0, // 缩放比例
|
minimumPixelSize: 64, // 最小像素尺寸(保证模型远处可见)
|
maximumScale: 128, // 最大缩放(可选)
|
},
|
})
|
}
|
}
|
}
|
|
removeViewInfoFrustum () {
|
this.multiNestData.forEach(item => {
|
if ('viewInfoFrustum' in item && item.viewInfoFrustum) {
|
item.viewInfoFrustum?.clear()
|
|
delete item.viewInfoFrustum
|
}
|
})
|
}
|
|
mapEntityRemove (host) {
|
const parent_sn = host?.parent_sn
|
|
if (parent_sn) {
|
const curDroneData = this.getCurDroneData(parent_sn)
|
|
curDroneData.viewInfoFrustum?.clear()
|
|
delete curDroneData.viewInfoFrustum
|
|
const entities = this.viewer?.entities.values.filter(i => {
|
return i?.name && i?.name.includes(`aircraft-glf-${parent_sn}`)
|
})
|
|
Array.isArray(entities) && entities.forEach(item => {
|
this.viewer?.entities.remove(item)
|
})
|
}
|
}
|
|
mapEntityRemoveAll () {
|
const entities = this.viewer?.entities.values.filter(i => {
|
return i?.name && i?.name.includes(`aircraft-glf-`)
|
})
|
|
Array.isArray(entities) && entities.forEach(item => {
|
this.viewer?.entities.remove(item)
|
})
|
|
this.multiNestData.length > 0 && (this.multiNestData.forEach(item => {
|
item.viewInfoFrustum?.clear()
|
}))
|
}
|
|
/**
|
* 更新多机场数据
|
* @param {*} device_sn 机巢SN
|
* @param {*} data 机巢对应需绑定数据
|
*/
|
updataMultiNestData (device_sn, data) {
|
const isHave = this.multiNestData.find(item => item.device_sn === device_sn)
|
const isHaveInd = this.multiNestData.findIndex(item => item.device_sn === device_sn)
|
|
if (isHave) {
|
this.multiNestData[isHaveInd] = {
|
...this.multiNestData[isHaveInd],
|
|
...data
|
}
|
} else {
|
this.multiNestData.push({
|
device_sn,
|
...data
|
})
|
}
|
}
|
|
/**
|
* 根据机巢sn获取当前机巢对应的相关信息
|
* @param {*} device_sn
|
*/
|
getCurDroneData (device_sn) {
|
const isHave = this.multiNestData.find(item => item.device_sn === device_sn)
|
|
if (isHave) return this.multiNestData.find(item => item.device_sn === device_sn)
|
|
return false
|
}
|
|
showDetailMapPopup (data) {
|
const that = this
|
this.detailsMapPopupData = data.map(item => {
|
return {
|
...item,
|
show: true,
|
uuid: uuidv4()
|
}
|
})
|
this.viewer.scene.postRender.addEventListener(that.labelBoxRenderHandler)
|
}
|
|
showSingleDetailMapPopup (data) {
|
this.detailsMapPopupData.forEach(i => i.job_id === data.job_id && i.device_sn === data.device_sn && (i.show = true))
|
}
|
|
getLabelDom (data) {
|
const that = this
|
const vNode = h(MapPopUpBox, { data, removeLabel: that.removeLabelHandler })
|
const tooltipContainer = document.createElement('div')
|
|
tooltipContainer.id = data.uuid
|
tooltipContainer.style.position = 'absolute'
|
tooltipContainer.style.transform = 'translate(-50%,10%)'
|
tooltipContainer.style.pointerEvents = 'none'
|
document.querySelector('.content-map-popups')?.append(tooltipContainer)
|
render(vNode, tooltipContainer)
|
return tooltipContainer
|
}
|
|
labelBoxRender () {
|
this.detailsMapPopupData.filter(i => i.show === true).forEach(item => {
|
const { showPopupPosition } = this.getCurDroneData(item.device_sn)
|
|
let dom = document.querySelector(`[id="${item.uuid}"]`)
|
|
if (!dom) {
|
dom = this.getLabelDom(item)
|
}
|
|
const screenPosition = this.viewer?.scene.cartesianToCanvasCoordinates(showPopupPosition)
|
if (screenPosition) {
|
dom.style.left = `${screenPosition.x}px`
|
dom.style.top = `${screenPosition.y}px`
|
dom.style.display = 'block'
|
}
|
})
|
}
|
|
// 移除弹框标签
|
removeLabel (data) {
|
const that = this
|
|
that.removeDom(data)
|
}
|
|
removeDom (data) {
|
const that = this
|
|
const dom = document.querySelector(`[id="${data.uuid}"]`)
|
|
if (dom && dom.parentNode) {
|
that.detailsMapPopupData.forEach(i => i.uuid === data.uuid && (i.show = false))
|
|
dom.parentNode.removeChild(dom)
|
}
|
}
|
|
destroyedCustomDom () {
|
const that = this
|
that.viewer?.scene.postRender.removeEventListener(that.labelBoxRenderHandler)
|
}
|
}
|