From d87242f609a6ebaba6f2b45b2c0b41f961e92d4b Mon Sep 17 00:00:00 2001
From: GuLiMmo <2820890765@qq.com>
Date: Fri, 01 Mar 2024 20:16:00 +0800
Subject: [PATCH] update

---
 src/hooks/use-cesium-tsa.ts                                              |   24 ++
 src/pages/page-web/projects/components/route-edit/index.vue              |  373 +++++++++++++++++++++++++++++++++++++++++++---
 src/pages/page-web/projects/wayline.vue                                  |    2 
 src/components/cesiumMap/cesium.vue                                      |    1 
 src/utils/cesium/kmz.ts                                                  |    2 
 src/pages/page-web/projects/components/route-edit/components/setting.vue |   41 ++++
 src/utils/cesium/mapUtils.ts                                             |    1 
 7 files changed, 412 insertions(+), 32 deletions(-)

diff --git a/src/components/cesiumMap/cesium.vue b/src/components/cesiumMap/cesium.vue
index 771efdb..390d7c7 100644
--- a/src/components/cesiumMap/cesium.vue
+++ b/src/components/cesiumMap/cesium.vue
@@ -151,6 +151,7 @@
 
 <style scoped lang="scss">
 .cesium {
+  position: relative;
   :deep(.cesium-viewer-bottom) {
     display: none !important;
   }
diff --git a/src/hooks/use-cesium-tsa.ts b/src/hooks/use-cesium-tsa.ts
index bc22c3b..a25ff3b 100644
--- a/src/hooks/use-cesium-tsa.ts
+++ b/src/hooks/use-cesium-tsa.ts
@@ -184,7 +184,7 @@
       }
     })
   }
-  // 添加点击事件
+  // 添加左键点击事件
   let leftClickHandler: Cesium.ScreenSpaceEventHandler
   const addClickEvent = (sid: string, cb: Function) => {
     if (leftClickHandler) {
@@ -198,9 +198,25 @@
       }
     }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
   }
-  // 移除事件
+  // 移除左键事件
   const removeClickEvent = () => {
     leftClickHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
+  }
+
+  let rightClickHandler: Cesium.ScreenSpaceEventHandler
+  const addRightClick = (sid: string, cb: Function) => {
+    if (leftClickHandler) {
+      removeRightClickEvent()
+    }
+    rightClickHandler = new Cesium.ScreenSpaceEventHandler(viewer?.scene.canvas)
+    rightClickHandler.setInputAction(function (click: { position: Cesium.Cartesian2 }) {
+      const pick = viewer?.scene.pick(click.position)
+      cb(click, pick, viewer, handler)
+    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
+  }
+  // 移除右键事件
+  const removeRightClickEvent = () => {
+    rightClickHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
   }
 
   // 添加线段
@@ -356,6 +372,8 @@
     loadGeoJson,
     removeAllDataSource,
     addClickEvent,
-    removeClickEvent
+    removeClickEvent,
+    addRightClick,
+    removeRightClickEvent
   }
 }
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 19832fc..1548230 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
@@ -20,6 +20,16 @@
               <a-switch />
             </div>
           </div>
+          <div class="height-mode common">
+            <div class="title">航线高度模式</div>
+            <div class="mode-box">
+              <a-radio-group button-style="solid">
+                <a-radio-button value="a">绝对高度</a-radio-button>
+                <a-radio-button value="b">相对起飞高度</a-radio-button>
+                <a-radio-button value="c">相对地面高度</a-radio-button>
+              </a-radio-group>
+            </div>
+          </div>
         </div>
       </template>
       <slot name="show"></slot>
@@ -31,6 +41,9 @@
 const getResource = (name: string) => {
   return new URL(`/src/assets/icons/${name}`, import.meta.url).href
 }
+
+const waylineSetting = reactive({})
+
 </script>
 
 <style lang="scss" scoped>
@@ -74,6 +87,32 @@
         display: flex;
         .title {
           font-weight: bold;
+          margin-right: auto;
+        }
+      }
+    }
+    .height-mode {
+      .mode-box {
+        margin-top: 10px;
+        :deep() {
+          .ant-radio-group {
+            display: flex;
+            .ant-radio-button-wrapper {
+              flex: 1;
+              text-align: center;
+              background-color: #3c3c3c;
+              border: 1px solid #101010;
+              color: #fff;
+              font-weight: bold;
+              border: 0;
+              &::before {
+                background-color: #101010;
+              }
+              &-checked {
+                background-color: #409eff !important;
+              }
+            }
+          }
         }
       }
     }
@@ -99,5 +138,3 @@
   }
 }
 </style>
-今日情况
-航线展示:照片计算 (已完成)
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 d45b13b..0d6b76a 100644
--- a/src/pages/page-web/projects/components/route-edit/index.vue
+++ b/src/pages/page-web/projects/components/route-edit/index.vue
@@ -7,7 +7,7 @@
         </template>
         返回
       </a-button>
-      <!-- <setting>
+      <setting>
         <template #show>
           <a-button type="text" class="setting-btn">
             <div class="router-setting">
@@ -20,7 +20,7 @@
             </div>
           </a-button>
         </template>
-      </setting> -->
+      </setting>
     </div>
     <div class="wayline-info">
       <div
@@ -32,7 +32,11 @@
       </div>
     </div>
     <ul class="point-list">
-      <li v-for="(item, index) in tragetPointArr" :key="index">
+      <li
+        v-for="(item, index) in tragetPointArr"
+        :key="index"
+        :class="{ 'active-point': index == selectPointIndex }"
+        @click="pointSelect(item, index)">
         <div class="graph">
           <div class="left"></div>
           <div class="right">{{ index + 1 }}</div>
@@ -56,7 +60,7 @@
 </template>
 
 <script setup lang="ts">
-import _ from 'lodash'
+import _, { divide } from 'lodash'
 import * as Cesium from 'cesium'
 import setting from './components/setting.vue'
 import { ref, reactive, defineEmits, defineProps, watch, onMounted } from 'vue'
@@ -70,11 +74,17 @@
 const { appContext }: any = getCurrentInstance()
 const global = appContext.config.globalProperties
 
-const { removeAllPoint, getEntityById, addPolyline } = cesiumOperation()
+const {
+  removeAllPoint,
+  getEntityById,
+  addPolyline,
+  addRightClick,
+  removeRightClickEvent,
+} = cesiumOperation()
 
 interface waylineDetails {
   title: string
-  value: string | number
+  value: number | string
 }
 interface eventParmas {
   key: string
@@ -167,6 +177,9 @@
   | null
   | any = null
 
+let mouseRightClickEvent: any = null
+
+// 初始化KML,判断当中存在多少事件
 const initKML = () => {
   analyzeKmzFile(filePath.value).then((kmlRes) => {
     // 所有航点
@@ -213,6 +226,15 @@
               }
             }
           })
+          // 判断一共有多少个拍照模式
+          const actionFunc = getKmlParams(point, true, {
+            name: 'actionActuatorFunc',
+            findRegx: 'takePhoto',
+            mode: 'g',
+          })
+          if (actionFunc) {
+            ;(waylineDetails[3] as any).value++
+          }
         })
         tragetPointArr.value[index].eventList = eventArr
       }
@@ -248,6 +270,11 @@
     .then((res: any) => {
       kmlDataSource = res
       createMapMarker(kmlDataSource)
+      initKML()
+      if (!mouseRightClickEvent) {
+        // 添加右键事件
+        addMapPointEvent()
+      }
     })
 }
 
@@ -276,14 +303,24 @@
   },
 ])
 // 样式
-const createMapMarker = async (dataSource: {
-  entities: { values: { _children: any }[] }
-  show: boolean
-}) => {
-  const ellipsoid = global.$viewer.scene.globe.ellipsoid
-  kmlEntity.value = dataSource.entities.values
-  dataSource.show = true
-  const kmlEntityArr = dataSource.entities.values[0]._children
+const kmlEntities = ref<Cesium.Entity[]>([])
+const ellipsoid = global.$viewer.scene.globe.ellipsoid
+const createMapMarker = async (
+  dataSource:
+    | {
+        entities: { values: { _children: any }[] }
+        show: boolean
+      }
+    | any,
+  entitiesList: Cesium.Entity[] = [],
+) => {
+  dataSource.show = false
+  let kmlEntityArr = [...entitiesList]
+  // kmlEntity.value = dataSource.entities.values
+  if (dataSource) {
+    kmlEntityArr = dataSource.entities.values[0]._children
+    kmlEntities.value = kmlEntityArr
+  }
   const cartesianArr: any[] = []
   let btmStartPoint = null
   // 获取所有的点位
@@ -294,9 +331,15 @@
     findRegx: '([\\s\\S]*?)',
     mode: 'g',
   })
+  // 获取当前航线全局速度
+  const getGlobalSpeed: any = getKmlParams(kmlRes, true, {
+    name: 'autoFlightSpeed',
+    findRegx: '([\\s\\S]*?)',
+  })
+  const speed = Number(getGlobalSpeed[1])
   // 修改点位样式信息等
   for (let i = 0; i < kmlEntityArr.length; i++) {
-    const entity = kmlEntityArr[i]
+    const entity: any = kmlEntityArr[i]
     // 将cartographic3D坐标转换为正常坐标
     const c3Position = entity.position._value
     const c2Postion = ellipsoid.cartesianToCartographic(c3Position)
@@ -305,12 +348,20 @@
     // 获取当前航点中的值
     const point = points[i]
     const getPointHeight: any = getKmlParams(point, true, {
+      name: 'ellipsoidHeight',
+      findRegx: '([\\s\\S]*?)',
+    })
+    const getHaeHeight: any = getKmlParams(point, true, {
       name: 'height',
       findRegx: '([\\s\\S]*?)',
     })
-    console.log(getPointHeight[0])
-    const height = 100
-    entity.position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
+    const AslHeight = Number(getPointHeight[1])
+    const HeaHeight = Number(getHaeHeight[1])
+    entity.position = Cesium.Cartesian3.fromDegrees(
+      longitude,
+      latitude,
+      AslHeight,
+    )
     if (i === 0) {
       btmStartPoint = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0)
     }
@@ -322,6 +373,15 @@
     entity.billboard = new Cesium.BillboardGraphics({
       image: billboard,
       pixelOffset: new Cesium.Cartesian2(0, -20),
+    })
+    entity.label = new Cesium.LabelGraphics({
+      text: `ASL:${Math.round(AslHeight)}m\nHAE:${Math.round(HeaHeight)}m`,
+      font: '13px monospace',
+      showBackground: true,
+      horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
+      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+      disableDepthTestDistance: Number.POSITIVE_INFINITY,
+      pixelOffset: new Cesium.Cartesian2(0, -40),
     })
     // 修改点的信息
     entity.point = new Cesium.PointGraphics({
@@ -336,7 +396,7 @@
         positions: Cesium.Cartesian3.fromDegreesArrayHeights([
           longitude,
           latitude,
-          height,
+          AslHeight,
           longitude,
           latitude,
           0,
@@ -347,6 +407,7 @@
         }),
       },
     })
+    // 获取虚线中心点
     cartesianArr.push(entity.position._value)
     tragetPointArr.value[i] = {
       position: entity.position._value,
@@ -379,14 +440,25 @@
       clampToGround: false, // 关闭贴地效果,保留高度
     },
   })
+  dataSource.show = true
   const lineEntity = getEntityById('entityLine')
-  const polylineLength = getPolylineLength(lineEntity).toFixed(1) || 0
+  // 获取距离
+  const polylineLength: any = getPolylineLength(lineEntity).toFixed(1) || 0
   waylineDetails[0].value = polylineLength + 'm'
+  // 航点数
   waylineDetails[2].value = cartesianArr.length
+  // 计算时间
+  const sportTime = polylineLength / speed
+  // 判断有没有超过一分钟
+  const time = sportTime / 60
+  waylineDetails[1].value =
+    Math.trunc(time) + ' m ' + Math.round((time % 1) * 60) + ' s'
   global.$viewer.flyTo(lineEntity, {
     offset: new Cesium.HeadingPitchRange(0, -90, 300),
   })
 }
+
+// const createPointOrPolyline = () => {}
 
 // 创建广告牌
 const createBillboard = (title: string | number, color: string) => {
@@ -408,14 +480,256 @@
   return billboard
 }
 
+// 选择点位
+let prevPointEntity: any = null
+let nextPointEntity: any = null
+// 选中的点
+const selectPointIndex = ref<string | number | any>(null)
+const pointSelect = (value: tragetPoint, index: number) => {
+  removeCesiumChildDom(popupDom)
+  if (selectPointIndex.value === index) {
+    global.$viewer.entities.remove(prevPointEntity)
+    global.$viewer.entities.remove(nextPointEntity)
+    kmlEntities.value.forEach((entity: Cesium.Entity | any, i: number) => {
+      entity.billboard.image = createBillboard(i + 1, '#61d396')
+    })
+    selectPointIndex.value = null
+    return
+  }
+  if (prevPointEntity) {
+    global.$viewer.entities.remove(prevPointEntity)
+  }
+  if (nextPointEntity) {
+    global.$viewer.entities.remove(nextPointEntity)
+  }
+  // 点击点相邻两个点的距离
+  const points = _.cloneDeep(tragetPointArr.value)
+  const currentPoint = points[index]?.position
+  const prevPoint = points[index - 1]?.position
+  const nextPoint = points[index + 1]?.position
+  if (prevPoint) {
+    // 获取中心点
+    const centerPoint = Cesium.Cartesian3.lerp(
+      currentPoint,
+      prevPoint,
+      0.5,
+      new Cesium.Cartesian3(),
+    )
+    // 获取两个点之间的距离
+    let distance = Cesium.Cartesian3.distance(currentPoint, prevPoint)
+    distance = Math.round(distance)
+    prevPointEntity = createDistanceLabel(centerPoint, distance)
+  }
+  if (nextPoint) {
+    // 获取中心点
+    const centerPoint = Cesium.Cartesian3.lerp(
+      currentPoint,
+      nextPoint,
+      0.5,
+      new Cesium.Cartesian3(),
+    )
+    // 获取两个点之间的距离
+    let distance = Cesium.Cartesian3.distance(currentPoint, nextPoint)
+    distance = Math.round(distance)
+    nextPointEntity = createDistanceLabel(centerPoint, distance)
+  }
+  // 更新点击点的样式
+  kmlEntities.value.forEach((entity: Cesium.Entity | any, i: number) => {
+    if (i === index) {
+      entity.billboard.image = createBillboard(index + 1, '#f3be4f')
+    } else {
+      entity.billboard.image = createBillboard(i + 1, '#61d396')
+    }
+  })
+  selectPointIndex.value = index
+}
+
+// 添加右键事件,弹出窗口
+const showCreatePointPopup = ref<boolean>(false)
+let popupDom: any = null
+const addMapPointEvent = () => {
+  mouseRightClickEvent = true
+  addRightClick('', (click: { position: Cesium.Cartesian2 }) => {
+    showCreatePointPopup.value = true
+    removeCesiumChildDom(popupDom)
+    const { position } = click
+    const { x, y } = position
+    const pointEvents = [
+      {
+        class: 'add-prev-point',
+        title: `在${Number(selectPointIndex.value) + 1}号航点前插入`,
+      },
+      {
+        class: 'add-next-point',
+        title: `在${Number(selectPointIndex.value) + 1}号航点前插入`,
+      },
+    ]
+    const defaultEvents = [
+      { class: 'finally-point', title: '在最后航点新增航点' },
+    ]
+    const events =
+      selectPointIndex.value !== null
+        ? [...defaultEvents, ...pointEvents]
+        : defaultEvents
+    popupDom = createPointPopupDom(events)
+    global.$viewer.container.appendChild(popupDom)
+    popupDom.style.transform = `translate3d(${x}px, ${y}px, 0)`
+    // 添加点击事件
+    addMenuEvent(popupDom, position)
+  })
+}
+
+// 创建距离标签
+const createDistanceLabel = (position: Cesium.Cartesian3, dist: number) => {
+  return global.$viewer.entities.add({
+    position: position,
+    name: 'distance',
+    label: {
+      text: `${dist}m`,
+      font: '13px monospace',
+      showBackground: true,
+      horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
+      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+      disableDepthTestDistance: Number.POSITIVE_INFINITY,
+      pixelOffset: new Cesium.Cartesian2(0, -0),
+    },
+  })
+}
+
+// 创建右键弹窗
+const createPointPopupDom = (arr: any[] = []) => {
+  const pointPopup: HTMLDivElement | any = document.createElement('div')
+  pointPopup.className = 'point-popup'
+  arr.forEach((item) => {
+    const title: HTMLDivElement | any = document.createElement('div')
+    title.innerText = item.title
+    title.className = item.class
+    title.style = `
+      cursor: pointer;
+      padding: 5px 7px;
+    `
+    pointPopup.appendChild(title)
+  })
+  pointPopup.style = `
+    width: 'fit-content';
+    background-color: #232323;
+    position: absolute;
+    top: 0;
+    left: 0;
+    color: #fff;
+  `
+  return pointPopup
+}
+// 给DOM添加点击事件
+const addMenuEvent = (dom: HTMLElement, position: Cesium.Cartesian2) => {
+  dom.addEventListener('click', (e: any) => {
+    removeCesiumChildDom(popupDom)
+    const className = e.target.className
+    const c3Position = global.$viewer.scene.globe.pick(
+      global.$viewer.camera.getPickRay(position),
+      global.$viewer.scene,
+    )
+    const c2Postion = ellipsoid.cartesianToCartographic(c3Position)
+    const longitude = Cesium.Math.toDegrees(c2Postion.longitude)
+    const latitude = Cesium.Math.toDegrees(c2Postion.latitude)
+    const height = 70
+    const createPointPosition = Cesium.Cartesian3.fromDegrees(
+      longitude,
+      latitude,
+      height,
+    )
+    let entity: Cesium.Entity | any = null
+    if (className === 'finally-point') {
+      entity = global.$viewer.entities.add({
+        position: createPointPosition,
+        label: {
+          text: 'ASL:70m',
+          font: '13px monospace',
+          showBackground: true,
+          horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
+          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
+          disableDepthTestDistance: Number.POSITIVE_INFINITY,
+          pixelOffset: new Cesium.Cartesian2(0, -40),
+        },
+        billboard: {
+          image: createBillboard(tragetPointArr.value.length + 1, '#61d396'),
+          pixelOffset: new Cesium.Cartesian2(0, -20),
+        },
+        point: {
+          pixelSize: 20,
+          color: Cesium.Color.GHOSTWHITE,
+          outlineColor: Cesium.Color.BLACK,
+        },
+      })
+      const prePostion =
+        tragetPointArr.value[tragetPointArr.value.length - 1].position
+      const polylinePositions = [prePostion, createPointPosition]
+      addPolyline({
+        polyline: {
+          positions: polylinePositions,
+          width: 7,
+          material: new ImageTrailMaterial({
+            backgroundColor: Cesium.Color.fromBytes(96, 210, 149),
+            image: getResource('arrow-right.png'),
+            imageW: 7,
+            duration: 0,
+            animation: false,
+          }),
+          clampToGround: false, // 关闭贴地效果,保留高度
+        },
+      })
+      addPolyline({
+        polyline: {
+          positions: Cesium.Cartesian3.fromDegreesArrayHeights([
+            longitude,
+            latitude,
+            height,
+            longitude,
+            latitude,
+            0,
+          ]),
+          width: 1,
+          material: new Cesium.PolylineDashMaterialProperty({
+            color: Cesium.Color.WHITE,
+          }),
+        },
+      })
+      tragetPointArr.value.push({
+        position: createPointPosition,
+        eventList: [],
+      })
+    }
+    // clearCesiumMap()
+    // createMapMarker(undefined, [...kmlEntities.value, entity])
+  })
+}
+
+// 移除popup弹窗
+const removeCesiumChildDom = (dom: HTMLElement) => {
+  if (dom) {
+    global.$viewer.container.removeChild(dom)
+    popupDom = null
+  }
+}
+
 const backPage = () => {
   emits('backFn')
+}
+// 清空画布
+const clearCesiumMap = () => {
+  removeAllPoint()
+  global.$viewer.dataSources.removeAll()
+
+  removeCesiumChildDom(popupDom)
+
+  if (mouseRightClickEvent) {
+    removeRightClickEvent()
+  }
 }
 
 onMounted(() => {
   // 清空画布
-  removeAllPoint()
-  global.$viewer.dataSources.removeAll()
+  clearCesiumMap()
   initDrawRoute()
 })
 
@@ -423,8 +737,7 @@
   // if (kmlDataSource) {
   //   global.$viewer.dataSources.remove(kmlDataSource)
   // }
-  removeAllPoint()
-  global.$viewer.dataSources.removeAll()
+  clearCesiumMap()
   store.commit('SET_WAYLINE_INFO', {
     isShow: false,
     wayline: {},
@@ -495,6 +808,8 @@
 
   .point-list {
     padding: 0;
+    height: calc(100vh - 180px);
+    overflow: auto;
     li {
       cursor: pointer;
       padding: 10px 0;
@@ -509,7 +824,7 @@
         .left {
           width: 0;
           height: 0;
-          border-top: 15px solid #2d8cf0;
+          border-top: 15px solid #61d396;
           border-right: 10px solid transparent;
           border-left: 10px solid transparent;
         }
@@ -545,4 +860,12 @@
     }
   }
 }
+.active-point {
+  background-color: #3c3c3c;
+  .graph {
+    .left {
+      border-top-color: #f3bf4e !important;
+    }
+  }
+}
 </style>
diff --git a/src/pages/page-web/projects/wayline.vue b/src/pages/page-web/projects/wayline.vue
index 37771e5..ce39371 100644
--- a/src/pages/page-web/projects/wayline.vue
+++ b/src/pages/page-web/projects/wayline.vue
@@ -461,7 +461,7 @@
     value: 0
   },
 ])
-function createPointMarker (dataSource: { entities: { values: { _children: any }[] }; show: boolean }) {
+async function createPointMarker (dataSource: { entities: { values: { _children: any }[] }; show: boolean }) {
   const ellipsoid = global.$viewer.scene.globe.ellipsoid
   kmlEntity.value = dataSource.entities.values
   dataSource.show = true
diff --git a/src/utils/cesium/kmz.ts b/src/utils/cesium/kmz.ts
index 3b2e345..47f3964 100644
--- a/src/utils/cesium/kmz.ts
+++ b/src/utils/cesium/kmz.ts
@@ -48,5 +48,5 @@
       )
     }
   }
-  return source.match(regx)
+  return source?.match(regx)
 }
diff --git a/src/utils/cesium/mapUtils.ts b/src/utils/cesium/mapUtils.ts
index 97297d4..7ea2e20 100644
--- a/src/utils/cesium/mapUtils.ts
+++ b/src/utils/cesium/mapUtils.ts
@@ -23,6 +23,7 @@
   return s * 1000
 }
 
+// 获取限polyline长度
 export function getPolylineLength (entity: any) {
   let length = 0
 

--
Gitblit v1.9.3