GuLiMmo
2024-02-28 d5e1d8a5f773738f6766175ea409f47740a24c97
src/pages/page-web/projects/wayline.vue
@@ -120,10 +120,17 @@
          <a-input v-model:value="currentWayLine.name" placeholder="请输入航线名称" />
        </a-modal>
      </div>
      <!-- 航线编辑 -->
      <ul class="targt-point scrollbar" :style="{ height: height + 'px' }" v-else>
        <div class="back-btn" @click="isPointListOpen = !isPointListOpen">
        <div class="back-btn" @click="backPage">
          <ArrowLeftOutlined />
          <span>返回上一页</span>
        </div>
        <div class="wayline-info">
          <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>
        </div>
        <li v-for="(item, index) in tragetPointArr" :key="index" :class="{ selectedColor: index === selectedPoint }"
          @click="tragetPointClick(item.position, index)">
@@ -154,6 +161,7 @@
import { message } from 'ant-design-vue'
import { onMounted, onUpdated, ref } from 'vue'
import ImageTrailMaterial from '/@/utils/cesium/ImageTrailMaterial'
import { getPolylineLength } from '/@/utils/cesium/mapUtils'
import {
  deleteWaylineFile,
  downloadWaylineFile,
@@ -188,6 +196,9 @@
const getResource = (name: string) => {
  return new URL(`/src/assets/icons/${name}`, import.meta.url).href
}
const getResourceSvg = (name: string) => {
  return new URL(`/src/assets/svg/${name}`, import.meta.url).href
}
const projectWayLine = ref<HTMLDivElement>()
@@ -226,7 +237,7 @@
)
const editVisible = ref<boolean>(false)
const height = ref()
const { removeById, addClickEvent, getEntityById, addPolyline } = cesiumOperation()
const { removeById, addClickEvent, getEntityById, addPolyline, removeAllPoint } = cesiumOperation()
const isPointListOpen = ref<boolean>(false)
const tragetPointArr = ref<
@@ -333,8 +344,8 @@
  if (kmlDataSource) {
    global.$viewer.dataSources.remove(kmlDataSource)
  }
  removeById('entityLine')
  removeById('bottomLine')
  // removeById('entityLine')
  removeAllPoint()
  removeById('clickBox')
  store.commit('SET_WAYLINE_INFO', {
    isShow: false,
@@ -431,10 +442,8 @@
 * @param file
 */
function initKmlFile (file: string) {
  // const [, address] = file.split('cloud-bucket')
  // file = import.meta.env.VITE_MEDIAPANEL_API_URL + address
  removeById('entityLine')
  removeById('bottomLine')
  // removeById('entityLine')
  removeAllPoint()
  const options = {
    camera: global.$viewer.scene.camera,
    canvas: global.$viewer.scene.canvas,
@@ -447,65 +456,131 @@
    .add(Cesium.KmlDataSource.load(file, options))
    .then((res: any) => {
      kmlDataSource = res
      kmlEntity.value = kmlDataSource.entities.values
      kmlDataSource.show = true
      const kmlEntityArr = kmlDataSource.entities.values[0]._children
      const cartesianArr: any[] = []
      for (let i = 0; i < kmlEntityArr.length; i++) {
        const entity = kmlEntityArr[i]
        const billboard = createBillboard(`${i + 1}`, '#2D8CF0')
        entity._id = 'tragetPoint' + i
        entity.billboard = new Cesium.BillboardGraphics({
          image: billboard,
          pixelOffset: new Cesium.Cartesian2(0, -20),
        })
        entity.point = new Cesium.PointGraphics({
          pixelSize: 20,
          color: Cesium.Color.GHOSTWHITE,
          outlineColor: Cesium.Color.BLACK,
        })
        cartesianArr.push(entity.position._value)
        tragetPointArr.value[i] = {
          position: entity.position._value,
          eventList: [],
        }
      }
      // tragetPointArr.value = cartesianArr
      // const stripe = createStripe()
      // 绘制静态线
      addPolyline({
        id: 'entityLine',
        polyline: {
          positions: cartesianArr,
          width: 10,
          material: new Cesium.ImageMaterialProperty({
            image: getResource('arrow-right.png'),
            color: Cesium.Color.WHITE,
            repeat: new Cesium.Cartesian2(30, 1),
          }),
          zIndex: 2,
          clampToGround: true, // 关闭贴地效果,保留高度
        },
      })
      addPolyline({
        id: 'bottomLine',
        polyline: {
          positions: cartesianArr,
          width: 7,
          material: Cesium.Color.fromBytes(96, 210, 149),
          zIndex: 1,
          clampToGround: true, // 关闭贴地效果,保留高度
        },
      })
      const lineEntity = getEntityById('entityLine')
      global.$viewer.flyTo(lineEntity, {
        offset: new Cesium.HeadingPitchRange(0, -90, 200),
      })
      createPointMarker(kmlDataSource)
      // 解析kmz文件
      readKmzFile(file)
    })
}
const waylineDetails = reactive([
  {
    title: '航线长度',
    value: '0'
  },
  {
    title: '预计执行时间',
    value: '0'
  },
  {
    title: '航点',
    value: 0
  },
  {
    title: '照片',
    value: 0
  },
])
function createPointMarker (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 cartesianArr: any[] = []
  let btmStartPoint = null
  for (let i = 0; i < kmlEntityArr.length; i++) {
    const entity = kmlEntityArr[i]
    // 将cartographic3D坐标转换为正常坐标
    const c3Position = entity.position._value
    const c2Postion = ellipsoid.cartesianToCartographic(c3Position)
    const longitude = Cesium.Math.toDegrees(c2Postion.longitude)
    const latitude = Cesium.Math.toDegrees(c2Postion.latitude)
    const height = 100
    entity.position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
    if (i === 0) {
      btmStartPoint = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0)
    }
    // 创建广告牌信息
    const billboard = createBillboard(`${i + 1}`, '#61d396')
    // 修改id
    entity._id = 'tragetPoint' + i
    // 修改广告牌样式
    entity.billboard = new Cesium.BillboardGraphics({
      image: billboard,
      pixelOffset: new Cesium.Cartesian2(0, -20),
    })
    // 修改点的信息
    entity.point = new Cesium.PointGraphics({
      pixelSize: 20,
      color: Cesium.Color.GHOSTWHITE,
      outlineColor: Cesium.Color.BLACK,
    })
    // 创建虚线
    addPolyline({
      id: 'dashLine' + i,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights([
          longitude,
          latitude,
          height,
          longitude,
          latitude,
          0
        ]),
        width: 1,
        material: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.WHITE
        })
      }
    })
    cartesianArr.push(entity.position._value)
    tragetPointArr.value[i] = {
      position: entity.position._value,
      eventList: [],
    }
  }
  // 创建起飞位置
  global.$viewer.entities.add({
    id: 'dronePosition',
    position: btmStartPoint,
    billboard: {
      image: getResource('dock.png'),
      width: 36,
      height: 36,
    }
  })
  // 绘制链接线
  addPolyline({
    id: 'entityLine',
    polyline: {
      positions: [btmStartPoint, ...cartesianArr],
      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, // 关闭贴地效果,保留高度
    },
  })
  const lineEntity = getEntityById('entityLine')
  const polylineLength = getPolylineLength(lineEntity).toFixed(1) || 0
  waylineDetails[0].value = polylineLength + 'm'
  waylineDetails[2].value = cartesianArr.length
  global.$viewer.flyTo(lineEntity, {
    offset: new Cesium.HeadingPitchRange(0, -90, 300),
  })
}
// 返回上一页
function backPage () {
  isPointListOpen.value = false
  store.commit('SET_WAYLINE_INFO', {
    isShow: false,
    wayline: {},
    position: 0,
  })
}
// 点击目标点
@@ -513,7 +588,7 @@
  selectedPoint.value = index
  store.commit('SET_WAYLINE_INFO', {
    isShow: true,
    wayline: currentWayLine,
    wayline: currentWayLine.value,
    position: index,
  })
  if (getEntityById('clickBox')) {
@@ -533,23 +608,6 @@
      })
    }
  )
  // 创建盒子
  const entity = {
    id: 'clickBox',
    position,
    box: {
      dimensions: new Cesium.Cartesian3(10.0, 10.0, 120),
      material: Cesium.Color.MEDIUMSPRINGGREEN.withAlpha(0.1),
      // outline: true,
      // outlineColor: Cesium.Color.MEDIUMSPRINGGREEN.withAlpha(0.8),
      heightReference: true,
    },
  }
  const boxEntity = global.$viewer.entities.add(entity)
  global.$viewer.flyTo(boxEntity, {
    duration: 3,
  })
}
function onScroll (e: any) {
@@ -606,7 +664,7 @@
}
// 创建广告牌
const createBillboard = (title: string, color: string) => {
const createBillboard = (title: string | number, color: string) => {
  // 创建canvas绘制广告牌
  const billboard = document.createElement('canvas')
  billboard.width = 30
@@ -620,35 +678,9 @@
  ctx.fill()
  ctx.font = '18px serif'
  ctx.fillStyle = '#ffffff'
  ctx.fillText(title, 10, 15)
  ctx.fillText(Number(title) === 1 ? 'S' : title, 10, 15)
  ctx.closePath()
  return billboard
}
// 创建条纹
const createStripe = () => {
  // 创建canvas绘制广告牌
  const stripe = document.createElement('canvas')
  stripe.width = 40
  stripe.height = 40
  const ctx: HTMLCanvasElement | any = stripe.getContext('2d')
  ctx.beginPath()
  ctx.moveTo(0, 20)
  ctx.lineTo(0, 40)
  ctx.lineTo(20, 20)
  ctx.lineTo(20, 0)
  ctx.fillStyle = '#fff'
  ctx.fill()
  ctx.closePath()
  ctx.beginPath()
  ctx.moveTo(20, 0)
  ctx.lineTo(20, 20)
  ctx.lineTo(40, 40)
  ctx.lineTo(40, 20)
  ctx.fillStyle = '#fff'
  ctx.fill()
  ctx.closePath()
  return stripe
}
/**
@@ -784,6 +816,28 @@
        color: #2d8cf0;
      }
    }
    .wayline-info {
      display: flex;
      height: 50px;
      margin: 10px 0;
      text-align: center;
      align-items: center;
      .info-box {
        flex: 1;
        border-right: 1px solid hsla(0,0%,100%,.1);
        .title {
          color: hsla(0,0%,100%,.65);
          font-size: 12px;
          font-weight: bold;
        }
        .info {
          font-weight: bold;
        }
        &:last-child {
          border: 0;
        }
      }
    }
    li {
      cursor: pointer;
@@ -882,3 +936,4 @@
  background-color: #3c3c3c;
}
</style>
../../../utils/cesium/polylineImageTrailMaterial