From a51171f691ec516929fbb29356ad9074d0439b6e Mon Sep 17 00:00:00 2001
From: GuLiMmo <2820890765@qq.com>
Date: Thu, 07 Mar 2024 17:32:45 +0800
Subject: [PATCH] update: 右键新增航线、事件编辑、kmz文件编辑

---
 src/utils/cesium/use-map-draw.ts                                         |    9 +
 src/pages/page-web/projects/components/route-edit/index.vue              |  212 +++++++++++++----------------------
 src/utils/cesium/use-kmz-tsa.ts                                          |   73 ++++++++++-
 src/utils/cesium/kmz.ts                                                  |   16 ++
 src/pages/page-web/projects/components/route-edit/components/setting.vue |    6 
 src/utils/cesium/mapUtils.ts                                             |   31 +++-
 6 files changed, 187 insertions(+), 160 deletions(-)

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 4f75774..c898a23 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
@@ -86,7 +86,7 @@
                   <li @click="numberControls(true, 100, 'globalHeight')">+100</li>
                   <li @click="numberControls(true, 10, 'globalHeight')">+10</li>
                   <li>
-                    <span>{{ Number(folderSetting.globalHeight) }}</span> m
+                    <span>{{ Math.round(folderSetting.globalHeight) }}</span> m
                   </li>
                   <li @click="numberControls(false, 100, 'globalHeight')">-100</li>
                   <li @click="numberControls(false, 10, 'globalHeight')">-10</li>
@@ -124,6 +124,7 @@
 import useMapDraw from '/@/utils/cesium/use-map-draw'
 import { getKmlParams } from '/@/utils/cesium/kmz'
 import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
+import { message } from 'ant-design-vue'
 import type { missionConfig, payloadParam as payloadParamConfig, Folder } from '/@/utils/cesium/types/kml'
 const { appContext }: any = getCurrentInstance()
 const global = appContext.config.globalProperties
@@ -227,6 +228,9 @@
     if (missionConfigSetting[key]) {
       missionConfigSetting[key] -= computeVal
     } else {
+      if (folderSetting[key] - computeVal <= 0) {
+        return message.warn('飞行高度较低!!!!')
+      }
       folderSetting[key] -= computeVal
     }
   }
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 c568d50..ea4e04e 100644
--- a/src/pages/page-web/projects/components/route-edit/index.vue
+++ b/src/pages/page-web/projects/components/route-edit/index.vue
@@ -7,17 +7,14 @@
         </template>
         返回
       </a-button>
-      <div class="save-button">
+      <div class="save-button" @click="saveWaylineFile">
         <SaveOutlined />
       </div>
       <setting v-model:loadCompleted="loadCompleted">
         <template #show>
           <a-button type="text" class="setting-btn">
             <div class="router-setting">
-              <img
-                class="wayline-icon"
-                :src="getResource('wayline.png')"
-                alt="icon" />
+              <img class="wayline-icon" :src="getResource('wayline.png')" alt="icon" />
               <span class="text">航线设置</span>
               <CaretDownOutlined />
             </div>
@@ -26,10 +23,7 @@
       </setting>
     </div>
     <div class="wayline-info">
-      <div
-        class="info-box"
-        v-for="(item, index) in waylineDetails"
-        :key="index">
+      <div class="info-box" v-for="(item, index) in waylineDetails" :key="index">
         <div class="title">{{ item.title }}</div>
         <div class="info">{{ item.value }}</div>
       </div>
@@ -45,10 +39,7 @@
           <div class="right">{{ index + 1 }}</div>
         </div>
         <div class="graph-right">
-          <div
-            v-for="(event, index) in item.eventList"
-            :key="index"
-            class="s-event-icon">
+          <div v-for="(event, index) in item.eventList" :key="index" class="s-event-icon">
             <a-tooltip placement="top">
               <template #title>
                 {{ event.name }}
@@ -66,24 +57,23 @@
 import _ from 'lodash'
 import * as Cesium from 'cesium'
 import setting from './components/setting.vue'
-import useKmzTsa from '/@/utils/cesium/use-kmz-tsa'
+import useKmzTsa, { kmlStr } from '/@/utils/cesium/use-kmz-tsa'
 import { ref, reactive, 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 from '/@/utils/cesium/use-map-draw'
+import useMapDraw, { kmlEntities as globalEntities } from '/@/utils/cesium/use-map-draw'
+import { getKmlParams } from '/@/utils/cesium/kmz'
+import { getHaeHeight } from '/@/utils/cesium/mapUtils'
 const store = useMyStore()
 const { appContext }: any = getCurrentInstance()
 const global = appContext.config.globalProperties
 
-const {
-  removeAllPoint,
-  getEntityById,
-  addPolyline,
-  addRightClick,
-  removeRightClickEvent,
-} = cesiumOperation()
+const kmzUtils = useKmzTsa()
+
+const { removeAllPoint, getEntityById, addPolyline, removeAllDataSource, addRightClick, removeRightClickEvent } =
+  cesiumOperation()
 
 interface waylineDetails {
   title: string
@@ -116,15 +106,12 @@
 
 const tragetPointArr = ref<tragetPoint[]>([])
 
-let kmlDataSource:
-  | { entities: { values: { _children: any }[] }; show: boolean }
-  | null
-  | any = null
+let kmlDataSource: { entities: { values: { _children: any }[] }; show: boolean } | null | any = null
 
 let mouseRightClickEvent: any = null
 
 // 绘制地图上的东西
-let mapDraw = null
+let mapDraw: any = null
 // 航线详情
 const waylineDetails = ref<waylineDetails[]>([])
 // 样式
@@ -141,31 +128,29 @@
   if (kmlDataSource) {
     global.$viewer.dataSources.remove(kmlDataSource)
   }
-  global.$viewer.dataSources
-    .add(Cesium.KmlDataSource.load(filePath.value, options))
-    .then((res: any) => {
-      kmlDataSource = res
-      mapDraw = useMapDraw(kmlDataSource, [], filePath.value, global)
-      const {
-        drawWayline,
-        waylineDetails: details,
-        waylinePointsEvent,
-        kmlEntities: entities,
-        clearWaylineData
-      } = mapDraw
-      clearWaylineData()
-      drawWayline()
-      useKmzTsa().init(filePath.value).then(kmlRes => {
-        loadCompleted.value = true
-      })
-      waylineDetails.value = details
-      tragetPointArr.value = waylinePointsEvent.value
-      kmlEntities.value = entities.value
-      if (!mouseRightClickEvent) {
-        // 添加右键事件
-        addMapPointEvent()
-      }
+  global.$viewer.dataSources.add(Cesium.KmlDataSource.load(filePath.value, options)).then((res: any) => {
+    kmlDataSource = res
+    mapDraw = useMapDraw(kmlDataSource, [], filePath.value, global)
+    const {
+      drawWayline,
+      waylineDetails: details,
+      waylinePointsEvent,
+      kmlEntities: entities,
+      clearWaylineData,
+    } = mapDraw
+    clearWaylineData()
+    drawWayline()
+    kmzUtils.init(filePath.value).then((kmlRes) => {
+      loadCompleted.value = true
     })
+    waylineDetails.value = details
+    tragetPointArr.value = waylinePointsEvent.value
+    kmlEntities.value = entities.value
+    if (!mouseRightClickEvent) {
+      // 添加右键事件
+      addMapPointEvent()
+    }
+  })
 }
 
 // const createPointOrPolyline = () => {}
@@ -219,12 +204,7 @@
   const nextPoint = points[index + 1]?.position
   if (prevPoint) {
     // 获取中心点
-    const centerPoint = Cesium.Cartesian3.lerp(
-      currentPoint,
-      prevPoint,
-      0.5,
-      new Cesium.Cartesian3(),
-    )
+    const centerPoint = Cesium.Cartesian3.lerp(currentPoint, prevPoint, 0.5, new Cesium.Cartesian3())
     // 获取两个点之间的距离
     let distance = Cesium.Cartesian3.distance(currentPoint, prevPoint)
     distance = Math.round(distance)
@@ -232,12 +212,7 @@
   }
   if (nextPoint) {
     // 获取中心点
-    const centerPoint = Cesium.Cartesian3.lerp(
-      currentPoint,
-      nextPoint,
-      0.5,
-      new Cesium.Cartesian3(),
-    )
+    const centerPoint = Cesium.Cartesian3.lerp(currentPoint, nextPoint, 0.5, new Cesium.Cartesian3())
     // 获取两个点之间的距离
     let distance = Cesium.Cartesian3.distance(currentPoint, nextPoint)
     distance = Math.round(distance)
@@ -274,13 +249,8 @@
         title: `在${Number(selectPointIndex.value) + 1}号航点前插入`,
       },
     ]
-    const defaultEvents = [
-      { class: 'finally-point', title: '在最后航点新增航点' },
-    ]
-    const events =
-      selectPointIndex.value !== null
-        ? [...defaultEvents, ...pointEvents]
-        : defaultEvents
+    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)`
@@ -330,84 +300,53 @@
   `
   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 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,
+    // 获取全局高度
+    const globalHeight: any = getKmlParams(kmlStr.value, true, {
+      name: 'globalHeight',
+      findRegx: '([\\s\\S]*?)',
+    })
+    const height = Number(globalHeight[1])
+    const createPointPosition = Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
+    const entity: Cesium.Entity = global.$viewer.entities.add({
+      position: createPointPosition,
+    })
+    // 加入kml文件中
+    const setting = {
+      Point: {
+        coordinates: `${longitude},${latitude}`,
+      },
+      index: tragetPointArr.value.length,
       height,
-    )
-    let entity: Cesium.Entity | any = null
+      ellipsoidHeight: height,
+    }
     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,
-          }),
-        },
-      })
+      removeAllDataSource()
+      removeAllPoint()
+      kmzUtils.writePoint(setting)
+      globalEntities.value.push(entity)
+      mapDraw.drawWayline(globalEntities.value, kmlStr.value)
       tragetPointArr.value.push({
         position: createPointPosition,
         eventList: [],
       })
+    }
+    if (className === 'add-prev-point') {
+      // console.log(1)
+    }
+    if (className === 'add-next-point') {
+      // const index = selectPointIndex.value
+      // globalEntities.value.splice(index, 0, entity)
+      // console.log()
     }
     // clearCesiumMap()
     // createMapMarker(undefined, [...kmlEntities.value, entity])
@@ -437,6 +376,11 @@
   }
 }
 
+// 保存文件
+const saveWaylineFile = () => {
+  kmzUtils.save()
+}
+
 onMounted(() => {
   // 清空画布
   clearCesiumMap()
diff --git a/src/utils/cesium/kmz.ts b/src/utils/cesium/kmz.ts
index ed14c43..fd1c3a8 100644
--- a/src/utils/cesium/kmz.ts
+++ b/src/utils/cesium/kmz.ts
@@ -2,6 +2,8 @@
 import { mode } from 'crypto-js'
 import JsZip from 'jszip'
 
+const noWmpl: string[] = ['Folder', 'Placemark', 'Point', 'coordinates']
+
 /**
  * @description: 读取kmz文件解析出kml文件
  * @param {string} filePath 文件地址
@@ -15,7 +17,10 @@
     .then((kmzZip) => {
       // 通过文件名找到 KML 文件
       const kmlFile = kmzZip.file(/\.kml$/i)[0]
-      return kmlFile.async('text')
+      return {
+        file: kmzZip,
+        content: kmlFile.async('text')
+      }
     })
 }
 
@@ -47,11 +52,14 @@
     if (Object.prototype.toString.call(settingParmas[key]) === '[object Object]') {
       let parmaStr = ''
       Object.keys(settingParmas[key]).forEach((v) => {
-        parmaStr += `<wpml:${v}>${settingParmas[key][v]}</wpml:${v}>`
+        const xml = noWmpl.includes(key) ? `<${v}>${settingParmas[key][v]}</${v}>` : `<wpml:${v}>${settingParmas[key][v]}</wpml:${v}>`
+        parmaStr += xml
       })
-      paramGroup += `<wpml:${key}>${parmaStr}</wpml:${key}>`
+      const xml = noWmpl.includes(key) ? `<${key}>${parmaStr}</${key}>` : `<wpml:${key}>${parmaStr}</wpml:${key}>`
+      paramGroup += xml
     } else {
-      paramGroup += `<wpml:${key}>${settingParmas[key]}</wpml:${key}>`
+      const xml = noWmpl.includes(key) ? `<${key}>${settingParmas[key]}</${key}>` : `<wpml:${key}>${settingParmas[key]}</wpml:${key}>`
+      paramGroup += xml
     }
   })
   return paramGroup
diff --git a/src/utils/cesium/mapUtils.ts b/src/utils/cesium/mapUtils.ts
index c84671c..ef5b8f6 100644
--- a/src/utils/cesium/mapUtils.ts
+++ b/src/utils/cesium/mapUtils.ts
@@ -1,11 +1,6 @@
 import * as Cesium from 'cesium'
 
-export const getLngLatDistance = (
-  lat1: number,
-  lng1: number,
-  lat2: number,
-  lng2: number,
-) => {
+export const getLngLatDistance = (lat1: number, lng1: number, lat2: number, lng2: number) => {
   const radLat1 = (lat1 * Math.PI) / 180.0
   const radLat2 = (lat2 * Math.PI) / 180.0
   const a = radLat1 - radLat2
@@ -13,10 +8,7 @@
   let s =
     2 *
     Math.asin(
-      Math.sqrt(
-        Math.pow(Math.sin(a / 2), 2) +
-          Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2),
-      ),
+      Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)),
     )
   s = s * 6378.137 // EARTH_RADIUS;
   s = Math.round(s * 10000) / 10000
@@ -63,3 +55,22 @@
   ctx.closePath()
   return billboard
 }
+
+// 获取当前经纬度海拔
+export const getHaeHeight = (start: { longitude: number; latitude: number; height: number }, end: { longitude: number; latitude: number; height: number }) => {
+  const ellipsoid = Cesium.Ellipsoid.WGS84 // 选择合适的椭圆体模型
+  // const { longitude, latitude, height } = start
+  // const { longitude: endLng, latitude: endLat, height: endHeight } = end
+  // const startC3Position = new Cesium.Cartographic(longitude, latitude, height)
+  // const endC3Position = new Cesium.Cartographic(endLng, endLat, endHeight)
+  // const startCartesianPosition = ellipsoid.cartographicToCartesian(startC3Position)
+  // const endCartesianPosition = ellipsoid.cartographicToCartesian(endC3Position)
+  // // 计算两个位置之间的距离
+  // const distance = new Cesium.EllipsoidGeodesic(startCartesianPosition, endCartesianPosition, ellipsoid)
+  // return distance
+  const { longitude, latitude, height } = end
+  const cartographic = Cesium.Cartographic.fromDegrees(longitude, latitude, height)
+  const cartesianPosition = ellipsoid.cartographicToCartesian(cartographic)
+  const haeHeight = ellipsoid.cartesianToCartographic(cartesianPosition).height
+  return haeHeight
+}
diff --git a/src/utils/cesium/use-kmz-tsa.ts b/src/utils/cesium/use-kmz-tsa.ts
index a37e16e..2f49acf 100644
--- a/src/utils/cesium/use-kmz-tsa.ts
+++ b/src/utils/cesium/use-kmz-tsa.ts
@@ -1,11 +1,47 @@
-import { ref } from 'vue'
+import { ref, getCurrentInstance } from 'vue'
 import { analyzeKmzFile, getKmlParams, generateKmlFormat } from '/@/utils/cesium/kmz'
+import { getLngLatAltitude } from './mapUtils'
+import JSZIP from 'jszip'
+import { saveAs } from 'file-saver'
+
+const JsZip = new JSZIP()
 
 const kmlStr = ref('')
+const kmzFile = ref<any>(null)
+
+// 点位参数
+const placemark: any = {
+  Point: {
+    coordinates: '',
+  },
+  index: 0,
+  executeHeight: 80,
+  height: 80,
+  waypointSpeed: 10,
+  waypointHeadingParam: {
+    waypointHeadingMode: 'followWayline',
+    waypointHeadingAngle: 0,
+    waypointPoiPoint: '0.000000,0.000000,0.000000',
+    waypointHeadingPathMode: 'followBadArc',
+    waypointHeadingPoiIndex: 0,
+  },
+  waypointTurnParam: {
+    waypointTurnMode: 'toPointAndStopWithDiscontinuityCurvature',
+    waypointTurnDampingDist: 0.2,
+  },
+  useGlobalHeight: 1,
+  useGlobalSpeed: 1,
+  useGlobalHeadingParam: 1,
+  useGlobalTurnParam: 1,
+  useStraightLine: 1,
+  actionGroup: {},
+}
 
 const useKmzTsa = () => {
   const init = async (fileUrl: string, fileContent?: string) => {
-    const kmzRes: string = await analyzeKmzFile(fileUrl)
+    const fileRes = await analyzeKmzFile(fileUrl)
+    kmzFile.value = fileRes.file
+    const kmzRes = await fileRes.content
     if (fileContent) {
       kmlStr.value = fileContent
       return false
@@ -33,10 +69,26 @@
     kmlStr.value = str
   }
 
-  const write = (settingParmas: any = {}, name?: string, isWpml?: boolean = false) => {}
-
-  const del = () => {
+  // const write = (settingParmas: any = {}, name: string) => {
+  // }
+  const writePoint = (settingParmas: any = {}) => {
+    Object.keys(settingParmas).forEach((key: string) => {
+      placemark[key] = settingParmas[key]
+    })
+    const Placemark = `<Placemark>${generateKmlFormat(placemark)}</Placemark>`
+    const points: RegExpMatchArray = getKmlParams(kmlStr.value, false, {
+      name: 'Placemark',
+      findRegx: '([\\s\\S]*?)',
+      mode: 'g',
+    }) || ['']
+    const lastPoint = points[points.length - 1]
+    const index = kmlStr.value.indexOf(lastPoint)
+    const beforeStr = kmlStr.value.slice(0, index)
+    const afterStr = kmlStr.value.slice(index + lastPoint.length)
+    kmlStr.value = beforeStr + lastPoint + Placemark + afterStr
   }
+
+  const del = () => {}
 
   const edit = (settingParmas: any = {}, keyName?: string, isKeyWpml: boolean = false) => {
     Object.keys(settingParmas).forEach((key: string) => {
@@ -50,7 +102,7 @@
           const regxVal: any = getKmlParams(kmlStr.value, true, {
             name: 'height',
             findRegx: '([\\s\\S]*?)',
-            mode: 'g'
+            mode: 'g',
           })
           regxVal.forEach((heightStr: string) => {
             const rstr = generateKmlFormat({ height: settingParmas[key] })
@@ -66,13 +118,18 @@
   }
 
   const save = () => {
-    console.log(kmlStr.value)
+    JsZip.file('wpmz/template.kml', kmlStr.value)
+    kmzFile.value.file('wpmz/template.kml', kmlStr.value)
+    JsZip.generateAsync({ type: 'blob' }).then((content) => {
+      saveAs(content, '新建航线-' + new Date().toLocaleString() + '.kmz')
+    })
   }
 
   return {
     init,
     create,
-    write,
+    // write,
+    writePoint,
     del,
     edit,
     save,
diff --git a/src/utils/cesium/use-map-draw.ts b/src/utils/cesium/use-map-draw.ts
index 3734bd9..c088045 100644
--- a/src/utils/cesium/use-map-draw.ts
+++ b/src/utils/cesium/use-map-draw.ts
@@ -123,7 +123,8 @@
   let cartesianArr: Cesium.Cartesian3[] = []
 
   //   绘制路线
-  const drawWayline = async (entities: Cesium.Entity[], kmlStr: string) => {
+  const drawWayline = async (entities?: Cesium.Entity[], kmlStr?: string) => {
+    console.log(kmlStr)
     if (!entities && !kmlStr) {
       dataSource.show = false
     }
@@ -137,7 +138,8 @@
     if (kmlStr) {
       kmlRes = kmlStr
     } else {
-      kmlRes = await analyzeKmzFile(fileUrl)
+      const fileRes = await analyzeKmzFile(fileUrl)
+      kmlRes = await fileRes.content
     }
     // 所有航点
     kmlPoints = getKmlParams(kmlRes, false, {
@@ -293,7 +295,8 @@
     if (kmlStr) {
       kmlRes = kmlStr
     } else {
-      await analyzeKmzFile(fileUrl)
+      const fileRes = await analyzeKmzFile(fileUrl)
+      kmlRes = await fileRes.content
     }
     // 所有航点
     const points = getKmlParams(kmlRes, false, {

--
Gitblit v1.9.3