From d5e1d8a5f773738f6766175ea409f47740a24c97 Mon Sep 17 00:00:00 2001
From: GuLiMmo <2820890765@qq.com>
Date: Wed, 28 Feb 2024 19:09:25 +0800
Subject: [PATCH] 航线库更新

---
 src/hooks/use-cesium-tsa.ts             |    2 
 src/pages/page-web/projects/wayline.vue |  275 ++++++++++++++++-----------
 src/assets/svg/qfei.svg                 |    1 
 src/utils/cesium/ImageTrailMaterial.ts  |  263 ++++++++++++++-----------
 src/utils/cesium/mapUtils.ts            |   44 ++++
 5 files changed, 360 insertions(+), 225 deletions(-)

diff --git a/src/assets/svg/qfei.svg b/src/assets/svg/qfei.svg
new file mode 100644
index 0000000..333a277
--- /dev/null
+++ b/src/assets/svg/qfei.svg
@@ -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>
\ No newline at end of file
diff --git a/src/hooks/use-cesium-tsa.ts b/src/hooks/use-cesium-tsa.ts
index dacf74c..bc22c3b 100644
--- a/src/hooks/use-cesium-tsa.ts
+++ b/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({
diff --git a/src/pages/page-web/projects/wayline.vue b/src/pages/page-web/projects/wayline.vue
index 0776a50..072dd6f 100644
--- a/src/pages/page-web/projects/wayline.vue
+++ b/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
diff --git a/src/utils/cesium/ImageTrailMaterial.ts b/src/utils/cesium/ImageTrailMaterial.ts
index b0394d1..84434d1 100644
--- a/src/utils/cesium/ImageTrailMaterial.ts
+++ b/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)
diff --git a/src/utils/cesium/mapUtils.ts b/src/utils/cesium/mapUtils.ts
new file mode 100644
index 0000000..97297d4
--- /dev/null
+++ b/src/utils/cesium/mapUtils.ts
@@ -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
+}

--
Gitblit v1.9.3