Browse Source

fix: 地图的interSect放地面

xzw 3 năm trước cách đây
mục cha
commit
9fddd0a5f6

+ 13 - 6
src/EventDispatcher.js

@@ -38,7 +38,7 @@ export class EventDispatcher{
 		this._listeners = {};
 	}
 
-	addEventListener(type, listener){
+	addEventListener(type, listener, importance=0  ){//add importance
 
 		const listeners = this._listeners;
 
@@ -47,7 +47,8 @@ export class EventDispatcher{
 		}
 
 		if(listeners[type].indexOf(listener) === - 1){
-			listeners[type].push( listener );
+			listeners[type].push({ listener,  importance});
+            listeners[type] = listeners[type].sort((e,a)=> a.importance - e.importance)//add
 		}
 
 	}
@@ -66,11 +67,14 @@ export class EventDispatcher{
 
 		if (listenerArray !== undefined){
 
-			let index = listenerArray.indexOf(listener);
+			/* let index = listenerArray.indexOf(listener);
 
 			if(index !== - 1){
 				listenerArray.splice(index, 1);
-			}
+			} */
+            let item = listenerArray.find(e=>e.listener == listener)
+            item && listenerArray.splice(listenerArray.indexOf(item), 1);
+            
 		}
 
 	}
@@ -89,8 +93,11 @@ export class EventDispatcher{
 		if ( listenerArray !== undefined ) {
 			event.target = this;
 
-			for(let listener of listenerArray.slice(0)){
-				listener.call(this, event);
+			for(let {listener} of listenerArray.slice(0)){
+				let result = listener.call(this, event);   //add stopContinue
+                if(result && result.stopContinue){
+                    break
+                }
 			}
 		}
 

+ 3 - 0
src/PointCloudOctree.js

@@ -120,7 +120,10 @@ export class PointCloudOctree extends PointCloudTree {
 		this.level = 0;
 		this.position.copy(geometry.offset);
 		this.updateMatrix();
+        
         this.transformMatrix = new THREE.Matrix4;//add 数据集的变化矩阵
+        this.transformInvMatrix = new THREE.Matrix4;//add 数据集的变化矩阵
+        
         
 		{
 

+ 17 - 23
src/modules/Images360/Images360.js

@@ -285,9 +285,10 @@ export class Images360 extends EventDispatcher{
                         
                         if(mode == 'showPanos'){  
                             camera.far = viewer.farWhenShowPano 
-                        }else if(Potree.settings.limitFar){ 
-                            camera.far = Potree.settings.cameraFar;
-                                
+                            Potree.settings.pointDensity = 'panorama'
+                        }else{
+                            if(camera.limitFar)   camera.far = Potree.settings.cameraFar;
+                            Potree.settings.pointDensity = Potree.settings.UserPointDensity    
                         }  
                         camera.updateProjectionMatrix() 
 
@@ -843,38 +844,31 @@ export class Images360 extends EventDispatcher{
     }
 
     updateClosestPano(intersect) {//距离reticule最近的点  可以是null
-    
+        if(this.flying)return; 
         intersect = intersect && intersect.location
         if(!intersect)return
-        //intersect = intersect && (intersect.location || intersect)
-        
+         
         var filterFuncs = [];
-        //if (this.mode === ViewMode.PANORAMA) {
-            /* if (!Potree.settings.isOfficial && !this.currentPano) {
-                return;
-            } */
+     
         if(this.isAtPano() ){ 
             filterFuncs.push(Images360.filters.not(this.currentPano));
- 			filterFuncs.push(Images360.filters.inFloorDirection(this.position, viewer.scene.view.direction, .25)),//许钟文改
-			//filterFuncs.push(Images360.filters.isNeighbourPanoTo(this.currentPano));
+            
+            //当静止在漫游点时closestPano只限制在每个漫游点附近,而在观看整个模型时,范围夸大,识别为离鼠标最近的漫游点。 (故而要排除flying时)
+ 			filterFuncs.push(Images360.filters.inFloorDirection(this.position, viewer.scene.view.direction, .25))//许钟文改
             filterFuncs.push(Images360.filters.isCloseEnoughTo(intersect, 0.35));
-       /*  } else {
-			if(!this.linkEditor.noPanoHasNeighbor){//xzw add  如果不是全孤立点的话,就要避开孤立点
-				filterFuncs.push((pano)=>{return this.linkEditor.checkHasNeighbor(pano)})
-			}
-            objects.record.control.isRecording || filterFuncs.push(Panorama.filters.isOnVisibleFloor());
-            this.mode !== ViewMode.FLOORPLAN && filterFuncs.push(Panorama.filters.inDirection(this.position, this.getDirection(), .25));
-        } */
+        
+        }else{
+			 
         }
         
+        
         var pano = Common.find(this.panos,  filterFuncs, [Images360.sortFunctions.floorDistanceToPoint(intersect)]);
         if (pano != this.closestPano) {
             pano && (this.isPanoHover = !0);
-            //触发事件,导致地面的marker变清晰
-            //this.emit(PlayerEvents.ClosestPanoChanging, this.closestPano, pano, this.mode);
             
-            this.closestPanoChanging(this.closestPano, pano)
-             
+            
+            this.closestPanoChanging(this.closestPano, pano) // 高亮marker
+            //console.log('closestPano '+ (pano ? pano.id : 'null' )) 
             this.closestPano = pano;
         } else {
             this.isPanoHover = !1;

+ 9 - 3
src/modules/Images360/Panorama.js

@@ -73,9 +73,14 @@ class Panorama extends EventDispatcher{
         this.pointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == o.dataset_id) || viewer.scene.pointclouds[0]
         this.pointcloud.panos.push(this)
         this.pointcloud.addEventListener('isVisible',(e)=>{ 
-            if(e.reason == 'datasetSelection'){//数据集隐藏时漫游点也隐藏
-                viewer.updateVisible(this, 'pointcloudVisi', e.visible) 
-            }
+            /* if(!e.visible){//数据集隐藏时漫游点也隐藏
+                e.reason == 'datasetSelection' && viewer.updateVisible(this, 'pointcloudVisi', false) 
+            }else{
+                console.log('pointcloudVisi 1')
+                viewer.updateVisible(this, 'pointcloudVisi', true) 
+            } */
+            e.reason == 'datasetSelection' && viewer.updateVisible(this, 'pointcloudVisi', e.visible) 
+            
         })
         this.addEventListener('isVisible',(e)=>{//是否显示该点的mesh(不显示也能走)
             this.marker.visible = e.visible
@@ -412,6 +417,7 @@ class Panorama extends EventDispatcher{
         this.label = new TextSprite($.extend(
            labelProp, {text: this.id}) //{text: `id:${this.id}, dataset:${this.pointcloud.name}, 4dkkId:${this.originID}`}
         );
+
         this.images360.node.add(this.label);
         this.floorPosition && this.label.position.copy(this.floorPosition)
     }

+ 107 - 7
src/modules/datasetAlignment/Alignment.js

@@ -1,24 +1,56 @@
 
 import * as THREE from "../../../libs/three.js/build/three.module.js";
 import SplitScreen from "../../utils/SplitScreen"
-
+import math from "../../utils/math"
 
 
 
 var Alignment = {
     SplitScreen, 
-    handleState:null,  //'translate'|'rotate'
+    handleState:null,  //操作状态 'translate'|'rotate'
+    init:function(){ 
+        let rotateInfo  
+        
+        viewer.fpControls.addEventListener("transformPointcloud",(e)=>{ 
+            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
+        })
+    },
+    
     
     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);//移动到中心
+        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.getInverse(matrix)  
         pointcloud.rotateMatrix = rotMatrix
         pointcloud.panos.forEach(e=>e.transformByPointcloud())
         
@@ -31,6 +63,10 @@ var Alignment = {
         //pointcloud.matrixWorldNeedsUpdate = true //更新matrixWorld (非计算,直接赋值)
         pointcloud.updateMatrixWorld(true)
         
+        if(this.editing){
+            Alignment.changeCallBack && Alignment.changeCallBack();
+        } 
+        
     },
     rotate:function(pointcloud, deg, angle){//假设点云位移position后0,0,0就是它的中心了(根据navvis观察这样做是绕同一个点旋转的)
         var angle = angle != void 0 ? angle : THREE.Math.degToRad(deg)
@@ -42,25 +78,89 @@ var Alignment = {
         Alignment.setMatrix(pointcloud)
     },
     
-    
+    saveTemp:function(){//记录最近一次保存后的状态,便于恢复
+        this.originData = viewer.scene.pointclouds.map(e=>{
+            return {
+                id : e.dataset_id,
+                orientationUser : e.orientationUser,
+                translateUser : e.translateUser,
+            }
+        } )
+    },
     enter:function(){
+        this.saveTemp()  
         
-        SplitScreen.splitScreen4Views({alignment:true})
         
         
+        SplitScreen.splitScreen4Views({alignment:true})
+        viewer.viewports.find(e=>e.name == 'Top').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
     },
     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.updateModelBound();
+        
+        this.editing = false
+        
+         
+        
     } 
     
     ,
     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.updateModelBound();
+            viewer.scene.measurements.forEach(e=>e.transformByPointcloud())
+            
+        }
+        
+        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 = data[0]//暂时只传第一个
+        
+        
+        //test:
+        //callback() 
         
+        
+        return {data, callback}
     }
-    
+        
     
 }
 

+ 12 - 7
src/navigation/FirstPersonControls.js

@@ -128,15 +128,20 @@ export class FirstPersonControls extends EventDispatcher {
                      
                     moveVec.set(-1 * e.drag.mouseDelta.x * cameraViewWidth / ViewWidthPX, e.drag.mouseDelta.y * cameraViewHeight / ViewHeightPX , 0).applyQuaternion(camera.quaternion)  
                      */
-                    let moveVec = Utils.getOrthoCameraMoveVec(e.drag.pointerDelta, camera )
-                      
-                      
-                    if(viewport.alignment && viewport.alignment.handleState == 'translate' && e.drag.intersectStart){//如果拖拽着点云  修改模型位置
-                        this.viewer.dispatchEvent({
-                            type : "translatePointcloud", 
-                            vec : moveVec
+                    
+                    let moveVec = Utils.getOrthoCameraMoveVec(e.drag.pointerDelta, camera )//最近一次移动向量
+                    
+                    let handleState = window.viewer.modules.Alignment.handleState
+                    if(viewport.alignment && handleState && viewport.alignment[handleState] && e.drag.intersectStart.pointcloud){
+                        this.dispatchEvent({
+                            type : "transformPointcloud", 
+                            intersectPoint: e.intersectPoint.orthoIntersect,   
+                            intersectStart: e.drag.intersectStart.orthoIntersect,
+                            moveVec,        
+                            pointcloud: e.drag.intersectStart.pointcloud,
                         }) 
                     }else{ 
+                        
                         this.translationWorldDelta.add(moveVec.negate()) 
                         
                     }

+ 36 - 11
src/navigation/InputHandler.js

@@ -385,7 +385,8 @@ export class InputHandler extends EventDispatcher {
 					viewer: this.viewer,
                     pressDistance,
                     button : e.button,//add 放开的鼠标按键
-                    isAtDomElement: e.target == this.domElement
+                    isAtDomElement: e.target == this.domElement,
+                    viewport:this.dragViewport 
                     
 				});
 			} else {
@@ -395,13 +396,14 @@ export class InputHandler extends EventDispatcher {
 						drag: this.drag,
 						viewer: this.viewer,
                         pressDistance,
+                        isAtDomElement: e.target == this.domElement,
                         button: e.button //add
 					});
 				//}
                 
                 
                 // check for a click 
-                if(pressDistance < 2){
+                if(pressDistance < Potree.config.clickMaxDragDis){
                     if(this.hoveredElements && this.hoveredElements[0]){
                         if (this.logMessages) console.log(`${this.constructor.name}: click ${clicked.name}`);
                         this.hoveredElements[0].object.dispatchEvent({
@@ -409,6 +411,7 @@ export class InputHandler extends EventDispatcher {
                             viewer: this.viewer,
                             consume: consume,
                             viewport: this.hoverViewport,
+                            isAtDomElement: e.target == this.domElement,
                             button: e.button //add
                         });
                     }else{
@@ -418,6 +421,7 @@ export class InputHandler extends EventDispatcher {
                                 drag: this.drag,
                                 viewer: this.viewer,
                                 pressDistance,
+                                isAtDomElement: e.target == this.domElement,
                                 button: e.button //add
                             });
                         //}
@@ -559,6 +563,7 @@ export class InputHandler extends EventDispatcher {
           
         if(viewport.camera.type == 'OrthographicCamera'/*  == 'mapViewport' */){ 
             let pos3d = new THREE.Vector3(this.pointer.x,this.pointer.y,-1).unproject(viewport.camera); //z:-1朝外   
+            pos3d.setZ(viewer.bound.boundingBox.z += 0.2) //大概放地面上
             if(!intersectPoint){
                 intersectPoint = {}
             }   
@@ -597,6 +602,7 @@ export class InputHandler extends EventDispatcher {
 						type: 'global_drag',
 						drag: this.drag,
 						viewer: this.viewer,
+                        intersectPoint,
 						consume: () => {dragConsumed = true;}
 					});
 
@@ -640,16 +646,35 @@ export class InputHandler extends EventDispatcher {
 			}
 
             //仅在鼠标不按下时更新:
+            {
+                let handleState = viewer.modules.Alignment.handleState
+                if(viewport.alignment && handleState && viewport.alignment[handleState]){
+                    if(handleState == 'translate'){
+                        if( intersectPoint && intersectPoint.location ){ 
+                            viewer.dispatchEvent({
+                                type : "CursorChange", action : "add",  name:"movePointcloud"
+                            })
+                        }else{
+                            viewer.dispatchEvent({
+                                type : "CursorChange", action : "remove",  name:"movePointcloud"
+                            })
+                        }
+                    }else if(handleState == 'rotate'){ 
+                        if( intersectPoint && intersectPoint.location ){ 
+                            viewer.dispatchEvent({
+                                type : "CursorChange", action : "add",  name:"rotatePointcloud"
+                            })
+                        }else{
+                            viewer.dispatchEvent({
+                                type : "CursorChange", action : "remove",  name:"rotatePointcloud"
+                            })
+                        }
+                    }  
+            }
+            }
             
-            if(viewport.alignment && intersectPoint && intersectPoint.location ){
-                viewer.dispatchEvent({
-                    type : "CursorChange", action : "add",  name:"movePointcloud"
-                })
-            }else{ 
-                viewer.dispatchEvent({
-                    type : "CursorChange", action : "remove",  name:"movePointcloud" 
-                })
-            } 
+
+                
             
             
 		}

+ 18 - 10
src/navigation/Reticule.js

@@ -1,7 +1,7 @@
 import * as THREE from "../../libs/three.js/build/three.module.js";
 import {MOUSE} from '../defines.js'
 import {transitions, easing, lerp} from '../utils/transitions.js'
-
+import math from '../utils/math.js'
 
 
 let texLoader = new THREE.TextureLoader()
@@ -52,7 +52,7 @@ export default class Reticule extends THREE.Mesh{
             this.hidden = false,
             this.mouseLastMoveTime = Date.now()
             
-            this.updatePosition(e.intersectPoint, viewer.scene.getActiveCamera().position)
+            this.updatePosition(e.intersectPoint, e.hoverViewport)
         }
     }
 
@@ -74,22 +74,30 @@ export default class Reticule extends THREE.Mesh{
         Date.now() - this.mouseLastMoveTime > 1500 && !this.hidden && this.hide()
     }
 
-    updatePosition(intersectPoint, cameraPos ){ //在地图(当地图融合到viewer时)和场景里都显示且完全相同(大小可能不同)
+    updatePosition(intersectPoint, viewport ){ //在地图(当地图融合到viewer时)和场景里都显示且完全相同(大小可能不同)
         if (!this.hidden && this.visible) {
             if (!intersectPoint /* || !intersectPoint.point.normal */)
                 return //this.hide();
-             
+            var atMap = !intersectPoint.location
             let normal = intersectPoint.point ? new THREE.Vector3().fromArray(intersectPoint.point.normal ) : new THREE.Vector3(0,0,1)//地图无normal
-             
-            let location = intersectPoint.location || intersectPoint
-                , n = cameraPos.distanceTo(location)
-                , r = 1 + .01 * n; 
+            let s, camera
+            let location = intersectPoint.location || intersectPoint.orthoIntersect.clone()
                 
-            n < 1 && (r -= 1 - n)
+            if(!atMap){
+                camera = viewport.camera
+                let n = camera.position.distanceTo(location)
+                s = 1 + .01 * n;
+                n < 1 && (s -= 1 - n)
+            }else{
+                camera = viewer.mapViewer.camera
+                s = math.getScaleForConstantSize({width2d:300, position:location, camera, resolution:viewport.resolution2} )
+                location.setZ(0);//低于相机高度即可
+            }
+            
             
             
             this.show();
-            this.scale.set(r, r, r);
+            this.scale.set(s, s, s);
             this.direction = this.direction.multiplyScalar(.8); 
             this.direction.add(normal.clone().multiplyScalar(.2));
             this.position.copy(location).add(normal.clone().multiplyScalar(.01));

+ 1 - 1
src/navigation/RouteGuider.js

@@ -273,7 +273,7 @@ export class RouteGuider extends EventDispatcher{
             
             Potree.fileServer.get(url).then((data)=>{
                 console.log(data.data)
-                if(!this.routeStart || !this.routeEnd)return 
+                if(!this.routeStart || !this.routeEnd && !data.data)return 
                 
                 data.data.forEach(item=>{
                     let pos = viewer.transform.lonlatToLocal.forward(item.location.slice(0))

+ 15 - 2
src/settings.js

@@ -83,11 +83,19 @@ const config = {//配置参数   不可修改
     },
     
     pointDensity:{
+        panorama:{//显示全景时的漫游。因为点只能显示1个像素的大小,所以必须很密集,但又要限制点的数量
+            maxLevel: 8,
+            pointBudget :0.25*1000*1000,
+        },
+        fourViewports:{//分四屏时防止卡顿
+            maxLevel: 5,  
+            pointBudget :0.25*1000*1000, // 只要限制这个就足够 (为什么分屏focus区域不同会闪烁,navvis不会)(navvis:maxLevel:5,pointBudget:1*1000*1000)
+        },
         low:{//highPerformance
             maxLevel: 4, //最小为0
             pointBudget :1*1000*1000,
         }, 
-        middle:{//balanced
+        middle:{//balanced  //不同场景相同级别所产生的numVisibleNodes和numVisiblePoints不同,如果分层比较细,可能要到level8才能看清,那么level5看到的点就很大且很少,如隧道t-e2Kb2iU
             maxLevel: 5,
             pointBudget:4*1000*1000,
         },
@@ -148,6 +156,9 @@ const config = {//配置参数   不可修改
         map:8,
         mapObjects:9,//default
         
+        //bothMapAndScene:15,
+        
+        
         siteModeOnlyMapVisi:12,//只能mapViewer可见
         siteModelMapUnvisi:13,//只有mapViewer不可见
         siteModeSideVisi:14,//只有侧面可见
@@ -201,6 +212,8 @@ const config = {//配置参数   不可修改
     ,
     highQualityMaxZoom: 2,
     ultraHighQualityMaxZoom: 3,
+    
+    clickMaxDragDis:5,
 }
 /* 显示模式:
 
@@ -222,7 +235,7 @@ let settings = {//设置   可修改
     displayMode:'',
     isTest :browser.urlHasValue('test'),
     prefix:getPrefix(),
-    pointDensity: '',
+    pointDensity: '',    UserPointDensity:'',//pointDensity会随着进入不同的模块而自动改变,UserPointDensity记录了用户的设置
     ifShowMarker:true,//显示漫游点
     floorplanType:null,//平面图类型 'default' | 'diy'
     floorplanEnable:false,

+ 12 - 1
src/utils.js

@@ -1183,6 +1183,8 @@ Utils.getOrthoCameraMoveVec = function(pointerDelta, camera ){//获取当camera
 }
 
 
+
+
 Utils.VectorFactory = {
     fromArray : function(t) {
         if (t) {
@@ -1247,4 +1249,13 @@ Utils.QuaternionFactory = {
 }
  
  
- 
+Utils.datasetPosTransform = {
+    toDataset:function(o={}){ 
+        let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
+        return pointcloud && (new THREE.Vector3).copy(o.position).applyMatrix4(pointcloud.transformInvMatrix)
+    },
+    fromDataset:function(o={}){
+        let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
+        return pointcloud && (new THREE.Vector3).copy(o.dataset_location).applyMatrix4(pointcloud.transformMatrix)
+    },
+}

+ 1 - 0
src/utils/CursorDeal.js

@@ -13,6 +13,7 @@ var CursorDeal = {
         {"polygon_AtWrongPlace":'not-allowed'},
         {'mapClipMove':'move'},
         {'mapClipRotate':`url({Potree.resourcePath}/images/rotate-cursor.png), url({Potree.resourcePath}/images/rotate-cursor.cur),auto`},
+        {'rotatePointcloud':`url({Potree.resourcePath}/images/rotate-cursor.png), url({Potree.resourcePath}/images/rotate-cursor.cur),auto`},
         {'siteModelFloorDrag':'row-resize'},
     ], 
     list:[], //当前存在的cursor状态

+ 66 - 19
src/utils/Measure.js

@@ -49,22 +49,12 @@ export class Measure extends ctrlPolygon{
         
 		super('measure',prop);
 		this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
-		 
+        
         
         this.name = this.measureType + this.constructor.counter  //'Measure_' + this.constructor.counter;
-         
-		/* this._showDistances = true;
-		this._showCoordinates = false;
-		this._showArea = false;
-		this._closed = true;
-		this._showAngles = false;
-		this._showCircle = false;
-		this._showHeight = false;
-		this._showEdges = true;
-		this._showAzimuth = false; */
- 
+           
 		this.color = new THREE.Color(config.measure.lineColor)//new THREE.Color(0xff0000);
-
+    
 		
 		this.markerLabels = [];
 		this.edgeLabels = [];
@@ -93,20 +83,72 @@ export class Measure extends ctrlPolygon{
         //addMarkers:
         this.initData(prop)
         
+         
+        this.points_datasets || (this.points_datasets = []) //存每个点是哪个数据集
+
+
+        this.updateDatasetBelong()
+        
+        this.addEventListener('marker_dropped',(e)=>{ 
+            this.updateDatasetBelong()
+        })  
 	}
  
  
     
  
- 
- 
+    updateDatasetBelong(){//更新所属数据集
+        let old = this.datasetId
+        
+        let maxCount = {id:null,count:0}
+        let datasets = {}
+        
+        this.points_datasets.forEach(e=>{
+            if(datasets[e]){
+                datasets[e] ++ 
+            }else{
+                datasets[e] = 1
+            } 
+        })
+        for(let i in datasets) {
+            if(datasets[i]>maxCount.count){
+                maxCount = {id:i, count:datasets[i]}
+            }
+        }
+        this.datasetId = maxCount.count > 0 ?  maxCount.id : null
+         
+        if(this.datasetId != old){
+            this.dispatchEvent({type:'changeDatasetId'})
+            if(this.datasetId == void 0){
+                this.dataset_points = null
+            }else{
+                this.dataset_points = this.points.map(e=>{ 
+                    return Potree.Utils.datasetPosTransform.toDataset({datasetId:this.datasetId, position:e.clone()})
+                })
+            }  
+        }
+    }
+    
+    
+     
+
+    
+    transformByPointcloud(){//每次移动点云 or 加载测量线时要获取一下当前position
+        if(this.datasetId == void 0)return 
+        this.points = this.dataset_points.map(e=>{ 
+            return Potree.Utils.datasetPosTransform.fromDataset({datasetId:this.datasetId, dataset_location:e.clone()})
+        })
+        this.getPoint2dInfo(this.points)
+        this.update(true)
+        this.setSelected(false)//隐藏edgelabel
+    }
  
 	update(ifUpdateMarkers) { 
         super.update(ifUpdateMarkers)
         
-        if(this.showCoordinates){
-            let point = this.points[0];
-            let position = point 
+        if(this.showCoordinates && this.points.length>0){
+            let position = this.points[0];
+       
             this.markers[0].position.copy(position);
 
             { // coordinate labels
@@ -346,6 +388,9 @@ export class Measure extends ctrlPolygon{
         
         viewer.mapViewer.emit('content_changed') 
     }
+    
+    
+    
     setSelected(state, hoverObject){//add
         
         hoverObject && (this.selectStates[hoverObject] = state)
@@ -393,7 +438,9 @@ export class Measure extends ctrlPolygon{
     
 	removeMarker(index ){  
         super.removeMarker(index)
-         
+        
+        this.points_datasets.splice(index, 1);
+        this.dataset_points.splice(index, 1)
         this.coordinateLabels.splice(index, 1);
          
         let edgeIndex = index//(index === 0) ? 0 : (index - 1);

+ 175 - 142
src/utils/MeasuringTool.js

@@ -179,6 +179,134 @@ export class MeasuringTool extends EventDispatcher{
 	}
 
 
+    
+
+
+    
+    createMeasureFromData(data){//add
+        const measure = new Measure(data);
+        
+        viewer.scene.addMeasurement(measure);
+        
+        if(measure.guideLine)measure.guideLine.visible = false
+        return  measure       
+    }
+    
+    
+	update(){
+        return;
+        
+        
+        
+        
+		let camera = this.viewer.scene.getActiveCamera();
+		let domElement = this.renderer.domElement;
+		let measurements = this.viewer.scene.measurements;
+
+	 
+		// make size independant of distance
+        let mainLabels = [], subLabels = [];
+        
+      
+        
+		for (let measure of measurements) {
+			measure.lengthUnit = this.viewer.lengthUnit;
+			measure.lengthUnitDisplay = this.viewer.lengthUnitDisplay;
+			//measure.update();
+
+			updateAzimuth(this.viewer, measure);
+
+			 
+            /*  [...measure.markers, ...measure.edgeLabels, measure.areaLabel].forEach(e=>{
+                e && e.update() 
+            }); */
+             
+
+			// labels
+			/* let labels = measure.edgeLabels.concat(measure.angleLabels);
+			for(let label of labels){ 
+                label.update()
+                if(label.elem.hasClass('sub')){
+                    subLabels.push(label)
+                }else{ 
+                    mainLabels.push(label)
+                }
+			}
+
+			// coordinate labels
+			for (let j = 0; j < measure.coordinateLabels.length; j++) { 
+				let label = measure.coordinateLabels[j]; 
+                label.update() 
+                mainLabels.push(label)
+			} 
+ 
+
+			if(measure.showArea){ // area label
+				let label = measure.areaLabel; 
+                label.update()
+                mainLabels.push(label)
+			} */
+             
+            
+
+			/* if(measure.showCircle){ // radius label
+				let label = measure.circleRadiusLabel;
+				let distance = label.position.distanceTo(camera.position);
+				let pr = Utils.projectedRadius(1, camera, distance, clientWidth, clientHeight);
+
+				let scale = (70 / pr);
+				label.scale.set(scale, scale, scale);
+			} */ 
+			if(!this.showLabels){ 
+				const labels = [
+					...measure.sphereLabels,  
+					...measure.angleLabels,  
+					measure.circleRadiusLabel,
+				]; 
+				for(const label of labels){
+					label.visible = false;
+				}
+			}
+		}
+        //this.updateLabelZIndex([{labels:subLabels},{labels:mainLabels}])
+        
+	}
+    setSize(e){ //e.resolution
+        /* if(Measure.lineMats){
+            for(var m in Measure.lineMats){
+                Measure.lineMats[m].resolution.set(e.canvasWidth, e.canvasHeight);
+            }  
+        }  
+        if(Measure.sphereMats){
+            for(var s in Measure.sphereMats){
+                Measure.sphereMats[s].uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
+            }
+        }
+        for (let measure of this.viewer.scene.measurements) { 
+            measure.edgeLabels.concat(measure.areaLabel).forEach(label=>{ 
+                label.sprite.material.uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
+            })
+        } */
+    }
+    
+    updateLabelZIndex(group){//[{labels:[]},{}] 顺序按照z-index低到高
+        
+        group.forEach((e,i)=>{
+            e.base = group[i-1] ? group[i-1].base + group[i-1].labels.length : 0
+         
+            var labels = e.labels.sort((a,b)=>{
+                return b.pos2d.z - a.pos2d.z
+            }) 
+            labels.forEach((label,index)=>{
+                $(label.elem).css('z-index', e.base+index) 
+            }) 
+        }) 
+        
+    }
+    
+    
+    
+    
     editStateChange(e){
         //console.log("editStateChange" , e.state)
         let state = e.state
@@ -192,9 +320,12 @@ export class MeasuringTool extends EventDispatcher{
             viewer.dispatchEvent({type:"endMeasureMove"})
         }
         
+        
+        //this.editing = 
     }
-
-
+    
+    
+    
 	startInsertion (args = {}, callback, cancelFun) {
         
         
@@ -237,9 +368,9 @@ export class MeasuringTool extends EventDispatcher{
 			measure: measure
 		});
          
-        
-        measure.editStateChange(true)
         measure.addEventListener('editStateChange', this.editStateChange.bind(this))
+        measure.editStateChange(true)
+        
         let timer;
 
 
@@ -270,7 +401,7 @@ export class MeasuringTool extends EventDispatcher{
                 } 
 				 
 			} else if (e.button === THREE.MOUSE.RIGHT /* e.drag.mouse === MOUSE.RIGHT */) {
-				if(e.pressDistance < 2 )end(e);//非拖拽的话
+				if(e.pressDistance < Potree.config.clickMaxDragDis )end(e);//非拖拽的话
                 else continueDrag(e.drag.object)
                  
 			}
@@ -283,10 +414,11 @@ export class MeasuringTool extends EventDispatcher{
                     //this.viewer.scene.removeMeasurement(measure)
                     //cancelFun && cancelFun()
                     //重新开始画
-                    let pointCount = measure.points.length-1
-                    for(let i=0;i<pointCount;i++){
-                        measure.removeMarker(i)
-                    }  
+                    let pointCount = measure.points.length
+                    while(pointCount > 0){
+                        measure.removeMarker(--pointCount)
+                    }
+                       
                     if(measure.showArea){
                         measure.point2dInfo = null
                         measure.area = {value:0};
@@ -294,8 +426,8 @@ export class MeasuringTool extends EventDispatcher{
                     }
                     
                     
-                    measure.markers[0].visible = false
-                    continueDrag(measure.markers[0])
+                    this.viewer.addEventListener('global_click', click, 10)
+                   
                     measure.editStateChange(true)
                     return
                     
@@ -314,7 +446,8 @@ export class MeasuringTool extends EventDispatcher{
             clearTimeout(timer) 
 			this.viewer.removeEventListener('cancel_insertions', Exit);
             pressExit && this.viewer.inputHandler.removeEventListener('keydown', pressExit);
-            callback && callback() 
+            this.viewer.removeEventListener('global_click', click)
+            e.remove || callback && callback() 
             /* this.viewer.dispatchEvent({
                 type: 'finish_inserting_measurement',
                 measure: measure
@@ -323,8 +456,11 @@ export class MeasuringTool extends EventDispatcher{
 
         
         let Exit = (e)=>{//模拟右键点击 
-            console.log('Exit')
-            if(this.viewer.inputHandler.drag){//还未触发drop的话
+            console.log('Exit: ' +  measure.id)
+            if(e.remove){
+                viewer.scene.removeMeasurement(measure)  
+            }
+            if(this.viewer.inputHandler.drag && !e.remove){//还未触发drop的话
                 this.viewer.inputHandler.drag.object.dispatchEvent({
                     type: 'drop',
                     drag: this.viewer.inputHandler.drag, 
@@ -332,13 +468,15 @@ export class MeasuringTool extends EventDispatcher{
                     pressDistance:0,
                     button : THREE.MOUSE.RIGHT  
                 });
-                this.viewer.inputHandler.drag = null 
+                
             }else{
-                end({finish:true})  //未结束时添加新的measure时会触发
+                end({finish:true, remove:e.remove})  //未结束时添加新的measure时会触发
             }
+            this.viewer.inputHandler.drag = null 
+            measure.editStateChange(false)
         }
         this.viewer.addEventListener('cancel_insertions', Exit);
-        
+         
         
         let pressExit
         if(!Potree.settings.isOfficial){
@@ -351,13 +489,30 @@ export class MeasuringTool extends EventDispatcher{
         }
 		  
           
-        var marker = measure.addMarker({point:new THREE.Vector3(0, 0, 0)})
+        /* var marker = measure.addMarker({point:new THREE.Vector3(0, 0, 0)})
         this.viewer.inputHandler.startDragging(marker , {endDragFun, notPressMouse:true} ); //notPressMouse代表不是通过按下鼠标来拖拽
              
         if(measure.maxMarkers > 1){
             marker.visible = false
-        }            
-             
+        }   */          
+        let click = (e)=>{
+            
+            var marker = measure.addMarker({point:new THREE.Vector3(0, 0, 0)})
+            this.viewer.inputHandler.startDragging(marker , {endDragFun, notPressMouse:true} ); //notPressMouse代表不是通过按下鼠标来拖拽
+            e.drag = this.viewer.inputHandler.drag
+            e.drag.endDragFun = endDragFun
+            e.drag.notPressMouse = true
+            e.intersectPoint = this.viewer.inputHandler.intersectPoint
+            measure.dragMarker(e) 
+            measure.dropMarker(e)
+            
+            this.viewer.removeEventListener('global_click', click)///* global_drop */
+            
+            return {stopContinue:true}//防止继续执行别的侦听,如flytopano
+        }
+        this.viewer.addEventListener('global_click', click, 10)//add importance:10
+            
+          
         
 		this.viewer.scene.addMeasurement(measure);
         
@@ -365,128 +520,6 @@ export class MeasuringTool extends EventDispatcher{
 	}
 	
     
-    createMeasureFromData(data){//add
-        const measure = new Measure(data);
-        
-        viewer.scene.addMeasurement(measure);
-        
-        if(measure.guideLine)measure.guideLine.visible = false
-        return  measure       
-    }
-    
-    
-	update(){
-        return;
-        
-        
-        
-        
-		let camera = this.viewer.scene.getActiveCamera();
-		let domElement = this.renderer.domElement;
-		let measurements = this.viewer.scene.measurements;
-
-	 
-		// make size independant of distance
-        let mainLabels = [], subLabels = [];
-        
-      
-        
-		for (let measure of measurements) {
-			measure.lengthUnit = this.viewer.lengthUnit;
-			measure.lengthUnitDisplay = this.viewer.lengthUnitDisplay;
-			//measure.update();
-
-			updateAzimuth(this.viewer, measure);
-
-			 
-            /*  [...measure.markers, ...measure.edgeLabels, measure.areaLabel].forEach(e=>{
-                e && e.update() 
-            }); */
-             
-
-			// labels
-			/* let labels = measure.edgeLabels.concat(measure.angleLabels);
-			for(let label of labels){ 
-                label.update()
-                if(label.elem.hasClass('sub')){
-                    subLabels.push(label)
-                }else{ 
-                    mainLabels.push(label)
-                }
-			}
-
-			// coordinate labels
-			for (let j = 0; j < measure.coordinateLabels.length; j++) { 
-				let label = measure.coordinateLabels[j]; 
-                label.update() 
-                mainLabels.push(label)
-			} 
- 
-
-			if(measure.showArea){ // area label
-				let label = measure.areaLabel; 
-                label.update()
-                mainLabels.push(label)
-			} */
-             
-            
-
-			/* if(measure.showCircle){ // radius label
-				let label = measure.circleRadiusLabel;
-				let distance = label.position.distanceTo(camera.position);
-				let pr = Utils.projectedRadius(1, camera, distance, clientWidth, clientHeight);
-
-				let scale = (70 / pr);
-				label.scale.set(scale, scale, scale);
-			} */ 
-			if(!this.showLabels){ 
-				const labels = [
-					...measure.sphereLabels,  
-					...measure.angleLabels,  
-					measure.circleRadiusLabel,
-				]; 
-				for(const label of labels){
-					label.visible = false;
-				}
-			}
-		}
-        //this.updateLabelZIndex([{labels:subLabels},{labels:mainLabels}])
-        
-	}
-    setSize(e){ //e.resolution
-        /* if(Measure.lineMats){
-            for(var m in Measure.lineMats){
-                Measure.lineMats[m].resolution.set(e.canvasWidth, e.canvasHeight);
-            }  
-        }  
-        if(Measure.sphereMats){
-            for(var s in Measure.sphereMats){
-                Measure.sphereMats[s].uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
-            }
-        }
-        for (let measure of this.viewer.scene.measurements) { 
-            measure.edgeLabels.concat(measure.areaLabel).forEach(label=>{ 
-                label.sprite.material.uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
-            })
-        } */
-    }
-    
-    updateLabelZIndex(group){//[{labels:[]},{}] 顺序按照z-index低到高
-        
-        group.forEach((e,i)=>{
-            e.base = group[i-1] ? group[i-1].base + group[i-1].labels.length : 0
-         
-            var labels = e.labels.sort((a,b)=>{
-                return b.pos2d.z - a.pos2d.z
-            }) 
-            labels.forEach((label,index)=>{
-                $(label.elem).css('z-index', e.base+index) 
-            }) 
-        }) 
-        
-    }
-    
-    
 	render(o={}){
         viewer.setCameraLayers(o.camera, ['measure'])
 		this.viewer.renderer.render(this.scene, o.camera/* this.viewer.scene.getActiveCamera() */);

+ 2 - 2
src/viewer/sidebar.html

@@ -270,8 +270,8 @@ Thanks to all the companies and institutions funding Potree:
                 <span>平移</span>
                 <div><button>-x</button><button>+x</button><span class='gap'></span> <button>-y</button><button>+y</button> <span class='gap'> <button>-z</button><button>+z</button></div>
             </li>
-            <button name='rotTool'></button> 
-            <button name='moveTool'></button> 
+            <button id='rotTool'>旋转</button> 
+            <button id='moveTool'>平移</button> 
         </div>
 
         <h3 class="accordion-header ui-widget"><span>点云下载</span></h3>

+ 8 - 2
src/viewer/sidebar.js

@@ -105,9 +105,15 @@ export class Sidebar{
         pannel.find('#exitAlignment').on('click', ()=>{
             Alignment.leave()
         })
-        this.viewer.addEventListener("translatePointcloud",(e)=>{
-            applyToPointcloud(Alignment.translate, e.vec)()
+        pannel.find('#rotTool').on('click', ()=>{
+            Alignment.switchHandle('rotate')
         })
+        pannel.find('#moveTool').on('click', ()=>{
+            Alignment.switchHandle('translate')
+        })
+        
+        
+        
     }
     
     addAlignmentButton(pointcloud){

+ 48 - 17
src/viewer/viewer.js

@@ -314,8 +314,7 @@ export class Viewer extends ViewerBase{
                 this.navigationCube.visible = false;
 
                 this.compass = new Compass(this);
-                
-                
+                 
                 //add----------
                 this.magnifier = new Magnifier(this);
                 this.reticule = new Reticule(this) 
@@ -325,14 +324,10 @@ export class Viewer extends ViewerBase{
                     left:0, bottom:0, width:1, height: 1, name:'MainView' 
                 }) 
                 this.viewports = [this.mainViewport]
-                
-                
                 this.mapViewer = new MapViewer(mapArea/* $('#mapGaode')[0] */)
-                CursorDeal.init(this)//ADD
                 
-                this.modules.SiteModel.init()
                 
-                //-----------
+                //---------------------------
                 
                 
                 this.createControls();
@@ -402,7 +397,19 @@ export class Viewer extends ViewerBase{
             this.measuringTool = new MeasuringTool(this);
             this.profileTool = new ProfileTool(this);
             this.volumeTool = new VolumeTool(this);
-
+            
+            
+            
+            
+            
+            //-----------
+            CursorDeal.init(this)//ADD
+            
+            this.modules.SiteModel.init()
+            this.modules.Alignment.init()
+            //-----------
+            
+            
 		}catch(e){
 			this.onCrash(e);
 		}
@@ -421,9 +428,28 @@ export class Viewer extends ViewerBase{
                         viewer.scene.pointclouds.forEach(e=>{
                             e.maxLevel = config.maxLevel
                         }) 
+                        pointDensity = density
                     }
                 }
             })
+            
+            let UserPointDensity = ''
+            Object.defineProperty(Potree.settings , "UserPointDensity",{ 
+                get: function() {
+                    return UserPointDensity
+                },
+                set: (density)=>{
+                    if(UserPointDensity != density){
+                        if(Potree.settings.displayMode == 'showPointCloud' && this.viewports.length != 4){//漫游模式和四屏时都有自己的pointDensity
+                            Potree.settings.pointDensity = density 
+                        }
+                        UserPointDensity = density
+                    }
+                }
+            })
+            
+            
+            
         }
         {
             
@@ -438,6 +464,7 @@ export class Viewer extends ViewerBase{
                             this.mainViewport.camera.far = far;
                             this.mainViewport.camera.updateProjectionMatrix()
                         }
+                        cameraFar = far
                     }
                 }
             })
@@ -2404,7 +2431,7 @@ export class Viewer extends ViewerBase{
         
         
         if(!params.magnifier){//为什么要在点云之后渲染,否则透明失效 、 会被点云覆盖 
-            this.setCameraLayers(camera, ['sceneObjects','marker','reticule','route'], params.extraEnableLayers) //透明贴图层 skybox 、reticule marker 不能遮住测量线
+            this.setCameraLayers(camera, ['sceneObjects','marker','reticule','route',/* 'bothMapAndScene' */], params.extraEnableLayers) //透明贴图层 skybox 、reticule marker 不能遮住测量线
             this.renderer.render(this.scene.scene, camera); 
         } 
         this.dispatchEvent({type: "render.pass.scene", viewer: viewer});
@@ -2465,15 +2492,19 @@ export class Viewer extends ViewerBase{
            
         
         if(ifShow){
-            var index = object.unvisibleReasons.indexOf(reason)
-            index > -1 && object.unvisibleReasons.splice(index, 1)
-            if(object.unvisibleReasons.length == 0){
-                object.visible = true;
-                object.dispatchEvent({
-                    type: 'isVisible',
-                    visible:true
-                })
+            var index = object.unvisibleReasons.indexOf(reason) 
+            if(index > -1){
+                object.unvisibleReasons.splice(index, 1);
+                if(object.unvisibleReasons.length == 0){
+                    object.visible = true;
+                    object.dispatchEvent({
+                        type: 'isVisible',
+                        visible:true, 
+                        reason
+                    })
+                }
             }
+            
         }else{
             var visiBefore = object.visible
             if(!object.unvisibleReasons.includes(reason)) object.unvisibleReasons.push(reason)