import * as THREE from "../../../libs/three.js/build/three.module.js"; import SplitScreen from "../../utils/SplitScreen" import math from "../../utils/math" import {EventDispatcher} from "../../EventDispatcher.js"; var Alignment = { SplitScreen, handleState:null, //操作状态 'translate'|'rotate' bus: new THREE.EventDispatcher(), init:function(){ let rotateInfo viewer.fpControls.addEventListener("transformPointcloud",(e)=>{ if(e.pointcloud.dataset_id == Potree.settings.originDatasetId){//禁止手动移动初始数据集 return this.bus.dispatchEvent('forbitMoveOriginDataset') } if(this.handleState == 'translate'){ Alignment.translate(e.pointcloud,e.moveVec) }else if(this.handleState == 'rotate'){ let center = e.pointcloud.translateUser //移动到的位置就是中心 if(!rotateInfo){ rotateInfo = { orientationUser : e.pointcloud.orientationUser, vecStart : new THREE.Vector3().subVectors(e.intersectStart, center).setZ(0), pointcloud: e.pointcloud } }else{ let vec = new THREE.Vector3().subVectors(e.intersectPoint, center).setZ(0) let angle = math.getAngle(rotateInfo.vecStart,vec,'z') let diffAngle = rotateInfo.orientationUser + angle - rotateInfo.pointcloud.orientationUser Alignment.rotate(rotateInfo.pointcloud, null, diffAngle) } } }) viewer.fpControls.addEventListener("end",(e)=>{ rotateInfo = null }) // cursor: let updateCursor = (e)=>{ if(e.drag)return //仅在鼠标不按下时更新: let handleState = Alignment.handleState if(e.hoverViewport.alignment && handleState && e.hoverViewport.alignment[handleState]){ if(handleState == 'translate'){ if( e.intersectPoint && e.intersectPoint.location ){ viewer.dispatchEvent({ type : "CursorChange", action : "add", name:"movePointcloud" }) }else{ viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"movePointcloud" }) } }else if(handleState == 'rotate'){ if( e.intersectPoint && e.intersectPoint.location ){ viewer.dispatchEvent({ type : "CursorChange", action : "add", name:"rotatePointcloud" }) }else{ viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"rotatePointcloud" }) } } }else{ //清空: viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"movePointcloud" }) viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"rotatePointcloud" }) } } viewer.addEventListener('global_mousemove',updateCursor) viewer.addEventListener('global_drop',updateCursor)//拖拽结束 }, setMatrix : function(pointcloud){ var vec1 = pointcloud.position //position为数据集内部的偏移,在navvis中对应的是dataset.pointCloudSceneNode的children[0].position var vec2 = pointcloud.translateUser var angle = pointcloud.orientationUser var pos1Matrix = new THREE.Matrix4().setPosition(vec1);//先移动到点云本身应该在的初始位置(在4dkk里和其他应用中都是在这个位置的,也能和漫游点对应上) var rotMatrix = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1), angle)//再旋转 var pos2Matrix = new THREE.Matrix4().setPosition(vec2);//最后是平移 var matrix = new THREE.Matrix4().multiplyMatrices(pos2Matrix, rotMatrix); pointcloud.transformMatrix = matrix.clone();//为该数据集的变化矩阵。 对应navvis的m2w_ pointcloud.transformInvMatrix.copy(matrix).invert() pointcloud.rotateMatrix = rotMatrix pointcloud.rotateInvMatrix.copy(rotMatrix).invert() pointcloud.panos.forEach(e=>e.transformByPointcloud()) matrix = new THREE.Matrix4().multiplyMatrices(matrix, pos1Matrix); pointcloud.matrix = matrix; //pointcloud.matrixWorldNeedsUpdate = true //更新matrixWorld (非计算,直接赋值) pointcloud.updateMatrixWorld(true) if(this.editing){ Alignment.changeCallBack && Alignment.changeCallBack(); } if(pointcloud.spriteNodeRoot){ pointcloud.spriteNodeRoot.matrixWorld.copy(pointcloud.matrixWorld)//.multiplyMatrices(pointcloud.matrixWorld, pointcloud.matrixWorld); } //viewer.updateModelBound(); pointcloud.updateBound() }, rotate:function(pointcloud, deg, angle){//假设点云位移position后0,0,0就是它的中心了(根据navvis观察这样做是绕同一个点旋转的) var angle = angle != void 0 ? angle : THREE.Math.degToRad(deg) //正逆负顺 pointcloud.orientationUser += angle Alignment.setMatrix(pointcloud) }, translate:function(pointcloud, vec){ pointcloud.translateUser.add(vec) Alignment.setMatrix(pointcloud) }, saveTemp:function(){//记录最近一次保存后的状态,便于恢复 this.originData = viewer.scene.pointclouds.map(e=>{ return { id : e.dataset_id, orientationUser : e.orientationUser, translateUser : e.translateUser.clone(), } } ) }, enter:function(){ this.saveTemp() SplitScreen.splitScreen4Views({alignment:true}) viewer.images360.panos.forEach(pano=>{ viewer.updateVisible(pano.mapMarker, 'split4Screens', false) }) viewer.viewports.find(e=>e.name == 'mapViewport').alignment = {rotate:true,translate:true}; viewer.viewports.find(e=>e.name == 'Right').alignment = {translate:true}; viewer.viewports.find(e=>e.name == 'Back').alignment = {translate:true}; this.editing = true viewer.updateFpVisiDatasets() }, leave:function(){ this.switchHandle(null) this.originData.forEach(e=>{//恢复 var pointcloud = viewer.scene.pointclouds.find(p=>p.dataset_id == e.id) this.translate(pointcloud, new THREE.Vector3().subVectors(e.translateUser , pointcloud.translateUser)) this.rotate(pointcloud, null, e.orientationUser - pointcloud.orientationUser) }) SplitScreen.recoverFrom4Views() viewer.images360.panos.forEach(pano=>{ viewer.updateVisible(pano.mapMarker, 'split4Screens', true) }) this.editing = false viewer.updateFpVisiDatasets() } , switchHandle:function(state){ this.handleState = state //清空: viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"movePointcloud" }) viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"rotatePointcloud" }) }, save: function(){//保存所有数据集的位置和旋转 let callback = ()=>{//保存成功后 this.saveTemp(); //需要修改 测量线的position。漫游点已经实时修改了 viewer.scene.measurements.forEach(e=>e.transformByPointcloud()) viewer.images360.updateCube(viewer.bound) } var data = viewer.scene.pointclouds.map(e=>{ let pos = viewer.transform.lonlatToLocal.inverse(e.translateUser.clone()) return { id: e.dataset_id, orientation : e.orientationUser, location:[pos.x, pos.y, pos.z], //transformMatrix: e.transformMatrix.elements, } }) //data = JSON.stringify(data) //test: 退出后保留结果 if(!Potree.settings.isOfficial){ callback() } return {data, callback} } } /* 关于控制点: 两个控制点只能打在同一个数据集上。传输这两个点的4dkk中的本地坐标和经纬度,后台算出该数据集的旋转平移, 然后其他数据集绕该数据集旋转,并保持相对位置不变。 */ export {Alignment}