From aec00ecc093be803860c8675cbe1c4c776a7cb4e Mon Sep 17 00:00:00 2001
From: GuLiMmo <2820890765@qq.com>
Date: Tue, 19 Mar 2024 17:49:21 +0800
Subject: [PATCH] update: 新建航线、事件编辑、kmz文件问题修改
---
src/utils/cesium/use-map-draw.ts | 2
src/assets/icons/model-m30.png | 0
src/assets/icons/model-mavic3.png | 0
src/pages/page-web/projects/components/route-edit/index.vue | 21 ++-
src/pages/page-web/projects/routeLine.vue | 9 -
src/pages/page-web/projects/wayline.vue | 108 +++++++++++------
src/utils/cesium/use-kmz-tsa.ts | 130 +++++++++++++--------
src/utils/cesium/kmz.ts | 33 +++--
src/assets/icons/model-matrice3d.png | 0
src/utils/cesium/enums.ts | 0
10 files changed, 186 insertions(+), 117 deletions(-)
diff --git a/src/assets/icons/wrj.png b/src/assets/icons/model-m30.png
similarity index 100%
rename from src/assets/icons/wrj.png
rename to src/assets/icons/model-m30.png
Binary files differ
diff --git a/src/assets/icons/model-matrice3d.png b/src/assets/icons/model-matrice3d.png
new file mode 100644
index 0000000..ec59bd9
--- /dev/null
+++ b/src/assets/icons/model-matrice3d.png
Binary files differ
diff --git a/src/assets/icons/model-mavic3.png b/src/assets/icons/model-mavic3.png
new file mode 100644
index 0000000..140671c
--- /dev/null
+++ b/src/assets/icons/model-mavic3.png
Binary files differ
diff --git a/src/pages/page-web/projects/components/route-edit/index.vue b/src/pages/page-web/projects/components/route-edit/index.vue
index dc41084..b9955d6 100644
--- a/src/pages/page-web/projects/components/route-edit/index.vue
+++ b/src/pages/page-web/projects/components/route-edit/index.vue
@@ -75,18 +75,15 @@
</template>
<script setup lang="ts">
-import _, { template } from 'lodash'
+import _ from 'lodash'
import * as Cesium from 'cesium'
import setting from './components/setting.vue'
import useKmzTsa, { kmlStr, template as xmlTemplate } from '/@/utils/cesium/use-kmz-tsa'
-import { ref, reactive, defineEmits, defineProps, watch, onMounted } from 'vue'
+import { ref, defineEmits, defineProps, watch, onMounted } from 'vue'
import { ArrowLeftOutlined, CaretDownOutlined, SaveOutlined } from '@ant-design/icons-vue'
import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
import { useMyStore } from '/@/store'
-import ImageTrailMaterial from '/@/utils/cesium/ImageTrailMaterial'
import useMapDraw, { kmlEntities as globalEntities, selectPointIndex as pointIdx } from '/@/utils/cesium/use-map-draw'
-import { getKmlParams } from '/@/utils/cesium/kmz'
-import { getHaeHeight } from '/@/utils/cesium/mapUtils'
import contextMenu from './components/content-menu.vue'
const store = useMyStore()
const { appContext }: any = getCurrentInstance()
@@ -142,6 +139,7 @@
const loadCompleted = ref<boolean>(false)
+// 编辑时初始化
const initDrawRoute = () => {
const options = {
camera: global.$viewer.scene.camera,
@@ -184,6 +182,12 @@
addMapPointEvent()
}
})
+}
+// 新建航线初始化
+const initCreateRoute = () => {
+ mapDraw = useMapDraw('', [], '', global)
+ const xml = kmzUtils.generateXML(xmlTemplate.value)
+ mapDraw.drawWayline([], xml)
}
// 创建广告牌
@@ -494,7 +498,12 @@
onMounted(() => {
// 清空画布
clearCesiumMap()
- initDrawRoute()
+ console.log(!!filePath.value)
+ if (filePath.value) {
+ initDrawRoute()
+ } else {
+ initCreateRoute()
+ }
})
onUnmounted(() => {
diff --git a/src/pages/page-web/projects/routeLine.vue b/src/pages/page-web/projects/routeLine.vue
index c397424..52d812a 100644
--- a/src/pages/page-web/projects/routeLine.vue
+++ b/src/pages/page-web/projects/routeLine.vue
@@ -66,7 +66,6 @@
import * as Cesium from 'cesium'
import { convertTimestampToDate } from '/@/utils/time'
import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
-import CustomerSportLine from '/@/utils/cesium/customerSportLine'
const getResource = (name: string) => {
return new URL(`/src/assets/icons/${name}`, import.meta.url).href
@@ -229,13 +228,7 @@
polyline: {
width: 10,
positions: routeLine,
- // material: Cesium.Color.BLUE
- material: new CustomerSportLine({
- color: Cesium.Color.WHITE,
- speed: 20,
- image: getResource('arrow.png'),
- repeat: { x: 15, y: 0 },
- }),
+ material: Cesium.Color.BLUE,
clampToGround: false, // 关闭贴地效果,保留高度
},
}
diff --git a/src/pages/page-web/projects/wayline.vue b/src/pages/page-web/projects/wayline.vue
index 1c1e957..42a9319 100644
--- a/src/pages/page-web/projects/wayline.vue
+++ b/src/pages/page-web/projects/wayline.vue
@@ -134,28 +134,41 @@
@cancel="closeAddWaylineDialog"
:get-container="() => projectWayLine"
:cancel-button-props="{ ghost: true }">
- <a-form layout="vertical" :model="waylineFormState" ref="waylineFormRef" class="create-wayline-content">
- <a-form-item label="航线名称">
- <a-input class="wayline-input" v-model="waylineFormState.fileName" placeholder="请输入航线名称"></a-input>
+ <a-form
+ layout="vertical"
+ :model="waylineFormState"
+ ref="waylineFormRef"
+ :rules="waylineFormRules"
+ name="fileName"
+ class="create-wayline-content">
+ <a-form-item label="航线名称" name="fileName">
+ <a-input
+ class="wayline-input"
+ v-model:value="waylineFormState.fileName"
+ placeholder="请输入航线名称"></a-input>
</a-form-item>
- <a-form-item label="选择飞行器与负载">
+ <a-form-item label="选择飞行器与负载" name="droneEnumValue">
<a-select
- v-model="waylineFormState.droneType"
+ v-model:value="waylineFormState.droneEnumValue"
:options="droneTypeList"
class="drone-select"
:showArrow="false"
placeholder="请选择无人机型号"
- :getPopupContainer="(triggerNode: any) => triggerNode.parentNode"
- @change="droneTypeChange">
+ :getPopupContainer="(triggerNode: any) => triggerNode.parentNode">
</a-select>
+ </a-form-item>
+ <a-form-item name="payloadEnumValue">
<div class="drone-box">
- <img :src="getResource('wrj.png')" alt="" srcset="" class="drone-img" />
+ <img
+ :src="droneTypeList.find((item) => item.value === waylineFormState.droneEnumValue)?.icon"
+ alt="drone-img"
+ class="drone-img" />
</div>
<div class="payload-select">
<div class="title"><span></span> 云台I</div>
<a-select
- v-model="waylineFormState.payloadType"
- :options="dronePayloads"
+ v-model:value="waylineFormState.payloadEnumValue"
+ :options="droneTypeList.find((s) => s.value === waylineFormState.droneEnumValue)?.payloads"
allowClear
placeholder="请选择云台型号"
:showArrow="false"
@@ -181,27 +194,22 @@
import { message } from 'ant-design-vue'
import { onMounted, UnwrapRef, reactive, ref } from 'vue'
import routeEdit from './components/route-edit/index.vue'
-import ImageTrailMaterial from '/@/utils/cesium/ImageTrailMaterial'
-import { getPolylineLength } from '/@/utils/cesium/mapUtils'
import { deleteWaylineFile, downloadWaylineFile, getWaylineFiles, importKmzFile, getWayLineFile } from '/@/api/wayline'
-import EventBus from '/@/event-bus/'
import { ELocalStorageKey, ERouterName } from '/@/types'
import { EDeviceType } from '/@/types/device'
import { useMyStore } from '/@/store'
import { WaylineFile } from '/@/types/wayline'
import { downloadFile } from '/@/utils/common'
import { IPage } from '/@/api/http/type'
-import { CURRENT_CONFIG } from '/@/api/http/config'
-import { load } from '@amap/amap-jsapi-loader'
import { getRoot } from '/@/root'
import * as Cesium from 'cesium'
import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
import useMapDraw from '/@/utils/cesium/use-map-draw'
-import { fileAuthor } from '/@/utils/cesium/use-kmz-tsa'
-import axios from 'axios'
+import useKmzTsa, { fileAuthor } from '/@/utils/cesium/use-kmz-tsa'
import JSZIP from 'jszip'
// 初始化jszip
const JsZip = new JSZIP()
+const { create: createWayline } = useKmzTsa()
const getResource = (name: string) => {
return new URL(`/src/assets/icons/${name}`, import.meta.url).href
@@ -396,54 +404,71 @@
// 新建航线
interface waylineFormState {
fileName: string
- droneType: string | number | undefined
- payloadType: string | number | undefined
+ droneEnumValue: string
+ payloadEnumValue: string
}
const waylineFormRef = ref()
const addWaylineDialogShow = ref<boolean>(false)
const isCreateWayline = ref<boolean>(false)
+const waylineFormRules = {
+ fileName: [{ required: true, message: '请输入航线文件名称', trigger: 'blur' }],
+ droneEnumValue: [{ required: true, message: '请选择无人机型号', trigger: 'blur' }],
+ payloadEnumValue: [{ required: true, message: '请选择无人机云台型号', trigger: 'blur' }],
+}
const waylineFormState = reactive<UnwrapRef<waylineFormState>>({
fileName: '',
- droneType: 67,
- payloadType: '',
+ droneEnumValue: '67',
+ payloadEnumValue: undefined,
})
interface droneType {
label: string
- value: number
+ value: string
payloads?: droneType[]
+ icon?: string
}
const droneTypeList = reactive<droneType[]>([
{
label: 'M30系列',
- value: 67,
+ value: '67',
+ icon: getResource('model-m30.png'),
payloads: [
- { label: 'M30 相机', value: 0 },
- { label: 'M30T 相机', value: 0 },
+ { label: 'M30 相机', value: '52' },
+ { label: 'M30T 相机', value: '53' },
],
},
{
label: 'Mavic 3 行业系列',
- value: 77,
+ value: '77',
+ icon: getResource('model-mavic3.png'),
payloads: [
- { label: 'Mavic3E 相机', value: 0 },
- { label: 'Mavic3T 相机', value: 0 },
+ { label: 'Mavic3E 相机', value: '66' },
+ { label: 'Mavic3T 相机', value: '67' },
],
},
{
label: 'Matrice 3D 系列',
- value: 91,
+ value: '91',
+ icon: getResource('model-matrice3d.png'),
payloads: [
- { label: 'M3D 相机', value: 0 },
- { label: 'M3DT 相机', value: 0 },
+ { label: 'M3D 相机', value: '80' },
+ { label: 'M3TD 相机', value: '81' },
],
},
])
-const dronePayloads = ref<droneType[]>([])
-const droneTypeChange = (value: number) => {
- const payloads = droneTypeList.find((s) => s.value === value)?.payloads
- dronePayloads.value = payloads || []
+const addWaylineFile = () => {
+ waylineFormRef.value
+ .validate()
+ .then((values: waylineFormState) => {
+ createWayline(values).then((createRes: any) => {
+ if (createRes) {
+ store.commit('SET_WAYLINE_KMZPATH', '')
+ isPointListOpen.value = !isPointListOpen.value
+ } else {
+ message.error('创建航线失败,错误码:', createRes)
+ }
+ })
+ })
}
-const addWaylineFile = () => {}
const closeAddWaylineDialog = () => {
waylineFormRef.value.resetFields()
}
@@ -685,7 +710,7 @@
flex-direction: column;
}
.drone-img {
- width: 70%;
+ width: 60%;
}
:deep() {
.ant-form-item-label {
@@ -703,7 +728,7 @@
:deep() {
.ant-select-selector {
color: #fff;
- background-color: #3c3c3c;
+ background-color: #3c3c3c !important;
border: 0;
font-weight: bolder;
}
@@ -736,7 +761,9 @@
border-radius: 3px;
.title {
color: #fff;
- text-align: center;
+ display: flex;
+ align-items: center;
+ justify-content: center;
padding: 5px 0;
span {
width: 5px;
@@ -744,13 +771,14 @@
border-radius: 50%;
display: inline-block;
background-color: orange;
+ margin-right: 5px;
}
}
:deep() {
.ant-select-selector {
border: 0;
box-shadow: none !important;
- background-color: transparent;
+ background-color: transparent !important;
font-weight: bold;
color: #fff;
.ant-select-selection-placeholder {
diff --git a/src/utils/cesium/enums.ts b/src/utils/cesium/enums.ts
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/utils/cesium/enums.ts
diff --git a/src/utils/cesium/kmz.ts b/src/utils/cesium/kmz.ts
index 6d90117..84d9435 100644
--- a/src/utils/cesium/kmz.ts
+++ b/src/utils/cesium/kmz.ts
@@ -112,14 +112,22 @@
// element node
// 递归调用处理子节点
if (obj[nodeName] === undefined) {
- obj[nodeName] = deepParse(item)
+ const nodeValue = deepParse(item)
+ if (nodeValue[nodeName] === undefined) {
+ obj[nodeName] = nodeValue
+ } else {
+ obj[nodeName] = nodeValue[nodeName]
+ }
} else {
if (!obj[nodeName].push) {
const old = obj[nodeName]
obj[nodeName] = []
obj[nodeName].push(old)
}
- obj[nodeName].push(deepParse(item))
+ const nodeValue = deepParse(item)
+ if (nodeValue[nodeName] === undefined) {
+ obj[nodeName].push(nodeValue)
+ }
}
}
}
@@ -145,7 +153,7 @@
return xmlObj
} else {
return {
- Document: xmlObj
+ Document: xmlObj,
}
}
}
@@ -160,22 +168,23 @@
export const JSONToXML = (obj: any, rootName?: string | undefined, isEnd: boolean = false) => {
let xml = ''
- const buildXml = (obj: string | any[], rootName?: string | undefined) => {
+ const buildXml = (obj: string | any[], rootName: string = '') => {
let xml = ''
if (Array.isArray(obj)) {
obj.forEach((item) => {
- xml += `<${rootName}>${buildXml(item)}</${rootName}>\n`
+ const str = !noWmpl.includes(rootName) && isEnd ? 'wpml:' : ''
+ xml += `<${str}${rootName}>${buildXml(item)}</${str}${rootName}>`
})
} else if (typeof obj === 'object') {
Object.keys(obj).forEach((key) => {
if (key === '#text') {
xml += obj[key]
} else {
+ const str = !noWmpl.includes(key) && isEnd ? 'wpml:' : ''
if (key === 'Placemark') {
xml += `${buildXml(obj[key], key)}`
} else {
- const str = !noWmpl.includes(key) && isEnd ? 'wpml:' : ''
- xml += `<${str}${key}>${buildXml(obj[key], key)}</${str}${key}>\n`
+ xml += `<${str}${key}>${buildXml(obj[key], key)}</${str}${key}>`
}
}
})
@@ -186,11 +195,11 @@
}
const header = isEnd ? '<?xml version="1.0" encoding="UTF-8"?>' : ''
- xml += `
- ${header}
+ xml += `${header}
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:wpml="http://www.dji.com/wpmz/1.0.5">
- ${buildXml(obj, rootName)}
- </kml>
- `
+ <Document>
+ ${buildXml(obj, rootName)}
+ </Document>
+ </kml>`
return xml
}
diff --git a/src/utils/cesium/use-kmz-tsa.ts b/src/utils/cesium/use-kmz-tsa.ts
index a437f4a..d7ff54c 100644
--- a/src/utils/cesium/use-kmz-tsa.ts
+++ b/src/utils/cesium/use-kmz-tsa.ts
@@ -145,58 +145,73 @@
template.value = tplXmlJson.Document
return kmzRes
}
- const create = (waylineBasicInfo) => {
- const author = window.localStorage.getItem('username') || ''
- const createTime = new Date().getTime()
- // 模板
- const template = {
- author,
- createTime,
- updateTime: createTime,
- missionConfig: {
- flyToWaylineMode: 'safely',
- finishAction: 'goHome',
- exitOnRCLost: 'goContinue',
- executeRCLostAction: 'goBack',
- takeOffSecurityHeight: 20,
- takeOffRefPoint: '0.000000,0.000000,0.000000',
- takeOffRefPointAGLHeight: 0,
- globalTransitionalSpeed: 15,
- globalRTHHeight: 80,
- droneInfo: {
- droneEnumValue: 0,
- droneSubEnumValue: 0,
+ const create = async (waylineBasicInfo: { fileName: string; droneEnumValue: string; payloadEnumValue: string }) => {
+ try {
+ const { fileName, droneEnumValue, payloadEnumValue } = waylineBasicInfo
+ const author = window.localStorage.getItem('username') || ''
+ const createTime = new Date().getTime()
+ // 模板
+ const droneModel: { [key: string]: string } = {
+ 52: '0',
+ 53: '1',
+ 66: '0',
+ 67: '1',
+ 80: '0',
+ 81: '1',
+ } as const
+ const templateJson = {
+ author,
+ createTime,
+ updateTime: createTime,
+ missionConfig: {
+ flyToWaylineMode: 'safely',
+ finishAction: 'goHome',
+ exitOnRCLost: 'goContinue',
+ executeRCLostAction: 'goBack',
+ takeOffSecurityHeight: 20,
+ takeOffRefPoint: '0.000000,0.000000,0.000000',
+ takeOffRefPointAGLHeight: 0,
+ globalTransitionalSpeed: 15,
+ globalRTHHeight: 80,
+ droneInfo: {
+ droneEnumValue,
+ droneSubEnumValue: droneModel[payloadEnumValue],
+ },
+ payloadInfo: {
+ payloadEnumValue,
+ payloadSubEnumValue: droneModel[payloadEnumValue],
+ payloadPositionIndex: 0,
+ },
},
- payloadInfo: {
- payloadEnumValue: 0,
- payloadSubEnumValue: 0,
- payloadPositionIndex: 0,
+ Folder: {
+ templateType: 'waypoint',
+ useGlobalTransitionalSpeed: 0,
+ templateId: 0,
+ waylineCoordinateSysParam: {
+ coordinateMode: 'WGS84',
+ heightMode: 'EGM96',
+ globalShootHeight: 50,
+ positioningType: 'GPS',
+ surfaceFollowModeEnable: 1,
+ surfaceRelativeHeight: 100,
+ },
+ autoFlightSpeed: 7,
+ gimbalPitchMode: 'usePointSetting',
+ globalWaypointHeadingParam: {
+ waypointHeadingMode: 'followWayline',
+ waypointHeadingAngle: 0,
+ waypointPoiPoint: '0.000000,0.000000,0.000000',
+ waypointHeadingPathMode: 'followBadArc',
+ },
+ globalWaypointTurnMode: 'toPointAndStopWithDiscontinuityCurvature',
+ globalUseStraightLine: 0,
+ Placemark: [],
},
- },
- Folder: {
- templateType: 'waypoint',
- useGlobalTransitionalSpeed: 0,
- templateId: 0,
- waylineCoordinateSysParam: {
- coordinateMode: 'WGS84',
- heightMode: 'EGM96',
- globalShootHeight: 50,
- positioningType: 'GPS',
- surfaceFollowModeEnable: 1,
- surfaceRelativeHeight: 100,
- },
- autoFlightSpeed: 7,
- gimbalPitchMode: 'usePointSetting',
- globalWaypointHeadingParam: {
- waypointHeadingMode: 'followWayline',
- waypointHeadingAngle: 0,
- waypointPoiPoint: '0.000000,0.000000,0.000000',
- waypointHeadingPathMode: 'followBadArc',
- },
- globalWaypointTurnMode: 'toPointAndStopWithDiscontinuityCurvature',
- globalUseStraightLine: 0,
- Placemark: [],
- },
+ }
+ template.value = templateJson
+ return true
+ } catch (error) {
+ return error
}
}
const save = () => {
@@ -246,6 +261,21 @@
if (item === 'waylineId') {
waylinesObj[key][item] = templateJson[key].templateId
}
+ if (item === 'Placemark') {
+ const placemarks = _.cloneDeep(templateJson[key][item])
+ placemarks.forEach(
+ (placemark: {
+ executeHeight: { '#text': string }
+ ellipsoidHeight?: { [x: string]: string }
+ height?: { [x: string]: string }
+ }) => {
+ placemark.executeHeight = { '#text': placemark.ellipsoidHeight?.['#text'] || '' }
+ delete placemark.ellipsoidHeight
+ delete placemark.height
+ },
+ )
+ waylinesObj[key][item] = placemarks
+ }
})
} else {
waylinesObj[key] = templateJson[key]
diff --git a/src/utils/cesium/use-map-draw.ts b/src/utils/cesium/use-map-draw.ts
index d7361ed..e5a8005 100644
--- a/src/utils/cesium/use-map-draw.ts
+++ b/src/utils/cesium/use-map-draw.ts
@@ -311,7 +311,7 @@
if (Array.isArray(action)) {
action.forEach((item) => {
const { actionActuatorFunc } = item
- actionActuatorFunc['#text'] === 'takePhoto' && takePhotoNum++
+ actionActuatorFunc?.['#text'] === 'takePhoto' && takePhotoNum++
const actionObj: eventParmas | any = actionList.find((event) => actionActuatorFunc['#text'] === event.key)
waylinePointsEvent.value[index].eventList?.push(actionObj)
})
--
Gitblit v1.9.3