721 lines
31 KiB
JavaScript
721 lines
31 KiB
JavaScript
// 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; |