cesium-可视化区域分析

全部代码

<template>
	<div id="cesiumContainer" style="height: 100vh;"></div>
	<div id="toolbar" style="position: fixed;top:20px;left:220px;">
		<el-breadcrumb :separator-icon="ArrowRight">
			<el-breadcrumb-item>三维分析</el-breadcrumb-item>
			<el-breadcrumb-item>可视区域分析</el-breadcrumb-item>
		</el-breadcrumb>
		<el-row class="mb-4" style="margin-top: 15px">
			<el-button type="primary" @click="shootAreaAnalysis">分析</el-button>
			<el-button type="primary" @click="handleIntervisibilityCancel">清除</el-button>
		</el-row>
	</div>
</template>
<script setup>
import {ArrowRight} from '@element-plus/icons-vue'
import {onMounted, ref} from "vue";
import * as Cesium from "cesium";
import InitCesium from "../js/InitCesiumHide.js";
import ViewShed from "../js/8/ViewShed.js";

let viewer = null;

onMounted(() => {
	let initCesium = new InitCesium('cesiumContainer');
	viewer = initCesium.initViewer({});
	flyToRight2();
})

const shootAreaAnalysis = (type) => {
	// store.setSelected('shootArea')
	let i = 0
	let horizontalViewAngle = 90  //视角水平张角
	let verticalViewAngle = 60    //视角垂直张角
	let endPosition = null
	let viewShed = null
	let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
	handler.setInputAction(movement => {
		i++
		if (i === 1) {
			var startPosition = viewer.scene.pickPosition(movement.position) //鼠标点击一次获取开始坐标
			if (!startPosition) return
			viewShed = new ViewShed(viewer, {
				viewPosition: startPosition,
				viewPositionEnd: startPosition,
				horizontalViewAngle: horizontalViewAngle,
				verticalViewAngle: verticalViewAngle
			})
			// 鼠标移动的事件
			handler.setInputAction(movement => {
				endPosition = viewer.scene.pickPosition(movement.endPosition)
				if (!endPosition) return
				viewShed.updatePosition(endPosition)
				if (!viewShed.sketch) {
					viewShed.drawSketch()
				}
			}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
		}
		// 鼠标点击两次获取结束坐标
		if (i === 2) {
			i = 0
			endPosition = viewer.scene.pickPosition(movement.position)
			viewShed.updatePosition(endPosition)
			viewShed.update()
			handler && handler.destroy()  //销毁鼠标事件
			// store.setSelected(null)
		}
	}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}


const flyToRight2 = async () => {
	let tileset = await Cesium.Cesium3DTileset.fromUrl('/src/assets/tileset/12/tileset.json', {});

	update3dtilesMaxtrix(tileset);
	viewer.scene.primitives.add(tileset);
	viewer.flyTo(tileset);

	/*viewer.camera.flyTo({
		destination: Cesium.Cartesian3.fromDegrees(113.06408124924124, 22.64479293609514, 800.0), // 设置位置
		orientation: {
			heading: Cesium.Math.toRadians(20.0), // 方向
			pitch: Cesium.Math.toRadians(-90.0),// 倾斜角度
			roll: 0
		},
		duration: 5, // 设置飞行持续时间,默认会根据距离来计算
		complete: function () {
			// 到达位置后执行的回调函数
		},
		cancle: function () {
			// 如果取消飞行则会调用此函数
		},
		pitchAdjustHeight: -90, // 如果摄像机飞越高于该值,则调整俯仰俯仰的俯仰角度,并将地球保持在视口中。
		maximumHeight: 5000, // 相机最大飞行高度
		flyOverLongitude: 100, // 如果到达目的地有2种方式,设置具体值后会强制选择方向飞过这个经度(这个,很好用)
	});*/
}

function update3dtilesMaxtrix(tileSet) {
	//调整参数
	let params = {
		tx: 113.06265738392063, //模型中心X轴坐标(经度,单位:十进制度)
		ty: 22.646603971034342, //模型中心Y轴坐标(纬度,单位:十进制度)
		tz: 45, //模型中心Z轴坐标(高程,单位:米)
		rx: 0, //X轴(经度)方向旋转角度(单位:度)
		ry: 0, //Y轴(纬度)方向旋转角度(单位:度)
		rz: 0, //Z轴(高程)方向旋转角度(单位:度)
		scale: 1.35, //缩放比例
	};
	//旋转
	const mx = Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(params.rx));
	const my = Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(params.ry));
	const mz = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(params.rz));
	const rotationX = Cesium.Matrix4.fromRotationTranslation(mx);
	const rotationY = Cesium.Matrix4.fromRotationTranslation(my);
	const rotationZ = Cesium.Matrix4.fromRotationTranslation(mz);
	//平移
	const position = Cesium.Cartesian3.fromDegrees(
		params.tx,
		params.ty,
		params.tz
	);
	const m = Cesium.Transforms.eastNorthUpToFixedFrame(position);
	//旋转、平移矩阵相乘
	Cesium.Matrix4.multiply(m, rotationX, m);
	Cesium.Matrix4.multiply(m, rotationY, m);
	Cesium.Matrix4.multiply(m, rotationZ, m);
	//比例缩放
	const scale = Cesium.Matrix4.fromUniformScale(params.scale);
	Cesium.Matrix4.multiply(m, scale, m);
	// console.log("矩阵m:", m);
	//赋值给tileset
	tileSet._root.transform = m;
}
</script>
<style scoped>
#cesiumContainer {
	overflow: hidden;
}
</style>
<style>
.el-breadcrumb__inner, .el-breadcrumb__separator {
	color: #ffffff !important;
}
</style>

 工具类

InitCesiumHide.js
import * as Cesium from "cesium";

class InitCesiumHide {

	constructor(cesiumContainer, options) {
		this.cesiumContainer = cesiumContainer;
	}

	initViewer(options) {
		Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9';
		// 西南东北,默认显示中国
		Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(90, -20, 110, 90);
		return new Cesium.Viewer(this.cesiumContainer, {
			animation: false, // 隐藏动画控件
			baseLayerPicker: false, // 隐藏图层选择控件
			fullscreenButton: false, // 隐藏全屏按钮
			vrButton: false, // 隐藏VR按钮,默认false
			geocoder: false, // 隐藏地名查找控件  地理编码
			homeButton: false, // 隐藏Home按钮
			infoBox: false, // 隐藏点击要素之后显示的信息窗口
			sceneModePicker: false, // 隐藏场景模式选择控件
			selectionIndicator: false, // 显示实体对象选择框,默认true
			timeline: false, // 隐藏时间线控件
			navigationHelpButton: false, // 隐藏帮助按钮
			scene3DOnly: true, // 每个几何实例将只在3D中呈现,以节省GPU内存
			shouldAnimate: true, // 开启动画自动播放
			sceneMode: 3, // 初始场景模式 1:2D 2:2D循环 3:3D,默认3
			requestRenderMode: true, // 减少Cesium渲染新帧总时间并减少Cesium在应用程序中总体CPU使用率
			...options
		});
	}
}

export default InitCesiumHide

glsl.js

export default `
 #define USE_CUBE_MAP_SHADOW true
 uniform sampler2D colorTexture;
 uniform sampler2D depthTexture;
 in vec2 v_textureCoordinates;
 uniform mat4 camera_projection_matrix;
 uniform mat4 camera_view_matrix;
 uniform samplerCube shadowMap_textureCube;
 uniform mat4 shadowMap_matrix;
 uniform vec4 shadowMap_lightPositionEC;
 uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
 uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
 uniform float helsing_viewDistance;
 uniform vec4 helsing_visibleAreaColor;
 uniform vec4 helsing_invisibleAreaColor;

 struct zx_shadowParameters
 {
     vec3 texCoords;
     float depthBias;
     float depth;
     float nDotL;
     vec2 texelStepSize;
     float normalShadingSmooth;
     float darkness;
 };

 float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
 {
     float depthBias = shadowParameters.depthBias;
     float depth = shadowParameters.depth;
     float nDotL = shadowParameters.nDotL;
     float normalShadingSmooth = shadowParameters.normalShadingSmooth;
     float darkness = shadowParameters.darkness;
     vec3 uvw = shadowParameters.texCoords;
     depth -= depthBias;
     float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
     return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
 }

 vec4 getPositionEC(){
     return czm_windowToEyeCoordinates(gl_FragCoord);
 }

 vec3 getNormalEC(){
     return vec3(1.);
 }

 vec4 toEye(in vec2 uv,in float depth){
     vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
     vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
     posInCamera=posInCamera/posInCamera.w;
     return posInCamera;
 }

 vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
     vec3 v01=point-planeOrigin;
     float d=dot(planeNormal,v01);
     return(point-planeNormal*d);
 }

 float getDepth(in vec4 depth){
     float z_window=czm_unpackDepth(depth);
     z_window=czm_reverseLogDepth(z_window);
     float n_range=czm_depthRange.near;
     float f_range=czm_depthRange.far;
     return(2.*z_window-n_range-f_range)/(f_range-n_range);
 }

 float shadow(in vec4 positionEC){
     vec3 normalEC=getNormalEC();
     zx_shadowParameters shadowParameters;
     shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
     shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
     shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
     shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
     vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
     float distance=length(directionEC);
     directionEC=normalize(directionEC);
     float radius=shadowMap_lightPositionEC.w;
     if(distance>radius)
     {
         return 2.0;
     }
     vec3 directionWC=czm_inverseViewRotation*directionEC;
     shadowParameters.depth=distance/radius-0.0003;
     shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);
     shadowParameters.texCoords=directionWC;
     float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
     return visibility;
 }

 bool visible(in vec4 result)
 {
     result.x/=result.w;
     result.y/=result.w;
     result.z/=result.w;
     return result.x>=-1.&&result.x<=1.
     &&result.y>=-1.&&result.y<=1.
     &&result.z>=-1.&&result.z<=1.;
 }

out vec4 fragColor;
 void main(){
 	
     // 釉色 = 结构二维(颜色纹理, 纹理坐标)
     fragColor = texture(colorTexture, v_textureCoordinates);
     // 深度 = 获取深度(结构二维(深度纹理, 纹理坐标))
     float depth = getDepth(texture(depthTexture, v_textureCoordinates));
     // 视角 = (纹理坐标, 深度)
     vec4 viewPos = toEye(v_textureCoordinates, depth);
     // 世界坐标
     vec4 wordPos = czm_inverseView * viewPos;
     // 虚拟相机中坐标
     vec4 vcPos = camera_view_matrix * wordPos;
     float near = .001 * helsing_viewDistance;
     float dis = length(vcPos.xyz);
     if(dis > near && dis < helsing_viewDistance){
         // 透视投影
         vec4 posInEye = camera_projection_matrix * vcPos;
         // 可视区颜色
         // vec4 helsing_visibleAreaColor=vec4(0.,1.,0.,.5);
         // vec4 helsing_invisibleAreaColor=vec4(1.,0.,0.,.5);
         if(visible(posInEye)){
             float vis = shadow(viewPos);
             if(vis > 0.3){
                 fragColor = mix(fragColor,helsing_visibleAreaColor,.5);
             } else{
                 fragColor = mix(fragColor,helsing_invisibleAreaColor,.5);
             }
         }
     }
 }`;

glsl2.js

export default `
 #define USE_CUBE_MAP_SHADOW true
 uniform sampler2D colorTexture;
 uniform sampler2D depthTexture;
 in vec2 v_textureCoordinates;
 uniform mat4 camera_projection_matrix;
 uniform mat4 camera_view_matrix;
 uniform samplerCube shadowMap_textureCube;
 uniform mat4 shadowMap_matrix;
 uniform vec4 shadowMap_lightPositionEC;
 uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
 uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
 uniform float helsing_viewDistance; 
 uniform vec4 helsing_visibleAreaColor;
 uniform vec4 helsing_invisibleAreaColor;

 struct zx_shadowParameters
 {
     vec3 texCoords;
     float depthBias;
     float depth;
     float nDotL;
     vec2 texelStepSize;
     float normalShadingSmooth;
     float darkness;
 };
 
 float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
 {
     float depthBias = shadowParameters.depthBias;
     float depth = shadowParameters.depth;
     float nDotL = shadowParameters.nDotL;
     float normalShadingSmooth = shadowParameters.normalShadingSmooth;
     float darkness = shadowParameters.darkness;
     vec3 uvw = shadowParameters.texCoords;
     depth -= depthBias;
     float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
     return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
 }
 vec4 getPositionEC(){
     return czm_windowToEyeCoordinates(gl_FragCoord);
 }
 vec3 getNormalEC(){
     return vec3(1.);
 }
 vec4 toEye(in vec2 uv,in float depth){
     vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
     vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
     posInCamera=posInCamera/posInCamera.w;
     return posInCamera;
 }
 vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
     vec3 v01=point-planeOrigin;
     float d=dot(planeNormal,v01);
     return(point-planeNormal*d);
 }
 float getDepth(in vec4 depth){
     float z_window=czm_unpackDepth(depth);
     z_window=czm_reverseLogDepth(z_window);
     float n_range=czm_depthRange.near;
     float f_range=czm_depthRange.far;
     return(2.*z_window-n_range-f_range)/(f_range-n_range);
 }
 float shadow(in vec4 positionEC){
     vec3 normalEC=getNormalEC();
     zx_shadowParameters shadowParameters;
     shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
     shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
     shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
     shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
     vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
     float distance=length(directionEC);
     directionEC=normalize(directionEC);
     float radius=shadowMap_lightPositionEC.w;
     if(distance>radius)
     {
         return 2.0;
     }
     vec3 directionWC=czm_inverseViewRotation*directionEC;
     shadowParameters.depth=distance/radius-0.0003;
     shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);
     shadowParameters.texCoords=directionWC;
     float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
     return visibility;
 }
 bool visible(in vec4 result)
 {
     result.x/=result.w;
     result.y/=result.w;
     result.z/=result.w;
     return result.x>=-1.&&result.x<=1.
     &&result.y>=-1.&&result.y<=1.
     &&result.z>=-1.&&result.z<=1.;
 }
 out vec4 fragColor;
 void main(){
     // 釉色 = 结构二维(颜色纹理, 纹理坐标)
     fragColor = texture(colorTexture, v_textureCoordinates);
     // 深度 = 获取深度(结构二维(深度纹理, 纹理坐标))
     float depth = getDepth(texture(depthTexture, v_textureCoordinates));
     // 视角 = (纹理坐标, 深度)
     vec4 viewPos = toEye(v_textureCoordinates, depth);
     // 世界坐标
     vec4 wordPos = czm_inverseView * viewPos;
     // 虚拟相机中坐标
     vec4 vcPos = camera_view_matrix * wordPos;
     float near = .001 * helsing_viewDistance;
     float dis = length(vcPos.xyz);
     if(dis > near && dis < helsing_viewDistance){
         // 透视投影
         vec4 posInEye = camera_projection_matrix * vcPos;
         // 可视区颜色
         // vec4 helsing_visibleAreaColor=vec4(0.,1.,0.,.5);
         // vec4 helsing_invisibleAreaColor=vec4(1.,0.,0.,.5);
         if(visible(posInEye)){
             float vis = shadow(viewPos);
             if(vis > 0.3){
                 fragColor = mix(fragColor,helsing_visibleAreaColor,.5);
             } else{
                 fragColor = mix(fragColor,helsing_invisibleAreaColor,.5);
             }
         }
     }
 }`
ViewShed
import glsl from './glsl2.js'
import * as Cesium from "cesium";

/**
 * @param {Cesium.Viewer} viewer Cesium三维视窗。
 * @param {Object} options 选项。
 * @param {Cesium.Cartesian3} options.viewPosition 观测点位置。
 * @param {Cesium.Cartesian3} options.viewPositionEnd 最远观测点位置(如果设置了观测距离,这个属性可以不设置)。
 * @param {Number} options.viewDistance 观测距离(单位`米`,默认值100)。
 * @param {Number} options.viewHeading 航向角(单位`度`,默认值0)。
 * @param {Number} options.viewPitch 俯仰角(单位`度`,默认值0)。
 * @param {Number} options.horizontalViewAngle 可视域水平夹角(单位`度`,默认值90)。
 * @param {Number} options.verticalViewAngle 可视域垂直夹角(单位`度`,默认值60)。
 * @param {Cesium.Color} options.visibleAreaColor 可视区域颜色(默认值`绿色`)。
 * @param {Cesium.Color} options.invisibleAreaColor 不可视区域颜色(默认值`红色`)。
 * @param {Boolean} options.enabled 阴影贴图是否可用。
 * @param {Boolean} options.softShadows 是否启用柔和阴影。
 * @param {Boolean} options.size 每个阴影贴图的大小。
 */
class ViewShed {
	constructor(viewer, options) {
		this.viewer = viewer
		this.viewPosition = options.viewPosition //开始坐标
		this.viewPositionEnd = options.viewPositionEnd //结束坐标
		this.viewDistance = this.viewPositionEnd
			? Cesium.Cartesian3.distance(this.viewPosition, this.viewPositionEnd)
			: options.viewDistance || 100.0 //观测距离
		this.viewHeading = this.viewPositionEnd
			? this.getHeading(this.viewPosition, this.viewPositionEnd)
			: options.viewHeading || 0.0
		this.viewPitch = this.viewPositionEnd
			? this.getPitch(this.viewPosition, this.viewPositionEnd)
			: options.viewPitch || 0.0
		this.horizontalViewAngle = options.horizontalViewAngle || 90.0 //可视域的水平夹角
		this.verticalViewAngle = options.verticalViewAngle || 60.0 //可视域的垂直夹角
		this.visibleAreaColor = options.visibleAreaColor || Cesium.Color.GREEN
		this.invisibleAreaColor = options.invisibleAreaColor || Cesium.Color.RED
		this.enabled = typeof options.enabled === 'boolean' ? options.enabled : true
		this.softShadows = typeof options.softShadows === 'boolean' ? options.softShadows : true
		this.size = options.size || 2048
	}

	add() {
		this.createLightCamera()
		this.createShadowMap()
		this.drawFrustumOutline(); //视锥线
		this.drawSketch()
		this.createPostStage()
	}

	update() {
		this.clear()
		this.add()
	}

	/**
	 * @method 更新终点坐标,从而实时更新绘制的实体的方向和半径
	 *
	 */
	updatePosition(viewPositionEnd) {
		this.viewPositionEnd = viewPositionEnd
		this.viewDistance = Cesium.Cartesian3.distance(this.viewPosition, this.viewPositionEnd) //观测距离
		this.viewHeading = this.getHeading(this.viewPosition, this.viewPositionEnd)
		this.viewPitch = this.getPitch(this.viewPosition, this.viewPositionEnd)
	}

	clear() {
		if (this.sketch) {
			this.viewer.entities.remove(this.sketch)
			this.sketch = null
		}
		/*  if (this.frustumOutline) {
		  this.viewer.scene.primitives.destroy();
		  this.frustumOutline = null;
	  } */
		if (this.postStage) {
			this.viewer.scene.postProcessStages.remove(this.postStage)
			this.postStage = null
		}
	}

	/**
	 * @method 创建相机
	 */
	createLightCamera() {
		this.lightCamera = new Cesium.Camera(this.viewer.scene)
		this.lightCamera.position = this.viewPosition
		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: this.viewPosition,
			orientation: {
				heading: Cesium.Math.toRadians(this.viewHeading || 0),
				pitch: Cesium.Math.toRadians(this.viewPitch || 0),
				roll: 0
			}
		})
	}

	/**
	 * @method 创建阴影贴图
	 */
	createShadowMap() {
		this.shadowMap = new Cesium.ShadowMap({
			context: this.viewer.scene.context,
			lightCamera: this.lightCamera,
			enabled: this.enabled,
			isPointLight: true,
			pointLightRadius: this.viewDistance,
			cascadesEnabled: false,
			size: this.size,
			softShadows: this.softShadows,
			normalOffset: false,
			fromLightSource: false
		})
		this.viewer.scene.shadowMap = this.shadowMap
	}

	/**
	 * @method 创建PostStage
	 * 导入的glsl是做片元着色的
	 */
	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: this.visibleAreaColor,
				helsing_invisibleAreaColor: this.invisibleAreaColor
			}
		})
		this.postStage = this.viewer.scene.postProcessStages.add(postStage)
	}

	/**
	 * @method 创建视锥线
	 */
	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: this.viewPosition,
				orientation: orientation
			}),
			id: Math.random().toString(36).substr(2),
			attributes: {
				color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.YELLOWGREEN),
				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
				})
			})
		)
	}

	/**
	 * @method 创建视网
	 * 在实时绘制椭球实体时,其实不是一直创建entity,而是改变实体的方向(orientation)和改变椭球的半径(radii)
	 */
	drawSketch() {
		this.sketch = this.viewer.entities.add({
			name: 'sketch',
			position: this.viewPosition,
			orientation: new Cesium.CallbackProperty(() => {
				return Cesium.Transforms.headingPitchRollQuaternion(
					this.viewPosition,
					Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - this.horizontalViewAngle, this.viewPitch, 0.5)
				)
			}, false),
			ellipsoid: {
				//椭球的半径
				radii: new Cesium.CallbackProperty(() => {
					return new Cesium.Cartesian3(this.viewDistance,
						this.viewDistance,
						this.viewDistance)
				}, false),
				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 //轮廓的颜色
			}
		})
	}

	/**
	 * @method 获取偏航角
	 */
	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))
	}

	/**
	 * @method 获取俯仰角
	 */
	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 ViewShed

  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: Cesium提供了多种空间分析工具,可以帮助用户在三维场景中进行空间分析。以下是其中的一些工具: 1. 空间测量工具:该工具可以帮助用户测量两点之间的距离、两线之间的距离、多边形面积等。 2. 可视域分析工具:该工具可以帮助用户确定一个位置是否可以看到其他位置,从而帮助用户进行可视域分析。 3. 地形剖面工具:该工具可以帮助用户生成地形剖面图,以便用户更好地了解地形的变化情况。 4. 空间查询工具:该工具可以帮助用户查询三维场景中的对象信息,例如查找离某个位置最近的建筑物、查找所有高于某个高度的建筑物等。 5. 模拟分析工具:该工具可以帮助用户进行模拟分析,例如飞行模拟、车辆行驶模拟等。 这些工具可以通过Cesium的API进行调用并进行定制化配置,满足用户的不同分析需求。 ### 回答2: Cesium是一个基于Web的三维地球、地理空间数据可视化的开源库。虽然Cesium本身并不直接提供空间分析功能,但可以通过它的一些插件、扩展以及与其他库的结合来实现空间分析。 首先,Cesium提供了一些基本的几何对象,例如点、线、面等,可以用来表示和操作地理空间数据。通过这些基本对象,可以进行一些简单的空间分析,如计算两个点之间的距离、两条线的交点等。 其次,Cesium可以与其他地理空间数据处理库结合使用,如Turf.js、JSTS等。这些库提供了丰富的空间分析功能,例如缓冲区分析、叠加分析、网络分析等。通过将这些库与Cesium结合使用,可以在Cesium中实现更复杂的空间分析。 此外,Cesium还支持加载和展示各种地理空间数据格式,包括矢量数据(如GeoJSON、KML)、栅格数据(如影像、地形)以及点云数据等。通过加载和展示这些数据,可以对其进行空间分析,例如提取特定区域的数据、计算数据的统计特征等。 最后,Cesium还提供了一些插件和扩展,例如cesium-ion、cesium-sensor-volumes等。这些插件和扩展可以用来进行更复杂的空间分析,如视域分析阴影分析等。 综上所述,尽管Cesium本身并不直接提供空间分析功能,但通过结合其他库的使用、加载地理空间数据以及使用相关插件和扩展,我们可以在Cesium中实现各种空间分析操作。 ### 回答3: Cesium是一个用于构建虚拟地球和空间可视化的JavaScript库。通过Cesium,我们可以实现多种空间分析功能。 首先,Cesium提供了高度精确的地理坐标定位系统,支持包括经纬度、高度、海拔等在内的多种空间坐标系统。我们可以通过Cesium的坐标转换函数,在不同坐标系统之间进行转换,实现空间数据的兼容性。 其次,Cesium提供了强大的地理信息处理功能。我们可以使用该库加载和显示各种地理数据,如矢量数据、栅格数据、地形数据等。同时,Cesium还支持空间数据的可视化和渲染,可以将数据以三维模型、标注、热力图等形式呈现在虚拟地球上。 在空间分析方面,Cesium提供了一系列的工具和功能。例如,我们可以使用Cesium的渲染器,对空间数据进行空间关系分析,如相交、包含、相离等。此外,Cesium还支持路径规划和导航功能,可以进行经纬度之间的路线规划和导航。 另外,Cesium还提供了高级的空间分析功能,如可视域分析阴影分析、地形剖面等。我们可以使用Cesium可视化工具,在虚拟地球上模拟光照条件,并计算特定位置的可视域范围。同时,Cesium还支持地形剖面功能,可以跟踪沿着指定路径的地形特征,如高程、坡度等。 总而言之,Cesium通过提供强大的地理信息处理和可视化功能,为空间数据分析提供了丰富的工具和技术支持。无论是在地理信息系统、城市规划还是环境监测领域,Cesium都可以帮助我们更好地分析、展示和理解空间数据。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值