浏览代码

measure箭头对准点。吸附。shape

xzw 1 年之前
父节点
当前提交
1d7bed6a14

+ 4 - 2
src/custom/modules/panos/Images360.js

@@ -1433,12 +1433,14 @@ export class Images360 extends THREE.EventDispatcher{
             return this.depthSampler.sample( {dir }, pano, true )
         }else{
             origin = origin || pano.position
-            return viewer.inputHandler.getIntersect(viewer.inputHandler.hoverViewport, true, null, null, true, {
+            return viewer.inputHandler.getIntersect({
+                viewport:viewer.inputHandler.hoverViewport, 
+                onlyGetIntersect:true,  usePointcloud:true, 
                 point: origin.clone().add(dir),
                 cameraPos: origin
             })
         }
-    }                           
+    } 
                              
                                  
                                         

+ 1 - 1
src/custom/objects/Label.js

@@ -33,7 +33,7 @@ class Label  extends THREE.EventDispatcher{
      
     update(){
         if(!this.position || this.elem.hasClass('unvisible'))return
-        var p = Utils.getPos2d(this.position,this.camera,this.dom, viewer.mainViewport);
+        var p = Utils.getPos2d(this.position,viewer.mainViewport,this.dom );
         if(!p.trueSide){
             this.elem.addClass("hide");  return;
         }

+ 1 - 1
src/custom/objects/Magnifier.js

@@ -277,7 +277,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
          
         //自身位置 
         //let pos2d = viewer.inputHandler.pointer.clone();   //跟随鼠标 
-        let pos2d = Potree.Utils.getPos2d(aimPos, playerCamera, viewer.renderArea, viewer.mainViewport).vector   //更新目标点的实时二维位置
+        let pos2d = Potree.Utils.getPos2d(aimPos, viewer.mainViewport, viewer.renderArea  ).vector   //更新目标点的实时二维位置
         let margin = 0.4, maxY = 0.4
         let screenPos = pos2d.clone().setY(pos2d.y + (pos2d.y>maxY ? -margin : margin ))
         

+ 13 - 4
src/custom/objects/Sprite.js

@@ -15,8 +15,11 @@ export default class Sprite extends THREE.Mesh{
         this.dontFixOrient = options.dontFixOrient
         this.options = options
         this.lineDir = options.lineDir
-        this.position.y = options.disToLine || 0 //离线距离
-        
+        if(options.disToLine){
+            if(this.root != this) this.position.y = options.disToLine || 0 //离线距离
+            else this.posShift = new THREE.Vector3(0,options.disToLine,0)
+        } 
+         
         
         this.root.matrixAutoUpdate = false;
         this.matrixMap = new Map()
@@ -150,7 +153,7 @@ export default class Sprite extends THREE.Mesh{
                     
                     
                     
-                    let r1 = Potree.Utils.getPos2d(center, camera, viewer.renderArea, e.viewport); 
+                    let r1 = Potree.Utils.getPos2d(center, e.viewport, viewer.renderArea ); 
                     if(!r1.trueSide)return  Potree.Utils.updateVisible(this, 'unableCompute', false);// 但这句会使realVisible为false从而无法更新//console.error('!r1.trueSide') //中心点如果在背面直接不渲染了
                         
                     let r2, point2
@@ -159,7 +162,7 @@ export default class Sprite extends THREE.Mesh{
                     while(p2State != 'got' && p2StateHistory.length<10){ 
                         point2 = center.clone().add(lineDir.clone().multiplyScalar(len));
                          
-                        r2 = Potree.Utils.getPos2d(point2, camera, viewer.renderArea, e.viewport);  
+                        r2 = Potree.Utils.getPos2d(point2, e.viewport, viewer.renderArea);  
                         if(!r2.trueSide){ //很少遇到点2在背面的
                             if(!p2StateHistory.includes('tooLong-reverse')){
                                 p2State = 'tooLong-reverse'  //先尝试反向
@@ -287,6 +290,12 @@ export default class Sprite extends THREE.Mesh{
             } 
         }
         this.root.updateMatrix();
+        
+        if(this.posShift && this.root == this){//需要偏移
+            let m = new THREE.Matrix4().setPosition(this.posShift)
+            this.matrix.multiplyMatrices(this.matrix,m)
+        }
+         
         this.root.updateMatrixWorld(true)
         this.matrixMap.set(e.viewport, this.root.matrix.clone())
         this.needsUpdate = false

+ 108 - 26
src/custom/objects/tool/Measure.js

@@ -50,7 +50,7 @@ const mainLabelProp = {
     textBorderThick:3,
     fontsize: 15 * textSizeRatio,  
     borderRadius : 12, margin:{x:20,y:4},
-    renderOrder : 5, pickOrder:5, 
+    renderOrder : 8, pickOrder:8, 
     disToLine:-0.15,
     
     useDepth : true , 
@@ -68,7 +68,7 @@ const subLabelProp = {
     backgroundColor: {r: 255, g: 255, b: 255, a:config.measure.default.opacity},
     textColor: {r: 0.3, g: 0.3, b:0.3, a: 1.0},
     fontsize:15 * textSizeRatio,   borderRadius : 12,  margin:{x:20,y:4},
-    renderOrder : 4, pickOrder:4, 
+    renderOrder : 7, pickOrder:7, 
 }
 
 
@@ -127,7 +127,7 @@ export class Measure extends ctrlPolygon{
         //addMarkers:
        
         this.initData(prop)
-        
+        this.pointsPos2d = new Map //屏幕上的二维坐标
          
         this.points_datasets || (this.points_datasets = []) //存每个点是哪个数据集
 
@@ -151,6 +151,9 @@ export class Measure extends ctrlPolygon{
         let makeIt = super.initData(prop)
         if(makeIt){
             this.edges.forEach(edge=>{edge.dispatchEvent('addHoverEvent') })
+            if(this.measureType == 'MulDistance_shape'){
+                this.markers.forEach(e=>e.visible = false)
+            }
         }else{
             this.failBuilded = true
         }
@@ -422,19 +425,28 @@ export class Measure extends ctrlPolygon{
 	addMarker (o={}) {
          
         let marker = new Sprite({mat:this.getMarkerMaterial('default'), sizeInfo: markerSizeInfo, name:"measure_point"} )
+        
+        if(this.measureType != 'MulDistance_shape')marker.posShift = new THREE.Vector3(0.2,0,0);//使箭头中心对准端点位置(因贴图里箭头不在中心,如果单纯改贴图会导致raycaster热区偏移,所以修改mesh位置)
+         
         Potree.Utils.setObjectLayers(marker, 'measure' )
-        marker.pickOrder = marker.renderOrder = 3 
+        marker.pickOrder = marker.renderOrder = 6 
         marker.markerSelectStates = {} 
         marker.addEventListener('startDragging',(e)=>{
-            if(e.drag.dragViewport.name == 'MainView')viewer.inputHandler.dispatchEvent( {type: 'isMeasuring',v:true, cause:'startDragging'})
+            viewer.inputHandler.dispatchEvent( {type: 'measuring',v:true, cause:'startDragging', situation:'dragging', object:this})
         })
         marker.addEventListener('drop',(e)=>{
-            viewer.inputHandler.dispatchEvent({type: 'isMeasuring',  v:false, cause:'stopDragging'}  )
+            viewer.inputHandler.dispatchEvent({type: 'measuring',  v:false, cause:'stopDragging', situation:'dragging', object:this}  )
+            
+            if(Potree.settings.adsorption){
+                this.isNew || viewer.viewports.forEach((viewport)=>{
+                    this.getPointsPos2d(viewport, true )//forceUpdate
+                })  
+            }
         })
         marker.measure = this
         let edge
 		{ // edges 
-            edge = LineDraw.createFatLine( [ ],{material:this.getLineMat('edgeDefault')} ) 
+            edge = LineDraw.createFatLine( [ ],{material: this.getLineMat(this.clickSelected?'edgeSelect':'edgeDefault')} ) 
             edge.pickOrder = 0
             Potree.Utils.setObjectLayers(edge, 'measure' ) 
 
@@ -544,12 +556,23 @@ export class Measure extends ctrlPolygon{
                 absoluteState = true; break;
             }
         }
-        if(absoluteState){
-            marker.material = this.getMarkerMaterial('select')
-        }else{
-            marker.material = this.getMarkerMaterial('default')
-        }
         
+        
+        if(this.measureType == 'MulDistance_shape'){ 
+            if(state == 'hover' && hoverObject == 'single'){
+                marker.material = this.getMarkerMaterial('select') 
+            }else{
+                marker.material = this.getMarkerMaterial('default') //路径选中后marker是非选中状态, 但是颜色一样
+            }  
+             
+        }else{
+            if(absoluteState){
+                marker.material = this.getMarkerMaterial('select')
+            }else{
+                marker.material = this.getMarkerMaterial('default')
+            } 
+        } 
+         
         marker.selected = absoluteState
         
         viewer.mapViewer && viewer.mapViewer.dispatchEvent('content_changed') 
@@ -807,20 +830,27 @@ export class Measure extends ctrlPolygon{
     
     
     focus({dontMoveCamera=false}={}){ 
-        if(this.clickSelected)return    
-        if(Potree.settings.displayMode == 'showPanos')dontMoveCamera = true  //2023.10.24 新需求:点击后不移动,否则经常跳到别的点。且在app上会反应一秒才选中。
         
+        if(Potree.settings.displayMode == 'showPanos')dontMoveCamera = true  //2023.10.24 新需求:点击后不移动,否则经常跳到别的点。且在app上会反应一秒才选中。
         if(!dontMoveCamera){
             let dontChangeCamDir = viewer.mainViewport.camera.type == 'OrthographicCamera' /* && math.closeTo( viewer.mainViewport.view.pitch , -1.57079632)  */ // 不改角度
             viewer.focusOnObject(this, 'measure', null, {dontChangeCamDir})
         }
-        
+        if(this.clickSelected)return    
         this.setSelected(true, 'focus')
         this.dispatchEvent({type:'selected', state:true})
         this.clickSelected = true
+        if(this.measureType == 'MulDistance_shape'){
+            this.markers.forEach(e=>e.visible = true)
+        }
+        
         //viewer.dispatchEvent({type:'selectMeasure', measure:this})
         let cancelSelect = ()=>{
+            if(this.isNew)return;//添加过程中保持选中  主要for多路径
             this.clickSelected = false
+            if(this.measureType == 'MulDistance_shape'){
+                this.markers.forEach(e=>e.visible = false)
+            }
             this.removeEventListener('cancelSelect', cancelSelect)
             viewer.removeEventListener('global_click', cancelSelect) 
             this.setSelected(false, 'focus') 
@@ -905,19 +935,43 @@ export class Measure extends ctrlPolygon{
     
     getMarkerMaterial(type){ 
         let color = this.color.getHexString() 
-        if(!markerMats[type + color]){
-           
-            markerMats['default' + color] = new DepthBasicMaterial($.extend({},lineDepthInfo,{ 
+        let name   
+        if(this.measureType == 'MulDistance_shape'){//多线段路径
+             name = type + '_circle_' + color
+        }else{
+             name = type + '_arrow_' + color
+        }
+        
+        if(!markerMats[name]){
+            
+            markerMats['default_circle_' + color] = new DepthBasicMaterial($.extend({},lineDepthInfo,{ 
+                transparent: !0,
+                opacity: 1,
+                map: texLoader.load(Potree.resourcePath+'/textures/pic_point_s32.png' ),  
+                useDepth:true,
+                replaceColor:new THREE.Color(Potree.config.measure.highlight.color),
+                beReplacedRed: 0.184,  //0.18431372
+                mapColorReplace:true,
+            })),
+            markerMats['select_circle_' + color] = new DepthBasicMaterial($.extend({},lineDepthInfo,{ 
                 transparent: !0,
                 opacity: 1,
-                //map: texLoader.load(Potree.resourcePath+'/textures/pic_point_s32.png' ), 
+                map: texLoader.load(Potree.resourcePath+'/textures/pic_point32.png' ), 
+                //useDepth:true ,
+                replaceColor:  new THREE.Color(Potree.config.measure.highlight.color) ,
+                beReplacedRed: 0.184,   //0.18431372
+                mapColorReplace:true
+            })) 
+            markerMats['default_arrow_' + color] = new DepthBasicMaterial($.extend({},lineDepthInfo,{ 
+                transparent: !0,
+                opacity: 1, 
                 map: texLoader.load(Potree.resourcePath+'/textures/arrows_l_32.png' ),
                 useDepth:true,
                 replaceColor:this.color,
                 beReplacedRed: 0.184,  //0.18431372
                 mapColorReplace:true,
             })),
-            markerMats['select' + color] = new DepthBasicMaterial($.extend({},lineDepthInfo,{ 
+            markerMats['select_arrow_' + color] = new DepthBasicMaterial($.extend({},lineDepthInfo,{ 
                 transparent: !0,
                 opacity: 1,
                 map: texLoader.load(Potree.resourcePath+'/textures/arrows_l_32.png' ), 
@@ -925,9 +979,15 @@ export class Measure extends ctrlPolygon{
                 replaceColor:  new THREE.Color(Potree.config.measure.highlight.color) ,
                 beReplacedRed: 0.184,   //0.18431372
                 mapColorReplace:true
-            }))   
+            })) 
+          
+            
         }  
-        return markerMats[type + color] 
+        
+       
+        return markerMats[name]
+        
+         
         
     }
     
@@ -1032,7 +1092,26 @@ export class Measure extends ctrlPolygon{
 		intersects.sort(function (a, b) { return a.distance - b.distance; });
 	};
 
-    
+    getPointsPos2d(viewport, update){//获取屏幕上的二维坐标
+        let ps = this.pointsPos2d.get(viewport) 
+        if(update || !ps){
+            let points = this.points.slice()
+            if(this.measureType == 'MulDistance_shape'){
+                points.push(this.getCenter()) //中心点吸附
+            }
+            points = points.map(e=>{
+                let p = Potree.Utils.getPos2d(e,  viewport, viewer.renderArea )
+                p.pos3d = e.clone(),  p.object = this
+                return p
+            }); 
+            
+            
+            this.pointsPos2d.set(viewport, points)
+            //console.log('updatePointsPos2d',this.uuid,viewport.name)
+        }
+        
+        return this.pointsPos2d.get(viewport) 
+    }
     
     
     transformData(prop){
@@ -1046,10 +1125,13 @@ export class Measure extends ctrlPolygon{
             prop.showEdges = true,
             prop.maxMarkers = 2,
             prop.minMarkers = 2 
-        }else if(prop.measureType == 'MulDistance'){//new 
+        }else if(prop.measureType == 'MulDistance' ){//new 
             prop.showDistances = true,  
             prop.showEdges = true, 
             prop.minMarkers = 2 
+        }else if(prop.measureType == 'MulDistance_shape' ){//new 
+            prop.showEdges = true, 
+            prop.minMarkers = 2 
         }else if(prop.measureType == 'Ver MulDistance'){ 
             prop.showDistances = true,
             prop.atPlane = true,                
@@ -1168,8 +1250,8 @@ export class Measure extends ctrlPolygon{
             this.area = {value:0};
             this.areaLabel && this.areaLabel.setVisible(false)
         }
-        viewer.inputHandler.dispatchEvent( {type:'isMeasuring', v:true, cause:'reDraw'}  )
-	            
+        viewer.inputHandler.dispatchEvent( {type:'measuring', v:true, cause:'reDraw',object:this, situation:'dragging'}  )
+	             
     }
     
 

+ 54 - 9
src/custom/objects/tool/MeasuringTool.js

@@ -5,8 +5,8 @@ import math from "../../utils/math.js";
 import {CameraMode} from "../../../defines.js"; 
 import {TextSprite} from '../TextSprite.js'; 
 import  browser  from "../../utils/browser.js"; 
- 
- 
+import Sprite from '../Sprite.js' 
+import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
  
 function updateAzimuth(viewer, measure){
     if(!measure.showAzimuth)return
@@ -155,7 +155,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
 		}
 		 
         viewer.addEventListener('camera_changed',(e)=>{ 
-            if(e.viewport == viewer.mainViewport ) this.update()
+             this.update(e)
         })
         
         
@@ -171,6 +171,39 @@ export class MeasuringTool extends THREE.EventDispatcher{
         
         
         
+        if( Potree.settings.adsorption ){
+            let texLoader = new THREE.TextureLoader()  
+            
+            this.sorptionSign = new Sprite({mat:new DepthBasicMaterial({ 
+                transparent: !0,
+                opacity: 1,
+                map: texLoader.load(Potree.resourcePath+'/textures/pic_point_s32.png' ), 
+                replaceColor:new THREE.Color(Potree.config.measure.default.color),
+                beReplacedRed: 0.184, 
+                mapColorReplace:true,
+            }), sizeInfo:   {
+                width2d:30,
+            }, name:"sorptionSign"} )
+            viewer.scene.scene.add(this.sorptionSign)  
+            this.sorptionSign.visible = false
+            const minShowTime = 5e3;//改变位置后至少显示这么久才消失
+            let canFade
+            let fade = ()=>{
+                canFade = true
+            } 
+            viewer.addEventListener('findAdsorption',(e)=>{
+                clearTimeout(timer)
+                this.sorptionSign.visible = true
+                this.sorptionSign.position.copy(e.intersect.location)
+                canFade = false
+                timer = setTimeout(fade,minShowTime)
+            })
+            viewer.addEventListener('camera_changed',(e)=>{//minShowTime后移动镜头就消失
+                canFade && (this.sorptionSign.visible = false)
+            })
+            //Potree.Utils.setObjectLayers(this.sorptionSign, 'measure' )
+       
+        }
         
         
         
@@ -208,8 +241,17 @@ export class MeasuringTool extends THREE.EventDispatcher{
     }
     
     
-	update(){ 
+	update(e){ 
         //add
+        
+        if(viewer.inputHandler.measuring && Potree.settings.adsorption){
+            viewer.scene.measurements.forEach(measure=>{
+                measure.getPointsPos2d(e.viewport, true) 
+            })
+            
+        }
+        
+        
         viewer.scene.measurements.forEach(measure=>{
             
             let lastIndex = measure.points.length - 1; 
@@ -436,7 +478,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
 
 		let end = (e={}) => {//确定、结束 
             if(!measure.isNew )return
-       console.log('end')      
+            console.log('end')      
             if(args.minMarkers != void 0 ){
                 
                 if(!e.finish && measure.markers.length<=args.minMarkers ){//右键  当个数不够时取消
@@ -497,7 +539,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
                 type : "CursorChange", action : "remove",  name:"polygon_AtWrongPlace"
             });
             
-            viewer.inputHandler.dispatchEvent({type:'isMeasuring',  v:false, cause:'stopInsertion'}  ) 
+            viewer.inputHandler.dispatchEvent({type:'measuring',  v:false, cause:'stopInsertion', situation:'adding', object:measure}  ) 
             viewer.controls.setEnable(true) 
             
             //var isIntersectSelf = measure.atPlane && measure.closed && !measure.isRect && measure.point2dInfo && measure.intersectSelf(measure.point2dInfo.points2d.slice(0,measure.point2dInfo.points2d.length-1))//检测除了最后一个点的相交情况
@@ -505,7 +547,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
             if(isIntersectSelf) return cancelFun && cancelFun() //请求删除,不重建 
             
             
-            
+            measure.editStateChange(false)
             e.remove || callback && callback()  
             /* this.viewer.dispatchEvent({
                 type: 'finish_inserting_measurement',
@@ -573,7 +615,10 @@ export class MeasuringTool extends THREE.EventDispatcher{
           
             if(ifAtWrongPlace(e))return  
             if(e.clickElement || e.drag.object)return  //如点击label时focusOnObject, 或拖拽marker
-              
+            measure.measureType == 'MulDistance_shape' &&  measure.focus({dontMoveCamera:true}) //多路径变为选中态
+
+
+            
             if(e.button === THREE.MOUSE.RIGHT )return  
             
             
@@ -639,7 +684,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
         
         //点击第n下拥有n+1个marker, n>0
         
-        viewer.inputHandler.dispatchEvent({type: 'isMeasuring', v: true, cause:'startInsertion'})
+        viewer.inputHandler.dispatchEvent({type: 'measuring', v: true, cause:'startInsertion', situation:'adding', object:measure})
         
             
         if( isMobile ){

+ 1 - 1
src/custom/objects/tool/ctrlPolygon.js

@@ -741,7 +741,7 @@ export class ctrlPolygon extends THREE.Object3D {
         object.isDragging = true 
         this.editStateChange(true)
         var timer = setTimeout(()=>{//等 drag=null之后 //右键拖拽结束后需要重新得到drag 
-            if(this.parent && object.isDragging){
+            if(this.parent && object.parent && object.isDragging){
                 console.log('continueDrag', object.uuid)        
                 viewer.inputHandler.startDragging( object ,
                     {endDragFun: e.drag.endDragFun, notPressMouse:e.drag.notPressMouse, dragViewport:e.drag.dragViewport} 

+ 3 - 4
src/custom/potree.shim.js

@@ -443,13 +443,12 @@ Utils.mouseToRay = function(pointer, camera  ){
 
     return ray;
 }
-
-Utils.getPos2d = function(point, camera, dom, viewport){//获取一个三维坐标对应屏幕中的二维坐标
+Utils.getPos2d = function(point, viewport , dom  ){//获取一个三维坐标对应屏幕中的二维坐标
     var pos
-    if(math.closeTo(camera.position, point, 1e-5) ){ //和相机位置重合时显示会四处飘,看是要改成一直显示中间还是隐藏?
+    if(math.closeTo(viewport.camera.position, point, 1e-5) ){ //和相机位置重合时显示会四处飘,看是要改成一直显示中间还是隐藏?
         pos = new THREE.Vector3(0,0,1.5); //1.5是为了不可见
     }else{ 
-        pos = point.clone().project(camera)	//比之前hotspot的计算方式写得简单  project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
+        pos = point.clone().project(viewport.camera)	//比之前hotspot的计算方式写得简单  project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
     }
     
     

+ 3 - 3
src/custom/settings.js

@@ -180,8 +180,8 @@ const config = {//配置参数   不可修改
          
         lineWidth: 3,
        
-        textColor: "#000000" //"#FFFFFF"
-        
+        textColor: "#000000", //"#FFFFFF"
+        adsorptMinDis:30,
     },
     material:{//初始化
         pointSize: 0.1,  
@@ -440,7 +440,7 @@ let settings = {//设置   可修改
     //showCompass : isTest,
     showAxis : isTest,
     //testCube : true,
-    
+    adsorption:true, 
 }
   
  

+ 2 - 2
src/custom/viewer/ViewerNew.js

@@ -2,7 +2,7 @@
 import * as THREE from "../../../libs/three.js/build/three.module.js";
 import {ClipTask, ClipMethod, CameraMode, LengthUnits, ElevationGradientRepeat} from "../../defines.js";
 import {TagTool} from "../objects/tool/TagTool.js"; 
-import Compass from "../objects/tool/Compass.js";
+import Compass from "../objects/tool/Compass.js";  
 import {ExtendScene} from '../../viewer/ExtendScene.js' 
 import {transitions, easing, lerp} from '../utils/transitions.js' 
 import {Renderer} from "../../PotreeRendererNew.js"; 
@@ -36,7 +36,6 @@ import {BoxVolume} from "../../utils/VolumeNew.js";
 import {VolumeTool} from "../../utils/VolumeTool.js";
 import {Images360} from "../modules/panos/Images360.js";
 import {Clip} from '../modules/clipModel/Clip.js' 
- 
 
 import {InputHandler} from "../../navigation/InputHandlerNew.js";
 
@@ -511,6 +510,7 @@ export class Viewer extends ViewerBase{
             
             
             
+            
             //-----------
             CursorDeal.init(this, this.mapViewer ? [this, this.mapViewer] : [this])//ADD
            

+ 142 - 94
src/navigation/InputHandlerNew.js

@@ -10,7 +10,7 @@ import {Utils} from "../utils.js";
 import Common from "../custom/utils/Common.js";
 import DepthBasicMaterial from '../custom/materials/DepthBasicMaterial.js' 
 import browser from "../custom/utils/browser.js"; 
-
+import math from "../custom/utils/math.js"; 
 
 let {Buttons} = Potree.defines
 
@@ -89,12 +89,28 @@ export class InputHandler extends THREE.EventDispatcher {
           
         
         {
-            this.addEventListener('isMeasuring',(e)=>{ 
-                //console.log('isMeasuring',e.v,e.cause)
-                this.isMeasuring = e.v 
+            this.measuring = [] //正在编辑的measure
+            //let mesureInfo = new THREE.EventDispatcher()
+            this.addEventListener('measuring',(e)=>{ 
+                //true优先级高于false, 正在添加时dropMarker也不会停止
+                
+                //Potree.Utils.updateVisible(mesureInfo, e.situation,  e.v, 0, e.v?'add':'cancel' )//借用该函数,使true优先级高于false,防止正在添加时dropMarker而停止
+                if(e.v){
+                    this.measuring.includes(e.object) || this.measuring.push(e.object)
+                }else{
+                    let index = this.measuring.indexOf(e.object)
+                    index > -1 && this.measuring.splice(index, 1)
+                }
+                 
+                if(this.measuring.length == 0 && this.measuring.length>0   ){
+                    this.viewer.viewports.forEach((viewport)=>{
+                        this.collectClosePoints(viewport, true )//forceUpdate
+                    }) 
+                } 
+                //console.log('measuring',e.v, e.cause, e.situation, this.measuring.length )
             }) 
         }
-        
+             
         window.viewer.addEventListener('loopStart',()=>{
             this.interactHistory = {}  //清空
         })
@@ -407,7 +423,7 @@ export class InputHandler extends THREE.EventDispatcher {
         //if(isTouch || !Potree.settings.intersectWhenHover ){ 
         if(isTouch || !this.dragViewport.view.isFlying()){ 
             this.hoveredElements = this.getHoveredElements(); 
-            this.intersect = this.getIntersect(viewport) //更新intersect,避免在没有mousemove但flyToPano后intersect未更新。
+            this.intersect = this.getIntersect({viewport, clientX:e.clientX, clientY:e.clientY}) //更新intersect,避免在没有mousemove但flyToPano后intersect未更新。
             //this.intersect = this.getWholeIntersect()  
         } //isTouch必须更新 否则是旧的
         if(!viewport)return //why add this?
@@ -767,47 +783,64 @@ export class InputHandler extends THREE.EventDispatcher {
 
 
     ifBlockedByIntersect({point, margin=0, cameraPos, pickWindowSize, pano, useDepthTex}={}){//某点是否被遮挡(不允许camera修改位置, 因为depthTex不好置换)
-          
-        let intersect = this.getIntersect(this.hoverViewport, true, pickWindowSize, null, null, useDepthTex, {point, cameraPos, pano})
-        let cameraPos_ = (!cameraPos && pano) ? pano.position : (cameraPos||this.hoverViewport.view.position)
+        viewport = viewport || this.hoverViewport || viewer.mainViewport
+        let intersect = this.getIntersect({viewport, onlyGetIntersect:true, pickWindowSize,  useDepthTex,  point, cameraPos, pano })
+        let cameraPos_ = (!cameraPos && pano) ? pano.position : (cameraPos||viewport.view.position)
         if(intersect && intersect.distance+margin <= point.distanceTo(cameraPos_)){
             return intersect //被遮挡
         }
         //点云模式,对没加载出的点云不准确。 尤其是需要修改相机位置时,因临时修改并不能使点云加载。
     }
 
-
-
-    getIntersect(viewport,   onlyGetIntersect, pickWindowSize, dontIntersect, usePointcloud, useDepthTex, prop={}){// usePointcloud:必须使用点云
-        let intersectPoint  
+    collectClosePoints(viewport, forceUpdate){//获取吸附点
+        if(!Potree.settings.adsorption)return
+    
+        let point2ds = []
+        
+        //吸附测量线端点
+        
+        viewer.scene.measurements.forEach(e=>{
+            if(this.measuring.includes(e)) return//不吸附到正在拖拽的自身
+            point2ds.push(...e.getPointsPos2d(viewport, forceUpdate))
+        })
+        viewer.fixPoints 
+        
+        return point2ds
+        
+        
+    }
+    getIntersect({viewport, onlyGetIntersect, pickWindowSize, dontIntersect, usePointcloud, useDepthTex,  cameraPos,  point, pano, clientX, clientY}={}){// usePointcloud:必须使用点云
+        let intersect, intersectPoint, intersectOnModel, allElements 
         let camera = viewport.camera
         let raycaster 
-        
+         
+       
         viewer.addTimeMark('getIntersect','start')
  
         let getByDepthTex = ()=>{ 
             let intersect
-            if(prop.point){
-                let cameraPos = prop.pano ? prop.pano.position : camera.position
-                let dir = new THREE.Vector3().subVectors(prop.point, cameraPos).normalize(); 
+            if(point){
+                let cameraPos = pano ? pano.position : camera.position
+                let dir = new THREE.Vector3().subVectors(point, cameraPos).normalize(); 
                 intersect = {dir} 
             }else{
                 intersect = Utils.getIntersect(camera, [viewer.images360.cube], this.pointer, raycaster) 
             } 
-            intersectPoint = viewer.images360.depthSampler.sample(intersect, prop.pano, !!prop.point)  //可能不准确, 因pano可能未加载depthTex
+            intersectPoint = viewer.images360.depthSampler.sample(intersect, pano, !!point)  //可能不准确, 因pano可能未加载depthTex
             if(intersectPoint && Potree.settings.depTexLocBindDataset){
-                intersectPoint.pointcloud = (prop.pano || viewer.images360.currentPano).pointcloud
+                intersectPoint.pointcloud = ( pano || viewer.images360.currentPano).pointcloud
                 //在全景模式下,虽然深度图上的点可能对应别的pointcloud,但因为是在当前全景图处得到的,所以即使将原本对应的点云移走,该点也不移动是有道理的。它可以永远跟着该全景图。
             }
         }
         
-        let getByCloud = ()=>{
-            if(prop.point){//指定了目标点,而非只是用pointer所在位置
-                prop.cameraPos && camera.position.copy(prop.cameraPos)
-                camera.lookAt(prop.point)
+        let getByCloud = ()=>{ 
+            let pointer, mouse
+            if(point){//指定了目标点,而非只是用pointer所在位置
+                cameraPos && camera.position.copy( cameraPos)
+                camera.lookAt(point)
                 camera.updateMatrixWorld()
-                prop.pointer = this.pointer.clone()
-                prop.mouse = this.mouse.clone()
+                pointer = this.pointer.clone()
+                mouse = this.mouse.clone()
                 this.pointer.set(0,0)   //画布中心
                 this.mouse.set(Math.round(viewport.resolution.x/2), Math.round(viewport.resolution.y/2))
             } 
@@ -819,80 +852,105 @@ export class InputHandler extends THREE.EventDispatcher {
                 camera, 
                 this.viewer, 
                 this.viewer.scene.pointclouds,
-                {pickClipped: true, isMeasuring: this.isMeasuring, pickWindowSize, cameraChanged: !!prop.point }  
+                {pickClipped: true, measuring: this.measuring.length>0, pickWindowSize, cameraChanged: !!point }  
                 
             );
             
         
             //恢复
-            if(prop.point){
+            if(point){
                 viewport.view.applyToCamera(camera)
-                this.pointer.copy(prop.pointer)
-                this.mouse.copy(prop.mouse)
+                this.pointer.copy(pointer)
+                this.mouse.copy(mouse)
             }  
         }
         
+        if(this.measuring.length && Potree.settings.adsorption ){//吸附
+            let points = this.collectClosePoints(viewport)
+            
+            let points2 = points.filter(e=>e.trueSide && e.inSight 
+               &&  math.closeTo(this.mouse, e.posInViewport, Potree.config.measure.adsorptMinDis)
+            )
+            
+            let disArr = points2.map(e=> e.pos.distanceToSquared(this.mouse)  )
+             
+            let min = points2.slice().sort((a,b)=>disArr[points.indexOf(a)] - disArr[points.indexOf(b)])
+            if(min[0]){
+                intersect = {
+                    //hoveredElement  
+                    location: min[0].pos3d,
+                    //point: {normal: allElements[0].face.normal },
+                    //normal 
+                    //distance 
+                    object: min[0].object,
+                    adsorption:true
+                }
+                console.log('找到吸附点', min[0].pos3d, min[0].object.uuid)
+                
+                viewer.dispatchEvent({
+                    type:'findAdsorption',
+                    intersect
+                })
+            } 
+        } 
         
-        
-        let canUseDepthTex = !Potree.settings.unableUseDepTexPick && (Potree.settings.displayMode == 'showPanos' || useDepthTex)
-            && viewer.images360.currentPano.pointcloud.hasDepthTex && viewport == viewer.mainViewport && !usePointcloud 
-        
-        
-        /* if(canUseDepthTex)getByDepthTex()
-        else getByCloud()  */
-        if(canUseDepthTex && !this.isMeasuring){
-            getByDepthTex()
-        }else{
-            getByCloud() 
-            /* if(!intersectPoint && canUseDepthTex  ){  //若在测量,先尝试点云,再用全景 //后来发现有深度图的点云全景visibleNode为空,pick不到的//如果允许的话,裁剪掉的点云也会得到intersect
+        if(!intersect){
+            let canUseDepthTex = !Potree.settings.unableUseDepTexPick && (Potree.settings.displayMode == 'showPanos' || useDepthTex)
+                && viewer.images360.currentPano.pointcloud.hasDepthTex && viewport == viewer.mainViewport && !usePointcloud 
+            
+            
+            /* if(canUseDepthTex)getByDepthTex()
+            else getByCloud()  */
+            if(canUseDepthTex && !this.isMeasuring){
                 getByDepthTex()
-            } */
-        }  
-        
+            }else{
+                getByCloud() 
+                /* if(!intersectPoint && canUseDepthTex  ){  //若在测量,先尝试点云,再用全景 //后来发现有深度图的点云全景visibleNode为空,pick不到的//如果允许的话,裁剪掉的点云也会得到intersect
+                    getByDepthTex()
+                } */
+            }  
+            
         
                    
 
          
         //console.log(viewport.name , intersectPoint &&  intersectPoint.location )
-        let intersect
-        let intersectOnModel, allElements
-       
         
-        if(Potree.settings.intersectOnObjs && !dontIntersect){
-            if(prop.point){
-                raycaster = new THREE.Raycaster() 
-                var dir = new THREE.Vector3().subVectors(prop.point, camera.position).normalize()
-                raycaster.set(camera.position, dir) //var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
-            }  
-            
-            
-            allElements = this.getHoveredElements(viewer.objs.children, true, raycaster)
-            
-            
-            if(allElements[0]){
-                intersectOnModel = {//模拟点云的intersectPoint的结构写法
-                    hoveredElement : allElements[0] ,
-                    location: allElements[0].point,
-                    //point: {normal: allElements[0].face.normal },
-                    normal: allElements[0].face && allElements[0].face.normal,
-                    distance: allElements[0].distance,
-                    object: allElements[0].object
-                } 
+            if(Potree.settings.intersectOnObjs && !dontIntersect){
+                if(point){
+                    raycaster = new THREE.Raycaster() 
+                    var dir = new THREE.Vector3().subVectors(point, camera.position).normalize()
+                    raycaster.set(camera.position, dir) //var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
+                }  
+                
+                
+                allElements = this.getHoveredElements(viewer.objs.children, true, raycaster)
+                
+                
+                if(allElements[0]){
+                    intersectOnModel = {//模拟点云的intersectPoint的结构写法
+                        hoveredElement : allElements[0] ,
+                        location: allElements[0].point,
+                        //point: {normal: allElements[0].face.normal },
+                        normal: allElements[0].face && allElements[0].face.normal,
+                        distance: allElements[0].distance,
+                        object: allElements[0].object
+                    } 
+                }
+                
+                 
             }
             
-             
-        }
-        
-        if(intersectPoint && intersectOnModel){
-            if(intersectPoint.distance < intersectOnModel.distance){
-                intersect = intersectPoint
+            if(intersectPoint && intersectOnModel){
+                if(intersectPoint.distance < intersectOnModel.distance){
+                    intersect = intersectPoint
+                }else{
+                    intersect = intersectOnModel
+                } 
             }else{
-                intersect = intersectOnModel
-            } 
-        }else{
-            intersect = intersectOnModel || intersectPoint
-        }                
-          
+                intersect = intersectOnModel || intersectPoint
+            }  
+        }
         
         if(viewport.camera.type == 'OrthographicCamera'/*  == 'mapViewport' */){ 
             let pos3d = new THREE.Vector3(this.pointer.x,this.pointer.y,-1).unproject(viewport.camera); //z:-1朝外   
@@ -980,30 +1038,20 @@ export class InputHandler extends THREE.EventDispatcher {
             let dontIntersect =  this.drag && viewport.alignment || isFlying /* viewer.images360.flying */ // flying 时可能卡顿
             //console.log('dontIntersectPointcloud',dontIntersectPointcloud)
                
-            intersect = this.getIntersect(viewport,  e.onlyGetIntersect, e.pickWindowSize, !!dontIntersect, e.whichPointcloud || e.usePointcloud || this.drag) //深度图不准,尽量用点云
+            intersect = this.getIntersect(Object.assign({}, e, {viewport,  dontIntersect, clientX:e.clientX, clientY:e.clientY })) //数据集多的时候卡顿
              
 	                 
             //console.log('intersectPoint', intersectPoint)
         } 
         
         if(e.onlyGetIntersect){ 
-            /* if(Potree.settings.intersectOnObjs){
-                let hoveredElements = this.getHoveredElements() //应该不用发送mouseover事件吧
-                let intersect = this.getWholeIntersect(hoveredElements, intersectPoint)
-                return intersect
-            }
-         
-            return intersectPoint */
+          
             return intersect
         }
         e.preventDefault();
          
         
-        /* if(intersectPoint && intersectPoint.pointcloud){
-            console.log(intersectPoint.pointcloud.name)
-        } */
-            
-        
+       
         if (this.drag) {//有拖拽(不一定拖拽了物体, 也不一定按下了鼠标)
             this.drag.mouse = isTouch ? 1 : e.buttons; 
             //add:
@@ -1335,7 +1383,7 @@ export class InputHandler extends THREE.EventDispatcher {
                     }
                 });
             }  
-		}  
+		}else interactables = interactables.filter(e=>e.visible)
 		 
 		let camera = this.hoverViewport.camera
         if(!raycaster){ 
@@ -1360,7 +1408,7 @@ export class InputHandler extends THREE.EventDispatcher {
         //this.hoverViewport.beforeRender && this.hoverViewport.beforeRender()
         
         viewer.dispatchEvent( {type:'raycaster',  viewport: this.hoverViewport})//add
-		let intersections = raycaster.intersectObjects(interactables.filter(o => o.visible), true, null, true); //原本是false 检测不到children
+		let intersections = raycaster.intersectObjects(interactables , true, null, true); //原本是false 检测不到children
     
         let intersectionsCopy = intersections.slice()
         

+ 12 - 10
src/viewer/NavigationCube.js

@@ -26,7 +26,8 @@ import {OrbitControls} from "../navigation/OrbitControlsNew.js";
 const Colors = {
     black : '#161A1A',
     blue: '#3290ff',
-    gray: '#878585' ,
+    gray: '#f6f6f6' ,
+    grayDeep:'#f3f3f3',
     white:'#ffffff'
 }
 
@@ -37,10 +38,10 @@ let navCubeViewer
 
 class base{
     constructor(){
-        this.faceDefaultColor = Colors.black//14936556,
-        this.wireframeDefaultColor = 13421772,
+        this.faceDefaultColor = Colors.gray//14936556,
+        /* this.wireframeDefaultColor = 13421772,
         this.faceHighlightColor = 12255212,
-        this.wireframeHighlightColor = 3330982
+        this.wireframeHighlightColor = 3330982 */
     }
 
 
@@ -51,7 +52,7 @@ class base{
             n[o++] = s + 1;
         var r = new THREE.MeshBasicMaterial({
             color: this.faceDefaultColor,
-            side: THREE.DoubleSide
+            side: THREE.DoubleSide, 
         })
           , a = new Float32Array(3 * e.length);
         t.setAttribute("position", new THREE.BufferAttribute(a,3).copyVector3sArray(e)),
@@ -63,7 +64,7 @@ class base{
      
     createWireframe(e ) { 
         let line = LineDraw.createFatLine(e,{
-	        color: Colors.white , 
+	        color: Colors.grayDeep , 
 			lineWidth : 2,
             viewer:   navCubeViewer,
             depthTest:true, depthWrite:true,
@@ -379,8 +380,8 @@ class Face extends base{
             side: THREE.DoubleSide,
             transparent: !1, 
             uniforms:{
-                faceColor: {type:'v3',   value:  new THREE.Color(Colors.black)  } , 
-                textColor: {type:'v3',   value:  new THREE.Color(Colors.white)  } , 
+                faceColor: {type:'v3',   value:  new THREE.Color(Colors.white)  } , 
+                textColor: {type:'v3',   value:  new THREE.Color(Colors.black)  } , 
                 map: {type: 't',    value: this.texture },
             },
             vertexShader:`
@@ -575,7 +576,7 @@ class NavigationCube{
                 });
                 faceMesh.addEventListener('mouseleave', (e)=>{
                     if(viewer.mainViewport.view.isFlying())return
-                    faceMesh.material.uniforms.faceColor.value.set(Colors.black)
+                    faceMesh.material.uniforms.faceColor.value.set(Colors.white)
                     //console.log('回', name)
                     navCubeViewer.dispatchEvent('content_changed')
                 });
@@ -591,7 +592,7 @@ class NavigationCube{
                     }                        
                      
                     navCubeViewer.switchView('ortho', dir, ()=>{ 
-                        faceMesh.material.uniforms.faceColor.value.set(Colors.black)
+                        faceMesh.material.uniforms.faceColor.value.set(Colors.white)
                         viewer.dispatchEvent({type:'viewChanged', name })
                     }) 
                     faceMesh.material.uniforms.faceColor.value.set(Colors.blue) 
@@ -656,6 +657,7 @@ class NavigationCube{
 class NavCubeViewer extends ViewerBase{
    constructor(domElement, listenViewport){
         super(domElement,  {name:'navCube', antialias:true/* , preserveDrawingBuffer:true */} )
+        domElement.style.opacity = 0.9
         
         navCubeViewer = this 
         this.scene = new THREE.Scene