// ViewShed.js import glsl from './glsl' import Event from "../../../Event"; import MouseTip from "../../../MouseTip"; import Tools from "../../../Tools"; import Controller from "../../../Controller"; import Dialog from '../../../BaseDialog'; import { html } from "./_element"; /** * @constructor * @description 可视域分析(测试中) * @param sdk * @param {Object} options 选项。 * @param {Cesium.Cartesian3} options.viewPosition 观测点位置。 * @param {Cesium.Cartesian3} options.viewPositionEnd 最远观测点位置(如果设置了观测距离,这个属性可以不设置)。 * @param {Number} options.viewDistance 观测距离(单位`米`)。 * @param {Number} options.viewHeading 航向角(单位`度`)。 * @param {Number} options.viewPitch 俯仰角(单位`度`)。 * @param {Number} options.horizontalViewAngle=90 可视域水平夹角(单位`度`)。 * @param {Number} options.verticalViewAngle=60 可视域垂直夹角(单位`度`)。 * @param {String} options.visibleAreaColor=#008000 可视区域颜色(默认值`绿色`)。 * @param {String} options.invisibleAreaColor=#FF0000 不可视区域颜色(默认值`红色`)。 */ class ViewShedStage extends Tools { constructor(sdk, options = {}, _Dialog = {}) { super(sdk, options) // if (Object.hasOwn(options.viewPosition, 'lng') && Object.hasOwn(options.viewPosition, 'lat') && Object.hasOwn(options.viewPosition, 'alt')) { // this.error = '请提供观测点位置!' // window.ELEMENT && window.ELEMENT.Message({ // message: '请提供观测点位置!', // type: 'warning', // duration: 1500 // }); // return // } this.viewer = sdk.viewer; this.options = {} this.options.viewPosition = options.viewPosition; this.options.viewPositionEnd = options.viewPositionEnd; this.options.horizontalViewAngle = (options.horizontalViewAngle || options.horizontalViewAngle === 0) ? options.horizontalViewAngle : 90.0; this.options.verticalViewAngle = (options.verticalViewAngle || options.verticalViewAngle === 0) ? options.verticalViewAngle : 60.0; this.options.visibleAreaColor = options.visibleAreaColor || '#008000'; this.options.invisibleAreaColor = options.invisibleAreaColor || '#FF0000'; // this.enabled = (typeof options.enabled === "boolean") ? options.enabled : true; // this.softShadows = (typeof options.softShadows === "boolean") ? options.softShadows : true; // this.size = options.size || 10240; // 2048 this.ids = [] this.Dialog = _Dialog this.html = null YJ.Analysis.AnalysesResults.push(this) ViewShedStage.create(this) // ViewShedStage.edit(this) // this.update(); } get viewPosition() { return this.options.viewPosition } set viewPosition(v) { this.options.viewPosition = v this.ids[0] && (this.viewer.entities.getById(this.ids[0]).position = new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt)) this.update() // let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt) } get viewPositionEnd() { return this.options.viewPositionEnd } set viewPositionEnd(v) { this.options.viewPositionEnd = v this.ids[1] && (this.viewer.entities.getById(this.ids[1]).position = new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt)) this.update() // let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt) // this.viewDistance = this.viewPositionEnd ? Cesium.Cartesian3.distance(this.viewPosition, this.viewPositionEnd) : (options.viewDistance || 100.0); } get horizontalViewAngle() { return this.options.horizontalViewAngle } set horizontalViewAngle(v) { this.options.horizontalViewAngle = v if (this._DialogObject && this._DialogObject._element && this._DialogObject._element.content) { let contentElm = this._DialogObject._element.content let e_horizontalViewAngle = contentElm.querySelector("input[name='horizontalViewAngle']") e_horizontalViewAngle.value = v let rangeNodeActive = contentElm.getElementsByClassName('range-node-active')[0] let rangeNodeActiveText = rangeNodeActive.getElementsByClassName('range-node-active-text')[0] rangeNodeActiveText.innerHTML = v + '°'; let rangeProcess = contentElm.getElementsByClassName('range-process')[0] rangeProcess.style.width = v / 180 * 100 + '%' } this.update() } get visibleAreaColor() { return this.options.visibleAreaColor } set visibleAreaColor(v) { this.options.visibleAreaColor = v this.update() } get invisibleAreaColor() { return this.options.invisibleAreaColor } set invisibleAreaColor(v) { this.options.invisibleAreaColor = v this.update() } get verticalViewAngle() { return this.options.verticalViewAngle } set verticalViewAngle(v) { this.options.verticalViewAngle = v this.update() } get viewDistance() { let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt) let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt) let distance = Cesium.Cartesian3.distance(viewPosition3, viewPositionEnd3) return distance } get viewHeading() { let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt) let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt) let heading = getHeading(viewPosition3, viewPositionEnd3) if (this.html) { let e_viewHeading = this.html.querySelector("span[name='viewHeading']") e_viewHeading.innerHTML = Number(heading.toFixed(8)) } return heading } get viewPitch() { let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt) let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt) let pitch = getPitch(viewPosition3, viewPositionEnd3) if (this.html) { let e_viewPitch = this.html.querySelector("span[name='viewPitch']") e_viewPitch.innerHTML = Number(pitch.toFixed(8)) } return pitch } static create(that) { let count = 0; if (!YJ.Measure.GetMeasureStatus()) { that.event = new Event(that.sdk) that.tip = new MouseTip('左键选择观测点位置,右键取消', that.sdk) YJ.Measure.SetMeasureStatus(true) that.event.mouse_left((movement, cartesian) => { if (!that.viewPosition) { that.options.viewPosition = that.cartesian3Towgs84(cartesian, that.viewer) that.ids.push(ViewShedStage.create_point(that, cartesian)) that.tip.set_text("左键选择最远观测点位置,右键取消") } count++ if (count === 2) { that.options.viewPositionEnd = that.cartesian3Towgs84(cartesian, that.viewer) that.ids.push(ViewShedStage.create_point(that, cartesian)) end() that.update() } }) that.event.mouse_move((movement, cartesian) => { that.tip.setPosition(cartesian, movement.endPosition.x, movement.endPosition.y) }) that.event.mouse_right((movement, cartesian) => { that.ids.forEach(id => { that.viewer.entities.removeById(id) }) that.ids = [] end() }) that.event.gesture_pinck_start((movement, cartesian) => { let startTime = new Date() that.event.gesture_pinck_end(() => { let endTime = new Date() if (endTime - startTime >= 500) { that.ids.forEach(id => { that.viewer.entities.removeById(id) }) that.ids = [] end() } }) }) } else { console.log('上一次测量未结束') } function end() { that.ids.forEach(id => { let entity = that.viewer.entities.getById(id) entity.show = false }) YJ.Measure.SetMeasureStatus(false) that.tip.destroy() that.event.destroy() that.tip = null that.event = null if (count === 2) { ViewShedStage.edit(that) } } } static create_point(that, cartesian) { let id = that.randomString() let p = that.cartesian3Towgs84(cartesian, that.viewer) let params = { id: id, position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt), billboard: { image: that.getSourceRootPath() + '/img/point.png', verticalOrigin: Cesium.VerticalOrigin.BOTTOM, disableDepthTestDistance: Number.POSITIVE_INFINITY, color: Cesium.Color.WHITE.withAlpha(0.99) } } that.viewer.entities.add( new Cesium.Entity(params) ) return id } add() { this.createLightCamera(); this.createShadowMap(); this.createPostStage(); this.drawFrustumOutline(); this.drawSketch(); } update() { this.clear(); this.add(); } static async edit(that) { if (that._DialogObject && that._DialogObject.close) { that._DialogObject.close() that._DialogObject = null } that._DialogObject = await new Dialog(that.sdk.viewer._container, { title: '可视域分析', left: '180px', top: '100px', closeCallBack: () => { that.Dialog.closeCallBack && that.Dialog.closeCallBack() YJ.Measure.SetMeasureStatus(false) that.editevent && that.editevent.destroy() that.ControllerObject && that.ControllerObject.destroy() that.ids.forEach(id => { that.viewer.entities.removeById(id) }) }, }) await that._DialogObject.init() that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' view-shed' let contentElm = document.createElement('div'); contentElm.innerHTML = html() that._DialogObject.contentAppChild(contentElm) let resetBtn = that._DialogObject._element.body.getElementsByClassName('edit')[0]; resetBtn.addEventListener('click', () => { that.nodeEdit() }) that.html = contentElm //经度值 let e_lng = contentElm.querySelector("span[name='lng']") e_lng.innerHTML = Number(that.options.viewPosition.lng.toFixed(8)) //纬度值 let e_lat = contentElm.querySelector("span[name='lat']") e_lat.innerHTML = Number(that.options.viewPosition.lat.toFixed(8)) //高度值 let e_alt = contentElm.querySelector("span[name='alt']") e_alt.innerHTML = Number(that.options.viewPosition.alt.toFixed(8)) //偏航角 let e_viewHeading = contentElm.querySelector("span[name='viewHeading']") e_viewHeading.innerHTML = Number(that.viewHeading.toFixed(8)) //俯仰角 let e_viewPitch = contentElm.querySelector("span[name='viewPitch']") e_viewPitch.innerHTML = Number(that.viewPitch.toFixed(8)) //视域夹角 let e_horizontalViewAngle = contentElm.querySelector("input[name='horizontalViewAngle']") e_horizontalViewAngle.value = that.options.horizontalViewAngle let rangeNodeActive = contentElm.getElementsByClassName('range-node-active')[0] let rangeNodeActiveText = rangeNodeActive.getElementsByClassName('range-node-active-text')[0] let rangeProcess = contentElm.getElementsByClassName('range-process')[0] let percentage = that.horizontalViewAngle / 180 * 100 rangeNodeActive.style.left = percentage + '%'; rangeProcess.style.width = percentage + '%' rangeNodeActiveText.innerHTML = that.horizontalViewAngle + '°'; let timeout e_horizontalViewAngle.addEventListener('input', () => { let percentage = e_horizontalViewAngle.value / 180 * 100 rangeNodeActive.style.left = percentage + '%'; rangeProcess.style.width = percentage + '%'; rangeNodeActiveText.innerHTML = e_horizontalViewAngle.value + '°'; }) e_horizontalViewAngle.addEventListener('change', () => { clearTimeout(timeout) timeout = setTimeout(() => { that.horizontalViewAngle = e_horizontalViewAngle.value; }, 300); }); } clear() { YJ.Measure.SetMeasureStatus(false) this.tip && this.tip.destroy() this.event && this.event.destroy() this.tip = null this.event = null if (this.sketch) { this.viewer.entities.removeById(this.sketch.id); this.sketch = null; } if (this.frustumOutline) { this.frustumOutline.destroy(); this.frustumOutline = null; } if (this.FrustumBottomSurface) { this.FrustumBottomSurface.destroy(); this.FrustumBottomSurface = null; } if (this.postStage) { this.viewer.scene.postProcessStages.remove(this.postStage); this.postStage = null; } } destroy() { this.clear() this.editevent && this.editevent.destroy() this.ControllerObject && this.ControllerObject.destroy() this.ids.forEach(id => { this.viewer.entities.removeById(id) }) YJ.Measure.SetMeasureStatus(false) } nodeEdit() { if (YJ.Measure.GetMeasureStatus()) { console.log('上一次测量未结束') } else { this.editevent && this.editevent.destroy() this.ids.forEach(id => { let entity = this.viewer.entities.getById(id) entity.show = true }) let selectPoint YJ.Measure.SetMeasureStatus(true) // this.tip = new MouseTip('左键选择要操作的观测点,右键取消', this.sdk) this.editevent = new Event(this.sdk) this.editevent.mouse_left((movement, cartesian) => { let pick = this.viewer.scene.pick(movement.position); if (pick && pick.id && pick.id.id && this.ids.indexOf(pick.id.id) != -1 && (!selectPoint || selectPoint.id != pick.id.id)) { selectPoint = pick.id // this.event.destroy() // this.tip.destroy() this.viewer.entities.getById(this.ids[0]).position = new Cesium.Cartesian3.fromDegrees(this.viewPosition.lng, this.viewPosition.lat, this.viewPosition.alt) this.viewer.entities.getById(this.ids[1]).position = new Cesium.Cartesian3.fromDegrees(this.viewPositionEnd.lng, this.viewPositionEnd.lat, this.viewPositionEnd.alt) this.viewPosition this.ControllerObject && this.ControllerObject.destroy() console.log(this.cartesian3Towgs84(selectPoint.position._value, this.sdk.viewer)) this.ControllerObject = new Controller(this.sdk, { position: { ...this.cartesian3Towgs84(selectPoint.position._value, this.sdk.viewer) } }) this.ControllerObject.controllerCallBack = (params, status) => { if (params.position.alt < 0) { params.position.alt = 0 } selectPoint.position = new Cesium.Cartesian3.fromDegrees(params.position.lng, params.position.lat, params.position.alt) if (status) { if (this.ids.indexOf(pick.id.id) == 0) { this.viewPosition = params.position } else { this.viewPositionEnd = params.position } YJ.Measure.SetMeasureStatus(true) } } this.ControllerObject.editTranslational() } }) this.editevent.mouse_right((movement, cartesian) => { YJ.Measure.SetMeasureStatus(false) this.editevent && this.editevent.destroy() this.ControllerObject && this.ControllerObject.destroy() this.ids.forEach(id => { let entity = this.viewer.entities.getById(id) entity.show = false }) selectPoint = null }) this.editevent.mouse_move((movement, cartesian) => { // this.tip.setPosition( // cartesian, // movement.endPosition.x, // movement.endPosition.y // ) }) this.editevent.gesture_pinck_start((movement, cartesian) => { let startTime = new Date() this.editevent.gesture_pinck_end(() => { let endTime = new Date() if (endTime - startTime >= 500) { YJ.Measure.SetMeasureStatus(false) this.editevent && this.editevent.destroy() this.ControllerObject && this.ControllerObject.destroy() this.ids.forEach(id => { let entity = this.viewer.entities.getById(id) entity.show = false }) selectPoint = null } }) }) } } createLightCamera() { let _this = this this.lightCamera = new Cesium.Camera(this.viewer.scene); this.lightCamera.position = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt); // if (this.viewPositionEnd) { // let direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.viewPositionEnd, this.viewPosition, new Cesium.Cartesian3()), new Cesium.Cartesian3()); // this.lightCamera.direction = direction; // direction是相机面向的方向 // } this.lightCamera.frustum.near = this.viewDistance * 0.001; this.lightCamera.frustum.far = this.viewDistance; const hr = Cesium.Math.toRadians(this.horizontalViewAngle); const vr = Cesium.Math.toRadians(this.verticalViewAngle); const aspectRatio = (this.viewDistance * Math.tan(hr / 2) * 2) / (this.viewDistance * Math.tan(vr / 2) * 2); this.lightCamera.frustum.aspectRatio = aspectRatio; if (hr > vr) { this.lightCamera.frustum.fov = hr; } else { this.lightCamera.frustum.fov = vr; } this.lightCamera.setView({ destination: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt), orientation: { heading: Cesium.Math.toRadians(this.viewHeading || 0), pitch: Cesium.Math.toRadians(this.viewPitch || 0), roll: 0 } }); } createShadowMap() { this.shadowMap = new Cesium.ShadowMap({ context: (this.viewer.scene).context, lightCamera: this.lightCamera, enabled: true, isPointLight: true, pointLightRadius: this.viewDistance, cascadesEnabled: false, size: 2048, // 2048 softShadows: true, normalOffset: false, fromLightSource: false }); this.viewer.scene.shadowMap = this.shadowMap; } createPostStage() { const fs = glsl const postStage = new Cesium.PostProcessStage({ fragmentShader: fs, uniforms: { shadowMap_textureCube: () => { this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState")); return Reflect.get(this.shadowMap, "_shadowMapTexture"); }, shadowMap_matrix: () => { this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState")); return Reflect.get(this.shadowMap, "_shadowMapMatrix"); }, shadowMap_lightPositionEC: () => { this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState")); return Reflect.get(this.shadowMap, "_lightPositionEC"); }, shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: () => { this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState")); const bias = this.shadowMap._pointBias; return Cesium.Cartesian4.fromElements( bias.normalOffsetScale, this.shadowMap._distance, this.shadowMap.maximumDistance, 0.0, new Cesium.Cartesian4() ); }, shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: () => { this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState")); const bias = this.shadowMap._pointBias; const scratchTexelStepSize = new Cesium.Cartesian2(); const texelStepSize = scratchTexelStepSize; texelStepSize.x = 1.0 / this.shadowMap._textureSize.x; texelStepSize.y = 1.0 / this.shadowMap._textureSize.y; return Cesium.Cartesian4.fromElements( texelStepSize.x, texelStepSize.y, bias.depthBias, bias.normalShadingSmooth, new Cesium.Cartesian4() ); }, camera_projection_matrix: this.lightCamera.frustum.projectionMatrix, camera_view_matrix: this.lightCamera.viewMatrix, helsing_viewDistance: () => { return this.viewDistance; }, helsing_visibleAreaColor: Cesium.Color.fromCssColorString(this.visibleAreaColor), helsing_invisibleAreaColor: Cesium.Color.fromCssColorString(this.invisibleAreaColor), shadowMap: this.shadowMap, far: () => { return this.viewDistance; }, } }); this.postStage = this.viewer.scene.postProcessStages.add(postStage); } drawFrustumOutline() { const scratchRight = new Cesium.Cartesian3(); const scratchRotation = new Cesium.Matrix3(); const scratchOrientation = new Cesium.Quaternion(); const position = this.lightCamera.positionWC; const direction = this.lightCamera.directionWC; const up = this.lightCamera.upWC; let right = this.lightCamera.rightWC; right = Cesium.Cartesian3.negate(right, scratchRight); let rotation = scratchRotation; Cesium.Matrix3.setColumn(rotation, 0, right, rotation); Cesium.Matrix3.setColumn(rotation, 1, up, rotation); Cesium.Matrix3.setColumn(rotation, 2, direction, rotation); let orientation = Cesium.Quaternion.fromRotationMatrix(rotation, scratchOrientation); let instance = new Cesium.GeometryInstance({ geometry: new Cesium.FrustumOutlineGeometry({ frustum: this.lightCamera.frustum, origin: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt), orientation: orientation }), id: Math.random().toString(36).substr(2), attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.YELLOWGREEN//new Cesium.Color(0.0, 1.0, 0.0, 1.0) ), show: new Cesium.ShowGeometryInstanceAttribute(true) } }); let frustum = this.lightCamera.frustum.clone() frustum.near = frustum.far - 100 let instance2 = new Cesium.GeometryInstance({ geometry: new Cesium.FrustumGeometry({ frustum: frustum, origin: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt), orientation: orientation, vertexFormat: Cesium.VertexFormat.POSITION_ONLY, }), id: Math.random().toString(36).substr(2), attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.YELLOWGREEN//new Cesium.Color(0.0, 1.0, 0.0, 1.0) ), show: new Cesium.ShowGeometryInstanceAttribute(true) } }); this.frustumOutline = this.viewer.scene.primitives.add( new Cesium.Primitive({ geometryInstances: [instance], appearance: new Cesium.PerInstanceColorAppearance({ flat: true, translucent: false }) }) ); const radius = this.viewDistance; const angle = this.viewHeading; let Ea = 6378137; // 赤道半径 let Eb = 6356725; // 极半径 const lng = this.options.viewPosition.lng, lat = this.options.viewPosition.lat; let positionArr = []; let boundaryPoints = []; positionArr.push(lng, lat); boundaryPoints.push([lng, lat]); //正北是0° let start = angle + 45 > 360 ? angle - 45 - 360 : angle - 45; let end = start + 90; for (let i = start; i <= end; i++) { let dx = radius * Math.sin((i * Math.PI) / 180.0); let dy = radius * Math.cos((i * Math.PI) / 180.0); let ec = Eb + ((Ea - Eb) * (90.0 - lat)) / 90.0; let ed = ec * Math.cos((lat * Math.PI) / 180); let BJD = lng + ((dx / ed) * 180.0) / Math.PI; let BWD = lat + ((dy / ec) * 180.0) / Math.PI; positionArr.push(BJD, BWD); } let polygon = new Cesium.PolygonGeometry({ polygonHierarchy: new Cesium.PolygonHierarchy( Cesium.Cartesian3.fromDegreesArray(positionArr) ), height: 0.0, extrudedHeight: 0.0, vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT, stRotation: 0.0, // 纹理的旋转坐标(以弧度为单位),正旋转是逆时针方向 ellipsoid: Cesium.Ellipsoid.WGS84, granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离(以弧度为单位),确定缓冲区中的位置数 perPositionHeight: false, // 每个位置点使用的高度 closeTop: true, closeBottom: true, // NONE 与椭圆表面不符的直线;GEODESIC 遵循测地路径;RHUMB 遵循大黄蜂或恶魔般的道路。 arcType: Cesium.ArcType.GEODESIC, // 多边形边缘线型 }); let polygonInstance = new Cesium.GeometryInstance({ geometry: polygon, name: "ViewershedPolygon", attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.BLUE ), show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏 }, }); // this.FrustumBottomSurface = this.viewer.scene.primitives.add( // new Cesium.GroundPrimitive({ // geometryInstances: polygonInstance, // appearance: new Cesium.PerInstanceColorAppearance({ // translucent: true, //false时透明度无效 // closed: false, // }), // }) // ); } drawSketch() { this.sketch = this.viewer.entities.add({ name: 'sketch', position: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt), orientation: Cesium.Transforms.headingPitchRollQuaternion( Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt), Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - 90, this.viewPitch, 0.0) ), ellipsoid: { radii: new Cesium.Cartesian3( this.viewDistance, this.viewDistance, this.viewDistance ), // innerRadii: new Cesium.Cartesian3(2.0, 2.0, 2.0), minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2), maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2), minimumCone: Cesium.Math.toRadians(this.verticalViewAngle + 7.75), maximumCone: Cesium.Math.toRadians(180 - this.verticalViewAngle - 7.75), fill: false, outline: true, subdivisions: 256, stackPartitions: 64, slicePartitions: 64, outlineColor: Cesium.Color.YELLOWGREEN } }); } } function getHeading(fromPosition, toPosition) { let finalPosition = new Cesium.Cartesian3(); let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition); Cesium.Matrix4.inverse(matrix4, matrix4); Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition); Cesium.Cartesian3.normalize(finalPosition, finalPosition); return Cesium.Math.toDegrees(Math.atan2(finalPosition.x, finalPosition.y)); } function getPitch(fromPosition, toPosition) { let finalPosition = new Cesium.Cartesian3(); let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition); Cesium.Matrix4.inverse(matrix4, matrix4); Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition); Cesium.Cartesian3.normalize(finalPosition, finalPosition); return Cesium.Math.toDegrees(Math.asin(finalPosition.z)); } export default ViewShedStage;