674 lines
20 KiB
JavaScript
674 lines
20 KiB
JavaScript
|
export default class Frustum {
|
|||
|
constructor(options, viewer, viewer1) {
|
|||
|
this.options = { ...options }
|
|||
|
this.viewer = viewer
|
|||
|
this.viewer1 = viewer1
|
|||
|
this.head = 0
|
|||
|
this.pitch = 90
|
|||
|
this.po = 0.00001
|
|||
|
this.position = null
|
|||
|
this.hpr = null
|
|||
|
this.currentFrustumOutline = null
|
|||
|
this.frustum = null
|
|||
|
this.setInterval1 = null
|
|||
|
this.webrtc = null
|
|||
|
|
|||
|
// 设置默认值
|
|||
|
Frustum.setDefaultValue(this)
|
|||
|
this.create()
|
|||
|
}
|
|||
|
|
|||
|
static setDefaultValue(that) {
|
|||
|
that.options.position = that.options.position || {}
|
|||
|
that.options.fov = that.options.fov || 30
|
|||
|
that.options.aspectRatio = that.options.aspectRatio || 1
|
|||
|
that.options.near = that.options.near || 1
|
|||
|
that.options.far = that.options.far || 120
|
|||
|
that.options.heading = that.options.heading || 0
|
|||
|
that.options.pitch = that.options.pitch || 90
|
|||
|
that.options.roll = that.options.roll || 0
|
|||
|
that.options.show = that.options.show ?? true
|
|||
|
that.options.videoUrl = that.options.videoUrl || ''
|
|||
|
that.options.index = that.options.index || 0
|
|||
|
that.options.arr = that.options.arr || []
|
|||
|
that.options.normalHeight = that.options.normalHeight || 100
|
|||
|
}
|
|||
|
|
|||
|
// 初始化视锥体
|
|||
|
create() {
|
|||
|
this.frustum = new Cesium.PerspectiveFrustum({
|
|||
|
fov: Cesium.Math.toRadians(this.options.fov),
|
|||
|
aspectRatio: this.options.aspectRatio,
|
|||
|
near: this.options.near,
|
|||
|
far: this.options.far
|
|||
|
})
|
|||
|
|
|||
|
const { lng, lat, alt } = this.options.position
|
|||
|
const { heading, pitch, roll } = this.options
|
|||
|
this.position = Cesium.Cartesian3.fromDegrees(
|
|||
|
lng,
|
|||
|
lat,
|
|||
|
alt + this.options.normalHeight
|
|||
|
)
|
|||
|
this.hpr = new Cesium.HeadingPitchRoll(
|
|||
|
Cesium.Math.toRadians(heading),
|
|||
|
Cesium.Math.toRadians(pitch),
|
|||
|
Cesium.Math.toRadians(roll)
|
|||
|
)
|
|||
|
|
|||
|
this.drawFrustumOutline()
|
|||
|
this.drawFrustumFilled()
|
|||
|
this.monitorKeyboard()
|
|||
|
this.updateFrustumSquareBase(40)
|
|||
|
this.syncHpr()
|
|||
|
if (this.options.videoUrl) {
|
|||
|
this.addVideoToFrustumTop2()
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 监听键盘事件
|
|||
|
monitorKeyboard() {
|
|||
|
const keyActions = {
|
|||
|
KeyQ: () => this.setIntervalhpr(-0.45),
|
|||
|
KeyE: () => this.setIntervalhpr(0.45),
|
|||
|
KeyB: () => this.setIntervalhprr(-0.45),
|
|||
|
KeyN: () => this.setIntervalhprr(0.45),
|
|||
|
KeyW: () => this.updateFrustumPosition('move', -0.00001),
|
|||
|
KeyS: () => this.updateFrustumPosition('move', 0.00001),
|
|||
|
KeyA: () => this.updateFrustumPosition('move', -0.00001, 0),
|
|||
|
KeyD: () => this.updateFrustumPosition('move', 0.00001, 0),
|
|||
|
KeyC: () => this.updateFrustumHeight(1), // 增加高度
|
|||
|
KeyZ: () => this.updateFrustumHeight(-1) // 降低高度
|
|||
|
}
|
|||
|
|
|||
|
this.keydownHandler = event => {
|
|||
|
if (keyActions[event.code]) keyActions[event.code]()
|
|||
|
}
|
|||
|
|
|||
|
this.keyupHandler = () => this.stopFrustumRotation()
|
|||
|
|
|||
|
document.addEventListener('keydown', this.keydownHandler)
|
|||
|
|
|||
|
document.addEventListener('keyup', this.keyupHandler)
|
|||
|
}
|
|||
|
// 渲染视频
|
|||
|
addVideoToFrustumTop() {
|
|||
|
// 创建视频元素
|
|||
|
const videoElement = document.createElement('video')
|
|||
|
videoElement.width = 640
|
|||
|
videoElement.height = 360
|
|||
|
videoElement.autoplay = true
|
|||
|
videoElement.loop = true
|
|||
|
videoElement.muted = true
|
|||
|
// videoElement.style.display = 'none'; // 隐藏视频元素
|
|||
|
document.body.appendChild(videoElement)
|
|||
|
|
|||
|
// 使用 flv.js 播放 FLV 视频
|
|||
|
if (flvjs.isSupported()) {
|
|||
|
const flvPlayer = flvjs.createPlayer({
|
|||
|
// url: 'http://zmkg.cqet.top:9991/live/2pUbcgTrly3mIDuxsDXN9h3hqcEKU6TlsV_YeIDyqHqXGzXafqWokXdU1q6j_S7hTCP7HynZQIsuNM6KQ5l-ag==.flv',
|
|||
|
type: 'flv',
|
|||
|
isLive: true,
|
|||
|
hasAudio: false,
|
|||
|
enableStashBuffer: true, //
|
|||
|
enableWorker: true,
|
|||
|
autoCleanupSourceBuffer: true, //自动清除缓存
|
|||
|
url: this.options.videoUrl
|
|||
|
})
|
|||
|
flvPlayer.attachMediaElement(videoElement)
|
|||
|
flvPlayer.load()
|
|||
|
flvPlayer.play()
|
|||
|
} else {
|
|||
|
console.error('FLV.js is not supported in this browser.')
|
|||
|
}
|
|||
|
|
|||
|
const corners = this.computeFrustumCorners(
|
|||
|
this.frustum,
|
|||
|
this.position,
|
|||
|
this.hpr
|
|||
|
)
|
|||
|
// 创建 PolygonGeometry 并应用视频作为纹理
|
|||
|
const polygonHierarchy = new Cesium.PolygonHierarchy([
|
|||
|
corners.bottomLeft,
|
|||
|
corners.bottomRight,
|
|||
|
corners.topRight,
|
|||
|
corners.topLeft
|
|||
|
])
|
|||
|
this.videoEntity = this.viewer.entities.add(
|
|||
|
new Cesium.Entity({
|
|||
|
id: '22222222',
|
|||
|
show: true,
|
|||
|
polygon: {
|
|||
|
hierarchy: polygonHierarchy
|
|||
|
}
|
|||
|
})
|
|||
|
)
|
|||
|
videoElement.addEventListener('loadeddata', () => {
|
|||
|
this.videoEntity.polygon.material = videoElement // 确保视频纹理加载后再设置
|
|||
|
})
|
|||
|
}
|
|||
|
// 渲染视频
|
|||
|
async addVideoToFrustumTop2() {
|
|||
|
// 创建视频元素
|
|||
|
const videoElement = document.createElement('video')
|
|||
|
videoElement.width = 640
|
|||
|
videoElement.height = 360
|
|||
|
videoElement.autoplay = true
|
|||
|
videoElement.loop = true
|
|||
|
videoElement.muted = true
|
|||
|
// videoElement.style.display = 'none'; // 隐藏视频元素
|
|||
|
document.body.appendChild(videoElement)
|
|||
|
await this.startPlay(videoElement, this.options.videoUrl)
|
|||
|
const corners = this.computeFrustumCorners(
|
|||
|
this.frustum,
|
|||
|
this.position,
|
|||
|
this.hpr
|
|||
|
)
|
|||
|
// 创建 PolygonGeometry 并应用视频作为纹理
|
|||
|
const polygonHierarchy = new Cesium.PolygonHierarchy([
|
|||
|
corners.bottomLeft,
|
|||
|
corners.bottomRight,
|
|||
|
corners.topRight,
|
|||
|
corners.topLeft
|
|||
|
])
|
|||
|
this.videoEntity = this.viewer.entities.add(
|
|||
|
new Cesium.Entity({
|
|||
|
id: '22222222',
|
|||
|
show: true,
|
|||
|
polygon: {
|
|||
|
hierarchy: polygonHierarchy
|
|||
|
}
|
|||
|
})
|
|||
|
)
|
|||
|
videoElement.addEventListener('loadeddata', () => {
|
|||
|
this.videoEntity.polygon.material = videoElement // 确保视频纹理加载后再设置
|
|||
|
})
|
|||
|
}
|
|||
|
async startPlay(element, url) {
|
|||
|
// Close existing SDK instance if any
|
|||
|
if (this.webrtc) {
|
|||
|
this.webrtc.close()
|
|||
|
}
|
|||
|
|
|||
|
// Initialize a new SDK instance
|
|||
|
this.webrtc = new SrsRtcWhipWhepAsync()
|
|||
|
|
|||
|
// Bind the video player to the SDK stream
|
|||
|
element.srcObject = this.webrtc.stream
|
|||
|
|
|||
|
try {
|
|||
|
const session = await this.webrtc.play(url)
|
|||
|
console.log(session)
|
|||
|
// this.sessionId = session.sessionid
|
|||
|
// this.simulatorUrl = `${session.simulator}?drop=1&username=${session.sessionid}`
|
|||
|
} catch (error) {
|
|||
|
// console.error('Error playing stream:', error)
|
|||
|
this.webrtc.close()
|
|||
|
// this.playerVisible = false
|
|||
|
}
|
|||
|
}
|
|||
|
// 计算视锥体远裁剪面(大面)的四个角点
|
|||
|
computeFrustumCorners(frustum, position, hpr) {
|
|||
|
const tanFov = Math.tan(frustum.fov * 0.5)
|
|||
|
const farHeight = frustum.far * tanFov
|
|||
|
const farWidth = farHeight * frustum.aspectRatio
|
|||
|
|
|||
|
const topLeft = new Cesium.Cartesian3(-farWidth, farHeight, -frustum.far)
|
|||
|
const topRight = new Cesium.Cartesian3(farWidth, farHeight, -frustum.far)
|
|||
|
const bottomLeft = new Cesium.Cartesian3(
|
|||
|
-farWidth,
|
|||
|
-farHeight,
|
|||
|
-frustum.far
|
|||
|
)
|
|||
|
const bottomRight = new Cesium.Cartesian3(
|
|||
|
farWidth,
|
|||
|
-farHeight,
|
|||
|
-frustum.far
|
|||
|
)
|
|||
|
const transform = Cesium.Transforms.headingPitchRollToFixedFrame(
|
|||
|
position,
|
|||
|
hpr
|
|||
|
)
|
|||
|
// console.log('transform111111111111111111111111', transform)
|
|||
|
return {
|
|||
|
topLeft: Cesium.Matrix4.multiplyByPoint(
|
|||
|
transform,
|
|||
|
topLeft,
|
|||
|
new Cesium.Cartesian3()
|
|||
|
),
|
|||
|
topRight: Cesium.Matrix4.multiplyByPoint(
|
|||
|
transform,
|
|||
|
topRight,
|
|||
|
new Cesium.Cartesian3()
|
|||
|
),
|
|||
|
bottomLeft: Cesium.Matrix4.multiplyByPoint(
|
|||
|
transform,
|
|||
|
bottomLeft,
|
|||
|
new Cesium.Cartesian3()
|
|||
|
),
|
|||
|
bottomRight: Cesium.Matrix4.multiplyByPoint(
|
|||
|
transform,
|
|||
|
bottomRight,
|
|||
|
new Cesium.Cartesian3()
|
|||
|
)
|
|||
|
}
|
|||
|
}
|
|||
|
// 封装的函数:更新 Polygon 面的位置
|
|||
|
updatePolygonPosition() {
|
|||
|
const corners = this.computeFrustumCorners(
|
|||
|
this.frustum,
|
|||
|
this.position,
|
|||
|
this.hpr
|
|||
|
)
|
|||
|
|
|||
|
this.videoEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
|
|||
|
return new Cesium.PolygonHierarchy([
|
|||
|
corners.bottomLeft,
|
|||
|
corners.bottomRight,
|
|||
|
corners.topRight,
|
|||
|
corners.topLeft
|
|||
|
])
|
|||
|
})
|
|||
|
}
|
|||
|
// 更新锥体底部为正方形的方法
|
|||
|
updateFrustumSquareBase(value) {
|
|||
|
// 将输入值范围从 56 到 1 映射到面积范围 10000 到 100
|
|||
|
const minArea = 100 // 最小面积
|
|||
|
const maxArea = 10000 // 最大面积
|
|||
|
|
|||
|
// 映射公式(反转映射)
|
|||
|
const newArea = ((56 - value) / (56 - 1)) * (maxArea - minArea) + minArea
|
|||
|
|
|||
|
// 确保aspectRatio保持为1(正方形)
|
|||
|
this.frustum.aspectRatio = 1
|
|||
|
|
|||
|
// 根据面积计算正方形边长
|
|||
|
const sideLength = Math.sqrt(newArea)
|
|||
|
|
|||
|
// 远平面距离
|
|||
|
const far = this.frustum.far
|
|||
|
|
|||
|
// 计算新的fov
|
|||
|
const fov = 2 * Math.atan(sideLength / (2 * far))
|
|||
|
|
|||
|
// 更新视锥体的fov
|
|||
|
this.frustum.fov = fov
|
|||
|
|
|||
|
// 重新绘制视锥体轮廓和填充
|
|||
|
this.drawFrustumOutline()
|
|||
|
this.drawFrustumFilled()
|
|||
|
this.syncHpr()
|
|||
|
}
|
|||
|
updateFrustumHeight(deltaHeight) {
|
|||
|
const cartographic = Cesium.Cartographic.fromCartesian(this.position)
|
|||
|
cartographic.height += deltaHeight // 更新高度
|
|||
|
this.position = Cesium.Cartesian3.fromDegrees(
|
|||
|
Cesium.Math.toDegrees(cartographic.longitude),
|
|||
|
Cesium.Math.toDegrees(cartographic.latitude),
|
|||
|
cartographic.height
|
|||
|
)
|
|||
|
this.options.position.alt = cartographic.height
|
|||
|
// this.options.arr[
|
|||
|
// this.options.index
|
|||
|
// ] = this.viewer.scene.globe.ellipsoid.cartographicToCartesian(cartographic)
|
|||
|
this.syncHpr()
|
|||
|
this.drawFrustumOutline() // 重新绘制视锥体轮廓
|
|||
|
this.drawFrustumFilled()
|
|||
|
}
|
|||
|
// 更新position变化后的视锥体属性
|
|||
|
updatePositionHeight(p) {
|
|||
|
this.options.position = this.cartesian3Towgs84(p)
|
|||
|
this.syncHpr()
|
|||
|
this.drawFrustumOutline() // 重新绘制视锥体轮廓
|
|||
|
this.drawFrustumFilled()
|
|||
|
}
|
|||
|
cartesian3Towgs84(cartesian) {
|
|||
|
var ellipsoid = this.viewer.scene.globe.ellipsoid
|
|||
|
var cartesian3 = new Cesium.Cartesian3(
|
|||
|
cartesian.x,
|
|||
|
cartesian.y,
|
|||
|
cartesian.z
|
|||
|
)
|
|||
|
var cartographic = ellipsoid.cartesianToCartographic(cartesian3)
|
|||
|
var lat = Cesium.Math.toDegrees(cartographic.latitude)
|
|||
|
var lng = Cesium.Math.toDegrees(cartographic.longitude)
|
|||
|
var alt = cartographic.height < 0 ? 0 : cartographic.height
|
|||
|
return {
|
|||
|
lng: lng,
|
|||
|
lat: lat,
|
|||
|
alt: alt
|
|||
|
}
|
|||
|
}
|
|||
|
setIntervalhpr(num) {
|
|||
|
this.stopFrustumRotation() // 先停止当前的定时器
|
|||
|
this.setInterval1 = setInterval(() => {
|
|||
|
this.head += num
|
|||
|
this.updateFrustumHPR(Cesium.Math.toRadians(this.head), this.pitch)
|
|||
|
}, 10)
|
|||
|
}
|
|||
|
setIntervalhprr(num) {
|
|||
|
this.stopFrustumRotation() // 先停止当前的定时器
|
|||
|
this.setInterval1 = setInterval(() => {
|
|||
|
// 限制 pitch 在 [60, 180] 范围内
|
|||
|
this.pitch = Math.max(60, Math.min(180, this.pitch + num))
|
|||
|
this.updateFrustumHPR(this.head, Cesium.Math.toRadians(this.pitch))
|
|||
|
}, 10)
|
|||
|
}
|
|||
|
// 停止视锥体旋转
|
|||
|
stopFrustumRotation() {
|
|||
|
if (this.setInterval1) {
|
|||
|
clearInterval(this.setInterval1)
|
|||
|
this.setInterval1 = null
|
|||
|
}
|
|||
|
}
|
|||
|
// 新增:绘制填充的视锥体
|
|||
|
drawFrustumFilled() {
|
|||
|
let that = this
|
|||
|
// console.log('that.options.show', that.options.show)
|
|||
|
|
|||
|
const transform = Cesium.Transforms.headingPitchRollToFixedFrame(
|
|||
|
this.position,
|
|||
|
this.hpr
|
|||
|
)
|
|||
|
|
|||
|
const frustumGeometry = new Cesium.FrustumGeometry({
|
|||
|
frustum: this.frustum,
|
|||
|
origin: Cesium.Matrix4.getTranslation(transform, new Cesium.Cartesian3()),
|
|||
|
orientation: Cesium.Quaternion.fromRotationMatrix(
|
|||
|
Cesium.Matrix4.getRotation(transform, new Cesium.Matrix3())
|
|||
|
)
|
|||
|
})
|
|||
|
|
|||
|
if (this.currentFrustumFilled) {
|
|||
|
this.viewer.scene.primitives.remove(this.currentFrustumFilled)
|
|||
|
}
|
|||
|
|
|||
|
this.currentFrustumFilled = new Cesium.Primitive({
|
|||
|
geometryInstances: new Cesium.GeometryInstance({
|
|||
|
geometry: frustumGeometry,
|
|||
|
attributes: {
|
|||
|
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
|
|||
|
Cesium.Color.fromAlpha(Cesium.Color.YELLOW, 0.4) // 半透明黄色填充
|
|||
|
)
|
|||
|
}
|
|||
|
}),
|
|||
|
appearance: new Cesium.MaterialAppearance({
|
|||
|
material: Cesium.Material.fromType('Color', {
|
|||
|
color: Cesium.Color.fromAlpha(Cesium.Color.YELLOW, 0.4) // 填充颜色
|
|||
|
}),
|
|||
|
translucent: true
|
|||
|
}),
|
|||
|
asynchronous: false,
|
|||
|
// show: false
|
|||
|
show: that.options.show
|
|||
|
})
|
|||
|
|
|||
|
this.viewer.scene.primitives.add(this.currentFrustumFilled)
|
|||
|
}
|
|||
|
// 绘制视锥体轮廓
|
|||
|
drawFrustumOutline() {
|
|||
|
let that = this
|
|||
|
// console.log('that.options.show', that.options.show)
|
|||
|
|
|||
|
const transform = Cesium.Transforms.headingPitchRollToFixedFrame(
|
|||
|
this.position,
|
|||
|
this.hpr
|
|||
|
)
|
|||
|
|
|||
|
const frustumOutlineGeometry = new Cesium.FrustumOutlineGeometry({
|
|||
|
frustum: this.frustum,
|
|||
|
origin: Cesium.Matrix4.getTranslation(transform, new Cesium.Cartesian3()),
|
|||
|
orientation: Cesium.Quaternion.fromRotationMatrix(
|
|||
|
Cesium.Matrix4.getRotation(transform, new Cesium.Matrix3())
|
|||
|
)
|
|||
|
})
|
|||
|
|
|||
|
if (this.currentFrustumOutline) {
|
|||
|
this.viewer.scene.primitives.remove(this.currentFrustumOutline)
|
|||
|
}
|
|||
|
|
|||
|
this.currentFrustumOutline = new Cesium.Primitive({
|
|||
|
geometryInstances: new Cesium.GeometryInstance({
|
|||
|
geometry: frustumOutlineGeometry,
|
|||
|
attributes: {
|
|||
|
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
|
|||
|
Cesium.Color.YELLOW
|
|||
|
)
|
|||
|
}
|
|||
|
}),
|
|||
|
appearance: new Cesium.PolylineColorAppearance({
|
|||
|
translucent: false
|
|||
|
}),
|
|||
|
asynchronous: false,
|
|||
|
show: that.options.show
|
|||
|
// show: false
|
|||
|
})
|
|||
|
|
|||
|
this.viewer.scene.primitives.add(this.currentFrustumOutline)
|
|||
|
}
|
|||
|
// 更新视锥体位置
|
|||
|
updateFrustumPosition(type = 'move', p, deg = 90, flag = true) {
|
|||
|
if (type === 'move') {
|
|||
|
// eslint-disable-next-line no-undef
|
|||
|
const point = turf.point([
|
|||
|
this.options.position.lng,
|
|||
|
this.options.position.lat
|
|||
|
])
|
|||
|
const degreesValue = Cesium.Math.toDegrees(this.hpr.heading)
|
|||
|
const bearing = degreesValue + deg
|
|||
|
const options = { units: 'degrees' }
|
|||
|
// eslint-disable-next-line no-undef
|
|||
|
const destination = turf.destination(point, p, bearing, options).geometry
|
|||
|
.coordinates
|
|||
|
|
|||
|
this.position = Cesium.Cartesian3.fromDegrees(
|
|||
|
destination[0],
|
|||
|
destination[1],
|
|||
|
this.options.position.alt + this.options.normalHeight
|
|||
|
)
|
|||
|
this.options.position.lng = destination[0]
|
|||
|
this.options.position.lat = destination[1]
|
|||
|
|
|||
|
this.viewer.camera.setView({
|
|||
|
destination: Cesium.Cartesian3.fromDegrees(
|
|||
|
destination[0],
|
|||
|
destination[1],
|
|||
|
this.viewer.camera.positionCartographic.height
|
|||
|
)
|
|||
|
})
|
|||
|
}
|
|||
|
if (type === 'update') {
|
|||
|
this.position = p
|
|||
|
this.options.videoUrl && this.updatePolygonPosition()
|
|||
|
}
|
|||
|
if (flag) {
|
|||
|
this.syncHpr()
|
|||
|
this.updateFrustumAttributes()
|
|||
|
}
|
|||
|
}
|
|||
|
// 同步视角
|
|||
|
syncHpr() {
|
|||
|
// console.log('this.viewer1', this.viewer1);
|
|||
|
if (this.viewer1) {
|
|||
|
const { lng, lat, alt } = this.options.position
|
|||
|
let pitch = -this.hpr.pitch - Cesium.Math.toRadians(-90.0)
|
|||
|
this.viewer1.camera.setView({
|
|||
|
destination: Cesium.Cartesian3.fromDegrees(
|
|||
|
lng,
|
|||
|
lat,
|
|||
|
alt + this.options.normalHeight
|
|||
|
),
|
|||
|
orientation: {
|
|||
|
heading: this.hpr.heading + Cesium.Math.toRadians(-90.0),
|
|||
|
pitch,
|
|||
|
roll: this.hpr.roll
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
// 更新视锥体的 HeadingPitchRoll
|
|||
|
updateFrustumHPR(
|
|||
|
h = this.head,
|
|||
|
p = this.pitch,
|
|||
|
r = 0,
|
|||
|
flag = true,
|
|||
|
type = ''
|
|||
|
) {
|
|||
|
function degreesToRadians(degrees) {
|
|||
|
return (degrees * Math.PI) / 180.0
|
|||
|
}
|
|||
|
if (type == 'alone') {
|
|||
|
this.hpr.heading = degreesToRadians(h)
|
|||
|
this.hpr.pitch = degreesToRadians(p)
|
|||
|
this.hpr.roll = degreesToRadians(r)
|
|||
|
} else {
|
|||
|
this.hpr.heading = Cesium.Math.negativePiToPi(h)
|
|||
|
this.hpr.pitch = Cesium.Math.negativePiToPi(p)
|
|||
|
this.hpr.roll = Cesium.Math.negativePiToPi(r)
|
|||
|
}
|
|||
|
if (flag) {
|
|||
|
this.syncHpr()
|
|||
|
this.updateFrustumAttributes()
|
|||
|
}
|
|||
|
}
|
|||
|
// 用于更新
|
|||
|
updateFrustumAttributes() {
|
|||
|
let that = this
|
|||
|
// 检查 position 和 hpr 是否已初始化
|
|||
|
if (!this.position || !this.hpr) {
|
|||
|
// eslint-disable-next-line no-console
|
|||
|
console.error('Position or HPR is not defined:', this.position, this.hpr)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// 生成变换矩阵
|
|||
|
const transform = Cesium.Transforms.headingPitchRollToFixedFrame(
|
|||
|
this.position,
|
|||
|
this.hpr
|
|||
|
)
|
|||
|
|
|||
|
if (!transform) {
|
|||
|
// eslint-disable-next-line no-console
|
|||
|
console.error('Transform generation failed.')
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
// 准备轮廓几何体和外观
|
|||
|
const outlineGeometry = new Cesium.FrustumOutlineGeometry({
|
|||
|
frustum: this.frustum,
|
|||
|
origin: Cesium.Matrix4.getTranslation(
|
|||
|
transform,
|
|||
|
new Cesium.Cartesian3()
|
|||
|
),
|
|||
|
orientation: Cesium.Quaternion.fromRotationMatrix(
|
|||
|
Cesium.Matrix4.getRotation(transform, new Cesium.Matrix3())
|
|||
|
)
|
|||
|
})
|
|||
|
|
|||
|
const outlineAppearance = new Cesium.PolylineColorAppearance({
|
|||
|
translucent: false
|
|||
|
})
|
|||
|
const outlineColor = Cesium.ColorGeometryInstanceAttribute.fromColor(
|
|||
|
Cesium.Color.YELLOW
|
|||
|
)
|
|||
|
|
|||
|
// 准备填充几何体和外观
|
|||
|
const filledGeometry = new Cesium.FrustumGeometry({
|
|||
|
frustum: this.frustum,
|
|||
|
origin: Cesium.Matrix4.getTranslation(
|
|||
|
transform,
|
|||
|
new Cesium.Cartesian3()
|
|||
|
),
|
|||
|
orientation: Cesium.Quaternion.fromRotationMatrix(
|
|||
|
Cesium.Matrix4.getRotation(transform, new Cesium.Matrix3())
|
|||
|
)
|
|||
|
})
|
|||
|
|
|||
|
const filledAppearance = new Cesium.MaterialAppearance({
|
|||
|
material: Cesium.Material.fromType('Color', {
|
|||
|
color: Cesium.Color.YELLOW.withAlpha(0.5)
|
|||
|
}),
|
|||
|
translucent: true
|
|||
|
})
|
|||
|
const filledColor = Cesium.ColorGeometryInstanceAttribute.fromColor(
|
|||
|
Cesium.Color.RED.withAlpha(0.5)
|
|||
|
)
|
|||
|
|
|||
|
// 删除旧的 Primitive
|
|||
|
if (this.currentFrustumOutline) {
|
|||
|
this.viewer.scene.primitives.remove(this.currentFrustumOutline)
|
|||
|
}
|
|||
|
if (this.currentFrustumFilled) {
|
|||
|
this.viewer.scene.primitives.remove(this.currentFrustumFilled)
|
|||
|
}
|
|||
|
|
|||
|
// 创建并添加新的轮廓 Primitive
|
|||
|
this.currentFrustumOutline = new Cesium.Primitive({
|
|||
|
geometryInstances: new Cesium.GeometryInstance({
|
|||
|
geometry: outlineGeometry,
|
|||
|
attributes: { color: outlineColor }
|
|||
|
}),
|
|||
|
appearance: outlineAppearance,
|
|||
|
asynchronous: false,
|
|||
|
show: that.options.show
|
|||
|
})
|
|||
|
this.viewer.scene.primitives.add(this.currentFrustumOutline)
|
|||
|
|
|||
|
// 创建并添加新的填充 Primitive
|
|||
|
this.currentFrustumFilled = new Cesium.Primitive({
|
|||
|
geometryInstances: new Cesium.GeometryInstance({
|
|||
|
geometry: filledGeometry,
|
|||
|
attributes: { color: filledColor }
|
|||
|
}),
|
|||
|
appearance: filledAppearance,
|
|||
|
asynchronous: false,
|
|||
|
show: that.options.show
|
|||
|
})
|
|||
|
this.viewer.scene.primitives.add(this.currentFrustumFilled)
|
|||
|
} catch (error) {
|
|||
|
// eslint-disable-next-line no-console
|
|||
|
console.error('Error in drawFrustum:', error)
|
|||
|
}
|
|||
|
}
|
|||
|
// 调整视锥体的 near 和 far 平面
|
|||
|
updateFrustumNearFar(newNear, newFar) {
|
|||
|
this.frustum.near = newNear
|
|||
|
this.frustum.far = newFar
|
|||
|
this.drawFrustumOutline()
|
|||
|
this.drawFrustumFilled()
|
|||
|
}
|
|||
|
// 调整视锥体的 fov
|
|||
|
updateFrustumFov(newFov) {
|
|||
|
this.frustum.fov = Cesium.Math.toRadians(newFov)
|
|||
|
this.drawFrustumOutline()
|
|||
|
this.drawFrustumFilled()
|
|||
|
}
|
|||
|
|
|||
|
get show() {
|
|||
|
return this.options.show
|
|||
|
}
|
|||
|
|
|||
|
set show(bool) {
|
|||
|
if (typeof bool === 'boolean') {
|
|||
|
this.options.show = bool
|
|||
|
this.currentFrustumOutline.show = bool
|
|||
|
this.currentFrustumFilled.show = bool
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
remove() {
|
|||
|
document.removeEventListener('keydown', this.keydownHandler)
|
|||
|
document.removeEventListener('keyup', this.keyupHandler)
|
|||
|
if (this.currentFrustumFilled) {
|
|||
|
this.viewer.scene.primitives.remove(this.currentFrustumFilled)
|
|||
|
}
|
|||
|
if (this.currentFrustumOutline) {
|
|||
|
this.viewer.scene.primitives.remove(this.currentFrustumOutline)
|
|||
|
}
|
|||
|
if (this.videoEntity) {
|
|||
|
this.viewer.entities.remove(this.videoEntity)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|