<template src="./webgl_rxdz_roam.html">

</template>
<script>
	import * as THREE from 'three';
	import Stats from 'three/addons/libs/stats.module.js';
	import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
	import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
	
	import TWEEN from 'three/addons/libs/tween.module.js';
	import {getStorage} from '@/utils/localStorage';
	var requestId = "";
    const util = require('@/utils/util.js').default;
	// import util from '@/utils/util.js';
    // const config = require('@/services/urlConfig.js');
    // import requestConfig from '@/static/lib/requestConfig.js';
	// import viewShell from'@/components/newBottomCom/viewShell/viewShell.vue';
	import viewMask from'@/components/newBottomCom/viewMask/viewMask.vue';

	// import { RGBELoader } from '@/webgl/jsm/loaders/RGBELoader.js';
	import screenshot from '@/mixins/screenshot.js';
	import floorMethod from '@/mixins/floorMethod.js';
	import loadModel from '@/mixins/loadModel.js';
	import wallMethod from '@/mixins/wallMethod.js';
	import commonPageMethod from '@/mixins/commonPageMethod.js';
	// import commonPageMethod from '@/common/commonPageMethod.js';
    // const app = getApp(); //获取应用实例
    export default {
		components:{viewMask},
		mixins:[screenshot,loadModel,floorMethod,wallMethod,commonPageMethod],
        /**
         * 页面的初始数据
         */
        data() {
            return {
				pvCurPageName: "room_show",
				locusBehaviorName: "房间展示",
				pvCurPageParams: null,
                houseId: "",
				pvId: 'p_2cmina_23080402',
				canvas:null,
				navbar: {
				    showCapsule: 1,
				    title: '客厅',
				    titleColor: '#000',
				    navPadding: 0,
				    navPaddingBg:'transparent',
				    navBarColor: 'transparent',
				    navBackColor: 'transparent',
				    haveCallback: true, // 如果是 true 会接手 navbarBackClk
				    fromShare: false,
				    fromProject: 0,
				    shareToken: "",
				    pageName: this.pvCurPageName,
				},
                id:'',// 户型编号
                spaceList:[], // 空间列表
                gltfSpaces:[], // 场景中地板模型数组
				gltfSpaceRoofs:[],
                curSpaceObj:null, // 当前选中的空间
                // curSpaceIndex:-1, // 当前选中的空间索引
				spaceId:null,
                wallIds:[], // 空间墙体id
				// wallList:[], // 墙体数据
                gltfWalls:[], // 场景中墙体模型数组
                loader:null,
                scene:null,
                // sky:null,
                camera:null,
				controlStarPosition : { x:0, y:0, z:0},	//控制器初始位置
				cameraStarPosition : { x:0, y:20, z:0}	,//摄像头初始位置
				cameraLastPosition: null,		//摄像头上一次移动到的位置
				controlLastPosition: null,		//观察点上一次移动到的位置
				canvasHeight:408,	//canvas视图的高度-计算得出
				chooseMesh:null,//标记鼠标拾取到的mesh
				shottingImg: [],
				progress:1,	//进度条
				myLoadingStatus:false,
				// textGeoList:[],
				repeatFlag:false,	//重复点击
				// skyPlan: null, // 天空盒子
				instancedMeshList: [],
				screenshotResolve:null,
				actors:[],
				showDownView:true,//默认显示下载按钮
				currentActor:null,
				circleGroup:null,//圆形地标
				isIOS:false,
				defaulIndex:null,	//默认视角的序号
				// aiImagesList:[
				// 	// "https://dm.static.elab-plus.com/miniProgram/plus_IM01.png",
				// 	// "https://dm.static.elab-plus.com/miniProgram/plus_IM02.png",
				// 	// "https://dm.static.elab-plus.com/miniProgram/plus_IM03.png",
				// 	// "https://dm.static.elab-plus.com/miniProgram/plus_IM04.png",
				// ]
            }
        },
		beforeDestroy() {
			cancelAnimationFrame(requestId, this.canvas)
			this.worker && this.worker.terminate()
			if (this.renderer instanceof THREE.WebGLRenderer) {
				// 遍历场景中的所有子对象，找到类型为Mesh的对象并移除
				let deleList = this.scene.children.filter(object=>{
					if (object instanceof THREE.Mesh) {
						return object
					}
				})
				if(deleList && deleList.length>0){
					this.scene.remove(...deleList);
				}
				this.scene.traverse(function(object) {
					if (object instanceof THREE.Mesh) {
						if(object.geometry && typeof(object.geometry.dispose)=='function'){
							object.geometry.dispose();
						}
						if(object.material && typeof(object.material.dispose)=='function'){
							object.material.dispose();
						}
						if(object.texture && typeof(object.texture.dispose)=='function'){
							object.texture.dispose();
						}
					}
				});
				this.renderer.clear();
				this.renderer.dispose();
				this.renderer.forceContextLoss();
				this.renderer.context = null;
				this.renderer.domElement = null;
				this.renderer = null;;
				this.clearHandle()
			}
			TWEEN && TWEEN.removeAll();//清除所有的tween;
			console.warn("***beforeDestroy-webgl_rxdz_roam***");
		},
        mounted(options) {
			var that = this;
			// alert("JavaScript 堆大小限制: "+performance.memory.jsHeapSizeLimit
			// +"\n已使用的 JavaScript 堆大小: "+performance.memory.usedJSHeapSize
			// +"\nJavaScript 堆的总大小: "+performance.memory.totalJSHeapSize);
			console.warn("***webgl_rxdz_roam-options***",this.$route.query)
			this.isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
			if(this.isIOS){
				this.curHouseObj = JSON.parse(getStorage('curHouseObj'));
				this.wallList = JSON.parse(getStorage('wallList'));
			}else{
				this.curHouseObj = 	this.$store.state.curHouseObj;
				this.wallList = 	this.$store.state.wallList;
			}
			// alert("***mounted-webgl_rxdz_roam***"+this.isIOS + this.curHouseObj)
			let screenWidth = window.screen.width;
			let screenHeight = window.screen.height;
			if(window.innerWidth && window.screen.width){
				screenWidth = Math.min(window.innerWidth,window.screen.width)
			}
			if(window.innerHeight && window.screen.height){
				screenHeight = Math.min(window.innerHeight,window.screen.height)
			}
			let unit = screenWidth / 750;//单位rpm 对应 px 的值
			this.canvasHeight = screenHeight - (600 * unit) + (40 * unit);
			this.houseId = this.$route.query.houseId?this.$route.query.houseId:'';
			this.spaceId = this.$route.query.spaceId?this.$route.query.spaceId:'';
			let container = this.$refs.webgl;
            let canvas3d = this.canvas = this.$refs.glcanvas;
			//uniapp 兼容写法，因为uni的页面对象的Vue 实例是$vm
			
			let camera = null, renderer = null;
			let needRender = false;	//是否需要渲染 false表示不需要渲染；true 表示需要渲染
            let loader = this.loader = new GLTFLoader();
            let scene = this.scene = new THREE.Scene();
            let raycaster = null;
            let mouse = new THREE.Vector2();
            let chooseMesh = this.chooseMesh;//标记鼠标拾取到的mesh
			let isUserContorl = true;//是否进入漫游状态-默认是
			//漫游时变量
			let onPointerDownMouseX = 0, onPointerDownMouseY = 0,
			lon = 0;
			let fingerCount = 0;	//触摸时的手指数目
			let startTime = 0;	//非漫游时的移动变量
			let tweenCameraAnma = false;	//表示当前是否处在动画过程中
			let controls = null,boundary=null;
			let stats;
			init();
			// this.$refs.myLoading.showLoading("加载中...1%")
			this.$store.state.loadingMsg="加载中...1%";
			// this.myLoadingStatus = true;
			this.progress = 1;
			this.clearEvent = clearEvent;
			this.attendEvent = attendEvent;
			// this.meshRoam = meshRoam;
			this.tweenCameraAnmaChange = tweenCameraAnmaChange;
			this.switchActor = switchActor;
			this.starRender = starRender;//对外暴露启动渲染的方法
			this.stopRender = stopRender;//对外暴露停止渲染的方法
			this.positionCamer = positionCamer;
			if(this.curHouseObj && this.curHouseObj.id){
				this.setHouseDetail(this.curHouseObj);
			}
			function init() {

                scene.background = new THREE.Color("#FFFFFF");
				// scene.environment = new THREE.Color("#F2F2F2");
				// 创建一个HDR贴图加载器
				// const rgbeloader = new RGBELoader();
				// // 加载HDR贴图
				// rgbeloader.load('https://dm.static.elab-plus.com/miniProgram/environment.hdr', (texture) => {
				// 	// 将HDR贴图设置为场景的环境贴图
				// 	texture.mapping = THREE.EquirectangularReflectionMapping;
				// 	scene.environment = texture;
				// })

				// 创建相机位置
				camera = new THREE.PerspectiveCamera(90, screenWidth / that.canvasHeight, 0.1, 10000 );
				// camera.up.set(0, 1, 0);//俯视状态，将相机的up向量设置为z轴负方向 {x:0,y:1,z:0}
				// camera.position.set(that.cameraStarPosition.x, that.cameraStarPosition.y, that.cameraStarPosition.z);
				scene.add(camera);
                that.camera = camera;

                // 环境光会均匀的照亮场景中的所有物体
				const ambientLight = new THREE.AmbientLight(0xFFEFE0, 3.5);
				scene.add(ambientLight);
				//平行光
				const light = new THREE.DirectionalLight(0xFFF8E5, 2.5);
				light.position.set(5, 7, 3); //default; light shining from top
				if(!that.isIOS){
					light.castShadow = true; // default false
					// 默认情况下光投影相机区域是一个长宽高为10x10x500的长方体区域，光源投射方向为通过坐标原点
					light.shadow.camera.left = -100; // 这个区域内产生阴影
					light.shadow.camera.right  = 100; // 这个区域内产生阴影
					light.shadow.camera.top  = 100; // 这个区域内产生阴影
					light.shadow.camera.bottom  = -100; // 这个区域内产生阴影
					
					light.shadow.mapSize.width = 1024; 	// 影响阴影的清晰度
					light.shadow.mapSize.height = 1024; // 影响阴影的清晰度
				}
				
				scene.add(light);
				
				//antialias 这个值得设置为false，不然IOS上截图会失效
                renderer = that.renderer = new THREE.WebGLRenderer( { 
					canvas:canvas3d, 
					alpha: true,
					antialias:true,
					preserveDrawingBuffer: true,
				});
				if(!that.isIOS){
					renderer.shadowMap.enabled = true;//产生阴影
					renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 阴影属性
				}
				renderer.outputEncoding = THREE.sRGBEncoding;
				renderer.outputColorSpace = THREE.SRGBColorSpace;
				// renderer.toneMappingExposure = 0.1;//色调映射的曝光级别。默认是1
				renderer.toneMapping = THREE.NoToneMapping;//色调映射
				renderer.physicallyCorrectLights = true;//关键参数，模拟物理光照影响，必须设置为true

                renderer.setPixelRatio(window.devicePixelRatio);
                renderer.setSize(screenWidth, that.canvasHeight);
                container.appendChild( renderer.domElement );
				
				controls = new OrbitControls( camera, renderer.domElement );
				controls.enableDamping = true;//启动缓动
				controls.minDistance = 0.0001;
				controls.maxDistance = 10;
				controls.minPolarAngle = 0;// 默认0
				controls.maxPolarAngle = Math.PI / 2; // 默认Math.PI，即可以向下旋转到的视角。
				// controls.target.set(  that.controlStarPosition.x, that.controlStarPosition.y, that.controlStarPosition.z);
				controls.enableZoom = true;//启用摄像机的缩放
				controls.enablePan = true;//禁用摄像机平移
				controls.enableRotate = true;//启用摄像机水平或垂直旋转
				// controls.zoomToCursor = true;
				
				// controls.target.copy(camera.position);
				// controls.update();
				// 监听相机移动事件-限制只能在当前空间范围内移动
				controls.addEventListener('change', () => {
					// 检查相机位置是否超出边界框
					if (boundary && !boundary.containsPoint(camera.position)) {
						let clampedPosition = new THREE.Vector3( );
						boundary.clampPoint(camera.position,clampedPosition);
						if(clampedPosition){
							camera.position.copy(clampedPosition);
							// controls.target.copy(clampedPosition);
						}
					}
				});
				// controls.target = new THREE.Vector3( );;
				// camera.lookAt(that.controlStarPosition.x,that.controlStarPosition.y,that.controlStarPosition.z);
                raycaster = new THREE.Raycaster();
				// stats = new Stats();
				// container.appendChild(stats.dom);
				// stats.domElement.style.top = '100px';
				attendEvent();//注册监听事件
				starRender();	//启动渲染
            }
			function tweenCameraAnmaChange (value) {
				tweenCameraAnma = value
			}
			function attendEvent () {
				renderer && renderer.domElement && renderer.domElement.addEventListener('touchstart', onPointerStart, false);
				renderer && renderer.domElement && renderer.domElement.addEventListener('touchmove', onPointerMove, false);
				renderer && renderer.domElement && renderer.domElement.addEventListener('touchend', onPointerUp, false);
			}
			//取消事件监听-避免二次进入时触发多次事件
			function clearEvent(){
				console.warn("**clearEvent****")
				renderer && renderer.domElement && renderer.domElement.removeEventListener('touchstart', onPointerStart);
				renderer && renderer.domElement && renderer.domElement.removeEventListener('touchmove', onPointerMove );
				renderer && renderer.domElement && renderer.domElement.removeEventListener('touchend', onPointerUp );
			}
			// 手指移动开始
			function onPointerStart(event){
				startTime = (new Date()).getTime();
				fingerCount = event.touches.length;//手指个数
				console.log('开始触摸事件：',lon,fingerCount,camera.position.y)
				if (fingerCount === 1) {
					// 只有一个手指时记录当前点的坐标作为平移起始点
					onPointerDownMouseX = event.changedTouches[0].clientX;
					onPointerDownMouseY = event.changedTouches[0].clientY;
				}
			}
			//持续触摸中
			function onPointerMove( event ) {
				fingerCount = event.touches.length;//手指个数
			}
			//触摸结束
			function onPointerUp(event) {
				fingerCount = event.touches.length;//手指个数
				console.warn("***触摸结束***",fingerCount,startTime)
				if(fingerCount==0){
					let now = new Date().getTime()
					if (Math.abs(event.changedTouches[0].clientX - onPointerDownMouseX) < 10 
					&& Math.abs(event.changedTouches[0].clientY - onPointerDownMouseY) < 10 
					&& (now - startTime) < 300 ){
						checkIntersection(event);
					}
				}
			}
			//射线检测handle
			function checkIntersection(event) {
			    let x = (event.changedTouches[0].clientX / screenWidth) * 2 - 1;
			    let y = -(event.changedTouches[0].clientY / that.canvasHeight) * 2 + 1;
			    mouse.x = x;
			    mouse.y = y;
			    //更新射线
			    raycaster.setFromCamera(mouse, camera);
			    let intersects = raycaster.intersectObjects(scene.children,true);
				console.warn("***checkIntersection***",intersects.length)
			    if (intersects.length > 0) {
					//找到最近的那个网格模型物体
					let mesh = intersects.find((it) => {
						if(it.object && it.object.isMesh == true  
							&& it.object.parent && it.object.parent.name == 'actor'
							&& it.object.parent.visible == true){
							return true;
						}
					});
					
					//拾取到了视角，就不继续拾取了
					if(mesh){
						moveActor(mesh.object.parent);
						return false;
					}
					mesh = intersects.find((it) => {
						if(it.object && it.object.isInstancedMesh
							&& (it.object.name == '地板' || it.object.name == '花园') && it.object.visible == true){
							return true;
						}
					});
					//拾取到了地板
					if(mesh){
						let floor = mesh.object;
						let index = mesh.instanceId;//射线相交是的实例序号
						let spaceId = that.gltfSpaces[index].spaceId;//获取选中实例的空间id
						if(floor.name == "花园"){//花园
							return false;
							let selectMesh = that.gltfSpaces.find(it=>{return it.spaceType==14 && it.instancedMeshIndexList[0].instancedAtIndex==index})
							spaceId = selectMesh.spaceId;
						}else{//室内
							// floor.name = "地板";
							let selectMesh = that.gltfSpaces.find(it=>{return it.spaceType!=14 && it.instancedMeshIndexList[0].instancedAtIndex==index})
							spaceId = selectMesh.spaceId;
						}
						// let spaceId = that.gltfSpaces[index].spaceId;//获取选中实例的空间id
						console.warn("***checkIntersection-地板***",floor,index,spaceId,that.spaceId)
						//当前拾取到的是本空间的底部-意味着用户点击了地板
						if(floor && spaceId == that.spaceId){
							moveCarmer(mesh.point);
							return false;
						}
					}
			    }
			}
			//自动切换视角
			function switchActor (toIndex=null) {
				if(!that.currentActor){
					this.$message.warning("没有当前视角!");
					return false;
				}
				if(!that.actors || that.actors.length==0){
					this.$message.warning("没有视角!");
					return false;
				}
				if(toIndex!=null){//存在要去往的视角
					moveActor(that.actors[toIndex]);
				}else{
					let index = that.currentActor.userIndex;//当前视角的序号
					let nextIndex = (index + 1) % that.actors.length;
					//移动到对应的视角去
					moveActor(that.actors[nextIndex]);
					that.defaulIndex = nextIndex;//更新下默认视角
				}
			}
			//移动到选中的位置-地板
			function moveCarmer (point) {
				//还在动画中，不能点击切换
				if(tweenCameraAnma == true){
					return false;
				}
				let _x =  point.x - camera.position.x;//x轴移动的距离
				let _z =  point.z - camera.position.z;//z轴移动的距离
				let cameraNewPosition = {x:camera.position.x + _x,y:1.5,z:camera.position.z + _z};
				let targetNewPosition = {x:controls.target.x + _x,y:1.5,z:controls.target.z + _z};
				let oldUp = {x:0,y:1,z:0};	
				let newUp = {x:0,y:1,z:0};
				moveTip(cameraNewPosition)
				// console.warn("**moveCarmer***",lon,JSON.stringify(cameraNewPosition),JSON.stringify(targetNewPosition))
				tweenCamera(camera.position,controls.target,cameraNewPosition,targetNewPosition,oldUp,newUp,2000);
				setTimeout(()=> {
					that.circleGroup.visible = false;
				}, 2000);
			}
			//创建地标
			function creatMoveTip(position){
				if(!that.circleGroup){
					that.circleGroup = new THREE.Group();
					let geometry = new THREE.CircleGeometry( 0.2, 32 );
					let material = new THREE.MeshBasicMaterial( { transparent: true } );
					let circle = new THREE.Mesh( geometry, material );
					circle.position.set(position.x,0.01,position.z);
					circle.rotation.x = -Math.PI / 2;
					// let geometry1 = new THREE.CircleGeometry( 0.4, 32 );
					// let circle2 = new THREE.Mesh( geometry1, material );
					// circle2.position.set(position.x,0.01,position.z);
					// 使用贴图
					const textureLoader = new THREE.TextureLoader();
					textureLoader.load('https://dm.static.elab-plus.com/miniProgram/circlemap1.png', function(texture) {
						material.map = texture; // 将贴图应用于材质的map属性
						material.needsUpdate = true; // 更新材质
					});
					that.circleGroup.add(circle);
					scene.add(that.circleGroup);
					that.circleGroup.visible = false;
				}
			}
			//移动地标
			function moveTip(position){
				if(!that.circleGroup){
					that.circleGroup = new THREE.Group();
					let geometry = new THREE.CircleGeometry( 0.2, 32 );
					let material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
					let circle = new THREE.Mesh( geometry, material );
					circle.position.set(position.x,0.01,position.z);
					circle.rotation.x = -Math.PI / 2;
					// let geometry1 = new THREE.CircleGeometry( 0.4, 32 );
					// let circle2 = new THREE.Mesh( geometry1, material );
					// circle2.position.set(position.x,0.01,position.z);
					that.circleGroup.add(circle);
					scene.add(that.circleGroup);
				}else{
					that.circleGroup.visible = true;
					that.circleGroup.children[0].position.set(position.x,0.01,position.z);
				}
			}
			//移动视角点位
			function moveActor (obj) {
				clearEvent();//注销事件监听
				// console.warn("***moveActor***",obj)
				that.currentActor = obj;//记录下当前的视角对象 mesh网格模型
				let cameraNewPosition = obj.position;
				let targetNewPosition = obj.targetNewPosition;
				let oldUp = {x:0,y:1,z:0};	//俯视
				let newUp = {x:0,y:1,z:0};	//正视
				// moveTip(cameraNewPosition);
				// console.warn("**moveActor***",JSON.stringify(cameraNewPosition),JSON.stringify(targetNewPosition))
				tweenCamera(camera.position,controls.target,cameraNewPosition,targetNewPosition,oldUp,newUp,2000);
				lon = 0;
				setTimeout(()=> {
					attendEvent()
					// that.circleGroup.visible = false;
				}, 2000);
			}
			//初始化点位视角
			function initActor(){
				if(!chooseMesh){
					console.error("[drawActor],没有选中的空间数据")
					return false;
				}
				let spaceObj = chooseMesh;//获取选中的空间模型的相关数据
				if(!spaceObj.actors){
					return false;
				}
				let defaulIndex = spaceObj.actors.findIndex(it=>it.isSelected==true);
				if(defaulIndex == -1){
					defaulIndex = 0;
				}
				that.defaulIndex = defaulIndex;//记录下默认视角
				that.actors = [];
				spaceObj.actors.forEach((actor,index)=>{
					// let model = gltf.scene; // 获取模型
					// let cloneModel = model.clone(true);//赋值模型，准备复用
					// cloneModel.children.map((v,i)=>{
					// 	if(v.material){
					// 		v.material = model.children[i].material.clone()
					// 	}
					// })
					// let cube = cloneModel;
					let cube = {};
					cube.name = "actor";
					cube.userType = "mesh";
					//新的摄像机的位置-新的摄像机角度是倾斜角度，所以z值需要计算，高度设置为模型高度的2倍
					let _actorLoaction = actor.actorLocation.split(',');//x y z
					let _actorTransform = actor.actorTransform.split(',');//旋转角度，取第三个值
					let _hd = THREE.MathUtils.degToRad(parseInt(_actorTransform[2]));//将度转化为弧度。
					let _hdY = THREE.MathUtils.degToRad(parseInt(_actorTransform[1]));//Y轴方向上将度转化为弧度。
					// if(parseInt(_actorLoaction[1])==0){//X轴
					// 	_actorLoaction[1] = spaceObj.centerX;
					// }
					// if(parseInt(_actorLoaction[0])==0){//Y轴
					// 	_actorLoaction[0] = spaceObj.centerY;
					// }
					let X_C = parseInt(_actorLoaction[0]);//X轴偏移量
					let Y_C = -parseInt(_actorLoaction[1]);//Y轴偏移量-取反，UE里面的Y轴方向跟Three.js相反
					let px = spaceObj.centerX + X_C;
					let py = -spaceObj.centerY + Y_C;//UE里面的centerY值跟Three.js Y轴相反；获得真实的坐标值
					let position = {
						x:(parseInt(px))/100,
						y:1.5, 
						z:(parseInt(py))/100,//模型Y轴坐标系正负值跟webglZ轴是相反的
					}
					//新的观察点的位置-取模型的中心点坐标，加上高度，由于模型都是贴地的，所以高度设置为1.5
					let targetNewPosition = {
						x:position.x + Math.sin(_hd),
						y:1.5 + Math.tan(_hdY),
						z:(position.z - Math.cos(_hd)),
					}
					cube.position = position;
					cube.userIndex = index;
					cube.actorEum = index;
					cube.targetNewPosition = targetNewPosition;
					// console.warn("*actors*",cube,defaulIndex)
					that.actors.push(cube);//添加视角
					if(index == defaulIndex){//隐藏当前视角
						that.currentActor = cube;//记录下当前的视角对象 mesh网格模型
						let param = {
							type: 'CLK', //埋点类型
							clkId: 'clk_2cmina_23080411', //点击ID
							clkName: 'visualangle_clk', //点击前往的页面名称
							clkParams: {
								locusName: "预制视角",
								type:that.actors[index].actorEum
							}
						};
						util.trackRequest(param);
					}
				})
			}
			//计算当前选中空间的平视时的观察点和摄像机的放置点位
			function roamPositionHandle(lon=''){
				if(!chooseMesh){
					console.error("[roamPositionHandle],没有选中的空间数据")
					return false;
				}
				let spaceObj = chooseMesh;//获取选中的空间模型的相关数据
				//获取视角
				let defaultActor = null;
				if(spaceObj.actors && spaceObj.actors.length>0){
					defaultActor = spaceObj.actors.find(it=>it.isSelected==true);
					if(!defaultActor){
						defaultActor = spaceObj.actors[0];
					}
				}
				let _actorLoaction = defaultActor.actorLocation.split(',');//x y z
				let _actorTransform = defaultActor.actorTransform.split(',');//旋转角度，取第三个值
				let _hd = THREE.MathUtils.degToRad(parseInt(_actorTransform[2]) + lon);//将度转化为弧度。
				let _hdY = THREE.MathUtils.degToRad(parseInt(_actorTransform[1]));//Y轴方向上将度转化为弧度。
				// if(parseInt(_actorLoaction[1])==0){//X轴
				// 	_actorLoaction[1] = spaceObj.centerX;
				// }
				// if(parseInt(_actorLoaction[0])==0){//Y轴
				// 	_actorLoaction[0] = spaceObj.centerY;
				// }
				let X_C = parseInt(_actorLoaction[0]);//X轴偏移量-UE原因
				let Y_C = -parseInt(_actorLoaction[1]);//Y轴偏移量-取反，UE里面的Y轴方向跟Three.js相反
				let px = spaceObj.centerX + X_C;
				let py = -spaceObj.centerY + Y_C;
				//新的摄像机的位置-新的摄像机角度是倾斜角度，所以z值需要计算，高度设置为模型高度的2倍
				let cameraNewPosition = {
					x:(parseInt(px))/100,
					y:1.5, 
					z:(parseInt(py))/100,//模型Y轴坐标系正负值跟webglZ轴是相反的
				}
				if(cameraNewPosition){
					let minX = 0,maxX = 0,minY = 0,maxY = 0;//0.1 是模型墙壁厚度
					minX = (spaceObj.centerX - (spaceObj.spaceWidth/2))/100 + 0.1;
					maxX = (spaceObj.centerX + (spaceObj.spaceWidth/2))/100 - 0.1;
					maxY = ((-spaceObj.centerY + (spaceObj.spaceHeight/2))/100 - 0.1);
					minY = ((-spaceObj.centerY - (spaceObj.spaceHeight/2))/100 + 0.1);
					//新的坐标轴不在房间范围内，则不能移动
					if(cameraNewPosition.x<minX || cameraNewPosition.x>maxX
					||cameraNewPosition.z<minY || cameraNewPosition.z>maxY){//不在房间范围
						let _x = ((spaceObj.spaceWidth/2) - 15)*defaultActor.presentX + spaceObj.centerX;
						let _z = ((spaceObj.spaceHeight/2) - 15)*defaultActor.presentY + (-spaceObj.centerY);
						cameraNewPosition.x = _x/100;
						cameraNewPosition.z = _z/100;
						console.warn("**roamPositionHandle-观察点不在空间范围-强制修正观察点位置****",JSON.stringify(cameraNewPosition))
					}
				}
				//新的观察点的位置-取模型的中心点坐标，加上高度，由于模型都是贴地的，所以高度设置为1.5
				let targetNewPosition = {
					x:cameraNewPosition.x + Math.sin(_hd),
					y:1.5 + Math.tan(_hdY),
					z:(cameraNewPosition.z - Math.cos(_hd)),
				}
				let lookPosition = {
					x:cameraNewPosition.x + (Math.sin(_hd)*0.01),
					y:1.5 + Math.tan(_hdY),
					z:(cameraNewPosition.z - (Math.cos(_hd))*0.01),
				}
				return {cameraNewPosition,targetNewPosition,lookPosition}
			}
			//直接定位到摄像头位置
			function positionCamer(mesh=null,needAni=false){
				if(mesh){//如果传入了模型，则取模型
					chooseMesh = mesh;
				}
				if(!chooseMesh){
					console.error("[positionCamer],没有选中的空间数据")
					return false;
				}
				if(!chooseMesh.actors || chooseMesh.actors.length==0){
					chooseMesh.actors = [{
						actorLocation:chooseMesh.actorLocation,
						actorTransform:chooseMesh.actorTransform,
						isSelected:true,
						presentX:chooseMesh.presentX,
						presentY:chooseMesh.presentY,
					}]
				}
				boundary = new THREE.Box3(
					new THREE.Vector3(chooseMesh.centerX/100 - chooseMesh.spaceWidth/100/2 + 0.1, 0, -chooseMesh.centerY/100 - chooseMesh.spaceHeight/100/2 + 0.1), // 边界框的最小点
					new THREE.Vector3(chooseMesh.centerX/100 + chooseMesh.spaceWidth/100/2 - 0.1, 2.7, -chooseMesh.centerY/100 + chooseMesh.spaceHeight/100/2 - 0.1) // 边界框的最大点
				);
				initActor();//初始化视角
				let data = roamPositionHandle();
				let cameraNewPosition = data.cameraNewPosition;
				let targetNewPosition = data.targetNewPosition;
				targetNewPosition.z = targetNewPosition.z;//增加偏差，防止极点翻转问题？不知道为啥会有用
				let lookPosition = data.lookPosition;
				creatMoveTip(cameraNewPosition);//创建移动的地标
				if(needAni){
					let oldUp = {x:0,y:1,z:0};	//俯视
					let newUp = {x:0,y:1,z:0};	//正视
					tweenCamera(camera.position,controls.target,cameraNewPosition,targetNewPosition,oldUp,newUp,2000);
				}else{
					camera.position.set(cameraNewPosition.x, cameraNewPosition.y, cameraNewPosition.z);
					controls.target.set(lookPosition.x,lookPosition.y,lookPosition.z);
					// controls.target.set(cameraNewPosition.x,cameraNewPosition.y,cameraNewPosition.z);
					// controls.target.copy(camera.position);
					camera.lookAt(targetNewPosition.x,targetNewPosition.y,targetNewPosition.z);
				}
			}
			// oldP  相机原来的位置
            // oldT  target原来的位置
            // newP  相机新的位置
            // newT  target新的位置
            function tweenCamera(oldP, oldT, newP, newT, oldUp, newUp, time=1000) {
				if(JSON.stringify(oldP) == JSON.stringify(newP) && JSON.stringify(oldT) == JSON.stringify(newT)){
					that.repeatFlag = false;//放开限制，可以再次点击
					return false;
				}
				if (!chooseMesh) {
					that.repeatFlag = false;//放开限制，可以再次点击
					return false;
				}
				tweenCameraAnma = true;
				var tween = new TWEEN.Tween({
					x1: oldP.x, // 相机x
					y1: oldP.y, // 相机y
					z1: oldP.z, // 相机z
					x2: oldT.x, // 控制点的中心点x
					y2: oldT.y, // 控制点的中心点y
					z2: oldT.z,	// 控制点的中心点z
					x3: oldUp.x, // 控制点的中心点x
					y3: oldUp.y, // 控制点的中心点y
					z3: oldUp.z  // 控制点的中心点z
				})
				.to({
			        x1: newP.x,
					y1: newP.y,
					z1: newP.z,
					x2: newT.x,
					y2: newT.y,
					z2: newT.z,
					x3: newUp.x, // up向量
					y3: newUp.y, // 控制点的中心点y
					z3: newUp.z  // 控制点的中心点z
			    }, time)
				.easing(TWEEN.Easing.Quadratic.InOut)
				.onUpdate((object)=> {
					camera.position.x = object.x1;
					camera.position.y = object.y1;
					camera.position.z = object.z1;
					// let newTarget = new THREE.Vector3(object.x3,object.y3,object.z3);
					// camera.up.copy(newTarget);
					camera.lookAt(object.x2,object.y2,object.z2);
					// controls.target.x = object.x2;
					// controls.target.y = object.y2;
					// controls.target.z = object.z2;
					// controls.update();
				}).onComplete(()=>{
					controls.target.x = newT.x;
					controls.target.y = newT.y;
					controls.target.z = newT.z;
					//修正最后的视角
					// let up = new THREE.Vector3(newUp.x,newUp.y,newUp.z);
					// camera.up.copy(up);
					camera.lookAt(newT.x,newT.y,newT.z);
					tweenCameraAnma = false;
					that.repeatFlag = false;//放开限制，可以再次点击
				})
				// 开始动画
				tween.start();
			}

			function stopRender () {
				needRender = false;
			}
			function starRender () {
				if(needRender==true){//如果已经在渲染中了，则不能再次开启，避免渲染过多
					false;
				}
				needRender = true;
				render();//开始渲染
			}
            function render() {
				if(needRender==false){
					return false;
				}
                TWEEN && TWEEN.update();
				// stats.update();
				renderer.render(scene, camera);//单次渲染
				requestId = requestAnimationFrame(render, canvas3d);
				if (that.screenshotResolve) {
					stopRender();
					that.screenshotResolve()
					that.screenshotResolve = null;//释放Promise
				}
            }

		},
		// computed: {
		// 	curHouseObj() {
		// 		return this.$store.state.curHouseObj;
		// 	},
		// 	wallList() {
		// 		return this.$store.state.wallList;
		// 	},
		// },
		methods: {
			navbarBackClk() {
				if(!this.$refs.viewMask){
					this.$router.go(-1);
					return false
				}
				if (this.$refs.viewMask.showAIImage) {
					this.$refs.viewMask.showOrHideWebGl();//隐藏显示的AI生图
					// if(this.currentActor.userIndex!=this.defaulIndex){//当前不是默认视角了
						this.switchActor(this.defaulIndex);//切换到默认视角
					// }
				} else {
					this.$router.go(-1);
				}
			},
			switchActor(){},
			positionCamer(){},
			clearHandle(){
				this.clearEvent();
			},
			save(){
				this.$refs.viewMask.save();//下载
			},
			/**
			 * 设置户型详情信息
			 * @param {Object} data 户型详情
			 */
			setHouseDetail(data){
				if(data){
					this.id = data.id;
					this.spaceId = this.$route.query.spaceId?this.$route.query.spaceId:'';
					console.warn("***curHouseObj***",data)
					// 加载户型
					this.loadSpace();
				}else{
					this.curHouseObj = {}
				}
			},
            // 绘制空间-即地板
            async loadSpace(){
				this.spaceList = [];
				this.wallIds = [];
				if(!this.curHouseObj || !this.spaceId){//减少重复请求
					alert("数据错误")
					console.warn("***数据错误***")
					return false
				}
                if(this.curHouseObj){
                    const spaceDetail = this.curHouseObj;
                    const spaceList = JSON.parse(spaceDetail.houseJson);
                    // 交换centerX， centerY;上一页面已经处理过了，这里不在需要处理
                    for (let index = 0; index < spaceList.length; index++) {
                        var element = spaceList[index];
                        // const centerX = JSON.parse(JSON.stringify(element.centerX))
						if(!element.actors || element.actors.length==0){
							element.actors = [{
								actorLocation:element.actorLocation,
								actorTransform:element.actorTransform,
								isSelected:true,
							}]
						}
						element.actors.forEach(actor=>{
							let _actorLoaction = actor.actorLocation.split(',');//x y z
							let X_C = parseInt(_actorLoaction[0]);//X轴偏移量-UE原因
							let Y_C = -parseInt(_actorLoaction[1]);//Y轴偏移量-取反，UE里面的Y轴方向跟Three.js相反
							let _x = element.centerX + X_C;
							let _z = -element.centerY + Y_C;//centerY 要取反，因为UE里面是反向的
							
							// let _x = parseInt(_actorLoaction[1]) || element.centerX;//观察点 X轴坐标 
							// let _z = parseInt(_actorLoaction[0]) || element.centerY;//观察点 Z轴坐标
							let _presentX = (_x - element.centerX)/((element.spaceWidth/2) - 10);//10是墙壁厚度-单位cm
							let _presentY = (_z + element.centerY)/((element.spaceHeight/2) - 10);
							//注意如果一开始就设置大超过空间大小，则处理成贴近空间边界
							actor.presentX = Math.abs(_presentX)>1 ? (_presentX>1?1:-1) : _presentX;//观察点跟空间中心原点的距离比例
							actor.presentY = Math.abs(_presentY)>1 ? (_presentY>1?1:-1) : _presentY;
						})
						element.wallMoveValue = "[0,0,0,0]"
                        this.spaceList.push(element);
                        this.wallIds.push(element.wallId);

                        if(element.spaceId == this.spaceId){ // 默认选中空间
                            this.curSpaceObj = element;
                        }
                    }
                    if(!this.curSpaceObj && this.spaceList.length > 0){
                        this.curSpaceObj = this.spaceList[0];
                    }
                }
				let curSpaceArea = parseFloat((this.curSpaceObj.spaceWidth * this.curSpaceObj.spaceHeight) / 10000).toFixed(1);
				this.navbar.title = this.curSpaceObj.spaceName + "  " + curSpaceArea + "㎡"
                console.log("该户型空间数据:", this.spaceList);
                console.log("当前选中的空间:", this.curSpaceObj);
				this.positionCamer(this.curSpaceObj);
				this.loaderSpaceArr(this.spaceList);//绘制地板
                // 获取墙体数据并且绘制墙体
                this.getHouseTypeSpaceWalls();
            },
			changeSpace(spaceId){
				console.warn("***changeSpace***",spaceId,this.spaceId)
				if(spaceId == this.spaceId){
					return false;
				}
				this.spaceId = spaceId;
				this.curSpaceObj = this.spaceList.find(it=>it.spaceId == spaceId);
				if(this.isIOS){
					this.furnSingleSpaceHandle(this.curSpaceObj);
				}
				this.positionCamer(this.curSpaceObj,true);
				let curSpaceArea = parseFloat((this.curSpaceObj.spaceWidth * this.curSpaceObj.spaceHeight) / 10000).toFixed(1);
				this.navbar.title = this.curSpaceObj.spaceName + "  " + curSpaceArea + "㎡";
				document.title = this.navbar.title;
			},
			// 获取墙体数据
            async getHouseTypeSpaceWalls(){
				let wallList = [];
				if(this.wallList){
					wallList = this.wallList;
				}else{
					let data = {id:this.wallIds}
					const res = await requestConfig('getHouseTypeSpaceWalls', data, true);
					// console.log("墙体数据:", res.list)
					if(res.success){
					    wallList = this.wallList = res.list;
					}
				}
                let wallArr = []
                for (let index = 0; index < wallList.length; index++) {//每个空间对应一个数据
                    let element = JSON.parse(wallList[index].wallJson);
					let space = this.spaceList.find(space=>space.spaceId==element.spaceId);
					this.computeWallHandleOld(space,element);//提前计算
                    for (let i = 0; i < element.wallData.length; i ++) {//对应空间里面的4个方向的墙壁数据
                        let wallData = element.wallData[i];
						//对应方向的墙壁的墙体模型数据列表，每一面墙可能有多个模型
                        for (let j = 0; j < wallData.wallModelData.length; j ++) {
                            let wallModelData = wallData.wallModelData[j];
                            wallArr.push({spaceId:element.spaceId, wallModelData:wallModelData, wallDirection:wallData.wallDirection})
                            // console.log("wallModelData", element,wallData.wallDirection, wallModelData.wallType );
                        }
                    }
                }
                this.loadSpaceObjWalls(wallArr, wallList);
				this.getOverallArrangementDetailsList();//
            },
            // 加载单个空间墙体资源
            async loadSpaceObjWalls(wallArr, wallList){
                // 加载远程墙体模型资源
				let startTime = new Date().getTime();
                // console.log("wallArr:", wallArr)
				let promise_list = [];
				let realWallArr = this.preWallData(wallArr);
				let arrLength = realWallArr.length;
				realWallArr && realWallArr.forEach((item,index) => {
					promise_list.push(
						new Promise((resolve, reject) => {
							this.loadWallModels(item, wallList, arrLength , resolve);
						})
					)
				});
				Promise.all(promise_list).then(()=>{
					let endTime = new Date().getTime();
					console.log("墙体模型全部加载完成，时间：",endTime - startTime);
					// 设置空间数组的墙体信息
					// this.setSpaceListWallInfo();
					this.$nextTick(()=>{
						// this.moveMeshCenter(this.curSpaceObj);
						this.progress = 100;
						// this.$refs.myLoading.showLoading("加载中..." + this.progress + '%')
						this.$nextTick(()=>{
							this.myLoadingStatus = false;
							// this.$refs.myLoading.hideLoading();
							// this.meshRoam(this.curSpaceObj);//开始漫游，必须先选中模型
						})
					})
				})
            },
        }
    }
</script>
<style lang="scss" scoped>
    @import "./webgl_rxdz_roam.scss";
	/* @import "@/common/css/common.css"; */
</style>