From 3a3cbd22dac6945039ba44e4ca14b1adaaaaa7ed Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Wed, 07 Jan 2026 11:04:45 +0800
Subject: [PATCH] feat:反无大屏基建
---
applications/drone-command/src/utils/cesium/createRouteLine.js | 923 +++++++++++++++++++++++++++++++++++---------------------
1 files changed, 572 insertions(+), 351 deletions(-)
diff --git a/applications/drone-command/src/utils/cesium/createRouteLine.js b/applications/drone-command/src/utils/cesium/createRouteLine.js
index 2c8195e..6ec1c1f 100644
--- a/applications/drone-command/src/utils/cesium/createRouteLine.js
+++ b/applications/drone-command/src/utils/cesium/createRouteLine.js
@@ -2,17 +2,16 @@
import { Decimal } from 'decimal.js'
import _, { cloneDeep, throttle } from 'lodash'
import { v4 as uuidv4 } from 'uuid'
-
import { render } from 'vue'
-
+import { analysisPointLineKmz, handlePointListForKmz } from '@/views/newRoutePlan/Waypoint/pointWayLineUtils'
import HistoryDronePopup from '@/components/DeviceJobDetails/HistoryDronePopup.vue'
-import { getNewPolygonData } from '@/views/RoutePlan/PlanarAirLine/planarRouteUtils'
+import {
+ getNewPolygonData,
+} from '@/views/newRoutePlan/routeUtils'
import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz'
-
-import { ArrowLineMaterialProperty, LineTrailMaterial, PolylineGlowMaterial, } from '@/utils/cesium/Material'
-
+import { ArrowLineMaterialProperty, LineTrailMaterial, PolylineGlowMaterial } from '@/utils/cesium/Material'
import CreateFrustum from '@/utils/cesium/frustum/CreateFrustum'
import { ElMessage } from 'element-plus'
@@ -23,61 +22,21 @@
import aircraftGltf from '@/assets/gltf/aircraft.gltf'
import newNumPoint from '@/assets/images/newStartPoint.png'
-import {
- getPolyLine,
-} from '@/views/RoutePlan/PointAirLine/pointWayLineUtils'
+import { getPolyLine } from '@/views/newRoutePlan/Waypoint/pointWayLineUtils'
import store from '@/store/index'
+import newStartPoint from '@/assets/images/newStartPoint.png'
+import newStartPointMore from '@/assets/images/newStartPointMore.png'
+import {
+ arrowLineMaterialProperty, arrowLineMaterialPropertyGray, arrowLineMaterialPropertyGrayT,
+ arrowLineMaterialPropertyGreen,
+ arrowLineMaterialPropertyOrange,
+} from '@/hooks/useMorePointLine/useMorePointLine'
-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 arrowLineMaterialPropertyOrange = new ArrowLineMaterialProperty({
- color: new Cesium.Color(255 / 255, 185 / 255, 58 / 255, 1),
- directionColor: new Cesium.Color(1, 1, 1, 1),
- outlineColor: new Cesium.Color(1, 1, 1, 1),
- outlineWidth: 0,
- speed: 5,
-})
-
-let arrowLineMaterialPropertyGreen = new ArrowLineMaterialProperty({
- color: new Cesium.Color(6 / 255, 217 / 255, 87 / 255, 1),
- directionColor: new Cesium.Color(1, 1, 1, 1),
- outlineColor: new Cesium.Color(1, 1, 1, 1),
- outlineWidth: 0,
- speed: 5,
-})
-
-// 记录index
-let indexLog = 0
-// 颜色
-function getLineColor(lineNumber) {
- // 颜色顺序: 蓝(0), 黄(1), 绿(2)
- const colors = [arrowLineMaterialProperty, arrowLineMaterialPropertyOrange, arrowLineMaterialPropertyGreen]
- // 计算颜色索引 (从0开始)
- const colorIndex = (lineNumber - 1) % 3
- // 返回对应颜色
- return colors[colorIndex]
-}
-
-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) {
@@ -95,10 +54,108 @@
return zoom_factor
}
+// 记录index
+let indexLog = 0
+// 颜色
+function getPendingExecutionLineColor (lineNumber) {
+ // 颜色顺序: 蓝(灰), 更灰
+ const colors = [arrowLineMaterialPropertyGray, arrowLineMaterialPropertyGrayT]
+ // 计算颜色索引 (从0开始)
+ const colorIndex = (lineNumber - 1) % 2
+ // 返回对应颜色
+ return colors[colorIndex]
+}
+
+function getLineColor (lineNumber) {
+ // 颜色顺序: 蓝(0), 黄(1), 绿(2)
+ const colors = [arrowLineMaterialProperty, arrowLineMaterialPropertyOrange, arrowLineMaterialPropertyGreen]
+ // 计算颜色索引 (从0开始)
+ const colorIndex = (lineNumber - 1) % 3
+ // 返回对应颜色
+ return colors[colorIndex]
+}
+
+function getBase64Image (imgUrl) {
+ const img = new Image()
+ const canvas = document.createElement('canvas')
+ const ctx = canvas.getContext('2d')
+
+ return new Promise(resolve => {
+ img.onload = function () {
+ canvas.width = img.width
+ canvas.height = img.height
+ ctx.drawImage(img, 0, 0)
+ const base64 = canvas.toDataURL('image/png')
+ resolve(base64)
+ }
+ img.src = imgUrl
+ })
+}
+async function createCombinedSVG (index, billboardImageUrl) {
+ const base64Image = await getBase64Image(billboardImageUrl)
+ const svg = `
+ <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
+ <image href="${base64Image}" x="10" y="10" width="80" height="80"/>
+ <text x="50" y="54" font-size="26" fill="white" text-anchor="middle" dominant-baseline="middle">
+ ${index + 1}
+ </text>
+ </svg>
+ `
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
+}
+
+function findHeightByCoordinates (data, targetLng, targetLat) {
+ // 展平二维数组,然后查找第一个匹配的点
+ const allPoints = data.flat()
+ const point = allPoints.find(point =>
+ point.longitude === targetLng && point.latitude === targetLat
+ )
+
+ return point ? point.height : null
+}
+
+function renderingMachineNest (options) {
+ const { viewer, dockTransformPosition, dockPosition, data } = options
+ viewer.entities.add({
+ name: 'work-drone-route-point-dock',
+ position: dockTransformPosition,
+ billboard: {
+ image: endingOnlineImg,
+ width: 50,
+ height: 50,
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
+ },
+ customData: {
+ data,
+ },
+ })
+ viewer.entities.add({
+ name: 'work-drone-route--point-polyline',
+ position: dockTransformPosition,
+ polyline: getPolyLine(viewer, { value: [dockPosition] }, 0),
+ })
+}
+
+function renderingStartingPoint (options) {
+ const { viewer, startPosition, data } = options
+ viewer.entities.add({
+ name: 'work-drone-route-point-start',
+ position: startPosition,
+ billboard: {
+ image: rwqfdImg,
+ width: 50,
+ height: 50,
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
+ },
+ customData: {
+ data,
+ },
+ })
+}
export default class CreateRouteLine {
/**
- *
+ *
* @param {*} options 参数
*/
constructor(options) {
@@ -119,10 +176,9 @@
/**
* 初始化viewer
- * @param {*} viewer
+ * @param {*} viewer
*/
initCreateRoute (viewer) {
- indexLog = 0
this.viewer = viewer
}
@@ -138,24 +194,27 @@
const currentWaypointIndex = output?.ext['current_waypoint_index']
this.updataMultiNestData(sn, {
- currentWaypointIndex
+ currentWaypointIndex,
})
}
}
/**
- * 请求航线文件数据并解析处理
+ * 请求航线文件数据并绘制解析处理
* @param {*} data 包含文件url等信息
- * @param {*} dronePosition 无人机位置
- * @returns
+ * @param {*} dockPosition 无人机位置
+ * @returns
*/
- async parsingFiles (data, dronePosition = null, isShowDock = false, isShowPointBillboard = true) {
+ async parsingFiles (data, dockPosition = null, isShowDock = false, isShowPointBillboard = true) {
+ console.log(data,'888')
const { url, wayline_type, device_sn } = data
-
- if (!url) return dronePosition != null ? {
- dronePosition: [{ lng: dronePosition.longitude, lat: dronePosition.latitude, alt: dronePosition.height }]
- } : {}
-
+ indexLog = 0
+ if (!url)
+ return dockPosition != null
+ ? {
+ dronePosition: [{ lng: dockPosition.longitude, lat: dockPosition.latitude, alt: dockPosition.height }],
+ }
+ : {}
this.updataMultiNestData(device_sn)
const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`)
@@ -178,16 +237,16 @@
const missionConfig = removeTextKey(waylinesXmlJson.missionConfig)
const waylinesXMLObj = removeTextKey(waylinesXmlJson.Folder)
- if (templateType === "mapping3d") {
+ if (templateType === 'mapping3d') {
if (!waylinesXMLObj[0].Placemark.length) return ElMessage.error('没有航线点位')
} else {
if (!waylinesXMLObj.Placemark.length) return ElMessage.error('没有航线点位')
}
- if ([2, 4, 5, 6, 7, 10].includes(Number(wayline_type))) {
- if (templateType === "mapping3d") {
+ if ([2, 4, 5, 7, 10].includes(Number(wayline_type))) {
+ if (templateType === 'mapping3d') {
let morePolygonData = waylinesXMLObj.map(i => ({
- data: i.Placemark
+ data: i.Placemark,
}))
let newPolygonData = getNewPolygonData(morePolygonData)
@@ -214,7 +273,7 @@
waylinesXMLObj[0],
missionConfig,
templateXmlJson,
- dronePosition,
+ dockPosition,
data,
startPoint,
isShowDock,
@@ -227,7 +286,7 @@
waylinesXMLObj,
missionConfig,
templateXmlJson,
- dronePosition,
+ dockPosition,
data,
startPoint,
isShowDock,
@@ -238,7 +297,7 @@
return this.drawPointRoute(
waylinesXMLObj,
missionConfig,
- dronePosition,
+ dockPosition,
data,
startPoint,
isShowDock,
@@ -248,50 +307,231 @@
}
}
+ // 拆分航线
+ async splitWayLine (data, dronePosition = null, isShowDock = false, isShowPointBillboard = true) {
+ const {
+ pointPlacemark,
+ polygonList,
+ pointList,
+ templateType,
+ startPoint,
+ execute_height_mode,
+ auto_flight_speed,
+ take_off_security_height,
+ buffer_distance_meters,
+ missionConfig,
+ waylinesXMLObjR,
+ } = await analysisPointLineKmz(`${data.domain_url}${data.object_key}`)
+ const { positionArray, filePositions } = this.disposeData(
+ waylinesXMLObjR,
+ missionConfig,
+ null,
+ data,
+ startPoint,
+ 0
+ )
+ let bigPointList = handlePointListForKmz({
+ placemark: pointPlacemark,
+ startPoint: startPoint,
+ execute_height_mode: execute_height_mode,
+ auto_flight_speed: auto_flight_speed,
+ })
+ // 路径线
+ let entityConfig
+ bigPointList.shift()
+ let flyPositions = bigPointList.map(i => [Number(i.longitude), Number(i.latitude), Number(i.height)])
+ // 渲染多个点
+ let firstTopPosition = null
+ let resultPosotions = []
+ await Promise.all(data.wayline_file_list.map(async (item, index) => {
+ // 小航线渲染线
+ const kmzUrl = import.meta.env.VITE_APP_AIRLINE_URL + item.object_key
+ const { pointList } = await analysisPointLineKmz(kmzUrl)
+ resultPosotions.push(pointList)
+ })).then(res => {
+ // 目的是区分大航线点属于哪条小航线
+ bigPointList.forEach(bigObj => {
+ let foundIndex = -1
+ // 遍历 resultPositions 查找匹配项
+ resultPosotions.some((subArray, subIndex) => {
+ const found = subArray.some(obj =>
+ obj.latitude === bigObj.latitude &&
+ obj.longitude === bigObj.longitude
+ )
+ if (found) {
+ foundIndex = subIndex
+ return true // 找到就停止搜索
+ }
+ return false
+ })
+ // 如果找到了,给 bigPointList 的对象添加标记
+ if (foundIndex !== -1) {
+ bigObj.log = foundIndex // 或 bigObj.index = foundIndex
+ }
+ })
+ console.log(bigPointList, '查看结果值') // 现在 bigPointList 会有 log 属性
+ bigPointList.map(async (i, index) => {
+ firstTopPosition = i
+ const position = Cesium.Cartesian3.fromDegrees(Number(i.longitude), Number(i.latitude), Number(findHeightByCoordinates(resultPosotions, i.longitude, i.latitude)))
+ const combinedImage = await createCombinedSVG(index, i.log % 2 ? newStartPoint : newStartPointMore)
+
+ entityConfig = {
+ name: 'work-drone-route-point-split',
+ position: position,
+ billboard: {
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
+ image: combinedImage,
+ width: 50,
+ height: 50,
+ verticalOrigin: Cesium.VerticalOrigin.CENTER,
+ horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
+ }
+ }
+
+ // 只在第一个点添加 label
+ if (index === 0) {
+ entityConfig.label = {
+ text: data.task_name || '',
+ font: 'bold 16px sans-serif',
+ fillColor: data.status === 2 ? runningTextColor : pendingTextColor,
+ pixelOffset: data.status === 2 ? runningTextOffset : pendingTextOffset,
+ style: Cesium.LabelStyle.FILL_AND_OUTLINE,
+ outlineWidth: 2,
+ outlineColor: Cesium.Color.BLACK,
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
+ }
+ }
+
+ this.viewer.entities.add(entityConfig)
+ })
+ })
+
+ // 渲染航线
+ data.wayline_file_list.map(async (item, index) => {
+ // 小航线渲染线
+ const kmzUrl = import.meta.env.VITE_APP_AIRLINE_URL + item.object_key
+ const { pointList } = await analysisPointLineKmz(kmzUrl)
+ // if (curRouteLineData.value.droneData && splitLines.length === 1) {
+ // // 把pointList的第一个点替换为无人机位置
+ // pointList[0] = curRouteLineData.value.droneData[0]
+ // }
+ if (take_off_security_height + pointList[0].height > firstTopPosition.height) {
+ // 安全高度+机巢高度 > 第一个点高度
+ const positionTest = {
+ longitude: pointList[0].longitude,
+ latitude: pointList[0].latitude,
+ height: take_off_security_height + pointList[0].height,
+ }
+
+ const positionTest1 = {
+ longitude: pointList[1].longitude,
+ latitude: pointList[1].latitude,
+ height: take_off_security_height + pointList[0].height,
+ }
+ pointList.splice(1, 0, positionTest)
+ // 往数组中插入元素
+ pointList.splice(2, 0, positionTest1)
+ // console.log(pointList, 'pointList')
+ } else if (take_off_security_height + pointList[0].height < firstTopPosition.height) {
+ const positionTest = {
+ longitude: pointList[0].longitude,
+ latitude: pointList[0].latitude,
+ height: firstTopPosition.height,
+ }
+ pointList.splice(1, 0, positionTest)
+ }
+ const routePositions = pointList.map(i =>
+ Cesium.Cartesian3.fromDegrees(Number(i.longitude), Number(i.latitude), Number(i.height))
+ )
+
+ this.viewer.entities.add({
+ name: 'work-drone-route-line-split',
+ polyline: {
+ width: 4,
+ positions: routePositions,
+ material: data.status === 1 ? arrowLineMaterialPropertyGray : getLineColor(index + 1),
+ clampToGround: false,
+ },
+ })
+ })
+ // 落点线
+ ; (bigPointList || [])?.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-split',
+ position: topPosition,
+ polyline: getPolyLine(this.viewer, { value: bigPointList }, index),
+ }
+ this.viewer.entities.add(setting)
+ })
+ return {
+ entity: entityConfig,
+ routeLinePositions: positionArray,
+ filePositions:
+ dronePosition != null
+ ? [{ lng: dronePosition.longitude, lat: dronePosition.latitude, alt: dronePosition.height }, ...filePositions]
+ : filePositions,
+ }
+ }
+
/**
* 绘制面状航线
* @param {*} lineObj 航线文件中的
* @param {*} missionConfig 航线文件中的
* @param {*} templateXmlJson 航线文件中的
- * @param {*} dronePosition 无人机位置
- * @param {*} data
- * @param {*} startPoint
- * @param {*} isShowPointBillboard 是否显示,航线起飞点,终点等标注
- * @returns
+ * @param {*} dockPosition 无人机位置
+ * @param {*} data
+ * @param {*} startPoint
+ * @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)
+ async drawPlanarRoute (
+ lineObj,
+ missionConfig,
+ templateXmlJson,
+ dockPosition,
+ data,
+ startPoint,
+ isShowDock,
+ isShowPointBillboard,
+ wayline_type
+ ) {
+ const { positionArray, filePositions } = this.disposeData(
+ lineObj,
+ missionConfig,
+ dockPosition,
+ data,
+ startPoint,
+ wayline_type
+ )
const { device_sn } = data
- const droneTransformPosition = Cesium.Cartesian3.fromDegrees(
- Number(dronePosition.longitude),
- Number(dronePosition.latitude),
- Number(dronePosition.height),
+ const dockTransformPosition = Cesium.Cartesian3.fromDegrees(
+ Number(dockPosition.longitude),
+ Number(dockPosition.latitude),
+ Number(dockPosition.height)
)
let coordArr = null
const placemark = templateXmlJson.Folder?.Placemark
// 取出点位
- const coordinates =
- placemark.Polygon?.outerBoundaryIs.LinearRing.coordinates?.[
- '#text'
- ]?.split('\n') || []
-
+ const coordinates = placemark.Polygon?.outerBoundaryIs.LinearRing.coordinates?.['#text']?.split('\n') || []
// 数组转换
- coordArr = coordinates.map((coordinate) =>
+ coordArr = coordinates.map(coordinate =>
coordinate
.replace(/\s+/g, '')
.split(',')
- .map((v) => Number(v)),
+ .map(v => Number(v))
)
// 获取当前经纬度绝对高度
- let newCoordArr = coordArr.map(item => ([item[0], item[1], 0]))
-
+ 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,
@@ -300,30 +540,30 @@
},
customData: {
- data
- }
+ 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)
- })
+ // 落点线
+ ; (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)
@@ -340,9 +580,7 @@
name: 'work-drone-route-planar-border',
polyline: {
- positions: Cesium.Cartesian3.fromDegreesArrayHeights(
- cloneCoordArr.flat(),
- ),
+ positions: Cesium.Cartesian3.fromDegreesArrayHeights(cloneCoordArr.flat()),
width: 4,
material: new Cesium.PolylineOutlineMaterialProperty({
color: new Cesium.Color.fromBytes(74, 138, 233),
@@ -357,11 +595,8 @@
// 绘制面状地块--------------------
this.viewer.entities.add({
name: 'work-drone-route-planar-polygon',
-
polygon: {
- hierarchy: Cesium.Cartesian3.fromDegreesArrayHeights(
- newCoordArr.flat(),
- ),
+ 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),
@@ -384,7 +619,7 @@
label: {
text: data.job_name || '',
- font: 'bold 16px YouSheBiaoTiHei',
+ font: 'bold 16px sans-serif',
fillColor: Cesium.Color.WHITE,
pixelOffset: new Cesium.Cartesian2(0, -50),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
@@ -395,64 +630,31 @@
})
} 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)
- )
-
+ isShowDock && renderingMachineNest({
+ viewer: this.viewer,
+ dockTransformPosition,
+ dockPosition,
+ data
+ })
// 起点
- 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 && renderingStartingPoint({
+ viewer: this.viewer,
+ startPosition: Cesium.Cartesian3.fromDegrees(
+ Number(filePositions[0].lng),
+ Number(filePositions[0].lat),
+ Number(filePositions[0].alt)
+ ),
+ data
})
}
return {
entity: planarRouteEntity,
routeLinePositions: positionArray,
- filePositions: dronePosition != null ? [
- { lng: dronePosition.longitude, lat: dronePosition.latitude, alt: dronePosition.height },
- ...filePositions
- ] : filePositions
+ filePositions:
+ dockPosition != null
+ ? [{ lng: dockPosition.longitude, lat: dockPosition.latitude, alt: dockPosition.height }, ...filePositions]
+ : filePositions,
}
}
@@ -472,9 +674,7 @@
let setting = {
name: 'work-drone-route-planar-start',
-
position: positions,
-
billboard: {
image: this.planarBillboard('#2D8CF0'),
pixelOffset: new Cesium.Cartesian2(146, 72),
@@ -489,35 +689,48 @@
* 绘制点航线
* @param {*} lineObj 航线文件中的
* @param {*} missionConfig 航线文件中的
- * @param {*} dronePosition 无人机位置
+ * @param {*} dockPosition 无人机位置
* @param {*} data 任务信息,航线地址等
- * @param {*} startPoint
+ * @param {*} startPoint
* @param {*} isShowDock 是否显示机巢位置
- * @param {*} isShowPointBillboard 是否显示,航线起飞点,终点等标注
- * @returns
+ * @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),
+ async drawPointRoute (
+ lineObj,
+ missionConfig,
+ dockPosition,
+ data,
+ startPoint,
+ isShowDock,
+ isShowPointBillboard,
+ wayline_type
+ ) {
+ const { positionArray, filePositions } = this.disposeData(
+ lineObj,
+ missionConfig,
+ dockPosition,
+ data,
+ startPoint,
+ wayline_type
)
+ const dockTransformPosition = Cesium.Cartesian3.fromDegrees(
+ Number(dockPosition.longitude),
+ Number(dockPosition.latitude),
+ Number(dockPosition.height)
+ )
// 路径线
let polyline
-
+
+ indexLog = indexLog + 1
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,
@@ -525,10 +738,9 @@
height: 50,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
-
label: {
text: data.job_name || '',
- font: 'bold 16px YouSheBiaoTiHei',
+ font: 'bold 16px sans-serif',
fillColor: data.type === 2 ? runningTextColor : pendingTextColor,
pixelOffset: data.type === 2 ? runningTextOffset : pendingTextOffset,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
@@ -540,9 +752,7 @@
} else if (index === filePositions.length - 1) {
this.viewer.entities.add({
name: 'work-drone-route-point-end',
-
position,
-
billboard: {
image: newEndPointImg,
outlineWidth: 0,
@@ -556,9 +766,7 @@
} else {
this.viewer.entities.add({
name: 'work-drone-route-point-approach',
-
position,
-
billboard: {
image: newNumPoint,
width: 50,
@@ -577,96 +785,56 @@
})
}
})
-
polyline = this.viewer.entities.add({
name: 'work-drone-route-point-polyline',
-
polyline: {
width: 4,
positions: positionArray,
- material: data.type === 2 ? runningLineMaterial : pendingLineMaterial,
+ material: data.type === 2 ? getLineColor(indexLog) : arrowLineMaterialPropertyGray,
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)
- )
-
+ isShowDock && renderingMachineNest({
+ viewer: this.viewer,
+ dockTransformPosition,
+ dockPosition
+ })
// 起点
- 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 && renderingStartingPoint({
+ viewer: this.viewer,
+ startPosition: Cesium.Cartesian3.fromDegrees(
+ Number(filePositions[0].lng),
+ Number(filePositions[0].lat),
+ Number(filePositions[0].alt)
+ ),
+ 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, // 底部对齐
- },
- })
-
+ 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, // 底部对齐
+ },
+ })
+ console.log(data.status, '失败')
polyline = this.viewer.entities.add({
name: 'work-drone-route-point-polyline',
-
polyline: {
width: 4,
positions: positionArray,
- material: getLineColor(indexLog),
+ material: data.status === 5 ? arrowLineMaterialPropertyGray : getLineColor(indexLog),
clampToGround: false,
},
-
customData: {
- data
- }
+ data,
+ },
})
}
@@ -674,47 +842,45 @@
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)
- )
+ // 落点线
+ ; (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)
- })
+ 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,
+ filePositions:
+ dockPosition !== null
+ ? [{ lng: dockPosition.longitude, lat: dockPosition.latitude, alt: dockPosition.height }, ...filePositions]
+ : filePositions,
}
}
/**
* 通用处理数据
- * @param {*} lineObj
- * @param {*} missionConfig
- * @param {*} dronePosition
- * @param {*} startPoint
+ * @param {*} lineObj
+ * @param {*} missionConfig
+ * @param {*} dronePosition
+ * @param {*} startPoint
* @returns {} {positionArray: 带拼接点位置, filePositions:光航线点位置}
*/
disposeData (lineObj, missionConfig, dronePosition, data, startPoint, wayline_type) {
- indexLog = indexLog + 1
const { device_sn } = data
-
- const executeHeightMode = lineObj.executeHeightMode === "WGS84"
+ const executeHeightMode = lineObj.executeHeightMode === 'WGS84'
let filePositions = lineObj.Placemark.map(item => {
const [lng, lat] = item.Point.coordinates.split(',')
@@ -730,12 +896,14 @@
let safetyHeight
if (executeHeightMode) {
- let startHeight = new Decimal(missionConfig.takeOffSecurityHeight)
- .plus(dronePosition.height).toNumber()
+ let startHeight = new Decimal(missionConfig.takeOffSecurityHeight).plus(dronePosition?.height || 0).toNumber()
safetyHeight = startHeight < filePositions[0].alt ? filePositions[0].alt : startHeight
} else {
- safetyHeight = missionConfig.takeOffSecurityHeight < filePositions[0].alt ? filePositions[0].alt : missionConfig.takeOffSecurityHeight
+ safetyHeight =
+ missionConfig.takeOffSecurityHeight < filePositions[0].alt
+ ? filePositions[0].alt
+ : missionConfig.takeOffSecurityHeight
}
let safetyPositions = []
@@ -773,28 +941,38 @@
})
this.updataMultiNestData(device_sn, {
- currentRoutePositions
+ 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)
+ 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())
+ 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)
+ 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())
+ new Cesium.Cartesian3()
+ ),
})
}
@@ -805,9 +983,9 @@
return {
...item,
- alt: Number(height)
+ alt: Number(height),
}
- })
+ }),
}
}
@@ -819,9 +997,10 @@
return i?.name && i?.name.includes('work-drone-route-')
})
- Array.isArray(entities) && entities.forEach(item => {
- this.viewer?.entities.remove(item)
- })
+ Array.isArray(entities) &&
+ entities.forEach(item => {
+ this.viewer?.entities.remove(item)
+ })
}
// 当前无人机视椎体相关
@@ -847,11 +1026,22 @@
['wide', 'ir', 'zoom'].includes(curDroneData?.camera_type)
) {
if (curDroneData.camera_type === 'wide') {
- fov = 60
+ fov = 65
} 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)
+ const cameraMultiplier = getZoomFactor(host?.cameras?.[0], curDroneData.camera_type)
+ switch (cameraMultiplier) {
+ case 2: fov = 30; break
+ case 3: fov = 19; break
+ case 4: fov = 15; break
+ case 5: fov = 13; break
+ case 6: fov = 11; break
+ case 7: fov = 9; break
+ case 8: fov = 8.34; break
+ case 9: fov = 7.68; break
+ case 10: fov = 6.9; break
+ case 14: fov = 5; break
+ default: fov = 55.946 * Math.exp(-0.4504 * cameraMultiplier) + 6.323
+ }
}
}
@@ -871,8 +1061,8 @@
pitch: 0,
heading: attitude_head,
- isShowVideoPlan: this.isShowVideoPlan
- })
+ isShowVideoPlan: this.isShowVideoPlan,
+ }),
})
}
}
@@ -882,7 +1072,7 @@
if (device_sn && live_status) {
this.updataMultiNestData(device_sn, {
- camera_type: live_status?.[0].video_type || 'wide'
+ camera_type: live_status?.[0].video_type || 'wide',
})
}
}
@@ -897,14 +1087,9 @@
}
}
+ // 设置当前无人机视椎体信息面板
setFrustumInfoDetails (data) {
- const {
- dock_sn,
- distance_to_airport,
- distance_to_next_point,
- estimated_time_to_next_point,
- plane_mileage
- } = 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 => {
@@ -924,7 +1109,9 @@
}
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`,
+ 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,
@@ -936,7 +1123,6 @@
return
}
-
}
}
@@ -954,8 +1140,10 @@
}
}
+ // 设置无人机模型
setAircraftGltf (host) {
const parent_sn = host?.parent_sn
+ const attitude_head = Number(host?.payloads?.[0]?.gimbal_yaw) - 90 || 0
if (parent_sn) {
const aircraftEntity = this.viewer?.entities.values.find(i => {
@@ -963,9 +1151,18 @@
})
const position = Cesium.Cartesian3.fromDegrees(host?.longitude, host?.latitude, host?.height)
+ // ✅ 新增:Heading / Pitch / Roll(单位:度 -> 弧度)
+ const heading = Cesium.Math.toRadians(attitude_head) // 航向角
+ const pitch = Cesium.Math.toRadians(0) // 俯仰角
+ const roll = Cesium.Math.toRadians(0) // 横滚角
+
+ // ✅ 新增:构造 HeadingPitchRoll 和 四元数
+ const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
+ const orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr)
if (aircraftEntity) {
aircraftEntity.position = new Cesium.ConstantPositionProperty(position)
+ aircraftEntity.orientation = new Cesium.ConstantProperty(orientation)
return
}
@@ -974,18 +1171,35 @@
this.viewer?.entities.add({
name: `aircraft-glf-${parent_sn}`,
position,
+ orientation,
label: {},
model: {
uri: aircraftGltf, // 或 .glb
- scale: 1.0, // 缩放比例
+ scale: 64, // 缩放比例
minimumPixelSize: 64, // 最小像素尺寸(保证模型远处可见)
- maximumScale: 128, // 最大缩放(可选)
+ maximumScale: 64, // 最大缩放(可选)
},
})
}
}
}
+ // 移除无人机模型
+ removeAircraftGltf (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) {
+ this.viewer?.entities.remove(aircraftEntity)
+ }
+ }
+ }
+
+ // 移除所有无人机视椎体
removeViewInfoFrustum () {
this.multiNestData.forEach(item => {
if ('viewInfoFrustum' in item && item.viewInfoFrustum) {
@@ -1010,9 +1224,10 @@
return i?.name && i?.name.includes(`aircraft-glf-${parent_sn}`)
})
- Array.isArray(entities) && entities.forEach(item => {
- this.viewer?.entities.remove(item)
- })
+ Array.isArray(entities) &&
+ entities.forEach(item => {
+ this.viewer?.entities.remove(item)
+ })
}
}
@@ -1021,13 +1236,15 @@
return i?.name && i?.name.includes(`aircraft-glf-`)
})
- Array.isArray(entities) && entities.forEach(item => {
- this.viewer?.entities.remove(item)
- })
+ Array.isArray(entities) &&
+ entities.forEach(item => {
+ this.viewer?.entities.remove(item)
+ })
- this.multiNestData.length > 0 && (this.multiNestData.forEach(item => {
- item.viewInfoFrustum?.clear()
- }))
+ this.multiNestData.length > 0 &&
+ this.multiNestData.forEach(item => {
+ item.viewInfoFrustum?.clear()
+ })
}
/**
@@ -1043,19 +1260,19 @@
this.multiNestData[isHaveInd] = {
...this.multiNestData[isHaveInd],
- ...data
+ ...data,
}
} else {
this.multiNestData.push({
device_sn,
- ...data
+ ...data,
})
}
}
/**
* 根据机巢sn获取当前机巢对应的相关信息
- * @param {*} device_sn
+ * @param {*} device_sn
*/
getCurDroneData (device_sn) {
const isHave = this.multiNestData.find(item => item.device_sn === device_sn)
@@ -1071,14 +1288,16 @@
return {
...item,
show: true,
- uuid: uuidv4()
+ 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))
+ this.detailsMapPopupData.forEach(
+ i => i?.job_id === data?.job_id && i?.device_sn === data?.device_sn && (i.show = true)
+ )
}
getLabelDom (data) {
@@ -1090,28 +1309,30 @@
tooltipContainer.style.position = 'absolute'
tooltipContainer.style.transform = 'translate(-50%,10%)'
tooltipContainer.style.pointerEvents = 'none'
- document.querySelector('.content-map-popups')?.append(tooltipContainer)
+ 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)
+ this.detailsMapPopupData
+ .filter(i => i.show === true)
+ .forEach(item => {
+ const { showPopupPosition } = this.getCurDroneData(item.device_sn)
- let dom = document.querySelector(`[id="${item.uuid}"]`)
+ let dom = document.querySelector(`[id="${item.uuid}"]`)
- if (!dom) {
- dom = this.getLabelDom(item)
- }
+ 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'
- }
- })
+ 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'
+ }
+ })
}
// 移除弹框标签
@@ -1137,4 +1358,4 @@
const that = this
that.viewer?.scene.postRender.removeEventListener(that.labelBoxRenderHandler)
}
-}
\ No newline at end of file
+}
--
Gitblit v1.9.3