// ViewShed.js import glsl from './glsl' import glsl2 from './glsl2' import Event from "../../../Event"; import MouseTip from "../../../MouseTip"; import Tools from "../../../Tools"; import EventBinding from '../../Element/Dialog/eventBinding'; 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.viewPointHeight=1.8 视点高度(单位`米`)。 * @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._elms = {}; this.viewPointHeight = options.viewPointHeight // 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._EventBinding = new EventBinding() this.html = null YJ.Analysis.AnalysesResults.push(this) ViewShedStage.edit(this) // ViewShedStage.edit(this) // this.update(); } get viewPointHeight() { return this.options.viewPointHeight } set viewPointHeight(v) { let viewPointHeight = Math.floor(Number(v) * 10) / 10 if (isNaN(viewPointHeight)) { viewPointHeight = 1.8 } if (viewPointHeight < 0) { viewPointHeight = 0 } this.options.viewPointHeight = viewPointHeight this._elms.viewPointHeight && this._elms.viewPointHeight.forEach((item) => { item.value = viewPointHeight }) } 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 + this.viewPointHeight) 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 + this.viewPointHeight) let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt) let heading = getHeading(viewPosition3, viewPositionEnd3) return heading } get viewPitch() { let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight) let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt) let pitch = getPitch(viewPosition3, viewPositionEnd3) return pitch } static create(that) { that.destroy() 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 } } 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(); ViewShedStage.getcanvas(this) } 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() }) let drawElm = document.createElement('button') drawElm.innerHTML = '绘制' drawElm.addEventListener('click', () => { ViewShedStage.create(that) }) that._DialogObject.footAppChild(drawElm) that.html = contentElm let all_elm = contentElm.getElementsByTagName("*") that._EventBinding.on(that, all_elm) that._elms = that._EventBinding.element // //经度值 // 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); }); } static getcanvas(that) { if (!that.viewPosition) { return } if (that.viewBillboardPrimitive) { that.viewer.scene.primitives.remove(that.viewBillboardPrimitive) that.viewBillboardPrimitive = null } const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d') canvas.width = 220 canvas.height = 180 canvas.style.background = "#000000" let img = new Image(); const data = [ { images: that.getSourceRootPath() + '/img/bubble/lng.png', text: '经度:' + parseFloat(that.viewPosition.lng.toFixed(10)) + '°' }, { images: that.getSourceRootPath() + '/img/bubble/lat.png', text: '纬度:' + parseFloat(that.viewPosition.lat.toFixed(10)) + '°' }, { images: that.getSourceRootPath() + '/img/bubble/h.png', text: '高度:' + Number(((parseFloat(that.viewPosition.alt.toFixed(2)) + Number(that.viewPointHeight))).toFixed(2)) + ' m' }, { images: that.getSourceRootPath() + '/img/bubble/heading.png', text: '偏航角:' + parseFloat(that.viewHeading.toFixed(10)) + '°' }, { images: that.getSourceRootPath() + '/img/bubble/pitch.png', text: '俯仰角:' + parseFloat(that.viewPitch.toFixed(10)) + '°' } ] img.src = that.getSourceRootPath() + '/img/bubble/bubble.png'; let imagesLoaded = 0 img.onload = () => { ctx.drawImage(img, 0, 0, canvas.width, canvas.height); data.forEach((item, index) => { const img = new Image(); img.src = item.images; img.onload = () => { ctx.drawImage(img, 12, 12 + (index * 26)); ctx.fillStyle = "#fff"; ctx.font = "12px Arial"; ctx.fillText(item.text, 44, 28 + (index * 26)); imagesLoaded++; if (imagesLoaded === data.length) { that.viewBillboardPrimitive = that.viewer.scene.primitives.add(new Cesium.BillboardCollection()) that.viewBillboardPrimitive.add({ position: Cesium.Cartesian3.fromDegrees(that.viewPosition.lng, that.viewPosition.lat, that.viewPosition.alt + that.viewPointHeight), image: canvas, width: 200, height: 180, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, disableDepthTestDistance: Number.POSITIVE_INFINITY, }) } }; }) }; } 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.viewer.entities.removeById(this.frustumOutline.id); this.frustumOutline = 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) }) this.ids = [] if (this.viewBillboardPrimitive) { this.viewer.scene.primitives.remove(this.viewBillboardPrimitive) } this.viewBillboardPrimitive = null this.options.viewPosition = null this.options.viewPositionEnd = null YJ.Measure.SetMeasureStatus(false) if (this._originalShadowMap) { this.viewer.scene.shadowMap = this._originalShadowMap this._originalShadowMap = null } this.viewer.shadows = this.viewer._shadows } 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.ControllerObject && this.ControllerObject.destroy() 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() { if (!this.options.viewPosition) { return } 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 + this.viewPointHeight); // 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 + this.viewPointHeight), 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 }); if (!this._originalShadowMap) { this._originalShadowMap = this.viewer.scene.shadowMap } this.viewer.scene.shadowMap = this.shadowMap; // setTimeout(() => { // this.viewer.shadows = this.viewer._shadows // }, 0); } createPostStage() { const fs = glsl if (Number(Cesium.VERSION.split('.')[1]) >= 102) { fs = glsl2 } 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), } }); 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 + this.viewPointHeight), 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) } }); this.frustumOutline = this.viewer.scene.primitives.add( new Cesium.Primitive({ geometryInstances: [instance], appearance: new Cesium.PerInstanceColorAppearance({ flat: true, translucent: 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 + this.viewPointHeight), orientation: Cesium.Transforms.headingPitchRollQuaternion( Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight), 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(90 - (this.verticalViewAngle / 2)), maximumCone: Cesium.Math.toRadians(90 + (this.verticalViewAngle / 2)), fill: false, outline: true, subdivisions: 256, stackPartitions: 64, slicePartitions: 64, outlineColor: Cesium.Color.YELLOWGREEN } }); this.frustumOutline = this.viewer.entities.add({ name: 'sketch', position: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight), orientation: Cesium.Transforms.headingPitchRollQuaternion( Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight), 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(0.0001, 0.0001, 0.0001), minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2), maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2), minimumCone: Cesium.Math.toRadians(90 - (this.verticalViewAngle / 2)), maximumCone: Cesium.Math.toRadians(90 + (this.verticalViewAngle / 2)), fill: false, outline: true, subdivisions: 256, stackPartitions: 1, slicePartitions: 1, 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;