GuLiMmo
2024-03-01 d87242f609a6ebaba6f2b45b2c0b41f961e92d4b
update
7 files modified
444 ■■■■■ changed files
src/components/cesiumMap/cesium.vue 1 ●●●● patch | view | raw | blame | history
src/hooks/use-cesium-tsa.ts 24 ●●●● patch | view | raw | blame | history
src/pages/page-web/projects/components/route-edit/components/setting.vue 41 ●●●●● patch | view | raw | blame | history
src/pages/page-web/projects/components/route-edit/index.vue 373 ●●●●● patch | view | raw | blame | history
src/pages/page-web/projects/wayline.vue 2 ●●● patch | view | raw | blame | history
src/utils/cesium/kmz.ts 2 ●●● patch | view | raw | blame | history
src/utils/cesium/mapUtils.ts 1 ●●●● patch | view | raw | blame | history
src/components/cesiumMap/cesium.vue
@@ -151,6 +151,7 @@
<style scoped lang="scss">
.cesium {
  position: relative;
  :deep(.cesium-viewer-bottom) {
    display: none !important;
  }
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
  }
}
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>
今日情况
航线展示:照片计算 (已完成)
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>
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
src/utils/cesium/kmz.ts
@@ -48,5 +48,5 @@
      )
    }
  }
  return source.match(regx)
  return source?.match(regx)
}
src/utils/cesium/mapUtils.ts
@@ -23,6 +23,7 @@
  return s * 1000
}
// 获取限polyline长度
export function getPolylineLength (entity: any) {
  let length = 0