From e72969f25dd1a243e48c783dedc0f198ee08c2b8 Mon Sep 17 00:00:00 2001
From: GuLiMmo <2820890765@qq.com>
Date: Wed, 20 Mar 2024 17:19:04 +0800
Subject: [PATCH] update:新增航线、航点事件编辑

---
 src/components/GMap.vue                                                            |    2 
 src/utils/cesium/use-map-draw.ts                                                   |   44 +++++---
 src/hooks/use-cesium-tsa.ts                                                        |    3 
 src/assets/icons/waylinetool/无人机起降场.png                                            |    0 
 src/pages/page-web/projects/components/route-edit/index.vue                        |   52 +++++++++-
 src/pages/page-web/projects/wayline.vue                                            |    6 
 src/utils/cesium/use-kmz-tsa.ts                                                    |   69 +++++++------
 src/pages/page-web/projects/components/route-edit/components/setting.vue           |   51 +++++++--
 src/pages/page-web/projects/components/route-edit/components/setting-point-tip.vue |   72 ++++++++++++++
 src/assets/icons/waylinetool/startpoint.png                                        |    0 
 src/assets/icons/waylinetool/cursor.png                                            |    0 
 11 files changed, 228 insertions(+), 71 deletions(-)

diff --git a/src/assets/icons/waylinetool/cursor.png b/src/assets/icons/waylinetool/cursor.png
new file mode 100644
index 0000000..e4421c9
--- /dev/null
+++ b/src/assets/icons/waylinetool/cursor.png
Binary files differ
diff --git a/src/assets/icons/waylinetool/startpoint.png b/src/assets/icons/waylinetool/startpoint.png
new file mode 100644
index 0000000..1a8eaea
--- /dev/null
+++ b/src/assets/icons/waylinetool/startpoint.png
Binary files differ
diff --git "a/src/assets/icons/waylinetool/\346\227\240\344\272\272\346\234\272\350\265\267\351\231\215\345\234\272.png" "b/src/assets/icons/waylinetool/\346\227\240\344\272\272\346\234\272\350\265\267\351\231\215\345\234\272.png"
new file mode 100644
index 0000000..7cad529
--- /dev/null
+++ "b/src/assets/icons/waylinetool/\346\227\240\344\272\272\346\234\272\350\265\267\351\231\215\345\234\272.png"
Binary files differ
diff --git a/src/components/GMap.vue b/src/components/GMap.vue
index e60c697..8b0fbc7 100644
--- a/src/components/GMap.vue
+++ b/src/components/GMap.vue
@@ -848,7 +848,7 @@
           :payloads="osdVisible.payloads">
         </DroneControlPanel>
       </div>
-      <waylineTool />
+      <!-- <waylineTool /> -->
       <routeProfile />
     </div>
     <div class="event-wrapper" v-if="false">
diff --git a/src/hooks/use-cesium-tsa.ts b/src/hooks/use-cesium-tsa.ts
index a25ff3b..b4fb7c7 100644
--- a/src/hooks/use-cesium-tsa.ts
+++ b/src/hooks/use-cesium-tsa.ts
@@ -196,6 +196,9 @@
       if (pick && (pick.id._id === sid || pick.id._id.includes(sid))) {
         cb(click, pick, viewer, handler)
       }
+      if (sid === '') {
+        cb(click, pick, viewer, handler)
+      }
     }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
   }
   // 移除左键事件
diff --git a/src/pages/page-web/projects/components/route-edit/components/setting-point-tip.vue b/src/pages/page-web/projects/components/route-edit/components/setting-point-tip.vue
new file mode 100644
index 0000000..ca13c61
--- /dev/null
+++ b/src/pages/page-web/projects/components/route-edit/components/setting-point-tip.vue
@@ -0,0 +1,72 @@
+<template>
+  <Teleport to="body">
+    <div class="tip-container">点击地图设置参考起飞点</div>
+  </Teleport>
+</template>
+
+<script lang="ts" setup>
+import { onMounted, onUnmounted } from 'vue'
+import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
+import * as Cesium from 'cesium'
+import useKmzTsa, { template as xmlTemplate } from '/@/utils/cesium/use-kmz-tsa'
+import useMapDraw, { kmlEntities as globalEntities } from '/@/utils/cesium/use-map-draw'
+const { appContext }: any = getCurrentInstance()
+const global = appContext.config.globalProperties
+const kmzUtils = useKmzTsa()
+const mapDraw = useMapDraw('', [], '', global)
+
+const { addClickEvent, removeClickEvent } = cesiumOperation()
+
+const getResource = (name: string) => {
+  return new URL(`/src/assets/icons/${name}`, import.meta.url).href
+}
+
+const createInitialPoint = () => {
+  const cesiumDom: any = document.querySelector('#cesiumContainer')
+  cesiumDom.style.cursor = `url(${getResource('waylinetool/cursor.png')}), auto`
+  addClickEvent('', addSettingEvent)
+}
+
+const addSettingEvent = (click: { position: Cesium.Cartesian2 }) => {
+  const { position } = click
+  const c3Position = global.$viewer.scene.globe.pick(global.$viewer.camera.getPickRay(position), global.$viewer.scene)
+  const ellipsoid = global.$viewer.scene.globe.ellipsoid
+  const c2Postion = ellipsoid.cartesianToCartographic(c3Position)
+  const longitude = Cesium.Math.toDegrees(c2Postion.longitude)
+  const latitude = Cesium.Math.toDegrees(c2Postion.latitude)
+  const height = 6
+  const takeOffPoint = [latitude, longitude, height]
+  xmlTemplate.value.missionConfig.takeOffRefPoint['#text'] = takeOffPoint.join(',')
+  const xmlStr = kmzUtils.generateXML(xmlTemplate.value)
+  mapDraw.drawWayline(globalEntities.value, xmlStr)
+}
+
+const delSettingEvent = () => {
+  const cesiumDom: any = document.querySelector('#cesiumContainer')
+  cesiumDom.style.cursor = 'auto'
+  removeClickEvent()
+}
+
+onMounted(() => {
+  createInitialPoint()
+})
+onUnmounted(() => {
+  delSettingEvent()
+})
+</script>
+
+<style lang="scss" scoped>
+.tip-container {
+  width: 60%;
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  background-color: rgba(0, 0, 0, 0.5);
+  padding: 20px;
+  color: #fff;
+  text-align: center;
+  font-weight: bold;
+  pointer-events: none;
+}
+</style>
diff --git a/src/pages/page-web/projects/components/route-edit/components/setting.vue b/src/pages/page-web/projects/components/route-edit/components/setting.vue
index 82b043a..fca2f18 100644
--- a/src/pages/page-web/projects/components/route-edit/components/setting.vue
+++ b/src/pages/page-web/projects/components/route-edit/components/setting.vue
@@ -3,11 +3,15 @@
     <a-popover placement="bottom" trigger="click" :getPopupContainer="(triggerNode: any) => triggerNode.parentNode">
       <template #content>
         <div class="setting-content">
-          <div class="start-point common">
+          <div class="start-point common" v-if="xmlTemplate.missionConfig?.takeOffRefPoint['#text']">
             <div class="title">起飞点</div>
             <div class="value">
               {{ xmlTemplate.missionConfig?.takeOffRefPoint['#text'] !== '' ? '已设置' : '未设置' }}
             </div>
+          </div>
+          <div class="no-start-point" v-else>
+            <img :src="getResource('waylinetool/无人机起降场.png')" alt="icon">
+            <span>参考起飞点未设置</span>
           </div>
           <div class="photo-setting common">
             <div class="title">拍照设置</div>
@@ -27,17 +31,6 @@
                 {{ item.title }}照片
               </li>
             </ul>
-            <!-- <div class="auto-low-light">
-              <div class="title">自动低光</div>
-              <a-tooltip
-                placement="right"
-                :title="tipDescriptionEnums.rowLightModeTip">
-                <a-switch
-                  v-model:checked="setting.orientedPhotoMode"
-                  checkedValue="lowLightSmartShooting"
-                  unCheckedValue="normalPhoto" />
-              </a-tooltip>
-            </div> -->
           </div>
           <!-- 爬升 -->
           <div class="climb-mode common">
@@ -155,6 +148,10 @@
   return new URL(`/src/assets/svg/${name}`, import.meta.url).href
 }
 
+const getResource = (name: string) => {
+  return new URL(`/src/assets/icons/${name}`, import.meta.url).href
+}
+
 const climbImage = getSvgResource('climb.svg')
 const imgs = []
 
@@ -216,6 +213,13 @@
 
 // 拍照选择
 const selectPhotoSetting = (value: string) => {
+  if (!xmlTemplate.value.Folder.payloadParam) {
+    xmlTemplate.value.Folder.payloadParam = {
+      imageFormat: {
+        '#text': '',
+      },
+    }
+  }
   const imageFormat = xmlTemplate.value.Folder.payloadParam.imageFormat
   const imageFormatArr = imageFormat['#text'].split(',')
   if (imageFormatArr.includes(value)) {
@@ -259,6 +263,29 @@
         margin-left: auto;
         color: #409eff;
       }
+
+      .no-setting {
+        &__value {
+          width: 100%;
+          text-align: center;
+          font-weight: bold;
+        }
+      }
+    }
+    .no-start-point {
+      border-radius: 10px;
+      padding: 15px;
+      margin-bottom: 16px;
+      background-color: #409eff;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-weight: bold;
+      img {
+        width: 18px;
+        height: 18px;
+        margin-right: 5px;
+      }
     }
 
     .photo-setting {
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 b9955d6..8bd0d1f 100644
--- a/src/pages/page-web/projects/components/route-edit/index.vue
+++ b/src/pages/page-web/projects/components/route-edit/index.vue
@@ -62,15 +62,16 @@
             <div v-for="(event, index) in item.eventList" :key="index" class="s-event-icon">
               <a-tooltip placement="top">
                 <template #title>
-                  {{ event.name }}
+                  {{ event?.name }}
                 </template>
-                <img :src="event.icon" alt="icon" />
+                <img :src="event?.icon" alt="icon" />
               </a-tooltip>
             </div>
           </div>
         </contextMenu>
       </li>
     </ul>
+    <startPointTips v-if="xmlTemplate.missionConfig?.takeOffRefPoint['#text'] === ''" />
   </div>
 </template>
 
@@ -85,6 +86,7 @@
 import { useMyStore } from '/@/store'
 import useMapDraw, { kmlEntities as globalEntities, selectPointIndex as pointIdx } from '/@/utils/cesium/use-map-draw'
 import contextMenu from './components/content-menu.vue'
+import startPointTips from './components/setting-point-tip.vue'
 const store = useMyStore()
 const { appContext }: any = getCurrentInstance()
 const global = appContext.config.globalProperties
@@ -186,8 +188,33 @@
 // 新建航线初始化
 const initCreateRoute = () => {
   mapDraw = useMapDraw('', [], '', global)
-  const xml = kmzUtils.generateXML(xmlTemplate.value)
-  mapDraw.drawWayline([], xml)
+  const {
+    drawWayline,
+    waylineDetails: details,
+    waylinePointsEvent,
+    kmlEntities: entities,
+    clearWaylineData
+  } = mapDraw
+  clearWaylineData()
+  drawWayline()
+  waylineDetails.value = details
+  tragetPointArr.value = waylinePointsEvent.value
+  watch(
+    () => waylinePointsEvent.value,
+    (val) => {
+      tragetPointArr.value = val
+    },
+    {
+      deep: true,
+    },
+  )
+  kmlEntities.value = entities.value
+  // const xml = kmzUtils.generateXML(xmlTemplate.value)
+  // mapDraw.drawWayline([], xml)
+  if (!mouseRightClickEvent) {
+    // 添加右键事件
+    addMapPointEvent()
+  }
 }
 
 // 创建广告牌
@@ -287,6 +314,7 @@
     removeCesiumChildDom(popupDom)
     const { position } = click
     const { x, y } = position
+    const createTakeOffPointEvent = [{ class: 'start-point', title: '设置参考起飞点' }]
     const pointEvents = [
       {
         class: 'add-prev-point',
@@ -298,7 +326,12 @@
       },
     ]
     const defaultEvents = [{ class: 'finally-point', title: '在最后航点新增航点' }]
-    const events = selectPointIndex.value !== null ? [...defaultEvents, ...pointEvents] : defaultEvents
+    let events = []
+    if (xmlTemplate.value.missionConfig?.takeOffRefPoint['#text'] === '') {
+      events = createTakeOffPointEvent
+    } else {
+      events = selectPointIndex.value !== null ? [...defaultEvents, ...pointEvents] : defaultEvents
+    }
     popupDom = createPointPopupDom(events)
     global.$viewer.container.appendChild(popupDom)
     popupDom.style.transform = `translate3d(${x}px, ${y}px, 0)`
@@ -398,6 +431,14 @@
       },
       isRisky: { '#text': 0 },
     }
+    // 添加参考点
+    if (className === 'start-point') {
+      // 默认高度为6
+      const height = 6
+      const takeOffPoint = [latitude, longitude, height]
+      xmlTemplate.value.missionConfig.takeOffRefPoint['#text'] = takeOffPoint.join(',')
+    }
+    // 添加航点
     if (className === 'finally-point') {
       globalEntities.value.push(entity)
       xmlTemplate.value.Folder.Placemark.push(setting)
@@ -498,7 +539,6 @@
 onMounted(() => {
   // 清空画布
   clearCesiumMap()
-  console.log(!!filePath.value)
   if (filePath.value) {
     initDrawRoute()
   } else {
diff --git a/src/pages/page-web/projects/wayline.vue b/src/pages/page-web/projects/wayline.vue
index 42a9319..ae6d9a4 100644
--- a/src/pages/page-web/projects/wayline.vue
+++ b/src/pages/page-web/projects/wayline.vue
@@ -16,7 +16,7 @@
                 <SelectOutlined />
               </a-button>
             </a-upload>
-            <a-button type="text" style="color: white" @click="addWaylineDialogShow = true">
+            <a-button type="text" v-if="!isPointListOpen" style="color: white" @click="addWaylineDialogShow = true">
               <template #icon>
                 <PlusOutlined />
               </template>
@@ -462,7 +462,9 @@
       createWayline(values).then((createRes: any) => {
         if (createRes) {
           store.commit('SET_WAYLINE_KMZPATH', '')
-          isPointListOpen.value = !isPointListOpen.value
+          isPointListOpen.value = true
+          closeAddWaylineDialog()
+          addWaylineDialogShow.value = false
         } else {
           message.error('创建航线失败,错误码:', createRes)
         }
diff --git a/src/utils/cesium/use-kmz-tsa.ts b/src/utils/cesium/use-kmz-tsa.ts
index d7ff54c..01a09c6 100644
--- a/src/utils/cesium/use-kmz-tsa.ts
+++ b/src/utils/cesium/use-kmz-tsa.ts
@@ -160,51 +160,52 @@
         81: '1',
       } as const
       const templateJson = {
-        author,
-        createTime,
-        updateTime: createTime,
+        author: { '#text': author },
+        createTime: { '#text': createTime },
+        updateTime: { '#text': 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,
+          flyToWaylineMode: { '#text': 'safely' },
+          finishAction: { '#text': 'goHome' },
+          exitOnRCLost: { '#text': 'goContinue' },
+          executeRCLostAction: { '#text': 'goBack' },
+          takeOffSecurityHeight: { '#text': 20 },
+          takeOffRefPoint: { '#text': '' },
+          takeOffRefPointAGLHeight: { '#text': 0 },
+          globalTransitionalSpeed: { '#text': 15 },
+          globalRTHHeight: { '#text': 80 },
           droneInfo: {
-            droneEnumValue,
-            droneSubEnumValue: droneModel[payloadEnumValue],
+            droneEnumValue: { '#text': droneEnumValue },
+            droneSubEnumValue: { '#text': droneModel[payloadEnumValue] },
           },
           payloadInfo: {
-            payloadEnumValue,
-            payloadSubEnumValue: droneModel[payloadEnumValue],
-            payloadPositionIndex: 0,
+            payloadEnumValue: { '#text': payloadEnumValue },
+            payloadSubEnumValue: { '#text': droneModel[payloadEnumValue] },
+            payloadPositionIndex: { '#text': 0 },
           },
         },
         Folder: {
-          templateType: 'waypoint',
-          useGlobalTransitionalSpeed: 0,
-          templateId: 0,
+          templateType: { '#text': 'waypoint' },
+          useGlobalTransitionalSpeed: { '#text': 0 },
+          templateId: { '#text': 0 },
           waylineCoordinateSysParam: {
-            coordinateMode: 'WGS84',
-            heightMode: 'EGM96',
-            globalShootHeight: 50,
-            positioningType: 'GPS',
-            surfaceFollowModeEnable: 1,
-            surfaceRelativeHeight: 100,
+            coordinateMode: { '#text': 'WGS84' },
+            heightMode: { '#text': 'EGM96' },
+            globalShootHeight: { '#text': 50 },
+            positioningType: { '#text': 'GPS' },
+            surfaceFollowModeEnable: { '#text': 1 },
+            surfaceRelativeHeight: { '#text': 100 },
           },
-          autoFlightSpeed: 7,
-          gimbalPitchMode: 'usePointSetting',
+          autoFlightSpeed: { '#text': 7 },
+          gimbalPitchMode: { '#text': 'usePointSetting' },
+          globalHeight: { '#text': '100' },
           globalWaypointHeadingParam: {
-            waypointHeadingMode: 'followWayline',
-            waypointHeadingAngle: 0,
-            waypointPoiPoint: '0.000000,0.000000,0.000000',
-            waypointHeadingPathMode: 'followBadArc',
+            waypointHeadingMode: { '#text': 'followWayline' },
+            waypointHeadingAngle: { '#text': 0 },
+            waypointPoiPoint: { '#text': '0.000000,0.000000,0.000000' },
+            waypointHeadingPathMode: { '#text': 'followBadArc' },
           },
-          globalWaypointTurnMode: 'toPointAndStopWithDiscontinuityCurvature',
-          globalUseStraightLine: 0,
+          globalWaypointTurnMode: { '#text': 'toPointAndStopWithDiscontinuityCurvature' },
+          globalUseStraightLine: { '#text': 0 },
           Placemark: [],
         },
       }
diff --git a/src/utils/cesium/use-map-draw.ts b/src/utils/cesium/use-map-draw.ts
index e5a8005..3f411f2 100644
--- a/src/utils/cesium/use-map-draw.ts
+++ b/src/utils/cesium/use-map-draw.ts
@@ -5,6 +5,7 @@
 import { ref } from 'vue'
 import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
 import { XMLToJSON } from './kmz'
+import _ from 'lodash'
 const { addPolyline, getEntityById, removeAllDataSource, removeAllPoint } = cesiumOperation()
 
 const getResource = (name: string) => {
@@ -125,7 +126,10 @@
 
   // 绘制路线
   const drawWayline = async (entities?: Cesium.Entity[], kmlStr?: string) => {
-    if (!entities && !kmlStr) {
+    // if (!entities && !kmlStr) {
+    //   dataSource.show = false
+    // }
+    if (dataSource) {
       dataSource.show = false
     }
     let kmlEntityArr = entities || [...entitiesList]
@@ -145,7 +149,9 @@
     }
     const kmlJson = XMLToJSON(kmlRes)
     // 所有航点
-    const kmlPoints = kmlJson.Document.Folder.Placemark
+    const kmlPoints = Array.isArray(kmlJson.Document.Folder.Placemark)
+      ? kmlJson.Document.Folder.Placemark
+      : [kmlJson.Document.Folder.Placemark]
     // 起飞点
     let btmStartPoint = null
     // 获取文件中的起飞点
@@ -303,23 +309,26 @@
       kmlRes = await fileRes.fileInfoObj['wpmz/template.kml']
     }
     const kmlJson = XMLToJSON(kmlRes).Document
-    const points = kmlJson.Folder?.Placemark
+    const points = Array.isArray(kmlJson.Folder?.Placemark) ? kmlJson.Folder.Placemark : [kmlJson.Folder.Placemark]
     let takePhotoNum = 0
     points?.forEach((point: { actionGroup: any }, index: number) => {
-      if (Reflect.has(point, 'actionGroup')) {
-        const action = point.actionGroup.action
-        if (Array.isArray(action)) {
-          action.forEach((item) => {
-            const { actionActuatorFunc } = item
-            actionActuatorFunc?.['#text'] === 'takePhoto' && takePhotoNum++
-            const actionObj: eventParmas | any = actionList.find((event) => actionActuatorFunc['#text'] === event.key)
+      if (point !== undefined) {
+        if (Reflect.has(point, 'actionGroup')) {
+          const action = point.actionGroup.action
+          if (Array.isArray(action)) {
+            action.forEach((item) => {
+              const { actionActuatorFunc } = item
+              actionActuatorFunc?.['#text'] === 'takePhoto' && takePhotoNum++
+              const actionObj: eventParmas | any = actionList.find((event) => actionActuatorFunc['#text'] === event.key)
+              waylinePointsEvent.value[index].eventList?.push(actionObj)
+            })
+          } else {
+            action?.actionActuatorFunc['#text'] === 'takePhoto' && takePhotoNum++
+            const actionObj: eventParmas | any = actionList.find(
+              (item) => action?.actionActuatorFunc['#text'] === item.key,
+            )
             waylinePointsEvent.value[index].eventList?.push(actionObj)
-          })
-        } else {
-          const { actionActuatorFunc } = action
-          actionActuatorFunc['#text'] === 'takePhoto' && takePhotoNum++
-          const actionObj: eventParmas | any = actionList.find((item) => actionActuatorFunc['#text'] === item.key)
-          waylinePointsEvent.value[index].eventList?.push(actionObj)
+          }
         }
       }
     })
@@ -328,6 +337,9 @@
   const clearWaylineData = () => {
     kmlEntities.value = []
     waylinePointsEvent.value = []
+    _.transform(waylineDetails, (_result, value) => {
+      value.value = 0
+    })
   }
 
   return {

--
Gitblit v1.9.3