uniapp-renderjs cesium 添加3Dtile 点击拾取属性

174 阅读4分钟

利用renderjs挂载cesium,通过renderjs层和逻辑层之间通信,实现拾取要素传输属性并弹窗展示

<template>
		<view class="content">
			<!-- #ifdef APP-PLUS || H5 -->
			
			<u-modal :show="showGd" title="管点信息" @confirm="confirm" :closeOnClickOverlay="true" confirmText="关闭">
				<view class="slot-content">
					<view>
						<text class="blue">管点名称:{{ porperty.name }}</text>
					</view>
					<view>
						<text class="blue">管线子类码:{{ porperty["管线子类码"] }}</text>
					</view>
					<view>
						<text class="blue">点编码:{{ porperty["点编码"] }}</text>
					</view>
					<view>
						<text class="blue">物探点号:{{ porperty["物探点号"] }}</text>
					</view>
					<view>
						<text class="blue">管点类型:{{ porperty["管线类型"] }}</text>
					</view>
					<view>
						<text class="blue">附属物:{{ porperty["附属物"] }}</text>
					</view>
					<view>
						<text class="blue">图上点号:{{ porperty["图上点号"] }}</text>
					</view>
					<view>
						<text class="blue">图幅号:{{ porperty["图幅号"] }}</text>
					</view>
					<view>
						<text class="blue">井深:{{ porperty["井深"] }}</text>
					</view>
					<view>
						<text class="blue">井盖材质:{{ porperty["井盖材质"] }}</text>
					</view>
					<view>
						<text class="blue">井盖规格:{{ porperty["井盖规格"] }}</text>
					</view>
					<view>
						<text class="blue">偏心井位:{{ porperty["偏心井位"] }}</text>
					</view>
					
					<view>
						<text class="blue">地面高程:{{ porperty["地面高程"] }}</text>
					</view>
					
					
					
					<view>
						<text class="blue">特征:{{ porperty["特征"] }}</text>
					</view>
					
					<view>
						<text class="blue">备注:{{ porperty["备注"] }}</text>
					</view>
					
				</view>
			</u-modal>
			<u-modal :show="showGx" title="管线信息" @confirm="confirm" :closeOnClickOverlay="true"
				confirmText="关闭">
				<view class="slot-content">
					<view>
						<text class="blue">管线名称:{{ porperty["name"] }}</text>
					</view>
					<view>
						<text class="blue">点编码:{{ porperty["点编码"] }}</text>
					</view>
					<view>
						<text class="blue">物探点号:{{ porperty["物探点号"] }}</text>
					</view>
					<view>
						<text class="blue">管线子类码:{{ porperty["管线子类码"] }}</text>
					</view>
					<view>
						<text class="blue">管线类型:{{ porperty["管线类型"] }}</text>
					</view>
					<view>
						<text class="blue">管线起点号:{{ porperty["管线起点号"] }}</text>
					</view>
					<view>
						<text class="blue">管线终点号:{{ porperty["管线终点号"] }}</text>
					</view>
					<view>
						<text class="blue">井深:{{ porperty["井深"] }}</text>
					</view>
					
					
					<view>
						<text class="blue">图上点号:{{ porperty["图上点号"] }}</text>
					</view>
					<view>
						<text class="blue">图幅号:{{ porperty["图幅号"] }}</text>
					</view>
					<view>
						<text class="blue">地面高程:{{ porperty["地面高程"] }}</text>
					</view>
					<view>
						<text class="blue">埋设类型:{{ porperty["埋设类型"] }}</text>
					</view>
					
					
					
					
					<view>
						<text class="blue">材质:{{ porperty["材质"] }}</text>
					</view>
					
					
					<view>
						<text class="blue">特征:{{ porperty["特征"] }}</text>
					</view>
					
					<view>
						<text class="blue">管径:{{ porperty["管径"] }}</text>
					</view>
					
					<view>
						<text class="blue">起点埋深:{{ porperty["起点埋深"] }}</text>
					</view>
					<view>
						<text class="blue">终点埋深:{{ porperty["终点埋深"] }}</text>
					</view>
					<view>
						<text class="blue">起点管顶高:{{ porperty["起点管顶高"] }}</text>
					</view>
					<view>
						<text class="blue">终点管顶高:{{ porperty["终点管顶高"] }}</text>
					</view>
					<view>
						<text class="blue">附属物:{{ porperty["附属物"] }}</text>
					</view>
					<view>
						<text class="blue">备注:{{ porperty["备注"] }}</text>
					</view>
					
				</view>
			</u-modal>
			
			
			
			<view id="container" :deviceFlyTo="deviceFlyTo" :change:deviceFlyTo="CesiumMap.updateFlyTo"
				:currentSection="currentSection" :change:currentSection="CesiumMap.onUpdateTestChange" 
				:resYhd="resYhd" :change:resYhd="CesiumMap.queryMessage" 
				:Json="Json" :change:Json="CesiumMap.fetchTilesJson"
				></view>
			<!-- #endif -->
			
		</view>
	</template>

逻辑层代码

import request from '@/utils/request';

export default {
			props: {
				currentSection: {
					type: Number,
					default: 0
				},
				deviceFlyTo: {
					type: Array,
					default: []
				}

			},

			data() {
				return {
					resYhd: [],
					Json: [],
					showGd: false,
					showGx: false,
					porperty:{},
				}

			},
                        methods: {
				
				confirm() {
					
					this.showGd = false;
					this.showGx = false;
				},
				
				reciveMessage(val) {
					if(val){
			
						this.fetch3DTilesSources();
					  	
					}
				},
				
				recivePorperty(val){
					if(val){
						console.log("收到的实体属性",val)
						this.porperty = val
						if (this.porperty.batchId && this.porperty.batchId.indexOf("管线") !== -1) {
							this.showGx = true
						} else if(this.porperty.batchId && this.porperty.batchId.indexOf("管点") !== -1){
							this.showGd = true
						}
					}
				},

				// 假设你有一个函数来获取3D Tiles数据源列表  
				async fetch3DTilesSources() {  
				 
				    try {  
                                        // 这里的uni.request因为框架搭建问题,可能不是识别,因此加上了uni.;axios在app模拟器中报错,因此使用的request
				        const response = await uni.request({
                                        // 这里我把所有3Dtile的url以列表的方式写成了json,放在后端通过请求获得,也可放在静态资源中
						  url: '换成你的url/3Dtiles.json',  
						  method: 'GET',
					 
						});

				        this.Json  = response.data; // 假设返回的是包含URLs的数组  

				    }
					 catch (error) {  
				        console.error('Failed to fetch 3D Tiles sources:', error);  
				        
				    }  
				},
				
                                }}


renderjs层,

<script module="CesiumMap" lang="renderjs">

export default {
			data() {
				return {
					domlist: null, // 动态引入dom标签合集
					viewer: null, // 三维视窗
					curMap: Number, // 接收逻辑层的currentSection
					flyto: Array, // 接收逻辑层的flyto
					imageryProvidersList: [],
					tempList: [],
					dataList: [],
					propertiesList:{},
					selectedEntity: null,
				}
			},
			mounted() {
				this.initResources(); // 初始化cesium
			},
                        methods: {
                            sendMsg(){
					// 向逻辑层传参,确保cesium资源请求完成,即viewer已存在
					this.$ownerInstance.callMethod('reciveMessage', 1)
				},
				
                            sendSelectPorperty(data){
					// 向页面传参,传递属性数据
					this.$ownerInstance.callMethod('recivePorperty', data)
				},
                                
                            fetchTilesJson(newVal, oldVal, ownerInstance, instance){
					// console.log("renderjs层收到的json", newVal)
					if (this.viewer && newVal !== null && newVal.length > 0){
					 	this.setup3DtilesAll(newVal, this.viewer)
					}
				},
                                
                                
                            // 初始化资源,加载后例化cesium
				initResources() {
					if (this.domlist) {
						this.removeResource()
					} else {
						// 动态引入css文件
						const linkDom = document.createElement('link')
						linkDom.rel = "stylesheet"
						//linkDom.href = "static/Cesium/Widgets/widgets.css"
						linkDom.href = "http://xxxxxx/Cesium/Widgets/widgets.css"
						// linkDom.href = "https://cesium.com/downloads/cesiumjs/releases/1.84/Build/Cesium/Widgets/widgets.css"
						document.head.appendChild(linkDom)
						var cesiumS = this.requireResources('script', 'http://xxxxxx/Cesium/Cesium.js', this
							.initCesium)
						//var cesiumS = this.requireResources('script', 'static/Cesium/Cesium.js', this.initCesium)
						// var cesiumS = this.requireResources('script',
						// 	'https://cesium.com/downloads/cesiumjs/releases/1.84/Build/Cesium/Cesium.js', this.initCesium)
						this.domlist = [linkDom, cesiumS]
					}
				},
				// 动态创建script引用第三方类库
				requireResources(dom, src, callback) {
					// 动态引入较大类库避免影响页面展示
					const script = document.createElement(dom)
					// view 层的页面运行在 www 根目录,其相对路径相对于 www 计算
					script.src = src;
					document.head.appendChild(script);
					callback && (callback instanceof Function) && (script.onload = callback.bind(this));
					return script
				},
				// 移除动态添加的标签,避免重复添加标签
				removeResource() {
					if (this.domlist)
						for (let i = 0; i < this.domlist.length; i++) {
							document.head.removeChild(this.domlist[i])
						}
				},
// 初始化
				initCesium() {

					Cesium.Ion.defaultAccessToken =
						"tk";
					this.viewer = new Cesium.Viewer('container', {
						// terrainProvider: Cesium.createWorldTerrain(), // 创建世界地形
						geocoder: false, //右上角 搜索
						homeButton: false, //右上角 Home
						// sceneModePicker: false, //右上角 2D/3D切换
						baseLayerPicker: false, //右上角图层选择器
						navigationHelpButton: false, //右上角 Help
						animation: false, // 左下角 圆盘动画控件
						timeline: false, //时间轴
						fullscreenButton: false, //右下角 全屏控件
						vrButton: false, // 如果设置为true,将创建VRButton小部件。
						scene3DOnly: true, // 每个几何实例仅以3D渲染以节省GPU内存
						infoBox: false, //隐藏点击要素后的提示信息
						selectionIndicator: false, //绿色的定位框
						// 加载天地图底图
						imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
							url: 'http://t0.tianditu.gov.cn/img_w/wmts?tk=tk',
							layer: 'img',
							style: 'default',
							tileMatrixSetID: 'w',
							format: 'tiles',
							maximumLevel: 18
						}),
					})
					this.viewer._cesiumWidget._creditContainer.style.display = 'none'; //隐藏版本信息
					this.viewer.scene.debugShowFramesPerSecond = false; // 显示帧数


					
					this.setupClickListener();
					this.sendMsg();
                                        },
                                        
                                        // 遍历json添加3Dtiles数据
				setup3DtilesAll(tilesetUrls, viewer) {  
					let boundingSpheres = []; 
					tilesetUrls.forEach(tilesetUrl => {  
					    let tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({  
					            url: tilesetUrl,  
					          }));
						
						tileset.readyPromise.then(() => {  
							viewer.scene.globe.depthTestAgainstTerrain = true;  
							let boundingSphere = tileset.boundingSphere;  
							            if (boundingSphere) {  
							                boundingSpheres.push(boundingSphere);  
							            }  
							  
							            // 检查是否所有Tilesets都已加载  
							            if (boundingSpheres.length === tilesetUrls.length) {  
							                // 所有Tilesets都已加载,执行定位飞行  
							                this.flyToBoundingSpheres(boundingSpheres, viewer);  
							            }  
						}).otherwise(function(error) {
							throw (error);
						});
				  
					});
				},
                                flyToBoundingSpheres(boundingSpheres, viewer) {
				    // 如果有多个包围球,可以根据实际情况选择合适的策略来确定最终飞行的目标位置  
				    // 例如,可以选择最大的包围球中心,或者计算所有包围球中心的平均值等  
				    if (boundingSpheres.length > 0) {  
				        let targetBoundingSphere = boundingSpheres[0]; // 示例:选择第一个包围球作为目标  
				        for (let i = 1; i < boundingSpheres.length; i++) {  
				            if (boundingSpheres[i].radius > targetBoundingSphere.radius) {  
				                targetBoundingSphere = boundingSpheres[i];  
				            }  
				        }  
						
				        let cartographic = Cesium.Cartographic.fromCartesian(targetBoundingSphere.center);  
						
				        let position = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude,cartographic.height*10); // 可以根据需要调整高度  
				        
						viewer.camera.flyTo({  
				            destination: position,  
				            orientation: {  
				                heading: Cesium.Math.toRadians(0),  
				                pitch: Cesium.Math.toRadians(-90),  
				                roll: 0.0  
				            }  
				        });  
				    } else {  
				        console.warn("No bounding spheres available, using default camera position.");  
				        // Fallback to default camera position or another strategy  
				    }  
				},
				
                                
                                setupClickListener() {

					const handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas);
					
					let selectedFeature = null;
					let selectedColor = null;
					
					handler.setInputAction((click) => {
						let ray = this.viewer.camera.getPickRay(click.position)
						let cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene)
						let pickedObject = this.viewer.scene.pick(click.position);
						// const pickedObject = this.viewer.scene.pick(click.position);
						console.log("pickedObject", pickedObject) 
						if (selectedFeature) {  
						            selectedFeature.color = new Cesium.Color(1, 1, 1, 1); // 或者设置为初始颜色,如 Cesium.Color.WHITE  
						        } 

						if (Cesium.defined(pickedObject) && pickedObject instanceof Cesium.Cesium3DTileFeature) {  
							const batchId = pickedObject.getProperty("batchId");
							
							
							pickedObject.getPropertyNames().forEach(propertyName=>{
								this.propertiesList[propertyName] = pickedObject.getProperty(propertyName)
							})
							console.log("this.propertiesList", this.propertiesList)
							this.sendSelectPorperty(this.propertiesList)
						
						    if (batchId && batchId.indexOf("管线") !== -1) {  
								selectedFeature = pickedObject;
								selectedColor = pickedObject.color
								console.log("pickedObject.color", pickedObject.color) 
						        pickedObject.color = Cesium.Color.MIDNIGHTBLUE;  
								 
						    } else if(batchId && batchId.indexOf("管点") !== -1){
								selectedFeature = pickedObject;
								selectedColor = pickedObject.color
								console.log("pickedObject.color", pickedObject.color) 
								pickedObject.color = Cesium.Color.MIDNIGHTBLUE;  
							}
							
						} else if(Cesium.defined(pickedObject) && pickedObject.entity){
							this.selectedEntity = pickedObject.entity;
							const id = pickedObject.id;
							const name = pickedObject.name;
							console.log(`拾取到的实体ID: ${id}, 名称: ${name}`);
						}
	
					}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
					
				},
                                
                                
                        },
                        


</script>