代码迁移

This commit is contained in:
zh
2025-07-03 13:54:01 +08:00
parent b04de8a084
commit 2a4da33e62
985 changed files with 358292 additions and 13 deletions

View File

@ -0,0 +1,89 @@
import MouseTip from '../../MouseTip/index'
import MouseEvent from '../../Event/index'
import Draw from '../../Draw/draw'
class DrawTakeOff extends Draw {
/**
* @constructor
* @desc 获取坐标点
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.options.tipText = options.tipText
? options.tipText
: '左键确定,右键结束;'
}
/**
* @desc 开始动态获取坐标点
* @method start
* @param cb {function} 回调函数
* @memberOf DrawPoint
* @example draw.start((err,position)=>{
*
* })
* */
start(cb) {
// eslint-disable-next-line no-undef
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
let car = undefined
// eslint-disable-next-line no-undef
YJ.Measure.SetMeasureStatus(true)
// this.options
this.tip = new MouseTip(this.options.tipText, this.sdk)
this.event = new MouseEvent(this.sdk)
this.isEntity = false
this.event.mouse_left((movement, cartesian) => {
this.end()
let p = this.cartesian3Towgs84(car || cartesian, this.viewer)
var pickedObject = this.viewer.scene.pick(movement.position)
if (
Cesium.defined(pickedObject) &&
Cesium.defined(pickedObject.id) &&
pickedObject.id.id === window.airportEntity.options.id
) {
this.isEntity = true
}
cb(null, p, this.isEntity)
})
this.event.mouse_right((movement, cartesian) => {
this.end()
cb(false)
})
this.event.mouse_move((movement, cartesian) => {
car = cartesian
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb(false)
} else {
this.end()
let p = this.cartesian3Towgs84(car || cartesian, this.viewer)
cb(null, p)
}
})
})
}
}
end() {
YJ.Measure.SetMeasureStatus(false)
this.event.destroy()
this.tip.destroy()
}
}
export default DrawTakeOff

View File

@ -0,0 +1,112 @@
// 根据米生成航线
function flyLine(earth, positions, unit) {
let arr = []
positions.forEach(item => {
arr.push([item.lng, item.lat])
})
arr.push(arr[0])
// eslint-disable-next-line no-undef
const turfPolygon = turf.polygon([arr])
// 获取四至
// eslint-disable-next-line no-undef
const turfExtent = turf.bbox(turfPolygon)
// 在turfPolygon中按网格取样点网格间距3米
// eslint-disable-next-line no-undef
const turfSamplePoints = turf.pointGrid(turfExtent, unit / 1000, {
units: 'kilometers',
mask: turfPolygon
})
// 将turf取样点转为Cesium的取样点
const cesiumSamplePoints = []
for (let i = 0; i < turfSamplePoints.features.length; i++) {
const coord = turfSamplePoints.features[i].geometry.coordinates
cesiumSamplePoints.push([coord[0], coord[1]])
}
// 计算两点的距离
function fromTo(point1, point2) {
if (!point2) {
return
}
// eslint-disable-next-line no-undef
let from = turf.point(point1)
// eslint-disable-next-line no-undef
let to = turf.point(point2)
// eslint-disable-next-line no-undef
return Math.round(turf.distance(from, to) * 1000)
}
// 进行分组并进行奇数反转
let polylinePosition = []
let flag = 0
let index = -1
for (let i = 0; i < cesiumSamplePoints.length; i++) {
if (fromTo(cesiumSamplePoints[i], cesiumSamplePoints[i + 1]) > unit) {
index++
let arr = cesiumSamplePoints.slice(flag, i + 1)
if (index % 2 !== 0) {
arr.reverse()
}
polylinePosition.push(arr)
flag = i + 1
}
}
let arr2 = cesiumSamplePoints.slice(flag, cesiumSamplePoints.length)
if ((index + 1) % 2 !== 0) {
arr2.reverse()
}
polylinePosition.push(arr2)
return polylinePosition.flat()
}
// 获取高程
function sampleHeightMostDetailed(earth, positions) {
return earth.viewer.scene.sampleHeightMostDetailed([
new Cesium.Cartographic.fromDegrees(positions[0], positions[1])
])
}
// 计算高程
async function countHeight(earth, item) {
return await sampleHeightMostDetailed(earth, item)
}
function cartesian3Towgs84(earth, cartesian) {
const viewer = earth.viewer
var ellipsoid = 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 {
longitude: lng,
latitude: lat,
height: alt
}
}
//更新路径高度
async function updateHeight(earth, height, positions, cb) {
let Cartesian = []
let locationList = []
for (let i = 0; i < positions.length; i++) {
const element = positions[i]
let Cartographic = await countHeight(earth, element)
if (isNaN(Cartographic[0].height)) {
Cartographic[0].height = 0
}
Cartographic[0].height = Cartographic[0].height + height
Cartesian.push(Cesium.Cartographic.toCartesian(Cartographic[0]))
if (i < positions.length) {
cb({
cur: i + 1,
total: positions.length
})
}
}
for (let i = 0; i < Cartesian.length; i++) {
locationList.push(cartesian3Towgs84(earth, Cartesian[i]))
}
let arr = [locationList, Cartesian]
cb(arr)
}
let GenerateRoute = {
flyLine,
updateHeight
}
export default GenerateRoute

View File

@ -0,0 +1,272 @@
export default class BillordPointLine {
constructor(options, viewer) {
this.options = { ...options }
this.pointEntity = null
this.billboardEntity = null
this.lineEntity = null
this.updatedPosition = []
this.pointUpdatedPosition = []
this.viewer = viewer
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
this.pinBuilder = new Cesium.PinBuilder()
this.index = null
//定义屏幕点击事件处理器
BillordPointLine.setDefaultValue(this)
BillordPointLine.init(this)
}
static setDefaultValue(that) {
that.options.positions = that.options.positions || {}
that.options.normalHeight = that.options.normalHeight || 100
that.options.airHeight = that.options.airHeight || 100
that.options.image = that.options.image || '/static/img/cluster2.png'
that.options.show = that.options.show || true
that.options.index = that.options.index || 1
that.options.saveFun = that.options.saveFun || null
that.options.selectFun = that.options.selectFun || null
that.options.keyboard = that.options.keyboard ?? true
that.options.updateFrustumFun = that.options.updateFrustumFun || null
that.options.frustum = that.options.frustum || null
}
static init(that) {
let positions = that.options.positions
// 添加一个Point稍微偏离地面高度使其完全可见
that.pointEntity = that.viewer.entities.add({
show: that.options.show,
position: Cesium.Cartesian3.fromDegrees(positions.lng, positions.lat, 0), // 地面上
point: {
pixelSize: 8,
color: Cesium.Color.WITHE,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 使用相对地面或贴地,
disableDepthTestDistance: 0
}
})
//
let pinIndex = that.pinBuilder
.fromText(
that.options.index,
Cesium.Color.fromCssColorString('#00d590'),
36
)
.toDataURL()
let altitude = 0
if (positions.altitude) {
altitude = positions.altitude
} else {
altitude = that.options.normalHeight
}
// 添加一个Billboard
that.billboardEntity = that.viewer.entities.add({
show: that.options.show,
position: Cesium.Cartesian3.fromDegrees(
positions.lng,
positions.lat,
positions.alt + that.options.normalHeight
),
// 判断altitude是否有值
label: {
text: `Lat: ${positions.lng.toFixed(8)}\nLon: ${positions.lat.toFixed(
8
)}\nAlt: ${altitude.toFixed(8)}m`,
font: '14px sans-serif',
fillColor: Cesium.Color.YELLOW,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 2,
pixelOffset: new Cesium.Cartesian2(0, -60), // 标签偏移量,防止重叠
heightReference: Cesium.HeightReference.RELATIVE_TO_TERRAIN, // 确保标签与地面贴合
show: false
},
billboard: {
image: pinIndex, // 示例图像路径
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 图像底部对齐
width: 36,
height: 36
},
index: that.options.index
})
// 创建一个连接Point和Billboard的竖线
that.lineEntity = that.viewer.entities.add({
show: that.options.show,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return [
that.pointEntity.position.getValue(),
that.billboardEntity.position.getValue()
]
}, false),
width: 1,
material: new Cesium.PolylineOutlineMaterialProperty({
outlineColor: Cesium.Color.GAINSBORO,
outlineWidth: 1,
color: Cesium.Color.WITHE
}),
zIndex: 99999999
}
})
if (that.options.keyboard) {
that.changeAltitude()
}
that.handler.setInputAction(function(movement) {
var pickedObject = that.viewer.scene.pick(movement.position)
if (
Cesium.defined(pickedObject) &&
Cesium.defined(pickedObject.id) &&
pickedObject.id === that.billboardEntity
) {
if (that.options.selectFun) {
that.options.selectFun(that.billboardEntity.index - 1)
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
// 改变高度
changeAltitude() {
var isMouseDown = false
var startPosition
var initialHeight
let that = this
let HHH = false
// 标识Alt键是否被按下
document.addEventListener('keydown', function(event) {
const key = event.key // 获取按下的键名
// 检查特定键是否被按下
if (key === 'h') {
HHH = true
}
})
document.addEventListener('keyup', function(event) {
HHH = false
})
// 按下鼠标左键
this.handler.setInputAction(function(movement) {
var pickedObject = that.viewer.scene.pick(movement.position)
if (
Cesium.defined(pickedObject) &&
Cesium.defined(pickedObject.id) &&
pickedObject.id === that.billboardEntity
) {
isMouseDown = true
startPosition = movement.position
// 获取Billboard当前的地理高度
var positionCartographic = Cesium.Cartographic.fromCartesian(
that.billboardEntity.position.getValue()
)
initialHeight = positionCartographic.height
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN)
// 移动鼠标
this.handler.setInputAction(function(movement) {
if (isMouseDown && HHH == false) {
// 移动位置
var newCartesian = that.viewer.scene.pickPosition(movement.endPosition)
that.disableCameraDrag(that.viewer, false)
if (newCartesian) {
var newCartographic = Cesium.Cartographic.fromCartesian(newCartesian)
// 保持高度不变
var newLongitude = newCartographic.longitude
var newLatitude = newCartographic.latitude
var updatedPosition = Cesium.Cartesian3.fromRadians(
newLongitude,
newLatitude,
initialHeight
)
var pointUpdatedPosition = Cesium.Cartesian3.fromRadians(
newLongitude,
newLatitude,
0
)
that.billboardEntity.position = new Cesium.CallbackProperty(() => {
return updatedPosition
}, false)
that.billboardEntity.label.text = `Lat: ${Cesium.Math.toDegrees(
newLongitude
).toFixed(6)}\nLon: ${Cesium.Math.toDegrees(newLatitude).toFixed(
6
)}\nAlt: ${initialHeight.toFixed(2)}m`
that.pointEntity.position = new Cesium.CallbackProperty(() => {
return pointUpdatedPosition
}, false)
}
}
if (isMouseDown && HHH) {
console.log(HHH)
// 改变高度
var endPosition = movement.endPosition
var deltaY = startPosition.y - endPosition.y // 计算Y轴方向上的移动距离
// 根据鼠标移动的距离来调整高度
var newHeight = initialHeight + deltaY
// 更新billboard位置
var positionCartographic = Cesium.Cartographic.fromCartesian(
that.billboardEntity.position.getValue()
)
var newPosition = Cesium.Cartesian3.fromDegrees(
Cesium.Math.toDegrees(positionCartographic.longitude),
Cesium.Math.toDegrees(positionCartographic.latitude),
newHeight
)
// 禁用相机
that.disableCameraDrag(that.viewer, false)
that.billboardEntity.position = new Cesium.CallbackProperty(() => {
return newPosition
}, false)
that.billboardEntity.label.text = `Lat: ${Cesium.Math.toDegrees(
positionCartographic.longitude
).toFixed(6)}\nLon: ${Cesium.Math.toDegrees(
positionCartographic.latitude
).toFixed(6)}\nAlt: ${newHeight.toFixed(2)}m`
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
// 松开鼠标左键
this.handler.setInputAction(function(movement) {
var pickedObject = that.viewer.scene.pick(movement.position)
isMouseDown = false // 禁用相机
HHH = false //
that.disableCameraDrag(that.viewer, true)
// 更新frustum的位置
if (
Cesium.defined(pickedObject) &&
Cesium.defined(pickedObject.id) &&
pickedObject.id === that.billboardEntity
) {
if (that.options.saveFun) {
that.options.saveFun(null, false)
}
if (that.options.selectFun) {
that.options.selectFun(that.billboardEntity.index - 1)
}
that.options.frustum.updatePositionHeight(
that.billboardEntity.position.getValue()
)
}
}, Cesium.ScreenSpaceEventType.LEFT_UP)
}
disableCameraDrag(viewer, bool) {
viewer.scene.screenSpaceCameraController.enableRotate = bool
viewer.scene.screenSpaceCameraController.enableTranslate = bool
viewer.scene.screenSpaceCameraController.enableZoom = bool
viewer.scene.screenSpaceCameraController.enableTilt = bool
viewer.scene.screenSpaceCameraController.enableLook = bool
}
get show() {
return this.options.show
}
/**
* @param {boolean} bool
*/
set show(bool) {
if (typeof bool === 'boolean') {
this.pointEntity.show = bool
this.billboardEntity.show = bool
this.lineEntity.show = bool
}
}
remove() {
this.viewer.entities.remove(this.pointEntity)
this.viewer.entities.remove(this.billboardEntity)
this.viewer.entities.remove(this.lineEntity)
}
}

673
src/Obj/AirLine/frustum.js Normal file
View File

@ -0,0 +1,673 @@
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)
}
}
}

257
src/Obj/AirLine/frustum2.js Normal file
View File

@ -0,0 +1,257 @@
export default class FRUSTUN {
constructor(options, viewer, viewer1) {
this.options = { ...options }
this.viewer = viewer
this.viewer1 = viewer1
this.head = 0
this.po = 0.00001
this.position = null
this.hpr = null
this.currentFrustumOutline = null
this.frustum = null
this.setInterval = null
FRUSTUN.setDefaultValue(this)
this.create()
}
static setDefaultValue(that) {
that.options.position = that.options.position || {}
that.options.fov = that.options.fov || 20
that.options.aspectRatio = that.options.aspectRatio || 1
that.options.near = that.options.near || 1
that.options.far = that.options.far || 100
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
}
// 初始化视锥体
create() {
this.frustum = new Cesium.PerspectiveFrustum()
this.frustum.fov = Cesium.Math.toRadians(this.options.fov)
this.frustum.aspectRatio = 1.0 // 保持 aspectRatio 不变
this.frustum.near = 1.0
this.frustum.far = 50.0
// 设置初始视锥体位置和方向
let { lng, lat, alt } = this.options.position
let { heading, pitch, roll } = this.options
this.position = Cesium.Cartesian3.fromDegrees(lng, lat, alt + 100)
this.hpr = new Cesium.HeadingPitchRoll(
Cesium.Math.toRadians(heading),
Cesium.Math.toRadians(pitch),
Cesium.Math.toRadians(roll)
)
console.log(heading)
this.drawFrustumOutline()
this.monitorKeyboard()
}
setIntervalhpr(num) {
if (!this.setInterval1) {
this.setInterval1 = setInterval(() => {
this.head += num
this.updateFrustumHPR(Cesium.Math.toRadians(this.head))
}, 10)
}
}
// 监听 键盘事件
// monitorKeyboard() {
// let that = this;
// document.addEventListener("keydown", function (event) {
// switch (event.code) {
// case "KeyQ":
// that.setIntervalhpr(-0.45);
// break;
// case "KeyE":
// that.setIntervalhpr(0.45);
// break;
// case "KeyW":
// that.updateFrustumPosition("move", -0.00001);
// break;
// case "KeyS":
// that.updateFrustumPosition("move", 0.00001);
// break;
// case "KeyA":
// that.updateFrustumPosition("move", -0.00001, 0);
// break;
// case "KeyD":
// that.updateFrustumPosition("move", 0.00001, 0);
// break;
// default:
// break;
// }
// });
// document.addEventListener("keyup", function (event) {
// clearInterval(that.setInterval1);
// that.setInterval1 = null; // 重置 interval
// });
// }
// 监听键盘事件
monitorKeyboard() {
const keyActions = {
KeyQ: () => this.setIntervalhpr(-0.45),
KeyE: () => this.setIntervalhpr(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) // 降低高度
}
document.addEventListener('keydown', event => {
if (keyActions[event.code]) keyActions[event.code]()
})
document.addEventListener('keyup', () => this.stopFrustumRotation())
}
// 停止视锥体旋转
stopFrustumRotation() {
clearInterval(this.setInterval1)
this.setInterval1 = null
}
// 使用 HeadingPitchRoll 创建视锥体轮廓
drawFrustumOutline() {
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
})
this.viewer.scene.primitives.add(this.currentFrustumOutline)
}
// 更新视锥体位置
updateFrustumPosition(type = 'move', p, deg = 90) {
if (type == 'move') {
var point = turf.point([
this.options.position.lng,
this.options.position.lat
])
const degreesValue = Cesium.Math.toDegrees(this.hpr.heading)
var distance = p
var bearing = degreesValue + deg
var options = { units: 'degrees' }
var destination = turf.destination(point, distance, bearing, options)
.geometry.coordinates
this.position = Cesium.Cartesian3.fromDegrees(
destination[0],
destination[1],
this.options.position.alt + 100
)
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
),
orientation: {
heading: this.viewer.camera.heading,
pitch: this.viewer.camera.pitch,
roll: this.viewer.camera.roll
}
})
}
if (type == 'update') {
this.position = p
}
// this.tongbuHpr();
this.drawFrustumOutline()
}
// 同步视角
tongbuHpr() {
const { lng, lat, alt } = this.options.position
this.viewer1.camera.setView({
destination: new Cesium.Cartesian3.fromDegrees(lng, lat, alt + 100),
orientation: {
heading: this.hpr.heading + Cesium.Math.toRadians(-90.0),
pitch: this.hpr.pitch + Cesium.Math.toRadians(-90.0),
roll: this.hpr.roll
}
})
}
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.tongbuHpr();
this.drawFrustumOutline() // 重新绘制视锥体轮廓
}
// 更新视锥体的 HeadingPitchRoll
updateFrustumHPR(h = 0, p = Cesium.Math.toRadians(90), r = 0) {
this.hpr.heading = Cesium.Math.negativePiToPi(h)
this.hpr.pitch = Cesium.Math.negativePiToPi(p)
this.hpr.roll = Cesium.Math.negativePiToPi(r)
// this.tongbuHpr();
this.drawFrustumOutline()
}
// 封装的函数:调整视锥体的 near 和 far 平面
updateFrustumNearFar(newNear, newFar) {
this.frustum.near = newNear
this.frustum.far = newFar
this.drawFrustumOutline()
}
// 封装的函数:调整视锥体的 fov远裁剪面的大小
updateFrustumFov(newFov) {
this.frustum.fov = Cesium.Math.toRadians(newFov)
this.drawFrustumOutline()
this.viewer.scene.requestRender() // 强制重新渲染场景
}
// 封装的函数:调整视锥体的高度
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.drawFrustumOutline()
this.viewer.scene.requestRender() // 强制重新渲染场景
}
get show() {
return this.options.show
}
set show(bool) {
if (typeof bool == 'boolean') {
this.currentFrustumOutline.show = bool
}
}
remove() {
if (this.currentFrustumOutline) {
this.viewer.scene.primitives.remove(this.currentFrustumOutline)
}
}
}

290
src/Obj/AirLine/index.js Normal file
View File

@ -0,0 +1,290 @@
import { closeRotateAround, closeViewFollow} from '../../Global/global'
export default class AirLine {
constructor(options, earth) {
this.earth = earth
this.positions = null
this.options = { ...options }
this.Model = null
this.pointCollection = null
this.entity = null
this.dataSouce = new Cesium.CustomDataSource('airLineSource' + options.id)
AirLine.setDefaultValue(this)
AirLine.add(this)
}
static setDefaultValue(that) {
that.options.id = that.options.id || Cesium.createGuid()
that.options.positions = that.options.positions || []
that.options.width = that.options.width || 5
that.options.show = that.options.show || true
that.options.color = that.options.color || '#00FFFF'
that.options.height = that.options.height || 20
that.options.url = that.options.url || ''
that.options.modelShow = that.options.modelShow || false
that.options.flag = that.options.flag || true
that.options.speed = that.options.speed || 1
that.options.billboard.show = that.options.billboard.show || true
that.options.billboard.image = that.options.billboard.image || ''
that.options.billboard.scale = that.options.billboard.scale || 1
that.options.billboard.width = that.options.billboard.width || 64
that.options.billboard.height = that.options.billboard.height || 64
that.options.billboard.near = that.options.billboard.near ?? 1000
that.options.billboard.far = that.options.billboard.far ?? 10000
}
static add(that) {
if (that.options.positions.length < 3) {
// eslint-disable-next-line no-console
console.warn('坐标数量至少需要3个')
return
}
that.pointCollection = that.earth.viewer.scene.primitives.add(
new Cesium.PointPrimitiveCollection()
)
for (let i = 0; i < that.options.positions.length - 1; i++) {
let entity = that.createLine([
that.options.positions[i],
that.options.positions[i + 1]
])
that.dataSouce.entities.add(entity)
}
that.earth.viewer.dataSources.add(that.dataSouce).then(r => {})
that.createPoint()
that.createModel()
}
// 创建线条
createLine(positions) {
let entity = new Cesium.Entity({
id: Cesium.createGuid(),
polyline: {
positions: positions,
clampToGround: false,
width: this.options.width,
material: new Cesium.PolylineArrowMaterialProperty(
Cesium.Color.fromCssColorString(this.options.color)
),
zIndex: 99999999
},
show: true,
})
return entity
}
// 生成点
createPoint() {
this.options.positions.forEach((item, index) => {
this.pointCollection.add({
show: true,
position: item,
pixelSize: 10.0,
color: Cesium.Color.GREENYELLOW,
id: index
})
})
}
get show() {
return this.entity.show
}
set show(status) {
if (typeof status == 'boolean') this.entity.show = status
}
get modelShow() {
return this.Model.show
}
set modelShow(status) {
if (typeof status == 'boolean') this.Model.show = status
}
// 添加一个模型
createModel() {
let scaleByDistance = new Cesium.NearFarScalar(
this.options.billboard.near,
1,
this.options.billboard.far,
0
)
const position = this.options.positions[0]
const heading = Cesium.Math.toRadians(0)
const pitch = 0
const roll = 0
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
const orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr
)
this.Model = this.earth.viewer.entities.add({
name: this.options.billboard.image,
position,
// orientation,
billboard: {
show: this.options.billboard.show,
image: this.options.billboard.image,
scale: this.options.billboard.scale,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
width: this.options.billboard.width,
height: this.options.billboard.height,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
scaleByDistance,
pixelOffsetScaleByDistance: scaleByDistance
},
// model: {
// uri: this.options.url,
// minimumPixelSize: 128,
// maximumScale: 20000
// },
show: this.options.modelShow
})
}
// 开始飞行
start() {
if (!this.options.positions) {
// eslint-disable-next-line no-console
console.warn('请先绘制并且生成航线')
return
}
let i
let that = this
this.timer = setInterval(function() {
if (this.index) {
i = this.index
} else {
i = 0
}
i++
this.index = i
if (i > that.options.positions.length) {
clearInterval(this.timer)
} else {
let position = that.options.positions[i]
if (position) {
that.Model.position = new Cesium.CallbackProperty(e => {
return position
})
that.Model.orientation = that.direction(
that.options.positions[i - 1],
that.options.positions[i]
).orientation
}
}
}, 100)
}
// 停止飞行
stop() {
if (this.timer) {
clearInterval(this.timer)
}
}
// 飞入
flyTo() {
closeRotateAround(this.earth)
closeViewFollow(this.earth)
let positionArray = []
for (let i = 0; i < this.options.positions.length; i++) {
let item = this.options.positions[i]
positionArray.push(item.x, item.y, item.z)
}
// console.log('cartesian',cartesian);
// let position = Cesium.Cartographic.fromCartesian(cartesian)
// console.log('position',position);
let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray)
this.earth.viewer.camera.flyToBoundingSphere(BoundingSphere, {
offset: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
}
})
}
// 计算一个到另一个点的方向
direction(pointA, pointB) {
//向量AB
const vector2 = Cesium.Cartesian3.subtract(
pointB,
pointA,
new Cesium.Cartesian3()
)
//归一化
const normal = Cesium.Cartesian3.normalize(vector2, new Cesium.Cartesian3())
//旋转矩阵 rotationMatrixFromPositionVelocity源码中有并未出现在cesiumAPI中
const rotationMatrix3 = Cesium.Transforms.rotationMatrixFromPositionVelocity(
pointA,
normal,
Cesium.Ellipsoid.WGS84
)
const modelMatrix4 = Cesium.Matrix4.fromRotationTranslation(
rotationMatrix3,
pointA
)
// 获取getHeadingPitchRoll
let m1 = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Matrix4.getTranslation(modelMatrix4, new Cesium.Cartesian3()),
Cesium.Ellipsoid.WGS84,
new Cesium.Matrix4()
)
// 矩阵相除
let m3 = Cesium.Matrix4.multiply(
Cesium.Matrix4.inverse(m1, new Cesium.Matrix4()),
modelMatrix4,
new Cesium.Matrix4()
)
// 得到旋转矩阵
let mat3 = Cesium.Matrix4.getMatrix3(m3, new Cesium.Matrix3())
// 计算四元数
let q = Cesium.Quaternion.fromRotationMatrix(mat3)
// 计算旋转角(弧度)
let hpr = Cesium.HeadingPitchRoll.fromQuaternion(q)
// hpr.pitch = hpr.pitch + 3.14 / 2 + 3.14;
hpr.pitch = 0
let orientation = Cesium.Transforms.headingPitchRollQuaternion(pointA, hpr)
return { hpr, orientation }
}
// 删除
remove() {
this.earth.viewer.entities.remove(this.entity)
this.dataSouce.entities.removeAll()
this.pointCollection && this.pointCollection.destroy()
this.Model && this.earth.viewer.entities.remove(this.Model)
this.timer && clearInterval(this.timer)
this.timer = null
}
// 返回照片数量 航点数
getInfo() {
return {
length: this.countLength(),
time: this.countTime(),
waypoint: this.options.positions.length,
photos: this.options.positions.length
}
}
//计算航线得长度
countLength() {
let totalDistance = 0
for (let i = 0; i < this.options.positions.length - 1; i++) {
const start = this.options.positions[i]
const end = this.options.positions[i + 1]
const distance = Cesium.Cartesian3.distance(start, end)
totalDistance += distance
}
return totalDistance.toFixed(2) // 返回保留两位小数的距离
}
//计算航线时间
countTime() {
let time = Math.floor(Number(this.countLength())) / this.options.speed
let s = Math.floor(time % 60)
let m = Math.floor(time / 60)
let str = m + '分' + s + '秒'
return str
}
//显示隐藏
isShow(status) {
if (typeof status === 'boolean') {
this.modelShow = status
this.dataSouce.show = status
let len = this.pointCollection.length
for (let i = 0; i < len; ++i) {
let p = this.pointCollection.get(i)
p.show = status
}
} else {
// eslint-disable-next-line no-console
console.error('参数须为Boolean类型')
}
}
}

View File

@ -0,0 +1,359 @@
import FRUSTUN from './frustum.js'
import BillordPointLine from './billord_point_line'
export default class PointRoute {
constructor(options = {}, viewer, viewer1) {
this.options = { ...options }
this.viewer = viewer
this.viewer1 = viewer1
this.entity = null
this.frustum = null
this.billordPointLineMaps = []
this.index = 0
this.positions = []
PointRoute.setDefaultValue(this)
this.create()
}
static setDefaultValue(that) {
that.options.positions = that.options.positions || []
that.options.show = that.options.show || true
that.options.color = that.options.color || '#00d590'
that.options.height = that.options.height || 500
that.options.speed = that.options.speed || 1
that.options.frustumShow = that.options.frustumShow ?? true
that.options.saveFun = that.options.saveFun || null
that.options.selectFun = that.options.selectFun || null
that.options.keyboard = that.options.keyboard ?? true
that.options.normalHeight = that.options.normalHeight || 100
that.options.airHeight = that.options.airHeight || 100
}
create() {
if (this.options.positions.length < 2) {
return
}
let that = this
let { frustumShow } = that.options
this.entity = this.viewer.entities.add({
show: this.options.show,
polyline: {
positions: new Cesium.CallbackProperty(() => {
let positions = []
for (let i = 0; i < this.billordPointLineMaps.length; i++) {
const element = this.billordPointLineMaps[i]
positions.push(element.billboardEntity.position.getValue())
}
return positions
}, false),
width: 3,
material: Cesium.Color.fromCssColorString(this.options.color)
}
})
// 创建点、线、billbord
for (let i = 0; i < this.options.positions.length; i++) {
const element = this.options.positions[i]
// console.log("elementelementelement", element);
if (frustumShow && i == this.index) {
this.frustum = new FRUSTUN(
{
position: element,
show: false,
arr: this.options.positions,
index: i,
normalHeight: this.options.normalHeight
},
this.viewer,
this.viewer1
)
}
let op = new BillordPointLine(
{
positions: element,
index: i + 1,
saveFun: that.options.saveFun,
selectFun: that.options.selectFun,
keyboard: that.options.keyboard,
updateFrustumFun: that.updateFrustumPosition,
normalHeight: that.options.normalHeight,
frustum: that.frustum,
airHeight: that.options.airHeight
},
this.viewer
)
this.billordPointLineMaps.push(op)
}
this.onKey()
}
get show() {
return this.options.show
}
set show(bool) {
if (typeof bool === 'boolean') {
this.frustum.currentFrustumOutline.show = bool
this.billordPointLineMaps.forEach(item => {
item.show = bool
})
this.entity.show = bool
}
}
// 监听键盘事件
onKey() {
let that = this
document.addEventListener('keydown', function(event) {
switch (event.key) {
case 'ArrowUp':
that.index += 1
that.updateFrustum(true)
break
case 'ArrowDown':
that.index -= 1
that.updateFrustum(false)
break
}
})
}
// 更新frustum
updateFrustum(flag) {
console.log(this.index)
let obj
if (this.index > this.options.positions.length - 1 || this.index < 0) {
let str = this.index > 0 ? '已选中最后一个航点' : '已选中第一个航点'
alert(str)
return
}
for (let i = 0; i < this.billordPointLineMaps.length; i++) {
const element = this.billordPointLineMaps[i]
const hpr = null
if (i == this.index) {
let position = element.billboardEntity.position.getValue()
if (this.index !== 0) {
obj = this.direction(
this.billordPointLineMaps[
i - 1
].billboardEntity.position.getValue(),
element.billboardEntity.position.getValue()
)
hpr = obj.hpr
}
if (this.index == 0) {
obj = this.direction(
this.billordPointLineMaps[0].billboardEntity.position.getValue(),
this.billordPointLineMaps[1].billboardEntity.position.getValue()
)
hpr = obj.hpr
}
if (hpr) {
this.frustum.updateFrustumHPR(
hpr.heading,
this.frustum.pitch,
hpr.roll
)
}
if (position) {
this.frustum.updateFrustumPosition('update', position)
}
}
}
}
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
}
}
// 计算一个到另一个点的方向
direction(pointA, pointB) {
//向量AB
const vector2 = Cesium.Cartesian3.subtract(
pointA,
pointB,
new Cesium.Cartesian3()
)
//归一化
const normal = Cesium.Cartesian3.normalize(vector2, new Cesium.Cartesian3())
//旋转矩阵 rotationMatrixFromPositionVelocity源码中有并未出现在cesiumAPI中
const rotationMatrix3 = Cesium.Transforms.rotationMatrixFromPositionVelocity(
pointA,
normal,
Cesium.Ellipsoid.WGS84
)
const modelMatrix4 = Cesium.Matrix4.fromRotationTranslation(
rotationMatrix3,
pointA
)
// 获取getHeadingPitchRoll
let m1 = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Matrix4.getTranslation(modelMatrix4, new Cesium.Cartesian3()),
Cesium.Ellipsoid.WGS84,
new Cesium.Matrix4()
)
// 矩阵相除
let m3 = Cesium.Matrix4.multiply(
Cesium.Matrix4.inverse(m1, new Cesium.Matrix4()),
modelMatrix4,
new Cesium.Matrix4()
)
// 得到旋转矩阵
let mat3 = Cesium.Matrix4.getMatrix3(m3, new Cesium.Matrix3())
// 计算四元数
let q = Cesium.Quaternion.fromRotationMatrix(mat3)
// 计算旋转角(弧度)
let hpr = Cesium.HeadingPitchRoll.fromQuaternion(q)
// hpr.pitch = hpr.pitch + 3.14 / 2 + 3.14;
hpr.pitch = 90
let orientation = Cesium.Transforms.headingPitchRollQuaternion(pointA, hpr)
return { hpr, orientation }
}
/**
*
* @param {index} 索引
*/
// 删除航点
delPosition(index) {
this.options.positions.splice(index, 1)
// this.options.positions = this.options.positions.filter((item, index) => index !== i);
this.remove()
this.create()
}
// 获取最新的positions
getNewPositions() {
let positions = []
for (let i = 0; i < this.billordPointLineMaps.length; i++) {
const element = this.billordPointLineMaps[i]
let position = this.cartesian3Towgs84(
element.billboardEntity.position.getValue()
)
positions.push(position)
}
return positions
}
// 删除
remove() {
this.billordPointLineMaps.forEach((item, i) => {
item.remove()
})
if (this.frustum) {
this.frustum.remove()
}
this.viewer.entities.remove(this.entity)
this.billordPointLineMaps = []
}
/**
*
* @param {String} type
* @param {Number} index
* @param {Array} position
*/
// 新增航点 beforeafterend
addPoint(positions) {
this.options.positions = positions
this.remove()
this.create()
}
// 根据选中的点更新视锥的位置
updateFrustumPosition(index) {
if (!this.billordPointLineMaps || this.billordPointLineMaps.length === 0)
return
if (this.frustum) {
this.frustum.show = true
}
let current = this.billordPointLineMaps[
index
].billboardEntity.position.getValue()
if (index !== 0) {
let obj
let after =
index === this.billordPointLineMaps.length - 1
? this.billordPointLineMaps[
index - 1
].billboardEntity.position.getValue() // 获取前一个位置
: this.billordPointLineMaps[
index + 1
].billboardEntity.position.getValue() // 获取下一个位置
obj = this.direction(
index === this.billordPointLineMaps.length - 1 ? after : current,
index === this.billordPointLineMaps.length - 1 ? current : after
)
let { hpr } = obj
this.frustum.updateFrustumHPR(
hpr.heading,
Cesium.Math.toRadians(this.frustum.pitch),
hpr.roll
)
} else {
let obj
let after = this.billordPointLineMaps[1].billboardEntity.position.getValue()
obj = this.direction(current, after)
let { hpr } = obj
this.frustum.updateFrustumHPR(
hpr.heading,
Cesium.Math.toRadians(this.frustum.pitch),
hpr.roll
)
}
if (current) {
this.frustum.updateFrustumPosition('update', current)
}
let position = this.cartesian3Towgs84(current)
this.billordPointLineMaps.forEach(item => {
item.billboardEntity.label.show = false // 先将所有元素的 label.show 设置为 false
})
const targetItem = this.billordPointLineMaps.find(
item => item.billboardEntity.index == index + 1
)
if (targetItem) {
targetItem.billboardEntity.label.show = true // 然后找到匹配的 index 设置为 true
}
return position
}
flyTo() {
let positionArray = []
for (let i = 0; i < this.options.positions.length; i++) {
let a = Cesium.Cartesian3.fromDegrees(
this.options.positions[i].lng,
this.options.positions[i].lat,
this.options.positions[i].alt + this.options.height
)
positionArray.push(a.x, a.y, a.z)
}
let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray)
this.viewer.camera.flyToBoundingSphere(BoundingSphere, {
offset: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-80.0),
roll: Cesium.Math.toRadians(0.0)
}
})
}
//计算航线的长度
countLength() {
if (this.options.positions.length < 2) {
return 0
} else {
let lineString = []
this.options.positions.forEach(item => {
lineString.push([item.lng, item.lat])
})
var line = turf.lineString(lineString)
return (turf.length(line) * 1000).toFixed(2)
}
}
//计算航线时间
countTime() {
let time = Math.floor(Number(this.countLength())) / this.options.speed
let s = Math.floor(time % 60)
let m = Math.floor(time / 60)
let str = m + '分' + s + '秒'
return str
}
}