GuLiMmo
2024-03-22 61f272f4a510ff5cbb1d35283fd3399d605b28a5
update
2 files modified
1 files added
259 ■■■■■ changed files
src/components/waylinetool/event-edit.vue 153 ●●●●● patch | view | raw | blame | history
src/pages/page-web/projects/components/route-edit/index.vue 1 ●●●● patch | view | raw | blame | history
src/utils/turf.ts 105 ●●●●● patch | view | raw | blame | history
src/components/waylinetool/event-edit.vue
@@ -12,8 +12,33 @@
        </div>
      </div>
      <div class="event-edit">
        <!-- 单拍 -->
        <template v-if="currentPointEvent.aciton.key === 'takePhoto'">
          1
          <div class="take-photo">
            <div class="title">
              <span
                :style="{
                  color: isTakePhotoNameShow || takePhotoSetting.fileSuffix ? 'rgba(255,255,255,0.4)' : '#fff',
                }"
                >DJI_YYYYMMDDhhmm_XXX_</span
              >
              <span @click="isTakePhotoNameShow = !isTakePhotoNameShow"><EditOutlined /></span>
            </div>
            <div class="title-name-input" v-if="isTakePhotoNameShow">
              <div class="input"><a-input size="small" v-model:value="takePhotoSetting.fileSuffix"></a-input></div>
              <div class="btn">
                <span class="check"><CheckOutlined /></span>
                <span class="close"><CloseOutlined /></span>
              </div>
            </div>
            <div class="photo-format">
              <a-button type="primary" shape="round" size="small" @click="photoFormatClick('wide')">广角照片</a-button>
              <a-button type="primary" shape="round" size="small" @click="photoFormatClick('zoom')">变焦照片</a-button>
              <a-button type="primary" shape="round" size="small" @click="photoFormatClick('global')"
                >跟随全局</a-button
              >
            </div>
          </div>
        </template>
      </div>
    </div>
@@ -22,7 +47,8 @@
</template>
<script lang="ts" setup>
import { DeleteOutlined } from '@ant-design/icons-vue'
import _ from 'lodash'
import { DeleteOutlined, EditOutlined, CheckOutlined, CloseOutlined } from '@ant-design/icons-vue'
import { useMyStore } from '/@/store'
import { actionList } from '/@/utils/cesium/use-map-draw'
import { template as xmlTemplate } from '/@/utils/cesium/use-kmz-tsa'
@@ -33,25 +59,79 @@
// 当前点事件
const selectedAction = computed(() => store.state.waylineTool.selectedAction)
// 当前点位
const serial = reactive<{
  placemark: number
  action: number
}>({
  placemark: 0,
  action: 0,
})
const currentPointEvent = computed(() => {
  const placemarks = xmlTemplate.value.Folder.Placemark
  const pointIndex = store.state.waylineTool.selectedPoint
  if (pointIndex === undefined) return null
  const currentPoint = placemarks[pointIndex]
  serial.placemark = pointIndex
  const actions = currentPoint.actionGroup.action
  let actionIndex = 1
  let actionIndex = 0
  if (Array.isArray(actions)) {
    actionIndex = actions.findIndex((item: { actionActuatorFunc: { '#text': string } }) => {
      return item.actionActuatorFunc['#text'] === selectedAction.value.key
    })
  }
  serial.action = actionIndex
  return {
    aciton: selectedAction.value,
    actionIndex: `${pointIndex + 1}-${actionIndex + 1}`,
  }
})
// 单拍
const isTakePhotoNameShow = ref<boolean>(false)
const takePhotoSetting = reactive({
  fileSuffix: '',
  payloadLensIndex: '',
  useGlobalPayloadLensIndex: 0,
})
const photoFormatClick = (value: string) => {
  if (value === 'global') {
    takePhotoSetting.useGlobalPayloadLensIndex = 1
  } else {
    let formats = takePhotoSetting.payloadLensIndex.split(',')
    const index = formats.findIndex((item: string) => item === value)
    if (index === -1) {
      if (takePhotoSetting.payloadLensIndex === '') {
        formats = [value]
      } else {
        formats.push(value)
      }
    } else {
      formats.splice(index, 1)
    }
    takePhotoSetting.payloadLensIndex = formats.join(',')
  }
  addActionParam(takePhotoSetting)
}
const handleDelAction = () => {}
// 加入事件参数
const addActionParam = <T extends { [key: string] : string }, >(params: T): void => {
  const obj = _.cloneDeep(params)
  const placemarks = xmlTemplate.value.Folder.Placemark
  let aciton = placemarks[serial.placemark].actionGroup?.action
  if (Array.isArray(aciton)) {
    aciton = aciton[serial.action]
  }
  console.log(aciton)
  const actionActuatorFuncParam = aciton.actionActuatorFuncParam
  // Object.keys(obj).forEach((key: string) => {
  //   if (!obj[key]) {
  //     delete obj[key]
  //   }
  // })
}
</script>
<style lang="scss" scoped>
@@ -104,6 +184,73 @@
      height: calc(100% - 50px);
      padding: 15px;
      overflow: auto;
      // 单排
      .take-photo {
        .title {
          display: flex;
          justify-content: flex-end;
          span {
            &:first-child {
              margin-right: auto;
            }
            &:last-child {
              cursor: pointer;
              &:hover {
                color: #409eff;
              }
            }
          }
        }
        .title-name-input {
          margin-top: 5px;
          display: flex;
          align-items: center;
          justify-content: center;
          .input {
            flex: 1;
            input {
              background-color: transparent;
              color: #fff;
            }
          }
          .btn {
            width: 50px;
            display: flex;
            gap: 10px;
            justify-content: center;
            align-items: center;
            span {
              cursor: pointer;
            }
            .check {
              color: #67d15a;
            }
            .close {
              color: red;
            }
          }
        }
        .photo-format {
          margin-top: 20px;
          display: flex;
          justify-content: flex-start;
          .ant-btn {
            margin-left: 10px;
            font-weight: bold;
            &:first-child {
              margin: 0;
            }
            &:nth-child(3) {
              margin-left: auto;
            }
          }
        }
      }
      .cannot-select {
        background-color: #3c3c3c;
        border: 0;
      }
    }
  }
  .map-box {
src/pages/page-web/projects/components/route-edit/index.vue
@@ -566,7 +566,6 @@
  }
  selectedPointAndAction.selectedPoint = index
  selectedPointAndAction.selectedAction = action.key
  console.log(params)
  store.commit('SET_WAYLINE_INFO', params)
}
src/utils/turf.ts
New file
@@ -0,0 +1,105 @@
/*
 * @Author: GuLiMmo 2820890765@qq.com
 * @Date: 2024-03-22 08:50:18
 * @LastEditors: GuLiMmo 2820890765@qq.com
 * @LastEditTime: 2024-03-22 08:57:01
 * @FilePath: /drone-web/src/utils/turf.ts
 * @Description: turf
 *
 * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
 */
import * as turf from '@turf/turf'
import * as Cesium from 'cesium'
// 中心点
export function getRegionCenter (params: any[]) {
  const arr: any[] = []
  params.forEach((areaArray) => {
    const data = JSON.parse(areaArray)
    if (data.type === 'Polygon') {
      data.coordinates.forEach((item: turf.helpers.Position[]) => {
        arr.push(turf.centroid(turf.polygon([item])).geometry.coordinates)
      })
    } else {
      data.coordinates.forEach((item: turf.helpers.Position[][]) => {
        arr.push(turf.centroid(turf.polygon([item[0]])).geometry.coordinates)
      })
    }
  })
  if (arr.length === 1) {
    return arr[0]
  } else if (arr.length === 2) {
    return turf.centroid(turf.midpoint(turf.point(arr[0]), turf.point(arr[1]))).geometry.coordinates
  } else {
    arr.push(arr[0])
    return turf.centroid(turf.polygon([arr])).geometry.coordinates
  }
}
// 最值
export const getMapBounds = (data: { x: number; y: number }[], type = '') => {
  const pointArr: turf.helpers.Feature<turf.helpers.Geometry, turf.helpers.Properties>[] = []
  data.forEach((item: { x: number; y: number }) => {
    pointArr.push(turf.point([item.x, item.y]))
    return false
  })
  const features = turf.featureCollection(pointArr)
  const scope = turf.envelope(features).bbox
  // const poly = turf.polygon([[[0, 29], [3.5, 29], [2.5, 32], [0, 29]]])
  return scope
}
// 加载面
export function addDataToGlobe (polygonArr: string[], viewer: Cesium.Viewer) {
  const polygonInstances: any[] = []
  polygonArr.forEach((item: string, index: any) => {
    let position: any = item
      .slice(9, item.length - 2)
      .replace(/,/g, ';')
      .replace(/ /g, ',')
      .split(';')
    position = position.map((item: string) => item.split(',').map((i) => Number(i)))
    position = position.map((item: any) => Cesium.GeoJsonDataSource.crsNames['EPSG:4524'](item))
    const polygonArr = position.reduce((pre: any[], cur: any[]) => {
      pre.push(cur[0])
      pre.push(cur[1])
      return pre
    }, [])
    // polygonArr 格式 [112, 24, 115, 25, 116, 27]
    const polygon = new Cesium.PolygonGeometry({
      polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(polygonArr)),
      vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
    })
    const geometry = Cesium.PolygonGeometry.createGeometry(polygon)
    polygonInstances.push(
      new Cesium.GeometryInstance({
        geometry: geometry as any,
        attributes: {
          color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.GREEN),
        },
      }),
    )
  })
  const polylinePrimitive = new Cesium.Primitive({
    geometryInstances: polygonInstances,
    appearance: new Cesium.PerInstanceColorAppearance(),
    asynchronous: false, // 确定基元是异步创建还是阻塞直到准备就绪
  })
  viewer.scene.primitives.add(polylinePrimitive)
}