import math from './math.js' let bimViewer export default class ConvertViews extends THREE.EventDispatcher{ constructor( ) { super() this.settings = { durations : {flyToPano:1000, dolly:20, bimAniOrigin:1000}, checkModeDelay : 1000, } } bindWithSameFakeType(sourceFakeApp, targetApp){//for mobile 实际只有一个场景,未分屏,和上一个场景相比 let sourceApp = {sceneType: sourceFakeApp.sceneType, fakeApp:sourceFakeApp} this.createTempApp(targetApp, true) let convertInfo = this.computeAveDiffLon(sourceFakeApp, targetApp.fakeApp) sourceApp.sceneName = 'sourceApp' targetApp.sceneName = 'targetApp' if(sourceApp.sceneType == 'laser'){ let data = this.computeShift({sourceApp,targetApp, convertInfo}) //因为有点云模式自由移动所以需要计算 convertInfo.convertMatrix = data.convertMatrix convertInfo.convertMatrixInvert = data.convertMatrixInvert } this.syncView(sourceApp, targetApp, convertInfo) if(sourceApp.sceneType == 'kankan' || sourceFakeApp.viewInfo.isAtPano){ this.flyToPano(targetApp, sourceFakeApp.viewInfo.currentPano,{duration:0}) } if(sourceApp.sceneType == 'laser'){ targetApp.viewer.mainViewport.view.applyToCamera(targetApp.viewer.mainViewport.camera)//使获得的cameraInfo正确 }else if(sourceApp.sceneType == 'kankan'){ targetApp.app.core.get('Player').cameraControls.activeControl.locked = false //怎么刚加载时lock了 targetApp.app.core.get('Player').update()//cameraControls.activeControl.update() //使获得的cameraInfo正确 } } bindWithSameType(sourceApp,targetApp, isSwitchScene){ this.sourceApp = sourceApp this.targetApp = targetApp this.createTempApp(sourceApp) this.createTempApp(targetApp) this.convertInfo = this.computeAveDiffLon(sourceApp.fakeApp, targetApp.fakeApp) sourceApp.sceneName = 'sourceApp' targetApp.sceneName = 'targetApp' if(sourceApp.sceneType == 'laser'){ { let data = this.computeShift({sourceApp,targetApp, convertInfo:this.convertInfo}) //因为有点云模式自由移动所以需要计算 this.convertInfo.convertMatrix = data.convertMatrix this.convertInfo.convertMatrixInvert = data.convertMatrixInvert } //只监听左边 let displayMode = (e)=>{ targetApp.Potree.settings.displayMode = e.mode } sourceApp.viewer.images360.addEventListener('endChangeMode', displayMode) let dispose = ()=>{ if(!sourceApp.viewer || !sourceApp.viewer.images360)return sourceApp.viewer.images360.removeEventListener('endChangeMode', displayMode) this.removeEventListener('clearBind-sameType',dispose) } this.addEventListener('clearBind-sameType',dispose) } let bind = (master, customer)=>{ //相互都能带动对方 if(sourceApp.sceneType == 'laser'){ var flyToPano = (e)=>{//同步点位 if(master != this.masterApp )return let pano = customer.viewer.images360.getPano(e.toPano.pano.id) if(!pano)return console.error('找不到该e.panoId', e.toPano.pano.id) customer.viewer.images360.flyToPano({pano} ) } master.viewer.images360.addEventListener('flyToPano',flyToPano) var cameraMove = (e)=>{ if(master != this.masterApp || !customer.viewer )return this.addViewInfo(master) master.fakeApp.viewInfo.quaternionChanged = e.changeInfo && e.changeInfo.quaternionChanged this.syncView(master, customer) } master.viewer.addEventListener('camera_changed',cameraMove) var dragEnd = (e)=>{ if(customer.viewer.inputHandler.drag){ customer.viewer.inputHandler.onMouseUp(e) //从一侧拖拽到另一侧松开时,需要执行原先一侧的mouseup } } master.addEventListener('mouseup',dragEnd) }else if(sourceApp.sceneType == 'kankan'){ var player1 = master.app.core.get('Player') var player2 = customer.app.core.get('Player') let this_ = this var flyToPano = (e)=>{//同步点位 if(master != this_.masterApp )return let pano = player2.model.panos.index[e.panoId] if(!pano)return console.error('找不到该e.panoId',e.panoId) player2.flyToPano({pano} ) } player1.on("flying.started",flyToPano) var cameraMove = (e)=>{//暂时只有漫游模式 if(!e.hasChanged.cameraChanged || !customer.app || !customer.app.core)return this.addViewInfo(master) this.syncView(master, customer) } player1.on("update",cameraMove) } let changeMaster = ()=>{ this.masterApp = master //主控方。只有主控方能控制被控方。鼠标操作过mousedown mousewheel等才能认定为主控方 } let dom = sourceApp.sceneType == 'laser' ? master.viewer.inputHandler.domElement : master.app.core.get('Player').domElement dom.addEventListener('pointerdown',changeMaster ) dom.addEventListener('mousewheel',changeMaster ) let dispose = ()=>{ if(master.sceneType == 'laser'){ if(!master.viewer )return //master已替换,不用处理 master.viewer.images360.removeEventListener('flyToPano',flyToPano) master.viewer.removeEventListener('camera_changed',cameraMove) }else if(master.sceneType == 'kankan'){ player1.off("flying.started",flyToPano) player1.off("update",cameraMove) } master.removeEventListener('mousedown',changeMaster) master.removeEventListener('mousewheel',changeMaster) master.removeEventListener('mouseup',dragEnd) this.removeEventListener('clearBind-sameType',dispose) } this.addEventListener('clearBind-sameType',dispose) } bind(sourceApp, targetApp) bind(targetApp, sourceApp) //切换其中一个场景后同步初始漫游点 if(isSwitchScene){ setTimeout(()=>{ let master = isSwitchScene == 'target' ? sourceApp : targetApp let customer = isSwitchScene == 'target' ? targetApp : sourceApp this.masterApp = master this.addViewInfo(master) this.syncView(master, customer) if(master.sceneType == 'laser'){ let pano = master.viewer.images360.nextPano || master.viewer.images360.currentPano pano && this.flyToPano(customer, pano.id, { duration: 0, callback:()=>{ customer.Potree.settings.displayMode = master.Potree.settings.displayMode }}) //master.viewer.dispatchEvent({type:'camera_changed',changeInfo:{quaternionChanged:true},viewport:master.viewer.mainViewport }) //朝向位置同步 }else{ //master.app.core.get('Player').emit("update",{ hasChanged:{cameraChanged:true} })//朝向同步 let pano = master.app.core.get('Player').nextPano || master.app.core.get('Player').currentPano pano && this.flyToPano(customer, pano.id, { duration: 0 }) } },1)//要延迟,否则角度和pano都不成功 } this.loaded = true } bindFakeWithBim(sourceFakeApp, targetApp, panoData ){// bim和其他类型互转(mobile) if(!panoData)return let sourceApp = {sceneType: sourceFakeApp.sceneType, fakeApp:sourceFakeApp} this.createTempApp(targetApp) let {sourcePano, targetPano} = this.bimGetPanoData(sourceApp, targetApp, panoData) let convertAxis = sourceApp.sceneType == 'kankan' ? 'YupToZup' : targetApp.sceneType == 'kankan' ? 'ZupToYup' : null let convertInfo = this.computeShift({sourcePano, targetPano, convertAxis}) console.log('convertInfo', convertInfo, sourcePano, targetPano) let selectBestPose = ()=>{ let data = this.getTranPosData(sourceFakeApp.viewInfo, convertInfo ) let panos = targetApp.fakeApp.panos; let panos2 = panos.sort((a,b)=>{ return data.position.distanceToSquared(a.position) - data.position.distanceToSquared(b.position) }) let dir = new THREE.Vector3().subVectors( data.target, data.position ) console.log('dir', dir) let prop = { duration:0,} if(targetApp.sceneType == 'laser'){ targetApp.viewer.mainViewport.view.direction = dir }else{ let player = targetApp.app.core.get('Player') console.log('nearest:', panos2[0].id) prop.aimDuration = 0 prop.lookAtPoint = new THREE.Vector3().addVectors(panos2[0].position, dir) } this.flyToPano(targetApp, panos2[0].id, prop) } if(targetApp.sceneType == 'bim'){ bimViewer = targetApp.viewer bimViewer.getViewer().setTransitionAnimationState(false) targetApp.CLOUD.GlobalData.WalkRotationSpeed = -0.2 //反向一下 } if(targetApp.sceneType == 'bim' ){ this.syncPosRot(sourceFakeApp.viewInfo, targetApp, convertInfo) }else if(targetApp.sceneType == 'laser' ){ selectBestPose() //刚好在点位上的话这句设置完就正确了 setTimeout(()=>{ //刚开始总是showPointCloud (且稍后会自动飞到某点)所以需要延时 this.laserCancelFly(targetApp) if(this.ifCanChangePos(targetApp)){//点云模式的话 this.syncPosRot(sourceFakeApp.viewInfo, targetApp, convertInfo) }else{ } },this.settings.checkModeDelay+10) }else{//bim -> 固定点位 selectBestPose() } } laserCancelFly(app){ app.viewer.images360.cancelFlyToPano() app.viewer.mainViewport.view.cancelFlying() } bindWithBim(sourceApp, targetApp, panoData ) { //if (!this.player1.model.panos.list.length || !this.player2.model.panos.list.length) return if(this.loaded || !targetApp ) return let needBindEvent = !this.targetApp // 若targetApp存在表明targetApp的dom未换掉,事件还存在 this.createTempApp(sourceApp) this.createTempApp(targetApp) let {sourcePano, targetPano} = this.bimGetPanoData(sourceApp, targetApp, panoData) this.sourceApp = sourceApp this.targetApp = targetApp let modelSize = new THREE.Vector3 bimViewer = this.bimViewer = targetApp.viewer let modelBound = bimViewer.getViewer().modelManager.boundingBox modelBound.getSize(modelSize) bimViewer.setNavigationMode(targetApp.Glodon.Bimface.Viewer.NavigationMode3D.Walk) bimViewer.setFlySpeedRate(THREE.MathUtils.clamp( modelSize.length() / 10, 1, 6)) //会被限制 //bimViewer.getViewer().setWalkSpeedRate(2) this.sourceDom = sourceApp.sceneType == 'laser' ? this.sourceApp.viewer.inputHandler.domElement : this.sourceApp.app.core.get('Player').domElement if(targetPano){ bimViewer.getViewer().setTransitionAnimationState(false) //setCameraStatus瞬间变化相机 ,or setCameraAnimation? var convertAxis = sourceApp.sceneType == 'kankan' && targetApp.sceneType == 'bim' && 'YupToZup'// Y朝上需要转换 this.lastCamStatus = bimViewer.getCameraStatus() this.convertInfo = this.computeShift({sourcePano, targetPano, convertAxis}) bimViewer.addEventListener('Rendered', (e)=>{//反向改变左侧相机 let info = bimViewer.getCameraStatus() let poseChanged = !math.closeTo(this.lastCamStatus.position, info.position) || !math.closeTo(this.lastCamStatus.target, info.target) || !math.closeTo(this.lastCamStatus.fov, info.fov) if(poseChanged){ if(this.ifCanChangePos(this.sourceApp)){ this.send(info) this.lastCamStatus = info } } }) if(needBindEvent){ this.bindCamEvent() }else{//替换的左侧的,需要使左侧和右侧同步, 其实是左侧要和上一个左侧先同步,再让右侧和左侧同步 this.bindWithSameFakeType(this.lastFakeApp, sourceApp) } { let cameraMove if(sourceApp.sceneType == 'laser'){ cameraMove = e => { targetApp && this.syncPosRot(this.getCameraData(sourceApp)) } sourceApp.viewer.addEventListener('camera_changed', cameraMove) }else if(sourceApp.sceneType == 'kankan'){ var player = this.sourceApp.app.core.get('Player') //this.sourceDom = player.domElement cameraMove = (e)=>{//暂时只有漫游模式 if(!e.hasChanged.cameraChanged2)return //console.log('cameraMove', this.getCameraData(sourceApp)) this.syncPosRot(this.getCameraData(sourceApp)) } player.on("update",cameraMove) } let dispose = ()=>{ if(sourceApp.sceneType == 'laser'){ //if(!sourceApp.viewer || !sourceApp.viewer.images360)return sourceApp.viewer.removeEventListener('camera_changed', cameraMove) }else{ //if(!sourceApp.app || !sourceApp.app.core)return player.off("update",cameraMove) } this.removeEventListener('clearBind-sameType',dispose) } this.addEventListener('clearBind-sameType',dispose) } /* bimViewer.addEventListener(targetApp.Glodon.Bimface.Viewer.Viewer3DEvent.ViewAdded, ()=>{ this.loaded = true if(this.firstData){ this.syncPosRot(this.firstData) } } ) */ let data = this.getCameraData(sourceApp) this.syncPosRot(data) this.loaded = true }else{ //分屏 不同步 let data = this.getCameraData(sourceApp) let camera = bimViewer.getViewer().camera if(camera.fov != data.fov){ camera.fov = data.fov camera.updateProjectionMatrix() } //将第一人称control补充完: //scroll let baseSpeed = THREE.MathUtils.clamp( Math.sqrt(modelSize.length()) / 5, 0.3, 8) //在modelBound中时的速度 //console.log('baseSpeed',baseSpeed) let dom = bimViewer.getDomElement(); dom.addEventListener('mousewheel', e => { //原版滚轮不能缩放,自己加一个 if(e.wheelDelta == 0)return //mac let info = bimViewer.getCameraStatus() let dis = modelBound.distanceToPoint(info.position) let speed = baseSpeed + dis / 6 //console.log('speed', speed) this.bimFlyTo({forwardDis: e.wheelDelta > 0 ? speed : -speed, duration:this.settings.durations.dolly , minRadius : baseSpeed}) }) //右键pan let dragging , pointerDelta = new THREE.Vector2, pointerStart = new THREE.Vector2 dom.addEventListener('mousedown', e => { if(e.button == 2){//右键 dragging = true pointerStart.set(e.clientX, e.clientY) } }) dom.addEventListener('mousemove', e => { if(!dragging)return let pointerEnd = new THREE.Vector2(e.clientX, e.clientY) pointerDelta.subVectors(pointerEnd, pointerStart) pointerStart.copy(pointerEnd) bimViewer.getViewer().cameraControl.pan(pointerDelta.x,pointerDelta.y) }) let mouseupAt = (target,e)=>{//触发target的mouseup let event = new MouseEvent('mouseup', { button : e.button, buttons:e.buttons }) target.dispatchEvent(event) } targetApp.addEventListener('mouseup', e => { dragging = false //触发当前sourceDom的mouseup mouseupAt(this.sourceDom,e) }) this.sourceDom.addEventListener('mouseup', e => { dragging = false //触发当前targetApp的mouseup mouseupAt(targetApp,e) }) this.addEventListener('mouseupOutOfWin', e => { dragging = false //触发当前targetApp的mouseup mouseupAt(targetApp,e) }) targetApp.CLOUD.GlobalData.WalkRotationSpeed = -0.2 //反向一下 //bimViewer.viewer.getViewer().editorManager.userInputEditor.enable = true//这句近似将control切换成orbit } } syncPosRot(data, customer, convertInfo ){//同步 自由位置和朝向(不被漫游点束缚时) /* if(!this.loaded){ return this.firstData = data } */ convertInfo = convertInfo || this.convertInfo let {position,target} = this.getTranPosData(data, convertInfo ) if(customer && customer.sceneType == 'laser'){ this.laserSyncView(customer, {position,target}) }else{ let msg = { position, target, up: new THREE.Vector3(0,0,1), //前三个缺一不可 fov: data.fov , //fov 用setCameraStatus 无效 } bimViewer.setCameraStatus(msg) this.lastCamStatus = msg //记录下来,防止反向传输 let camera = bimViewer.getViewer().camera if(camera.fov != data.fov){ camera.fov = data.fov camera.updateProjectionMatrix() } } } ifCanChangePos(app){ return app.sceneType == 'laser' && app.Potree.settings.displayMode != 'showPanos' //app.fakeApp.viewInfo.displayMode != 'showPanos' } send(info){ //let camera = bimViewer.getViewer().camera let data = this.getTranPosData(info, this.convertInfo, true ) this.laserSyncView(this.sourceApp, data) //左侧只有laser点云模式才能接收到 } computeAveDiffLon(sourceFakeApp, targetFakeApp) { //获取两个场景的lon偏差值 //需要点的个数>1, 且两个场景点一一对应,位置接近且顺序一致 let diffLonAve = 0, length, diffLons = [] let panoPos1 = sourceFakeApp.panos.map(e=>{ return e.position }) let panoPos2 = targetFakeApp.panos.map(e=>{ return e.position }) length = panoPos1.length //挑选连续的两个点为向量来计算,如有123个漫游点,则选取12 23 31作为向量 let index = 0 while (index < length) { let pos11 = new THREE.Vector3().copy(panoPos1[index]) let pos12 = new THREE.Vector3().copy(panoPos1[(index + 1) % length]) let pos21 = new THREE.Vector3().copy(panoPos2[index]) let pos22 = new THREE.Vector3().copy(panoPos2[(index + 1) % length]) let vec1 = new THREE.Vector3().subVectors(pos11, pos12).setY(0) let vec2 = new THREE.Vector3().subVectors(pos21, pos22).setY(0) let diffLon = math.getAngle(vec1, vec2, 'z') diffLons.push(diffLon) diffLonAve += diffLon index++ } console.log('diffLons', diffLons) diffLonAve /= length console.log('diffLonAve', diffLonAve) let diffQua = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), diffLonAve) return { diffLon : diffLonAve, diffQua , diffQuaInvert : diffQua.clone().invert() } } computeShift(o={}/* sourcePano, targetPano */) { //获取两个场景的旋转和位移偏差值 //需要点的个数>1, 且两个场景点一一对应,位置接近且顺序一致 let panoPos1, panoPos2 if(o.sourceApp && o.targetApp && o.sourceApp.sceneType == o.targetApp.sceneType){ var angle = o.convertInfo.diffLon; //直接使用 更精准 panoPos1 = o.sourceApp.fakeApp.panos.map(e=>{ return e.position }) panoPos2 = o.targetApp.fakeApp.panos.map(e=>{ return e.position }) }else{ panoPos1 = o.sourcePano.map(e=>e.position) //pick两个点来计算 panoPos2 = o.targetPano.map(e=>e.position) if(o.convertAxis){ panoPos1 = panoPos1.map(e=>math.convertVector[o.convertAxis](e)) } var vec1 = new THREE.Vector3().subVectors(panoPos1[0], panoPos1[1]) //旧的向量 var vec2 = new THREE.Vector3().subVectors(panoPos2[0], panoPos2[1])//新的向量 var angle = math.getAngle(vec1, vec2, 'z') } //var scale = vec2.length()/vec1.length() //var scaleMatrix = new THREE.Matrix4().makeScale(scale,scale,scale) //默认为1, 但由于坐标暂时是自己采集的,所以结果会是第一个点附近比较正确,越远偏差越大 var matrix = new THREE.Matrix4().setPosition(panoPos1[0].clone().negate())//先以点0为基准平移到000 //matrix.premultiply(scaleMatrix)//再缩放 var rotateMatrix = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1), angle ); matrix.premultiply(rotateMatrix)//和旋转 var moveBackMatrix = new THREE.Matrix4().setPosition(panoPos2[0]) matrix.premultiply(moveBackMatrix)//再移动到realPosition的点0处 return { convertMatrix: matrix, convertMatrixInvert:matrix.clone().invert(), convertAxis:o.convertAxis} } /* laser暂时做成这样: 全景模式时不跟踪pos,跟踪pano变化。点云模式时也跟踪pano变化,但移动时完全跟踪位置变化 ,所以会有左边marker在脚下,右边marker不在脚下的情况。 */ getCameraData(app){ if(app.sceneType == 'laser'){ let camera = app.viewer.mainViewport.camera return { position: camera.position.clone(), quaternion: camera.quaternion.clone(), fov: camera.fov, } }else if(app.sceneType == 'kankan'){ let player = app.app.core.get('Player') return { position: player.position.clone(), quaternion: player.quaternion.clone(), fov: player.zoomFov, } }else{ let bimViewer = app.viewer let info = bimViewer.getCameraStatus(); return { position: info.position, target: info.target, fov: info.fov, } } } createTempApp(app, addsubInfo){//for mobile let fakeApp = { isFake : true, //标志是虚拟的app。每个真实的app都要带一个这个。在移动端如果大的销毁了还有小的 sceneType : app.sceneType } if(app.sceneType != 'bim'){ function getPanos(panos){ // only data return panos.map(e=>{return {id:e.id, position:e.position, quaternion:e.quaternion}}) } fakeApp.panos = app.sceneType == 'laser' ? getPanos(app.viewer.images360.panos) : getPanos(app.app.core.get('Player').model.panos.list) } app.fakeApp = fakeApp if(addsubInfo){ this.addViewInfo(app) } return fakeApp } addViewInfo(app){ let viewInfo let cameraData = this.getCameraData(app) if(app.sceneType == 'laser'){ let images360 = app.viewer.images360 viewInfo = { displayMode : app.Potree.settings.displayMode, currentPano : images360.currentPano && images360.currentPano.id, isAtPano : images360.isAtPano(), quaternionChanged : true, } }else if(app.sceneType == 'kankan'){ let player = app.app.core.get('Player') viewInfo = { currentPano : player.currentPano.id, lon : player.cameraControls.activeControl.lon, lat : player.cameraControls.activeControl.lat, zoomLevel : player.zoomLevel, } }else{ viewInfo = {} } for(let i in cameraData){ viewInfo[i] = cameraData[i] } app.fakeApp.viewInfo = viewInfo } /* getPano(app){ return app.sceneType == 'laser' ? app.viewer.images360.getPano(id) : app.app.core.get('Player').panos.index[id] } */ syncView(master, customer, convertInfo ){//同类型 相当于moveCamera的函数 let fakeApp = master.fakeApp; convertInfo = convertInfo || this.convertInfo if(fakeApp.sceneType == 'laser'){ customer.Potree.settings.displayMode = fakeApp.viewInfo.displayMode if(fakeApp.viewInfo.isAtPano || fakeApp.viewInfo.displayMode == 'showPanos'){ //不改变漫游点,仅转换朝向 if( fakeApp.viewInfo.quaternionChanged){ let diffQua = customer == this.targetApp ? convertInfo.diffQua : convertInfo.diffQuaInvert let quaternion = fakeApp.viewInfo.quaternion.clone().premultiply(diffQua) let rotation = new THREE.Euler().setFromQuaternion(quaternion) customer.viewer.mainViewport.view.rotation = rotation //console.log('cameraMove',customer == this.targetApp) } if(fakeApp.viewInfo.displayMode == 'showPanos' ){ if(customer.viewer.mainViewport.camera.fov != fakeApp.viewInfo.fov){ customer.viewer.mainViewport.camera.fov = fakeApp.viewInfo.fov customer.viewer.mainViewport.camera.updateProjectionMatrix() } } }else{//转换朝向和位置 this.syncPosRot(fakeApp.viewInfo, customer , convertInfo) } }else if(fakeApp.sceneType == 'kankan'){ let player = customer.app.core.get('Player') let diffLon = THREE.Math.radToDeg(customer == this.sourceApp ? -convertInfo.diffLon : convertInfo.diffLon) player.cameraControls.controls.panorama.lon = fakeApp.viewInfo.lon + diffLon player.cameraControls.controls.panorama.lat = fakeApp.viewInfo.lat if(player.zoomLevel != fakeApp.viewInfo.zoomLevel){ player.zoomTo(fakeApp.viewInfo.zoomLevel) } } } bimGetPanoData(sourceApp, targetApp, panoData){ if(panoData){ let sourcePano,targetPano let pano1 = [{position:new THREE.Vector3().copy(panoData.p1.position)},{position:new THREE.Vector3().copy(panoData.p2.position)}] let getPano2 = (app)=>{ return [app.fakeApp.panos.find(e=>e.id == panoData.p1.id), app.fakeApp.panos.find(e=>e.id == panoData.p2.id)] } if(targetApp.sceneType == 'bim'){ targetPano = pano1 sourcePano = getPano2(sourceApp) }else{ targetPano = getPano2(targetApp) sourcePano = pano1 } if( !sourcePano[0] || !sourcePano[1] || !targetPano[0] || !targetPano[1] ){ console.error('!sourcePano[0] || !sourcePano[1] || !targetPano[0] || !targetPano[1]') } return {sourcePano, targetPano} }else return {} } getTranPosData(data, convertInfo, ifRevert ){ let position = new THREE.Vector3, target = new THREE.Vector3 if(data.position){ position = new THREE.Vector3().copy(data.position) } if(!data.target){ if(data.quaternion){ let dir = new THREE.Vector3(0, 0, -1).applyQuaternion(data.quaternion) target.copy(position).add(dir) } }else{ target.copy(data.target) } if(ifRevert){ position.applyMatrix4(convertInfo.convertMatrixInvert) target.applyMatrix4(convertInfo.convertMatrixInvert) if(convertInfo.convertAxis){ position = math.convertVector[convertInfo.convertAxis](position) target = math.convertVector[convertInfo.convertAxis](target) } }else{ if(convertInfo.convertAxis){ position = math.convertVector[convertInfo.convertAxis](position) target = math.convertVector[convertInfo.convertAxis](target) } position.applyMatrix4(convertInfo.convertMatrix) target.applyMatrix4(convertInfo.convertMatrix) } return {position, target} } bimFlyTo(data){ let info = bimViewer.getCameraStatus() let vec = new THREE.Vector3().subVectors(info.target, info.position) let radius = vec.length() //修改了target到position的距离会影响pan时的速度 let dir = vec.clone().normalize() let position = data.position if(!position){ position = new THREE.Vector3().addVectors(info.position, dir.clone().multiplyScalar(data.forwardDis))//forwardDis:前进距离 radius = Math.max(radius-data.forwardDis, data.minRadius || 0.7) } if(data.duration != void 0){ bimViewer.getViewer().animator.setDuration(data.duration)//滚轮缩放时长,原先:1000 } //console.log('radius',radius) let target = new THREE.Vector3().addVectors(position, dir.clone().multiplyScalar(radius)) let msg = {//不能修改 position, target, up: new THREE.Vector3(0,0,1), //前三个缺一不可 } bimViewer.setCameraStatus(msg) } flyToPano(app, panoId, o={}){ if(app.sceneType == 'laser'){ this.laserCancelFly(app)//app.viewer.images360.cancelFlyToPano() app.viewer.images360.flyToPano(Object.assign({},{ pano: app.viewer.images360.getPano(panoId) },o)) }else{ let player = app.app.core.get('Player') player.flyToPano(Object.assign({},{ pano: player.model.panos.index[panoId] },o)) } } laserSyncView(app,data){ app.viewer.mainViewport.view.position.copy(data.position) app.viewer.mainViewport.view.lookAt(data.target) } lockCamera(locked){//禁止操作改变相机 this.locked = locked this.updateCtrlEnable() } setPanoMode(state){ this.isPanoMode = state this.updateCtrlEnable() } updateCtrlEnable(){ this.bimViewer.camera3D.enableRotate(this.locked ? false : true) this.bimViewer.enableShortcutKey((this.locked || this.isPanoMode) ? false : true) //键盘移动 } bindCamEvent(){//传递到另一边的dom this.lockCamera(true) /* this.targetApp.addEventListener(this.targetApp.Glodon.Bimface.Viewer.Viewer3DEvent.MouseClicked,(e)=>{ console.log('MouseClicked',e) }); */ let dom1 = this.bimViewer.getDomElement() let getEvent = (type, e)=>{ let clientWidth1 = this.sourceDom.clientWidth let clientHeight1 = this.sourceDom.clientHeight let clientWidth2 = dom1.clientWidth let clientHeight2 = dom1.clientHeight return new MouseEvent(type, { bubbles: false,//? cancelable: true, view: this.sourceApp, /* clientX: e.clientX, clientY: e.clientY, */ clientX: clientWidth1 * e.clientX / clientWidth2 , //鼠标在右屏的比例的左屏的相同,针对右屏全屏等左右不对称的情况 clientY: clientHeight1 * e.clientY / clientHeight2, button: e.button, buttons: e.buttons, which: e.which, altKey: e.altKey, ctrlKey: e.ctrlKey, shiftKey:e.shiftKey, metaKey: e.metaKey, detail:e.detail, //target : dom2 }); } //let pointerDownPos = new THREE.Vector2 dom1.addEventListener('mousedown',(e)=>{ let event = getEvent('mousedown', e) this.sourceApp && this.sourceDom.dispatchEvent(event) //pointerDownPos.set(e.clientX,e.clientY) }) dom1.addEventListener('mousemove',(e)=>{ let event = getEvent('mousemove', e) this.sourceApp && this.sourceDom.dispatchEvent(event) }) dom1.addEventListener('mouseup',(e)=>{ if(!this.sourceApp)return let event = getEvent('mouseup', e) event.unableClick = true //最好禁止右侧点击行走。否则和点击效果冲突 if(this.sourceApp.sceneType == 'laser'){ this.sourceApp.dispatchEvent(event) //mouseup 在laser中加在window上的 }else{ let player = this.sourceApp.app.core.get('Player') player.mouseCouldBeClickToMove = false //dont click this.sourceDom.dispatchEvent(event) } }) dom1.addEventListener('mousewheel',(e)=>{ let event = getEvent('mousewheel', e) event.wheelDelta = e.wheelDelta //wheelDelta没法在getEvent参数中赋值 this.sourceApp && this.sourceDom.dispatchEvent(event) }) let stop = (e)=>{ //drag到另一边时停止旋转, 防止转到另一边 let event = getEvent('mouseup', e) this.sourceApp && this.sourceApp.dispatchEvent(event) } dom1.addEventListener('mouseout',stop) dom1.addEventListener('mouseover',stop) } clear(o={}){ this.loaded = false; if(o.dontClearTarget){ if(this.sourceApp){ this.lastFakeApp = this.sourceApp.fakeApp //记住当前左屏 this.addViewInfo(this.sourceApp) } }else{ this.targetApp = null this.lastFakeApp = null } this.sourceApp = null; this.dispatchEvent({type:'clearBind-sameType'}) window.Log('clear done') } } /* note: 旋转只能通过target设置, 不能直接改camera.quaternion 当且仅当发送方相机属性变化后才传递过来,就不在这里判断是否变化了。 (所以只需要实时检测相机是否改变, hasChanged后发送) */ /* 其他代码: initTagAdd(){ let markerConfig = new Bimface.Plugins.Marker3D.Marker3DContainerConfig(); markerConfig.viewer = this.viewer; let tags = new Bimface.Plugins.Marker3D.Marker3DContainer(markerConfig); console.log('tags',tags) this.addEventListener('addTag',(e)=>{ if(this.targetPano[e.index].tag){ tags.removeItemById(this.targetPano[e.index].tag.id) } let position = new THREE.Vector3 if(e.position){ position.copy(e.position) }else{ let currStatus = this.viewer.getCameraStatus() position.copy(currStatus.position) } let marker3dConfig = new Bimface.Plugins.Marker3D.Marker3DConfig(); marker3dConfig.src = 'images/hotpoint'+ e.index +'.png'//"http://static.bimface.com/resources/3DMarker/warner/warner_red.png"; marker3dConfig.worldPosition = new THREE.Vector3().copy(position) marker3dConfig.worldPosition.z -= belowHeight marker3dConfig.tooltip = '此为漫游点'+e.index //三维标签的提示 let tag = new Bimface.Plugins.Marker3D.Marker3D(marker3dConfig); tags.addItem(tag); this.viewer.clearSelectedComponents(); this.viewer.render(); this.targetPano[e.index].tag = tag this.updatePanoMatch(position, e.index ) }) } this.viewer.addEventListener( Bimface.Viewer.Viewer3DEvent.MouseClicked, (objectData)=>{ let position = objectData.worldPosition.clone().add({x:0,y:0,z:height}); }) addMesh(cameraData){ var mesh = new Bimface.Plugins.Geometry.Plane({ type:'rectangle', points:[{x:-0.1,y:-0.1,z:0},{x:0.1,y:0.1,z:0}] }); var extObjMng = new Bimface.Plugins.ExternalObject.ExternalObjectManager(viewer2); extObjMng.loadObject({ name: 'plane', object: mesh});//作为外部构件添加到场景中 //mesh.children[0].position.copy(cameraData.position).setZ(0.5) mesh.children[0].up.set(0,0,1) mesh.children[0].rotation.set(0,0,Math.PI/2) this.plane = mesh window.extObjMng = extObjMng } */