GuLiMmo
2024-02-28 d5e1d8a5f773738f6766175ea409f47740a24c97
航线库更新
3 files modified
2 files added
585 ■■■■■ changed files
src/assets/svg/qfei.svg 1 ●●●● patch | view | raw | blame | history
src/hooks/use-cesium-tsa.ts 2 ●●● patch | view | raw | blame | history
src/pages/page-web/projects/wayline.vue 275 ●●●●● patch | view | raw | blame | history
src/utils/cesium/ImageTrailMaterial.ts 263 ●●●●● patch | view | raw | blame | history
src/utils/cesium/mapUtils.ts 44 ●●●●● patch | view | raw | blame | history
src/assets/svg/qfei.svg
New file
@@ -0,0 +1 @@
<svg width="44" height="44" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><filter x="-16.7%" y="-16.7%" width="133.3%" height="133.3%" filterUnits="objectBoundingBox" id="a"><feOffset in="SourceAlpha" result="shadowOffsetOuter1"/><feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" in="shadowBlurOuter1"/></filter><circle id="b" cx="20" cy="18" r="18"/><path d="m14.717 10.35.212.016.425.022c.283.018.564.052.836.157.07.026.14.044.213.063.428.11.858.201 1.275.333.302.096.589.239.88.364.246.106.5.198.733.334.42.25.84.502 1.226.796.46.349.862.767 1.142 1.28.353.65.46 1.322.187 2.041-.331.877-.957 1.497-1.708 2.004-.413.279-.858.517-1.308.734a13.52 13.52 0 0 1-1.473.609c-.427.147-.873.246-1.31.345-.461.103-.925.194-1.39.26-.655.092-1.31.18-1.97.228a24.459 24.459 0 0 1-4.577-.096 20.238 20.238 0 0 1-2.475-.455c-.622-.15-1.226-.385-1.823-.612-.43-.166-.858-.356-1.263-.58-.899-.5-1.712-1.112-2.217-2.033-.328-.602-.442-1.24-.21-1.927.228-.682.656-1.214 1.204-1.651a13.85 13.85 0 0 1 1.282-.877c.232-.143.497-.235.748-.342.309-.132.618-.264.931-.377a7.7 7.7 0 0 1 .855-.272c.475-.117.953-.217 1.436-.305.195-.036.405-.033.604-.018.077.007.15.095.225.147-.052.066-.093.154-.159.198-.092.055-.206.08-.313.106-.387.096-.777.173-1.156.29-.38.118-.748.268-1.112.419-.243.099-.487.205-.711.337-.858.507-1.628 1.101-1.915 2.121-.077.28-.063.554.015.833.162.58.511 1.035.953 1.428a5.42 5.42 0 0 0 1.628 1.009c.556.216 1.112.448 1.687.616.486.147.99.235 1.491.32 1.046.172 2.1.29 3.204.235 1.123.077 2.269-.096 3.407-.268.512-.077 1.012-.239 1.513-.378.354-.1.707-.202 1.046-.345.961-.4 1.864-.903 2.527-1.74a2.31 2.31 0 0 0 .482-1.093c.092-.613-.162-1.123-.53-1.59-.313-.4-.722-.685-1.146-.96-.57-.379-1.204-.624-1.837-.86-.398-.15-.825-.227-1.238-.337l-.392-.1a2.662 2.662 0 0 1-.193-.061c-.07-.026-.118-.118-.177-.18.081-.066.166-.195.236-.187zm-.178 1.525c.226.004.379.122.435.326.113.407.214.815.33 1.219.134.463.275.926.416 1.389.093.315.201.626.278.94.016.06-.065.164-.133.208-.065.041-.17.03-.254.034-.665.003-1.33.007-1.994.007-.323 0-.403-.078-.415-.374-.017-.445-.037-.89-.057-1.334-.012-.24-.1-.318-.363-.318-1.12-.004-2.24-.004-3.364 0-.27 0-.383.089-.415.333-.056.452-.109.908-.157 1.363-.024.238-.097.326-.363.326-.737.008-1.479.008-2.216 0-.262-.003-.314-.118-.23-.344.141-.393.266-.79.383-1.186.214-.733.411-1.467.617-2.2.076-.278.241-.393.548-.393h1.208c.307 0 .395.078.383.367-.008.178-.036.356-.048.533-.016.27.076.36.366.36h1.532v.022h1.551c.342 0 .447-.104.423-.419-.012-.177-.04-.355-.044-.533-.004-.226.076-.315.314-.322.423-.011.846-.015 1.27-.004zm-4.783-1.9c.452.003.895.003 1.334.003h1.507c.238 0 .298.06.29.274-.004.104-.004.212-.008.315-.008.226-.105.323-.35.348-.053.004-.11.004-.162.004H9.752c-.39 0-.515-.115-.515-.474 0-.47 0-.47.52-.47zM12.585 8c.254 0 .31.056.306.282-.004.251 0 .503-.008.759-.004.215-.076.267-.31.267H9.595c-.294 0-.354-.052-.354-.323l-.004-.722c0-.207.056-.26.29-.263l.777.001.774-.001h1.507zM11.141.032c.254.319.504.642.747.972.637.859 1.27 1.721 1.908 2.58l1.002 1.358c.03.04.051.084.07.128.095.231-.004.393-.254.396-.509.008-1.02.004-1.529.004-.346 0-.38.033-.38.378 0 .503.005 1.002.008 1.505 0 .216-.051.271-.269.275-.464 0-.928-.004-1.395-.004H9.668c-.24 0-.288-.055-.288-.293.004-.507.004-1.017.004-1.523 0-.301-.044-.338-.339-.338-.504.004-1.005.011-1.51-.004-.103-.003-.272-.058-.29-.12a.474.474 0 0 1 .058-.368c.73-1.005 1.473-2 2.21-2.998.42-.572.836-1.145 1.256-1.717.066-.088.129-.18.21-.25.03-.025.136-.01.162.019z" id="c"/></defs><g fill="none" fill-rule="evenodd"><g transform="translate(2 4)"><use fill="#000" filter="url(#a)" xlink:href="#b"/><use fill="#2D8CF0" xlink:href="#b"/></g><g transform="translate(11 11.624)"><mask id="d" fill="#fff"><use xlink:href="#c"/></mask><use fill="#000" fill-rule="nonzero" xlink:href="#c"/><g mask="url(#d)"><path fill="#FFF" d="M-22-26h68v68h-68z"/></g></g></g></svg>
src/hooks/use-cesium-tsa.ts
@@ -72,7 +72,7 @@
    subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
    tilingScheme: new Cesium.GeographicTilingScheme(),
    tileMatrixLabels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19'],
    maximumLevel: 50,
    maximumLevel: 17,
  })
  // 标准地图图层变量
  const imageryProvider_stand = new Cesium.UrlTemplateImageryProvider({
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
src/utils/cesium/ImageTrailMaterial.ts
@@ -1,127 +1,162 @@
import * as Cesium from 'cesium'
/**
 * 定义Cesium材质对象
 */
class ImageTrailMaterial {
  _definitionChanged: Cesium.Event<(...args: any[]) => void>;
  _color: undefined;
  _colorSubscription: undefined;
  _speed: undefined;
  _speedSubscription: undefined;
  _image: undefined;
  _imageSubscription: undefined;
  _repeat: undefined;
  _repeatSubscription: undefined;
  color: any;
  speed: any;
  image: any;
  repeat: Cesium.Cartesian2;
  constructor (options : any = {}) {
    this._definitionChanged = new Cesium.Event()
    this._color = undefined
    this._colorSubscription = undefined
    this._speed = undefined
    this._speedSubscription = undefined
    this._image = undefined
    this._imageSubscription = undefined
    this._repeat = undefined
    this._repeatSubscription = undefined
    this.color = options.color || Cesium.Color.fromBytes(0, 0, 255, 255)
    this.speed = options.speed || 1
    this.image = options.image
    this.repeat = new Cesium.Cartesian2(
      options.repeat?.x || 1,
      options.repeat?.y || 1
    )
  }
import * as cesium from 'cesium'
  get isConstant () {
    return false
  }
const Cesium: any = cesium
  get definitionChanged () {
    return this._definitionChanged
  }
const getResource = (name: string) => {
  return new URL(`/src/assets/icons/${name}`, import.meta.url).href
}
  getType () {
    return Cesium.Material.ImageTrailMaterialType
  }
const defaultColor = Cesium.Color.TRANSPARENT
const defaultImage = getResource('arrow-right.png')
const defaultImageimageW = 10
const defaultAnimation = false
const defaultDuration = 3000
  getValue (time: any, result: any) {
    if (!result) {
      result = {}
    }
    result.color = Cesium.Property?.getValueOrUndefined(this._color, time)
    result.image = Cesium.Property?.getValueOrUndefined(this._image, time)
    result.repeat = Cesium.Property?.getValueOrUndefined(this._repeat, time)
    result.speed = this._speed
    return result
  }
function ImageTrailMaterial (this: any, opt: any = {}) {
  opt = Cesium.defaultValue(opt, Cesium.defaultValue.EMPTY_OBJECT)
  this._definitionChanged = new Cesium.Event()
  // 自定义材质
  // 自定义图片颜色
  this._color = undefined
  this._colorSubscription = undefined
  // 自定义背景颜色
  this._backgroundColor = undefined
  this._backgroundColorSubscription = undefined
  // 图片
  this._image = undefined
  this._imageSubscription = undefined
  // 图片宽度
  this._imageW = undefined
  this._imageWSubscription = undefined
  // 是否开启动画
  this._animation = undefined
  this._animationSubscription = undefined
  // 动画持续时间
  this._duration = undefined
  this._durationSubscription = undefined
  equals (other: this) {
    return (
      this === other ||
      (other instanceof ImageTrailMaterial &&
        Cesium.Property.equals(this._color, other._color) &&
        Cesium.Property.equals(this._image, other._image) &&
        Cesium.Property.equals(this._repeat, other._repeat) &&
        Cesium.Property.equals(this._speed, other._speed))
    )
  // 变量初始化
  this.color = opt.color || defaultColor // 颜色
  this.backgroundColor = opt.backgroundColor || defaultColor // 颜色
  this._image = opt.image || defaultImage // 材质图片
  this.imageW = opt.imageW || defaultImageimageW
  this.animation = opt.animation || defaultAnimation
  this.duration = opt.duration || defaultDuration
  this._time = undefined
}
ImageTrailMaterial.prototype.getType = function () {
  return Cesium.Material.ImageTrailMaterialType
}
// 这个方法在每次渲染时被调用,result的参数会传入glsl中。
ImageTrailMaterial.prototype.getValue = function (
  time: any,
  result: {
    color?: any
    backgroundColor?: any
    image?: any
    imageW?: any
    animation?: any
    time?: any
  },
) {
  if (!Cesium.defined(result)) {
    result = {}
  }
  // result.color = Cesium.Property.getValueOrClonedDefault(
  //   this._color,
  //   time,
  //   defaultColor,
  //   result.color,
  // )
  // result.backgroundColor = Cesium.Property.getValueOrClonedDefault(
  //   this._backgroundColor,
  //   time,
  //   defaultColor,
  //   result.backgroundColor,
  // )
  result.color = Cesium.Property.getValueOrUndefined(this._color, time)
  result.backgroundColor = Cesium.Property.getValueOrUndefined(this._backgroundColor, time)
  result.image = this._image
  result.imageW = this._imageW
  result.animation = this._animation
  if (this._time === undefined) {
    this._time = new Date().getTime()
  }
  result.time =
    ((new Date().getTime() - this._time) % this._duration) / this._duration
  return result
}
ImageTrailMaterial.prototype.equals = function (other: {
  _color: any
  _backgroundColor: any
}) {
  return (
    this === other ||
    (other instanceof ImageTrailMaterial &&
      Cesium.Property.equals(this._color, other._color) &&
      Cesium.Property.equals(this._backgroundColor, other._backgroundColor))
  )
}
Object.defineProperties(ImageTrailMaterial.prototype, {
  isConstant: {
    get: function get () {
      return false
    },
  },
  definitionChanged: {
    get: function get () {
      return this._definitionChanged
    },
  },
  color: Cesium.createPropertyDescriptor('color'),
  speed: Cesium.createPropertyDescriptor('speed'),
  backgroundColor: Cesium.createPropertyDescriptor('backgroundColor'),
  image: Cesium.createPropertyDescriptor('image'),
  repeat: Cesium.createPropertyDescriptor('repeat'),
  imageW: Cesium.createPropertyDescriptor('imageW'),
  animation: Cesium.createPropertyDescriptor('animation'),
  duration: Cesium.createPropertyDescriptor('duration'),
})
// 材质类型
Cesium.Material.ImageTrailMaterialType = 'PolylineImageTrail'
// 添加材质到缓冲区中
Cesium.Material._materialCache.addMaterial(
  Cesium.Material.ImageTrailMaterialType,
  {
    fabric: {
      type: Cesium.Material.ImageTrailMaterialType,
      // uniform变量
      uniforms: {
        color: new Cesium.Color(1.0, 0.0, 0.0, 0.7),
        image: Cesium.Material.DefaultImageId,
        speed: 1,
        repeat: new Cesium.Cartesian2(1, 1),
      },
      //
      source: `
                    uniform sampler2D image;
                    uniform float speed;
                    uniform vec4 color;
                    uniform vec2 repeat;
                    czm_material czm_getMaterial(czm_materialInput materialInput){
                        czm_material material=czm_getDefaultMaterial(materialInput);
                        vec2 st=repeat * materialInput.st;
                        float time=fract(czm_frameNumber*speed/1000.);
                        // st.s是横轴方向运动,st.t是纵轴,
                        // vec2(fract(st.s-time),st.t)是横轴按照时间变化而变化,纵轴保持正常不变化
                        vec4 colorImage=texture2D(image,vec2(fract(st.s-time),st.t));
                        vec4 fragColor;
                        fragColor.rgb=color.rgb / 1.0;
                        if(color.a==0.){
                            material.alpha=colorImage.a;
                            material.diffuse=colorImage.rgb;
                        }else{
                            material.alpha=colorImage.a*color.a;
                            material.diffuse=max(color.rgb*material.alpha*3.,color.rgb);
                        }
                        return material;
                    }
                    `
    },
    translucent: function () {
      return true
    },
  }
)
export default ImageTrailMaterial
// 写到Cesium对象上,就可以像其他MaterialProperty一样使用了
Cesium.Material.ImageTrailMaterialType = 'PolylineImageTrail'
Cesium.Material._materialCache.addMaterial(Cesium.Material.ImageTrailMaterialType, {
  fabric: {
    type: 'ImageLine',
    uniforms: {
      // uniforms参数跟我们上面定义的参数以及getValue方法中返回的result对应,这里值是默认值
      color: new Cesium.Color(1, 0, 0, 1.0),
      backgroundColor: new Cesium.Color(0, 0, 0, 0.0),
      image: '',
      imageW: 1,
      animation: false,
      duration: 30,
      time: 0,
    },
    // source编写glsl,可以使用uniforms参数,值来自getValue方法的result
    source: `
      czm_material czm_getMaterial(czm_materialInput materialInput)
      {
          czm_material material = czm_getDefaultMaterial(materialInput);
          vec2 st = materialInput.st;
          float s = st.s/ (abs(fwidth(st.s)) * imageW * czm_pixelRatio);
          if(animation==true){
            s = s-time;//增加运动效果
          }
          float t = st.t;
          vec4 colorImage = texture(image, vec2(fract(s), t));
          material.diffuse = colorImage.rgb;
          material.emission = max(backgroundColor.rgb*material.alpha*1.,backgroundColor.rgb);
          return material;
      }
    `,
  },
  translucent: function translucent () {
    return true
  },
})
export default (ImageTrailMaterial as any)
src/utils/cesium/mapUtils.ts
New file
@@ -0,0 +1,44 @@
import * as Cesium from 'cesium'
export function 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
  const b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0
  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),
      ),
    )
  s = s * 6378.137 // EARTH_RADIUS;
  s = Math.round(s * 10000) / 10000
  return s * 1000
}
export function getPolylineLength (entity: any) {
  let length = 0
  // 获取Polyline的所有顶点位置
  const positions = entity.polyline.positions.getValue()
  for (let i = 0; i < positions.length - 1; ++i) {
    const startPosition = positions[i]
    const endPosition = positions[i + 1]
    // 使用Cesium提供的distanceBetween函数计算两个顶点之间的距离
    const distance = Cesium.Cartesian3.distance(startPosition, endPosition)
    // 将每个顶点之间的距离相加得到总长度
    length += distance
  }
  return length
}