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 */ // 新增航点 (before,after,end) 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 } }