2025-09-01 16:17:11 +08:00
// 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 {
2025-09-05 18:39:00 +08:00
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 ;
2025-11-12 17:34:53 +08:00
this . options . horizontalViewAngle = ( options . horizontalViewAngle || options . horizontalViewAngle === 0 ) ? options . horizontalViewAngle : 30.0 ;
2025-09-05 18:39:00 +08:00
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 . tools = new Tools ( this . sdk )
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 horizontalViewAngles ( ) {
return this . horizontalViewAngle
}
set horizontalViewAngles ( v ) {
this . horizontalViewAngle = v
// 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 ( ) {
if ( this . options . viewPosition ) {
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
}
2025-11-12 17:34:53 +08:00
static create ( that , callBack ) {
2025-09-05 18:39:00 +08:00
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 ( "左键选择最远观测点位置,右键取消" )
2025-09-01 16:17:11 +08:00
}
2025-09-05 18:39:00 +08:00
count ++
if ( count === 2 ) {
that . options . viewPositionEnd = that . cartesian3Towgs84 ( cartesian , that . viewer )
that . ids . push ( ViewShedStage . create _point ( that , cartesian ) )
that . end ( )
that . update ( )
2025-11-12 17:34:53 +08:00
callBack ( true )
2025-09-01 16:17:11 +08:00
}
2025-09-05 18:39:00 +08:00
} )
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 )
2025-09-01 16:17:11 +08:00
} )
2025-09-05 18:39:00 +08:00
that . ids = [ ]
that . end ( )
2025-11-12 17:34:53 +08:00
callBack ( false )
2025-09-05 18:39:00 +08:00
} )
that . event . gesture _pinck _start ( ( movement , cartesian ) => {
let startTime = new Date ( )
that . event . gesture _pinck _end ( ( ) => {
let endTime = new Date ( )
if ( endTime - startTime >= 500 ) {
2025-09-01 16:17:11 +08:00
that . ids . forEach ( id => {
2025-09-05 18:39:00 +08:00
that . viewer . entities . removeById ( id )
2025-09-01 16:17:11 +08:00
} )
2025-09-05 18:39:00 +08:00
that . ids = [ ]
that . end ( )
2025-11-12 17:34:53 +08:00
callBack ( false )
2025-09-05 18:39:00 +08:00
}
2025-09-01 16:17:11 +08:00
} )
2025-09-05 18:39:00 +08:00
} )
}
else {
this . tools . message ( {
text : '上一次测量未结束' ,
type : 'warning' ,
} ) ;
2025-11-12 17:34:53 +08:00
callBack ( false )
2025-09-05 18:39:00 +08:00
}
}
end ( ) {
this . ids . forEach ( id => {
let entity = this . viewer . entities . getById ( id )
entity && ( entity . show = false )
} )
YJ . Measure . SetMeasureStatus ( false )
this . tip && this . tip . destroy ( )
this . event && this . event . destroy ( )
this . tip = null
this . event = null
}
2025-11-12 17:34:53 +08:00
draw ( callBack ) {
ViewShedStage . create ( this , callBack )
2025-09-05 18:39:00 +08:00
}
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 ( ) {
if ( this . options . viewPositionEnd ) {
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 )
2025-09-01 16:17:11 +08:00
} )
2025-09-05 18:39:00 +08:00
} ,
} )
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 ;
2025-09-01 16:17:11 +08:00
img . onload = ( ) => {
2025-09-05 18:39:00 +08:00
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 ,
2025-09-01 16:17:11 +08:00
} )
2025-09-05 18:39:00 +08:00
}
2025-09-01 16:17:11 +08:00
} ;
2025-09-05 18:39:00 +08:00
} )
} ;
}
clear ( ) {
YJ . Measure . SetMeasureStatus ( false )
2025-09-10 10:31:58 +08:00
// this.end()
2025-09-05 18:39:00 +08:00
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
}
close ( ) {
YJ . Measure . SetMeasureStatus ( false )
this . end ( )
this . editevent && this . editevent . destroy ( )
this . ControllerObject && this . ControllerObject . destroy ( )
this . ids . forEach ( id => {
this . viewer . entities . removeById ( id )
} )
}
nodeEdit ( ) {
if ( YJ . Measure . GetMeasureStatus ( ) ) {
this . tools . message ( {
text : '上一次测量未结束' ,
type : 'warning' ,
} ) ;
2025-09-10 10:31:58 +08:00
return
2025-09-05 18:39:00 +08:00
}
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 ( )
2025-09-01 16:17:11 +08:00
}
2025-09-05 18:39:00 +08:00
} )
this . editevent . mouse _right ( ( movement , cartesian ) => {
YJ . Measure . SetMeasureStatus ( false )
2025-09-01 16:17:11 +08:00
this . editevent && this . editevent . destroy ( )
this . ControllerObject && this . ControllerObject . destroy ( )
this . ids . forEach ( id => {
2025-09-05 18:39:00 +08:00
let entity = this . viewer . entities . getById ( id )
entity . show = false
2025-09-01 16:17:11 +08:00
} )
2025-09-05 18:39:00 +08:00
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 )
2025-09-01 16:17:11 +08:00
this . editevent && this . editevent . destroy ( )
2025-09-05 18:39:00 +08:00
this . ControllerObject && this . ControllerObject . destroy ( )
2025-09-01 16:17:11 +08:00
this . ids . forEach ( id => {
2025-09-05 18:39:00 +08:00
let entity = this . viewer . entities . getById ( id )
entity . show = false
2025-09-01 16:17:11 +08:00
} )
2025-09-05 18:39:00 +08:00
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
}
} ) ;
}
2025-09-01 16:17:11 +08:00
}
function getHeading ( fromPosition , toPosition ) {
2025-09-05 18:39:00 +08:00
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 ) ) ;
2025-09-01 16:17:11 +08:00
}
function getPitch ( fromPosition , toPosition ) {
2025-09-05 18:39:00 +08:00
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 ) ) ;
2025-09-01 16:17:11 +08:00
}
2025-09-05 18:39:00 +08:00
export default ViewShedStage ;