GuLiMmo
2024-03-20 e72969f25dd1a243e48c783dedc0f198ee08c2b8
update:新增航线、航点事件编辑
7 files modified
4 files added
279 ■■■■ changed files
src/assets/icons/waylinetool/cursor.png patch | view | raw | blame | history
src/assets/icons/waylinetool/startpoint.png patch | view | raw | blame | history
src/assets/icons/waylinetool/无人机起降场.png patch | view | raw | blame | history
src/components/GMap.vue 2 ●●● patch | view | raw | blame | history
src/hooks/use-cesium-tsa.ts 3 ●●●●● patch | view | raw | blame | history
src/pages/page-web/projects/components/route-edit/components/setting-point-tip.vue 72 ●●●●● patch | view | raw | blame | history
src/pages/page-web/projects/components/route-edit/components/setting.vue 51 ●●●● patch | view | raw | blame | history
src/pages/page-web/projects/components/route-edit/index.vue 52 ●●●● patch | view | raw | blame | history
src/pages/page-web/projects/wayline.vue 6 ●●●●● patch | view | raw | blame | history
src/utils/cesium/use-kmz-tsa.ts 69 ●●●● patch | view | raw | blame | history
src/utils/cesium/use-map-draw.ts 24 ●●●● patch | view | raw | blame | history
src/assets/icons/waylinetool/cursor.png
src/assets/icons/waylinetool/startpoint.png
src/assets/icons/waylinetool/无人机起降场.png
src/components/GMap.vue
@@ -848,7 +848,7 @@
          :payloads="osdVisible.payloads">
        </DroneControlPanel>
      </div>
      <waylineTool />
      <!-- <waylineTool /> -->
      <routeProfile />
    </div>
    <div class="event-wrapper" v-if="false">
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)
  }
  // 移除左键事件
src/pages/page-web/projects/components/route-edit/components/setting-point-tip.vue
New file
@@ -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>
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 {
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 {
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)
        }
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: [],
        },
      }
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,9 +309,10 @@
      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 (point !== undefined) {
      if (Reflect.has(point, 'actionGroup')) {
        const action = point.actionGroup.action
        if (Array.isArray(action)) {
@@ -316,10 +323,12 @@
            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)
            action?.actionActuatorFunc['#text'] === 'takePhoto' && takePhotoNum++
            const actionObj: eventParmas | any = actionList.find(
              (item) => action?.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 {