<template>
  <div class="btn-box" @click="init"></div>
</template>
<script lang="ts" setup>
import {
  sgp4,
  twoline2satrec,
  propagate,
  gstime,
  eciToEcf,
  geodeticToEcf,
  eciToGeodetic,
  ecfToLookAngles,
  degreesLong,
  degreesLat,
  degreesToRadians,
} from 'satellite.js'
let handler: Cesium.ScreenSpaceEventHandler

let planePrimitive: Cesium.Model
let position = Cesium.Cartesian3.fromDegrees(104.200403, 30.396231, 600.0)
const hpRoll = new Cesium.HeadingPitchRoll()
const fixedFrameTransform = Cesium.Transforms.localFrameToFixedFrameGenerator(
  'north',
  'west'
)

let activeIndex = 0 //插值经纬度索引
let maxIndex = 0 // 最大插值经纬度数组索引
let autoDirection = true //自动调整方向
let path: [number, number, number][] = [] //存在路线数组
let showPath: Cesium.Cartesian3[] = [] //插值数组
let camera: Cesium.Camera
let controller: Cesium.ScreenSpaceCameraController
let r: number
const hpRange = new Cesium.HeadingPitchRange()
let nodes: any[] = []
const init = () => {
  hpRoll.pitch = (90 * Math.PI) / 180
  planePrimitive = viewer.scene.primitives.add(
    Cesium.Model.fromGltf({
      url: './models/launchvehicle.glb',
      modelMatrix: Cesium.Transforms.headingPitchRollToFixedFrame(
        position,
        hpRoll,
        Cesium.Ellipsoid.WGS84,
        fixedFrameTransform
      ),
      minimumPixelSize: 128,
    })
  )
  const scene = viewer.scene
  console.log(planePrimitive, 'planePrimitive')
  planePrimitive.readyPromise.then(model => {
    camera = viewer.camera
    controller = scene.screenSpaceCameraController
    r = 2.0 * Math.max(model.boundingSphere.radius, camera.frustum.near)
    controller.minimumZoomDistance = r * 0.2

    modelAnimationController({
      type: 'SRBFlames Size',
      initVal: 0,
      maxVal: 1,
      step: 0.05,
      fn: () => {
        modelAnimationController({
          type: 'SRBFlames Size',
          initVal: 1,
          minVal: 0,
          step: -0.5,
        })
        modelAnimationController({
          type: 'SRBs Separate',
          initVal: 0,
          maxVal: 10,
          step: 0.5,
          fn: () => {
            //一级脱落
            modelAnimationController({
              type: 'SRBs Drop',
              initVal: 0,
              minVal: -5000, // 6个推进器，值越小掉得越远
              step: -0.5,
            })
          },
        })
        // modelAnimationController({ type: 'BoosterEngines Yaw', initVal: 0, maxVal: 1, step: 0.1 }) //左右
        // modelAnimationController({ type: 'BoosterEngines Pitch', initVal: 0, maxVal: 1, step: 0.1 }) //上下
        modelAnimationController({
          type: 'BoosterFlames Size',
          initVal: 0,
          maxVal: 1,
          step: 0.1,
          fn: () => {
            modelAnimationController({
              type: 'Fairing Open',
              initVal: 0,
              maxVal: 45,
              step: 0.5,
            })
            modelAnimationController({
              type: 'Fairing Separate',
              initVal: 0,
              minVal: -10,
              step: -0.1,
            })
            modelAnimationController({
              type: 'Fairing Drop',
              initVal: 0,
              minVal: -50,
              step: -0.5,
              fn: () => {
                //主推进器脱落
                modelAnimationController({
                  type: 'Booster MoveZ',
                  initVal: 0,
                  minVal: -50,
                  step: -0.5,
                })
                modelAnimationController({
                  type: 'UpperStageFlames Size',
                  initVal: 0,
                  maxVal: 1,
                  step: 0.05,
                  fn: () => {
                    modelAnimationController({
                      type: 'InterstageAdapter MoveZ',
                      initVal: 0,
                      minVal: -50,
                      step: -0.5,
                    })
                  },
                })
                // modelAnimationController({ type: 'UpperStageEngines Yaw', initVal: 0, maxVal: 1, step: 0.05,})//左右
                // modelAnimationController({ type: 'UpperStageEngines Pitch', initVal: 0, maxVal: 1, step: 0.05,}) //上下
              },
            })
          },
        })
      },
    })

    lookAt()
    pickup()
    console.log(model, 'nodes')

    nodes = planePrimitive.gltf.nodes
    // nodes.forEach(i => {
    //     if (new RegExp(/InterstageAdapter/).test(i.name)) {
    //         planePrimitive.getNode(i.name).show = false
    //     }
    // })

    // crateLine().then(() => {
    //   modelAnimationController({
    //     type: 'SRBFlames Size',
    //     initVal: 0,
    //     maxVal: 1,
    //     step: 0.05,
    //     fn: () => {
    //       viewer.scene.preUpdate.addEventListener(keepRun)
    //     },
    //   })
    // })
  })
}
function pickup() {
  console.log('pickup')

  handler.setInputAction(function (movement) {
    const pickedObject = viewer.scene.pick(movement.position)
    if (Cesium.defined(pickedObject)) {
      console.log(pickedObject)
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
const lookAt = () => {
  const center = Cesium.Matrix4.multiplyByPoint(
    planePrimitive.modelMatrix,
    Cesium.Cartesian3.ZERO,
    new Cesium.Cartesian3()
  )
  const heading = Cesium.Math.toRadians(10.0)
  const pitch = Cesium.Math.toRadians(-5.0)
  camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, r * 2))
}
type typeModelAnimationController = {
  type: string
  initVal: number
  maxVal?: number
  minVal?: number
  fn?: Function
  step?: number
}
function modelAnimationController(controller: typeModelAnimationController) {
  const { type, initVal, maxVal, fn, step, minVal } = controller
  let num = initVal
  let stopFrame: number
  const max = maxVal || 1
  const min = minVal || -99999
  const duration = step || 0.1
  const render = () => {
    num += duration
    planePrimitive.setArticulationStage(type, num)
    planePrimitive.applyArticulations()
    stopFrame = requestAnimationFrame(render)
    if (num > max || num <= min) {
      window.cancelAnimationFrame(stopFrame)
      fn && fn()
    }
  }
  render()
}
const crateLine = () => {
  const lon = 104.200403,
    lat = 30.396231,
    alt = 20600
  for (let index = 1; index < 20; index++) {
    path.push([lon, lat, 600 + 1000 * index])
  }
  const len = 1000
  let lastLat = 0,
    lastLon = 0,
    lastAlt = 0,
    activeLon,
    activeLat,
    activeAlt
  for (let index = 0; index < len; index++) {
    activeLon = Number((lon + index * 0.01).toFixed(6))
    activeLat = Number((lat + index * 0.02).toFixed(6))
    activeAlt = alt + index * 1000
    path.push([activeLon, activeLat, activeAlt])
    if (index === len - 1) {
      lastLon = activeLon
      lastLat = activeLat
      lastAlt = activeAlt
    }
  }
  for (let i = 0; i <= 360; i += 1) {
    path.push([lastLon + i, lastLat, lastAlt])
  }
  console.log(path, 'path')
  return new Promise(resolve => {
    getPosition().then(res => {
      showPath = res
      maxIndex = res.length
      const line = viewer.scene.primitives.add(
        new Cesium.Primitive({
          geometryInstances: new Cesium.GeometryInstance({
            geometry: new Cesium.PolylineGeometry({
              positions: res,
              width: 3.0,
              vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT,
            }),
            attributes: {
              color: Cesium.ColorGeometryInstanceAttribute.fromColor(
                Cesium.Color.BLUE.withAlpha(0.7)
              ),
            },
          }),
          appearance: new Cesium.PolylineColorAppearance(),
        })
      )
      line.readyPromise.then(() => {
        resolve('')
      })
    })
  })
}

const keepRun = (scene: Cesium.Scene, time: number) => {
  if (activeIndex >= maxIndex) return
  console.log(activeIndex)
  if (activeIndex === 1000) {
    modelAnimationController({
      type: 'SRBFlames Size',
      initVal: 1,
      minVal: 0,
      step: -0.5,
    })
    modelAnimationController({
      type: 'SRBs Separate',
      initVal: 0,
      maxVal: 10,
      step: 0.5,
      fn: () => {
        //一级脱落
        modelAnimationController({
          type: 'SRBs Drop',
          initVal: 0,
          minVal: -100,
          step: -1,
          fn: () =>
            nodes.forEach(i => {
              if (new RegExp(/SRB\d/).test(i.name)) {
                planePrimitive.getNode(i.name).show = false
              }
            }),
        })
      },
    })
    modelAnimationController({
      type: 'BoosterFlames Size',
      initVal: 0,
      maxVal: 1,
      step: 0.1,
    }) //主推期开始点火
  }
  if (activeIndex === 3000) {
    modelAnimationController({
      type: 'Fairing Open',
      initVal: 0,
      maxVal: 45,
      step: 0.5,
    })
    modelAnimationController({
      type: 'Fairing Separate',
      initVal: 0,
      minVal: -10,
      step: -0.1,
    })
    modelAnimationController({
      type: 'Fairing Drop',
      initVal: 0,
      minVal: -150,
      step: -1,
      fn: () => {
        //主推进器脱落
        modelAnimationController({
          type: 'BoosterFlames Size',
          initVal: 1,
          minVal: 0,
          step: -0.05,
        })
        modelAnimationController({
          type: 'Booster MoveZ',
          initVal: 0,
          minVal: -150,
          step: -1,
          fn: () => {
            nodes.forEach(i => {
              if (
                new RegExp(/Fairing\d/).test(i.name) ||
                new RegExp(/Booster/).test(i.name)
              ) {
                planePrimitive.getNode(i.name).show = false
              }
            })
          },
        })
        modelAnimationController({
          type: 'UpperStageFlames Size',
          initVal: 0,
          maxVal: 1,
          step: 0.05,
        })
      },
    })
  }
  if (activeIndex === 3600) {
    modelAnimationController({
      type: 'InterstageAdapter MoveZ',
      initVal: 0,
      minVal: -150,
      step: -1,
      fn: () => {
        nodes.forEach(i => {
          if (new RegExp(/InterstageAdapter/).test(i.name)) {
            planePrimitive.getNode(i.name).show = false
          }
        })
      },
    })
  }
  lookAt()
  if (
    autoDirection &&
    activeIndex > 0 &&
    !showPath[activeIndex - 1].equals(showPath[activeIndex])
  ) {
    const heading = Helper.getHeading(
      showPath[activeIndex - 1],
      showPath[activeIndex]
    )
    if (heading) hpRoll.heading = heading
    const pitch = Helper.getPitch(
      showPath[activeIndex - 1],
      showPath[activeIndex]
    )
    if (pitch) hpRoll.pitch = pitch
  }
  Cesium.Transforms.headingPitchRollToFixedFrame(
    showPath[activeIndex],
    hpRoll,
    Cesium.Ellipsoid.WGS84,
    fixedFrameTransform,
    planePrimitive.modelMatrix
  )
  activeIndex += 1
}
const getPosition = () => {
  //插值 new Cesium.LinearSpline  new Cesium.CatmullRomSpline esium.HermiteSpline.createNaturalCubic
  //let pos = Cesium.Cartesian3.lerp(startP, endP, i / duration, new Cesium.Cartesian3());
  return new Promise((resolve: (value: Cesium.Cartesian3[]) => void) => {
    const points = path.map(i => Cesium.Cartesian3.fromDegrees(...i))
    let times: number[] = []
    for (let index = 0; index < points.length; index++) {
      times.push(index)
    }
    const spline = new Cesium.CatmullRomSpline({
      points,
      times,
    })
    const positions: Cesium.Cartesian3[] = []
    for (let i = 1; i < times.length; i++) {
      for (let j = 0; j < 100; j++) {
        const cartesian3 = spline.evaluate(i - 1 + j * 0.01)
        positions.push(cartesian3)
      }
    }
    resolve(positions)
  })
}

// Sample TLE
const tleLine1 =
    '1 25544U 98067A   19156.50900463  .00003075  00000-0  59442-4 0  9992',
  tleLine2 =
    '2 25544  51.6433  59.2583 0008217  16.4489 347.6017 15.51174618173442'

// 初始化一条卫星记录
const satrec = twoline2satrec(tleLine1, tleLine2)
console.log('satrec===>', satrec)

//  获取卫星在某一时间点的位置与方向信息
// const positionAndVelocity = sgp4(satrec, timeSinceTleEpochMinutes)
// positionAndVelocity =
//  {position: {x: -3987.4321373686917, y: -4619.1250647378265, z: -3280.414501412166}
//velocity: {x: -3.1645649194011605, y: -1.9557509950512322, z: 6.603671697337737}
//__proto__: Object
//}

//  或者你可以使用JavaScript日期
const positionAndVelocity = propagate(satrec, new Date())

const positionEci = positionAndVelocity.position,
  velocityEci = positionAndVelocity.velocity

// 将观察者（固定区域）设为西经122.03度，北纬36.96度（degreesToRadians——角度转弧度）
const observerGd = {
  longitude: degreesToRadians(-122.0308),
  latitude: degreesToRadians(36.9613422),
  height: 0.37,
}

// 将GMT中国时、Julindate时转成格林尼治恒星时
const gmst = gstime(new Date())

// 你可以得到ECF，大地测量，观察角度和多普勒因子。
const positionEcf = eciToEcf(positionEci, gmst),
  observerEcf = geodeticToEcf(observerGd),
  positionGd = eciToGeodetic(positionEci, gmst),
  lookAngles = ecfToLookAngles(observerGd, positionEcf)
// dopplerFactor = dopplerFactor(
//   observerCoordsEcf,
//   positionEcf,
//   velocityEcf
// )

// 所有坐标都存储在键值对中。
// ECI和ECF被' x '， ' y '， ' z '属性访问。
const satelliteX = positionEci.x,
  satelliteY = positionEci.y,
  satelliteZ = positionEci.z

// 角度可以通过' azimuth '， ' elevation '， ' range_sat '属性访问。
const azimuth = lookAngles.azimuth,
  elevation = lookAngles.elevation,
  rangeSat = lookAngles.rangeSat

// 通过'经度'，'纬度'，'高度'访问大地坐标。
const longitude = positionGd.longitude,
  latitude = positionGd.latitude,
  height = positionGd.height

//  将弧度转换为度。
const longitudeDeg = degreesLong(longitude),
  latitudeDeg = degreesLat(latitude)
</script>
<style lang="scss" scoped>
.btn-box {
  position: absolute;
  top: 10px;
  z-index: 10;
  width: 10px;
  height: 10px;
  background-color: #fff;
  margin-left: 20px;
}
</style>
