| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587 |
- 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 {TransformControls} from "../../objects/tool/TransformControls.js";
- import CursorDeal from "../../utils/CursorDeal.js";
- var Alignment = {
- SplitScreen: SplitScreen4Views,
- handleState:null, //操作状态 'translate'|'rotate'
- bus: new THREE.EventDispatcher(),
- selectedClouds:[],
-
- /* prepareRecord : true,
-
- writeToHistory(pointclouds){
- if(!this.prepareRecord)return;
- this.prepareRecord = false
-
- let content = this.getTemp(pointclouds)
- 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 : typeof(e.orientationUser) == 'number' ? e.orientationUser : e.orientationUser.clone() ,
- translateUser : e.translateUser.clone(),
- }
- } )
- },
-
-
- getDatasetQuaternion(pointcloud){
- let quaternion
- if(typeof(pointcloud.orientationUser) == 'number' ){
- quaternion = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), pointcloud.orientationUser)
- }else{
- quaternion = pointcloud.orientationUser
- }
- return quaternion
- },
- getDatasetOrient(pointcloud){
- let orientation
- if(typeof(pointcloud.orientationUser) == 'number' ){
- orientation = pointcloud.orientationUser
- }else{
- orientation = math.getYawPitchByQua(pointcloud.orientationUser)
- }
- return orientation
- },
-
-
- init:function(){
- let transfromInfo, sideRotHovered
-
-
-
-
- this.history = new History({
- applyData: (data)=>{
- data.forEach(item=>{
- Alignment.applyTemp(item)
- })
- return true
- },
- getData:(pointclouds)=>{
- return Alignment.getTemp(pointclouds)
- }
- })
-
-
- {//侧视图旋转
- this.transformControls = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
- //dontHideWhenFaceCamera: true,
- rotFullCircle:true
- })
- this.transformControls.name = 'Alignment-transformControls'
- this.transformControls.setSize(0.5)
- viewer.scene.scene.add(this.transformControls)
- this.transformControls.setMode('rotate')
- this.transformControls.setRotateMethod(2)
- this.transformControls._gizmo.hideAxis = {rotate:['x','z','y'] }
- this.fakeMarkerForTran = new THREE.Mesh(new THREE.BoxBufferGeometry(0.3,0.3,0.3) , new THREE.MeshBasicMaterial({
- color:"#F00", opacity:0.9, transparent:true, visible:false
- }));//一个看不见的mesh,只是为了让transformControls移动点云
- this.fakeMarkerForTran.name = 'fakeMarkerForTran'
- viewer.scene.scene.add(this.fakeMarkerForTran)
-
- let afterMoveCtl = (type)=>{
- if(Alignment.afterMoveCtl){
- Alignment.afterMoveCtl(type)
- }else{
- if(type == 'position'){
- let moveVec = new THREE.Vector3().subVectors(this.fakeMarkerForTran.position, this.fakeMarkerForTran.oldState.position)
- Alignment.translate(this.selectedClouds[0], moveVec)
- }else{
- let center = this.selectedClouds[0].translateUser;
-
- let diffQua = new THREE.Quaternion().multiplyQuaternions(this.fakeMarkerForTran.quaternion, this.fakeMarkerForTran.oldState.quaternion.clone().invert())
- CursorDeal.add('rotatePointcloud')
- //Alignment.rotateAround(center, this.selectedClouds, diffQua)
- Alignment.rotate(this.selectedClouds[0], null, diffQua)
-
- }
- }
-
- this.fakeMarkerForTran.oldState = {
- position: this.fakeMarkerForTran.position.clone(),
- quaternion: this.fakeMarkerForTran.quaternion.clone(),
- }
-
- Alignment.history.beforeChange(this.selectedClouds)
-
- }
-
-
- this.fakeMarkerForTran.addEventListener('position_changed', afterMoveCtl.bind(this,'position'))
- this.fakeMarkerForTran.addEventListener("rotation_changed", afterMoveCtl.bind(this,'rotation') )
-
- this.transformControls.addEventListener('mouseUp',()=>{
- Alignment.history.afterChange(this.selectedClouds)
- })
- this.transformControls.addEventListener('axisHoveredChange',(e)=>{
- if(e.axis && e.mode == 'rotate'){
- CursorDeal.add('rotatePointcloud'),
- sideRotHovered = true
- }else{
- CursorDeal.remove('rotatePointcloud')
- sideRotHovered = false
- }
- })
- this.history.addEventListener('undo',()=>{
- this.updateFakeMarker()
- })
-
-
- }
-
- viewer.fpControls.addEventListener("transformPointcloud",(e)=>{
- if(e.pointclouds[0].dataset_id == Potree.settings.originDatasetId && Potree.settings.editType != 'pano'){//禁止手动移动初始数据集
- return this.bus.dispatchEvent('forbitMoveOriginDataset')
- }
-
-
- this.history.beforeChange(e.pointclouds)
- //this.writeToHistory( e.pointclouds )
-
- if(!transfromInfo){
- transfromInfo = {pointclouds:e.pointclouds}
- }
-
-
- if(this.handleState == 'translate'){
- e.pointclouds.forEach(cloud=>Alignment.translate(cloud, e.moveVec))
- //this.updateFakeMarker()
-
- }else if(this.handleState == 'rotate'){
- //if(Potree.settings.editType == 'pano'){
- //旋转中心是intersectStart的版本
- /* let center = e.intersectStart //旋转中心是mousedown的位置
- if(e.intersect.equals(center))return
- if(!transfromInfo){
- transfromInfo = {
- orientationUser : e.pointclouds[0].orientationUser,
- //vecStart : e.moveVec, // 首次移动向量 只有八个方向,精度太小,所以延迟
- pointclouds: e.pointclouds
- }
- this.bus.dispatchEvent({type:'rotateStart', startPoint:center})
- return
- }else if(!transfromInfo.vecStart){
- let vec = new THREE.Vector3().subVectors(e.intersect, center).setZ(0)
- if(vec.length() * e.camera.zoom > 30){ //在屏幕上距离初始点有一定距离后开始算
- //console.log('moveVec',vec)
- transfromInfo.vecStart = vec
- } */
-
-
- let center = e.pointclouds[0].translateUser //旋转中心是第一个点云的位置
- if(e.intersect.equals(center))return
- if(!transfromInfo.vecStart){
- //transfromInfo.orientationUser = e.pointclouds[0].orientationUser
- transfromInfo.vecStart = new THREE.Vector3().subVectors(e.intersectStart, center).setZ(0)
- transfromInfo.lastQua = new THREE.Quaternion()
- }else{
-
- let vec = new THREE.Vector3().subVectors(e.intersect, center).setZ(0)
- let angle = math.getAngle(transfromInfo.vecStart,vec,'z')
- //let diffAngle = transfromInfo.orientationUser + angle - transfromInfo.pointclouds[0].orientationUser
-
- let diffQuaFromStart = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), angle)
- let diffQua = new THREE.Quaternion().multiplyQuaternions(diffQuaFromStart, transfromInfo.lastQua.clone().invert())
-
- transfromInfo.lastQua.copy(diffQuaFromStart)
- transfromInfo.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:transfromInfo.pointcloud, position: centerNoTranfrom }) //中心点的现在位置
- */
-
- Alignment.rotateAround(center, cloud, diffQua)
-
-
- })
-
-
- }
- //this.bus.dispatchEvent({type:'rotate', endPoint: e.intersect})
-
- /* }else{ //旧版数据集校准只转z轴
- let center = e.pointclouds[0].translateUser //移动到的位置就是中心
- if(e.intersect.equals(center))return
- if(!transfromInfo.vecStart){
- transfromInfo.orientationUser = e.pointclouds[0].orientationUser
- transfromInfo.vecStart = new THREE.Vector3().subVectors(e.intersectStart, center).setZ(0)
- }else{
- let vec = new THREE.Vector3().subVectors(e.intersect, center).setZ(0)
- let angle = math.getAngle(transfromInfo.vecStart,vec,'z')
- let diffAngle = transfromInfo.orientationUser + angle - transfromInfo.pointclouds[0].orientationUser
- Alignment.rotate(transfromInfo.pointclouds[0], null, diffAngle)
- }
- } */
- }
- })
-
-
- viewer.fpControls.addEventListener("end",(e)=>{
- transfromInfo && this.history.afterChange(transfromInfo.pointclouds )
- transfromInfo = null
- })
-
-
-
-
- // 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 ){
- CursorDeal.add('movePointcloud')
- }else{
- CursorDeal.remove('movePointcloud')
- }
- }else if(handleState == 'rotate'){
- if( e.intersect && e.intersect.location ){
- CursorDeal.add('rotatePointcloud')
- }else{
- CursorDeal.remove('rotatePointcloud')
- }
- }
- }else{
- //清空:
- CursorDeal.remove('movePointcloud')
- if(!sideRotHovered) CursorDeal.remove('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 pos1Matrix = new THREE.Matrix4().setPosition(vec1);//先移动到点云本身应该在的初始位置(在4dkk里和其他应用中都是在这个位置的,也能和漫游点对应上)
-
- var rotMatrix = typeof(pointcloud.orientationUser ) == 'number' ? //再旋转
- new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1), pointcloud.orientationUser ) :
- new THREE.Matrix4().makeRotationFromQuaternion(pointcloud.orientationUser)
-
- var pos2Matrix = new THREE.Matrix4().setPosition(vec2);//最后是平移
-
- var matrix = new THREE.Matrix4().multiplyMatrices(pos2Matrix, rotMatrix);
- pointcloud.transformMatrix = matrix.clone();//为该数据集的变化矩阵。 对应navvis的m2w_
- pointcloud.transformInvMatrix.copy(pointcloud.transformMatrix).invert()
-
- pointcloud.rotateMatrix = rotMatrix
- pointcloud.rotateInvMatrix.copy(rotMatrix).invert()
-
-
- pointcloud.panos.forEach(e=>e.transformByPointcloud())
-
-
- matrix = new THREE.Matrix4().multiplyMatrices(matrix, pos1Matrix);
-
- //matrix.premultiply(viewer.scene.scene.matrix);////////////////////////add
-
- 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.boundNeedUpdate = true
- //pointcloud.updateBound()
- pointcloud.getPanosBound()
- viewer.dispatchEvent('content_changed')
- },
-
-
- rotateAround(center, pointcloud, angle, axis){//绕center点水平转动
-
- let vec1 = new THREE.Vector3().subVectors(pointcloud.translateUser, center);
- let rotMatrix = typeof(angle) == 'number' ?
- new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1), angle) :
- new THREE.Matrix4().makeRotationFromQuaternion(angle)
-
- let vec2 = vec1.clone().applyMatrix4(rotMatrix) //将到旋转中心的偏差也转动
- let vec3 = new THREE.Vector3().subVectors(vec2,vec1); //这个就是多出来的一步translateUser
- this.rotate(pointcloud, null, angle)
- this.translate(pointcloud, vec3)
- //绕点转动就是比普通转动多一步移动到相对center的某个位置。 1 初始点云移动到自己的position; 2 移动一个vec1 3绕原点旋转 4再移动一个原本的translateUser。 绘制出来后发现移动量就是第二步vec旋转后的偏移
- },
-
-
- rotate:function(pointcloud, deg, angle, axis){//绕各自中心水平转动(各自的position) 假设点云位移position后0,0,0就是它的中心了(根据navvis观察这样做是绕同一个点旋转的)
- let qua
-
- if(deg || typeof(angle) == 'number'){
- angle = angle != void 0 ? angle : THREE.Math.degToRad(deg) //正逆负顺
- }else if(angle instanceof Array){//when init
- qua = new THREE.Quaternion().fromArray(angle)
- }else{
- qua = angle
- }
-
- if(typeof(pointcloud.orientationUser) == 'number' ){
- //pointcloud.orientationUser += angle
- pointcloud.orientationUser = this.getDatasetQuaternion(pointcloud)
- }
-
- if(!qua){
- qua = new THREE.Quaternion().setFromAxisAngle(axis || new THREE.Vector3(0,0,1), angle)
- }
- pointcloud.orientationUser.premultiply(qua)
-
- //新版全部使用qua
- 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=>{
- Potree.Utils.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, translateVec:new THREE.Vector3(0,0,1)}; //只能上下移动
- viewer.viewports.find(e=>e.name == 'back').alignment = {translate:true, translateVec:new THREE.Vector3(0,0,1)}; //只能上下移动
- viewer.viewports.forEach(e=>{
- if(e.name == 'right' || e.name == 'back' ){
- e.layersAdd('sideVisi')
- /* if(e.name == 'right') e.layersAdd('layer1')
- else if(e.name == 'back') e.layersAdd('layer2') */
- }
- })
- Potree.Utils.setObjectLayers(this.transformControls, 'sideVisi' )
- /* Potree.Utils.setObjectLayers(this.transformControls, 'layer1' )
- Potree.Utils.setObjectLayers(this.transformControls, 'layer2' ) */
-
- {
- /* viewer.viewports.forEach(e=>{
- let oldFun = e.beforeRender
- e.beforeRender = function(){
- oldFun.bind(this)()
- if(e.name == 'right'){
- Alignment.transformControls._gizmo.hideAxis = {rotate:['e','z','y'] }
- }else if(e.name == 'back'){
- Alignment.transformControls._gizmo.hideAxis = {rotate:['e','z','x'] }
- }
- }
-
- }) */
- /* viewer.viewports.find(e=>e.name == 'right').beforeRender = function(){
- oldFun.bind(this)()
- if(this.name == right)
-
- }
- viewer.viewports.find(e=>e.name == 'back').beforeRender = (e)=>{
- old2()
- this.transformControls._gizmo.hideAxis = {rotate:['e','z','x'] }
- } */
- }
-
- 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=>{
- Potree.Utils.updateVisible(pano.mapMarker, 'split4Screens', true)
- }) */
- this.editing = false
- this.history.clear()
- viewer.updateFpVisiDatasets()
- CursorDeal.remove('movePointcloud')
- CursorDeal.remove('rotatePointcloud')
- }
-
- ,
- switchHandle:function(state){
- console.log('switchHandle',state)
- this.handleState = state
- //清空:
- CursorDeal.remove('movePointcloud')
- CursorDeal.remove('rotatePointcloud')
- this.bus.dispatchEvent({type:'switchHandle' , state })
-
- this.updateCtlDisplay()
- },
-
- updateCtlDisplay(){//仅数据集校准执行
- if(!this.editing)return
- let selected = this.handleState == 'rotate' && this.selectedClouds.length > 0
- if(selected){
- this.updateFakeMarker()
- }else{
- this.transformControls.detach()
- }
- },
-
- updateFakeMarker(){
- this.transformControls.attach(this.fakeMarkerForTran)
-
- let position = this.selectedClouds[0].translateUser
- let quaternion = this.getDatasetQuaternion(this.selectedClouds[0])
- this.fakeMarkerForTran.position.copy(position)
- this.fakeMarkerForTran.quaternion.copy(quaternion)
- this.fakeMarkerForTran.oldState = {
- position: position.clone(),
- quaternion: quaternion.clone()
- }
- }
- ,
- save: function(){//保存所有数据集的位置和旋转
- let callback = ()=>{//保存成功后
- this.originData = this.getTemp() //this.saveTemp();
- //需要修改 测量线的position。漫游点已经实时修改了
-
- viewer.scene.measurements.forEach(e=>e.transformByPointcloud())
- viewer.images360.updateCube(viewer.bound)
- }
-
- let initialPointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == Potree.settings.originDatasetId)
- var data = viewer.scene.pointclouds.map(e=>{
- let pos = viewer.transform.lonlatToLocal.inverse(e.translateUser.clone())
- let data = {
- id: e.dataset_id,
- quaternion: this.getDatasetQuaternion(e).toArray(),
- orientation : this.getDatasetOrient(e).yaw,
- location:[pos.x, pos.y, pos.z + initialPointcloud.datasetData.location[2]],
- //transformMatrix: e.transformMatrix.elements,
- }
-
- return data
- })
- //data = JSON.stringify(data)
-
- //test: 退出后保留结果
- if(!Potree.settings.isOfficial){
- callback()
- }
-
- return {data, callback}
- }
-
-
- }
-
-
-
-
-
-
- /*
- 关于控制点:
- 两个控制点只能打在同一个数据集上。传输这两个点的4dkk中的本地坐标和经纬度,后台算出该数据集的旋转平移,
- 然后其他数据集绕该数据集旋转,并保持相对位置不变。
- 关于cloud.js
- tightBoundingBox规定了整个点云应该放置后的边界范围。 boundingBox则是在其基础上变为正方体。
- 为了达成这个目标,需要将点云进行位移。在没有位移前,点云boundingBox的min是0,0,0(如果没出错的话)
- 所以要令min变为tightBoundingBox.min, 需要将点云position设置为 tightBoundingBox.min 。
- 设置完以后整体点云的旋转中心为0,0,0。如果不出错的话0,0,0大概在点云中央附近。
- 在添加经纬度信息后,非初始数据集又会有一个位置偏移,其旋转中心也跟着一起偏移,如偏移了 1,0,0,则旋转中心就是 1,0,0
-
- 但是,有的cloud.js的tightBoundingBox使用的是大地坐标,需要转成普通值
- */
-
- export {Alignment}
|