import * as THREE from "../../../libs/three.js/build/three.module.js"; import SplitScreen4Views from "../../utils/SplitScreen4Views.js" import math from "../../utils/math.js" import History from "../../utils/History.js" import { EventDispatcher } from "../../EventDispatcher.js"; var Alignment = { SplitScreen: SplitScreen4Views, handleState:null, //操作状态 'translate'|'rotate' bus: new EventDispatcher(), prepareRecord : true, writeToHistory(content){ if(!this.prepareRecord)return; this.prepareRecord = false this.history.writeIn(content) }, /* undo(){//撤销一步 let last = this.history.pop(); last && last.forEach(item=>{ this.applyTemp(item) }) }, */ applyTemp(item){ var pointcloud = viewer.scene.pointclouds.find(p=>p.dataset_id+p.name == item.sid) pointcloud.orientationUser = item.orientationUser pointcloud.translateUser = item.translateUser this.setMatrix( pointcloud ) }, getTemp(pointclouds){//记录最近一次保存后的状态,便于恢复 pointclouds = pointclouds || viewer.scene.pointclouds return pointclouds.map(e=>{ return { sid : e.dataset_id+e.name, orientationUser : e.orientationUser, translateUser : e.translateUser.clone(), } } ) }, init:function(){ let rotateInfo viewer.fpControls.addEventListener("transformPointcloud",(e)=>{ if(e.pointclouds[0].dataset_id == Potree.settings.originDatasetId){//禁止手动移动初始数据集 return this.bus.dispatchEvent('forbitMoveOriginDataset') } this.writeToHistory(this.getTemp(e.pointclouds) ) if(this.handleState == 'translate'){ e.pointclouds.forEach(cloud=>Alignment.translate(cloud, e.moveVec)) }else if(this.handleState == 'rotate'){ if(Potree.settings.editType == 'pano'){ let center = e.intersectStart //旋转中心是mousedown的位置 if(e.intersect.equals(center))return if(!rotateInfo){ rotateInfo = { orientationUser : e.pointclouds[0].orientationUser, //vecStart : e.moveVec, // 首次移动向量 只有八个方向,精度太小,所以延迟 pointclouds: e.pointclouds } this.bus.dispatchEvent({type:'rotateStart', startPoint:center}) return }else if(!rotateInfo.vecStart){ let vec = new THREE.Vector3().subVectors(e.intersect, center).setZ(0) if(vec.length() * e.camera.zoom > 30){ //在屏幕上距离初始点有一定距离后开始算 //console.log('moveVec',vec) rotateInfo.vecStart = vec } }else{ let vec = new THREE.Vector3().subVectors(e.intersect, center).setZ(0) let angle = math.getAngle(rotateInfo.vecStart,vec,'z') let diffAngle = rotateInfo.orientationUser + angle - rotateInfo.pointclouds[0].orientationUser rotateInfo.pointclouds.forEach(cloud=>{ /* let centerNoTranfrom = Potree.Utils.datasetPosTransform({ toDataset: true, pointcloud:cloud, position: center }) //中心点在数据集中的位置 Alignment.rotate(cloud, null, diffAngle) let centerNow = Potree.Utils.datasetPosTransform({ fromDataset: true, pointcloud:cloud, position: centerNoTranfrom }) //中心点的现在位置 let shift = new THREE.Vector3().subVectors( center, centerNow); //偏移量 Alignment.translate(cloud,shift) //使center还保留在原位 //let centerNow1 = Potree.Utils.datasetPosTransform({ fromDataset: true, pointcloud:rotateInfo.pointcloud, position: centerNoTranfrom }) //中心点的现在位置 */ Alignment.rotateAround(center, cloud, null, diffAngle) }) } this.bus.dispatchEvent({type:'rotate', endPoint: e.intersect}) }else{ let center = e.pointclouds[0].translateUser //移动到的位置就是中心 if(e.intersect.equals(center))return if(!rotateInfo){ rotateInfo = { orientationUser : e.pointclouds[0].orientationUser, vecStart : new THREE.Vector3().subVectors(e.intersectStart, center).setZ(0), //pointclouds: e.pointclouds pointcloud: e.pointclouds[0] } }else{ let vec = new THREE.Vector3().subVectors(e.intersect, 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 this.prepareRecord = true }) viewer.inputHandler.addEventListener('keydown',e=>{ if(e.keyCode == 90 && e.event.ctrlKey){//Z this.history.undo() } }) // cursor: let updateCursor = (e)=>{ if(e.drag || !this.editing)return //仅在鼠标不按下时更新: let handleState = Alignment.handleState if(e.hoverViewport.alignment && handleState && e.hoverViewport.alignment[handleState]){ if(handleState == 'translate'){ if( e.intersect && e.intersect.location ){ viewer.dispatchEvent({ type : "CursorChange", action : "add", name:"movePointcloud" }) }else{ viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"movePointcloud" }) } }else if(handleState == 'rotate'){ if( e.intersect && e.intersect.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)//拖拽结束 viewer.addEventListener('updateModelBound', (e)=>{ if(this.editing){ this.SplitScreen.updateCameraOutOfModel() } }) }, 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() pointcloud.getPanosBound() }, rotateAround(center, pointcloud, deg, angle){//绕center点转动 var angle = angle != void 0 ? angle : THREE.Math.degToRad(deg) let vec1 = new THREE.Vector3().subVectors(pointcloud.translateUser, center); let rotMatrix = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1), angle) let vec2 = vec1.clone().applyMatrix4(rotMatrix) //将到旋转中心的偏差也转动 let vec3 = new THREE.Vector3().subVectors(vec2,vec1); //这个就是多出来的一步translateUser this.rotate(pointcloud, deg, angle) this.translate(pointcloud, vec3) //绕点转动就是比普通转动多一步移动到相对center的某个位置。 1 初始点云移动到自己的position; 2 移动一个vec1 3绕原点旋转 4再移动一个原本的translateUser。 绘制出来后发现移动量就是第二步vec旋转后的偏移 }, rotate:function(pointcloud, deg, angle){//绕各自中心转动(各自的position) 假设点云位移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) }, enter:function(){ //this.saveTemp() this.originData = this.getTemp() this.SplitScreen.split({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) }) */ this.originData.forEach(e=>{//恢复 this.applyTemp(e) }) this.SplitScreen.recover() viewer.images360.panos.forEach(pano=>{ viewer.updateVisible(pano.mapMarker, 'split4Screens', true) }) this.editing = false this.history.clear() viewer.updateFpVisiDatasets() viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"movePointcloud" }) viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"rotatePointcloud" }) } , switchHandle:function(state){ this.handleState = state //清空: viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"movePointcloud" }) viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"rotatePointcloud" }) this.bus.dispatchEvent({type:'switchHandle' , state }) }, save: function(){//保存所有数据集的位置和旋转 let callback = ()=>{//保存成功后 this.originData = this.getTemp() //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} } } Alignment.history = new History({ callback: (data)=>{ data.forEach(item=>{ Alignment.applyTemp(item) }) } }) /* 关于控制点: 两个控制点只能打在同一个数据集上。传输这两个点的4dkk中的本地坐标和经纬度,后台算出该数据集的旋转平移, 然后其他数据集绕该数据集旋转,并保持相对位置不变。 */ export {Alignment}