/*
* 路径漫游主类
* @Author: jianlei wang
* @Date: 2024-02-26 10:59:50
* @Last Modified by: jianlei wang
* @Last Modified time: 2024-03-28 14:06:41
*/
import { Cesium } from '../../namespace'
import { shouldAnimate } from '../utils/Clock'
/**
* 路径漫游主类
* @class
*/
class Roaming {
/**
* 构造函数
* @param {Object} viewer - 地图场景对象
*/
constructor(viewer) {
this._viewer = viewer
this._id = 'first-person-navigation'
}
/**
* 按照路径节点,自动执行第一人称路径漫游动画
* @param {Array<DegreePosZ>} points - 路径相机位置点集合
* @param {Array<Number>} [times=null] - 时间集合,时间戳:毫秒),注意:如果要定义,请确保时间集合与路径点一一对应;若设置为null,则默认间隔为10s的时间集合
* @param {Boolean} path - 是否显示路径线
*/
async play(points, times, path) {
this.removeAll()
const viewer = this._viewer
shouldAnimate(this._viewer, true)
const option = this._getOption(points, times)
const czml = this._initCZML(option, path)
// 定义变量,模型和视角跟随事件
// 加载数据
this._trackItem = await viewer.dataSources.add(
Cesium.CzmlDataSource.load(czml)
)
// 获取模型对象
const entity = this._trackItem.entities.getById(this._id)
if (!entity) return
viewer.trackedEntity = entity
// 获取当前模型方向和位置
const { orientation, position } = entity
// 实时调整位置
function adjust() {
if (viewer.clock.shouldAnimate === true) {
let ori = orientation.getValue(viewer.clock.currentTime) // 获取偏向角
let center = position.getValue(viewer.clock.currentTime) // 获取位置
// 1、由四元数计算三维旋转矩阵
var mtx3 = Cesium.Matrix3.fromQuaternion(ori)
// 2、计算四维转换矩阵:
var mtx4 = Cesium.Matrix4.fromRotationTranslation(mtx3, center)
// 3、计算角度:
var hpr = Cesium.Transforms.fixedFrameToHeadingPitchRoll(mtx4)
// 获取角度(弧度)
const headingTemp = hpr.heading
const pitchTemp = hpr.pitch
// 调整角度为第一人称
const heading = Cesium.Math.toRadians(
Cesium.Math.toDegrees(headingTemp) + 90
)
const pitch = Cesium.Math.toRadians(
Cesium.Math.toDegrees(pitchTemp) - 12
)
// 视角高度,根据模型大小调整
const range = 5.0
// 动态改变模型视角
viewer.camera.lookAt(
center,
new Cesium.HeadingPitchRange(heading, pitch, range)
)
}
}
this._onTickEvent = viewer.clock.onTick.addEventListener(adjust)
}
/**
* 暂停漫游
*/
pause() {
shouldAnimate(this._viewer, false)
}
/**
* 继续漫游
*/
continue() {
shouldAnimate(this._viewer, true)
}
/**
* 清除所有
*/
removeAll() {
this._onTickEvent && this._onTickEvent()
this._viewer.trackedEntity = undefined
this._trackItem && this._viewer.dataSources.remove(this._trackItem)
}
_getOption(points, times) {
const length = points.length
if (!times || times.length != length) {
const time = new Date().getTime()
times = Array.from({ length }, (_, index) => time + index * 10000)
}
let cartographicDegrees = []
for (let index = 0; index < length; index++) {
const point = points[index]
cartographicDegrees.push((times[index] - times[0]) / 1000)
cartographicDegrees = cartographicDegrees.concat(point)
}
const startTime = new Date(times[0]).toISOString()
const endTime = new Date(times[times.length - 1]).toISOString()
const option = {
interval: `${startTime}/${endTime}`,
currentTime: startTime,
cartographicDegrees,
}
return option
}
_initCZML(option, show) {
const czml_team = [
{
id: 'document',
name: this._id,
version: '1.0',
clock: {
interval: option.interval,
currentTime: option.currentTime,
},
},
{
id: this._id,
name: 'path with GPS flight data',
description: '第一人称漫游。',
availability: option.interval,
path: {
material: {
polylineGlow: {
color: {
rgba: [0, 0, 255, 50],
},
glowPower: 0.1,
taperPower: 0.1,
},
},
width: 20,
show: show,
},
orientation: {
// 自动计算方向
velocityReference: '#position',
},
position: {
// 插值算法
interpolationAlgorithm: 'LAGRANGE',
interpolationDegree: 5,
epoch: option.currentTime,
cartographicDegrees: option.cartographicDegrees,
},
},
]
return czml_team
}
}
export default Roaming