xzw il y a 2 ans
Parent
commit
fac116b7f5

+ 6 - 4
src/ExtendPointCloudOctree.js

@@ -34,6 +34,8 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
         this.rotateMatrix = new THREE.Matrix4;
         this.transformMatrix = new THREE.Matrix4;// 数据集的变化矩阵
         this.transformInvMatrix = new THREE.Matrix4; 
+        /* this.transformMatrix2 = new THREE.Matrix4;// 数据集的变化矩阵
+        this.transformInvMatrix2 = new THREE.Matrix4;  */
         this.rotateInvMatrix = new THREE.Matrix4; 
         
         
@@ -74,7 +76,7 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
             this.nodeMaxLevel = level 
             //viewer.dispatchEvent({type:'updateNodeMaxLevel', pointcloud: this, nodeMaxLevel:level}) 
              
-            console.log('updateNodeMaxLevel ' + this.dataset_id + " : "+ this.nodeMaxLevel)                
+            //console.log('updateNodeMaxLevel ' + this.dataset_id + " : "+ this.nodeMaxLevel)                
               
             this.setPointLevel()//重新计算
              
@@ -600,10 +602,10 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
                         opacity = THREE.Math.clamp(opacity, 0, 0.999) //到1就不透明了(可能出现一段一样)
                     }
                 }else{
-                    let base = this.material.spacing / Math.pow(1.8, this.maxLevel) 
-                    let minBase = this.material.spacing / Math.pow(1.8, this.nodeMaxLevel)
+                    let base = this.material.spacing / Math.pow(2, this.maxLevel) 
+                    let minBase = this.material.spacing / Math.pow(2, this.nodeMaxLevel)
                     //console.log(1 / base, 1 / minBase / 6)
-                    let ratio = Math.min(1 / base, 1 / minBase / 6) //ratio为一个能使opacity不大于1 的 乘量,minBase要除以一个数,该数调越大减弱效果越强。level越低opacity和面板越接,level越高效果越弱,以减免过度重叠后的亮度。
+                    let ratio = Math.min(1 / base, 1 / minBase / 3) //ratio为一个能使opacity不大于1 的 乘量,minBase要除以一个数,该数调越大减弱效果越强。level越低opacity和面板越接,level越高效果越弱,以减免过度重叠后的亮度。
                     opacity = base * ratio * num
                     if(!canMoreThanOne){
                         opacity = THREE.Math.clamp(opacity, 0, 0.999) //到1就不透明了(可能出现一段一样)

+ 4 - 2
src/PotreeRendererNew.js

@@ -911,6 +911,8 @@ export class Renderer {
 			//shader.setUniformMatrix4("modelMatrix", world);
 			//shader.setUniformMatrix4("modelViewMatrix", worldView);
 			shader.setUniform1f("uLevel", level);
+            //shader.setUniform1f("levelPercent", octree.nodeMaxLevel ? level / octree.nodeMaxLevel : 0.5);//xzw add
+            
 			shader.setUniform1f("uNodeSpacing", node.geometryNode.estimatedSpacing);
 
 			shader.setUniform1f("uPCIndex", i);
@@ -1524,11 +1526,11 @@ export class Renderer {
 			gl.bindTexture(classificationTexture.target, classificationTexture.id);
 			currentTextureBindingPoint++;
 
-			let matcapTexture = this.textures.get(material.matcapTexture);
+			/* let matcapTexture = this.textures.get(material.matcapTexture);
 			shader.setUniform1i("matcapTextureUniform", currentTextureBindingPoint);
 			gl.activeTexture(gl.TEXTURE0 + currentTextureBindingPoint);
 			gl.bindTexture(matcapTexture.target, matcapTexture.id);
-			currentTextureBindingPoint++;
+			currentTextureBindingPoint++; */
 
             
             

+ 1 - 0
src/custom/materials/BasicMaterial.js

@@ -50,6 +50,7 @@ class BasicMaterial  extends THREE.ShaderMaterial{
         }else{
             delete this.defines.HasMap
         }
+        //可能需要needsUpdate
         //console.log('hasMap', !!o, this.name111 )
     } 
     get map(){

+ 30 - 15
src/custom/materials/ModelTextureMaterial.js

@@ -203,7 +203,7 @@ let shader = {
                 
                 vec2 getDepth(vec3 dir, sampler2D depthMap, float heightDown, float heightUp, vec4 eyePos){
                     vec2 depthValue = vec2(0.0, 0.0);
-                    vec2 uv2 = getSamplerCoord2(/* vWorldPosition12 */dir.xyz);  //暂时只用基于目标漫游点的方向
+                    vec2 uv2 = getSamplerCoord2( dir.xyz);  //暂时只用基于目标漫游点的方向
                     uv2.x -= 0.25;    //全景图和Cube的水平采样起始坐标相差90度,这里矫正 0.25 个采样偏移
                     vec4 depth = texture2D(depthMap, uv2);
                     //float distance = depth.r + 256. * (depth.g + 256. * depth.b);
@@ -241,15 +241,13 @@ let shader = {
             {
                 vec3 vWorldPosition0N = normalize(vWorldPosition0);
                 vec3 vWorldPosition1N = normalize(vWorldPosition1);
-                /* vec2 samplerCoord0 = getSamplerCoord(vWorldPosition0.xyz);
-                vec2 samplerCoord1 = getSamplerCoord(vWorldPosition1.xyz);  
-                vec4 colorFromPano0=texture2D(pano0Map,samplerCoord0);
-                vec4 colorFromPano1=texture2D(pano1Map,samplerCoord1); */
+               
                 
                 vec4 colorFromPano0 = vec4(0.0,0.0,0.0,0.0);
-                if(progress < 1.0){//通常是1
+                #if defined(usePanoMap0)
+                    //即progress < 1.0   通常是1
                     colorFromPano0=textureCube(pano0Map,vWorldPosition0N.xyz);
-                }
+                #endif
                 vec4 colorFromPano1=textureCube(pano1Map,vWorldPosition1N.xyz);
  
                 gl_FragColor=mix(colorFromPano0,colorFromPano1,progress);
@@ -269,16 +267,14 @@ let shader = {
                     vec4 clipPos = ndcPos / gl_FragCoord.w;
                     vec4 eyePos = inverseProjectionMatrix * clipPos;
                     vec2 depth0 = vec2(0.0,0.0); 
-                    if(progress < 1.0){
+                    #if defined(usePanoMap0)
                         depth0 = getDepth(vWorldPosition0N, depthMap0, cameraHeight0, ceilHeight0, eyePos);
-                    }
+                    #endif
                     vec2 depth1 = getDepth(vWorldPosition1N, depthMap1, cameraHeight1, ceilHeight1, eyePos);
                     
-                    /* if(progress < 1.0 && depth1.x == 0.0 && depth0.x > 0.0){
-                        gl_FragDepthEXT = depth0.y; 
-                    }else{ */
-                        gl_FragDepthEXT = mix(depth0.y,depth1.y,progress);
-                    //}
+                    
+                    gl_FragDepthEXT = mix(depth0.y,depth1.y,progress);
+                    
                     
                     
 
@@ -341,7 +337,26 @@ export default class ModelTextureMaterial extends THREE.RawShaderMaterial {
 
         } 
 
-        
+        let progress = 0
+        Object.defineProperty(this.uniforms.progress, 'value', {
+            get: function () {
+                return progress
+            },
+            set: e => {
+                if (e < 1) {
+                    if (!('usePanoMap0' in this.defines)) {
+                        this.defines.usePanoMap0 = ''
+                        this.needsUpdate = true
+                    }
+                } else {
+                    if ('usePanoMap0' in this.defines) {
+                        delete this.defines.usePanoMap0
+                        this.needsUpdate = true
+                    }
+                }
+                progress = e
+            },
+        })
 		//-------------------------------------
 	}
 

+ 17 - 5
src/custom/mergeStartTest.js

@@ -312,10 +312,18 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
         
         let loadDone = (model)=>{ 
             if(isFirstLoad){
-                modelEditing = model;
-                MergeEditor.setModelBtmHeight(model, 0) //默认离地高度为0
-                viewer.addEventListener('global_mousemove', moveModel); 
-                viewer.addEventListener('global_click', confirmPos, 3);
+                modelEditing = model; 
+                MergeEditor.setModelBtmHeight(model, 0) //默认离地高度为0                
+                if(name == '3dTiles'){
+                    setTimeout(()=>{
+                        moveModel({pointer:{x:0,y:0}}) //3dTiles的移动会错乱,先默认放在当前视图中间吧 
+                        confirmPos()
+                    },1)
+                }else{
+                    
+                    viewer.addEventListener('global_mousemove', moveModel); 
+                    viewer.addEventListener('global_click', confirmPos, 3);
+                } 
             }else{
                 modelEditing = null
             }
@@ -527,7 +535,11 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                  
                 viewer.loadModel({ 
                     fileType:'3dTiles',
-                     url: 'https://4dkk.4dage.com/fusion/test/b3dm/tileset.json',
+                    //url: 'https://4dkk.4dage.com/fusion/test/b3dm/tileset.json',
+                    //url: 'https://4dkk.4dage.com/fusion/test/b3dmtest001/tileset.json',
+                     //url: 'https://4dkk.4dage.com/fusion/test/model/modelId_570/3dt/3dtiles.json', //only has boundingVolume.sphere
+                    url: 'https://4dkk.4dage.com/fusion/test/model/modelId_602/Tile_016_011/tileset.json',
+                    
                     transform : { 
                         rotation : [Math.PI/2,  0,   0],
                         position : [0,0,0]  

+ 3 - 2
src/custom/modules/datasetAlignment/Alignment.js

@@ -230,7 +230,8 @@ var Alignment = {
          
         var matrix = new THREE.Matrix4().multiplyMatrices(pos2Matrix, rotMatrix);
         pointcloud.transformMatrix = matrix.clone();//为该数据集的变化矩阵。 对应navvis的m2w_
-        pointcloud.transformInvMatrix.copy(matrix).invert()
+        pointcloud.transformInvMatrix.copy(pointcloud.transformMatrix).invert() 
+        
         pointcloud.rotateMatrix = rotMatrix
         pointcloud.rotateInvMatrix.copy(rotMatrix).invert()
         
@@ -240,7 +241,7 @@ var Alignment = {
         
         matrix = new THREE.Matrix4().multiplyMatrices(matrix, pos1Matrix);
         
-        
+        //matrix.premultiply(viewer.scene.scene.matrix);////////////////////////add
         
         pointcloud.matrix = matrix;
         //pointcloud.matrixWorldNeedsUpdate = true //更新matrixWorld (非计算,直接赋值)

+ 145 - 61
src/custom/modules/panoEdit/panoEditor.js

@@ -14,8 +14,8 @@ import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
 import {BoxVolume} from '../../../utils/VolumeNew.js'
 
 
-let clickPanoToDisLink = false;//是否在编辑漫游点连接时,通过点击漫游点能断开连接
-let images360, Alignment,  SiteModel 
+const clickPanoToDisLink = false;//是否在编辑漫游点连接时,通过点击漫游点能断开连接
+let images360, Alignment,  SiteModel, suggestCircleMat
 
 const texLoader = new THREE.TextureLoader() 
     texLoader.crossOrigin = "anonymous" 
@@ -23,6 +23,7 @@ const rotQua = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1),
 const lineMats = {}
 const circleMats = {}
  
+
 const renderOrders = {
     circleSelected:3,
     circle:2,
@@ -72,7 +73,7 @@ class PanoEditor extends THREE.EventDispatcher{
     
     constructor(){
         super()
-        this.panoGroup = [], //分组
+        this.panoGroup = [], //分组 
         this.viewports = {},
         this.panoLink = {}, 
         this.panoMeshs = new THREE.Object3D,
@@ -85,6 +86,8 @@ class PanoEditor extends THREE.EventDispatcher{
         this.selectedGroup;
         this.operation; 
         this.visiblePanos = []
+        
+        this.suggestLines = []
     }
      
     init(){ 
@@ -106,10 +109,18 @@ class PanoEditor extends THREE.EventDispatcher{
                 lineWidth: 3,   
                 depthTest:false   
             }) 
-             
+            lineMats.suggestLink = LineDraw.createFatLineMat({
+                color: '#ff2222',  
+                lineWidth: 4,     dashed:true,
+                depthTest:false   
+            }) 
         }
     
-        
+        suggestCircleMat = new THREE.MeshBasicMaterial({
+            map: texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' ) ,  
+            color:'#ff2222',  transparent:true,  
+            depthTest:false, depthWrite:false  
+        })
         
         this.initViews()
         
@@ -285,7 +296,7 @@ class PanoEditor extends THREE.EventDispatcher{
             } */
             
             {//连接时的辅助线
-                this.linkGuideLine = LineDraw.createLine([], {color:'#aaa', deshed:true, dashSize:0.1,gapSize:0.1,})
+                this.linkGuideLine = LineDraw.createLine([], {color:'#ddd', deshed:true, dashSize:0.1,gapSize:0.05, depthTest:false})
                 this.linkGuideLine.visible = false
                 this.linkGuideLine.name = 'linkGuideLine'
                 viewer.scene.scene.add(this.linkGuideLine)
@@ -298,21 +309,22 @@ class PanoEditor extends THREE.EventDispatcher{
                     if(this.activeViewName == 'top' ){
                         endPos = e.intersect.orthoIntersect.clone().setZ(this.selectedPano.position.z)
                     }else if(this.activeViewName == 'mainView' ){
-                        if(!e.intersect.point)return
+                        if(!e.intersect || !e.intersect.point)return
                         endPos = e.intersect.point.position
                     }
                     
                     LineDraw.updateLine(this.linkGuideLine, [this.selectedPano.position, endPos] )  
                     this.linkGuideLine.visible = true 
+                    
                     viewer.dispatchEvent('content_changed')  
                 }
                 
-                viewer.addEventListener('global_mousemove', (e)=>{
+                viewer.addEventListener('global_mousemove', (e)=>{ 
                     update(e)  
                 })
                  
-                this.addEventListener('updateLinkGuideLine', update)
-                //为何打开调试时移动很卡
+                //this.addEventListener('updateLinkGuideLine', update)
+                
             }
             
             /* 
@@ -323,7 +335,7 @@ class PanoEditor extends THREE.EventDispatcher{
                     this.setTranMode('translate') 
                 }
             }) */      
-            { 
+            /* { 
                 viewer.addEventListener('camera_changed', (e)=>{ 
                     Common.intervalTool.isWaiting('updatePointLevels', ()=>{  
                         this.updatePointLevels()
@@ -333,7 +345,7 @@ class PanoEditor extends THREE.EventDispatcher{
                 setTimeout(()=>{ 
                     this.updatePointLevels()
                 }, viewer.scene.pointclouds.length*150)  //等待差不多updat出了正确的visibleNode时                
-            }
+            } */
             
             
             
@@ -353,6 +365,13 @@ class PanoEditor extends THREE.EventDispatcher{
         }else{
             Alignment.switchHandle(mode) 
         } 
+        this.updateIntersectEnable()
+    }
+    
+    updateIntersectEnable(){
+        //侧面容易因intersect卡住, 如果非必要关闭intersect. 3d页面也会卡,但controls需要所以不能去掉
+        Potree.settings.intersectWhenHover = !!(this.activeViewName == 'mainView' || this.selectedPano && this.tranMode )
+         
     }
     
     updateTranCtl(){// 设置3D页面的transformControls相关
@@ -386,7 +405,7 @@ class PanoEditor extends THREE.EventDispatcher{
             let view = new ExtendView()  
             this.views[prop.name] = view 
             this.cameras[prop.name] = this.orthoCamera
-             
+            view.name = prop.name
             view.direction = prop.direction
         }
         this.views.mainView = viewer.mainViewport.view
@@ -574,9 +593,9 @@ class PanoEditor extends THREE.EventDispatcher{
         this.updateTranCtl()
         this.setTranMode(this.tranMode) // update
         this.setZoomInState(false) //取消放大模式
-        this.updatePointLevels() 
+        //this.updatePointLevels() 
        
-         
+        this.updateIntersectEnable() 
         
         prop.openCount ++; 
     }
@@ -728,13 +747,13 @@ class PanoEditor extends THREE.EventDispatcher{
          
         informBy2d || this.dispatchEvent({type:"switchPanoVisible", pano, v})
         
-        { 
+        /* { 
             setTimeout(()=>{
                 Common.intervalTool.isWaiting('updatePointLevels2', ()=>{  
                     this.updatePointLevels() 
                 }, 50)
             },1)//等update过visibleNodes
-        }
+        } */
     } 
      
     
@@ -830,6 +849,7 @@ class PanoEditor extends THREE.EventDispatcher{
     initPanoLink(){
         images360.panos.forEach((pano)=>{
             this.panoLink[pano.id] = {}
+            this.panoGroup.push([pano])
         })
          
         images360.panos.forEach((pano)=>{
@@ -840,42 +860,8 @@ class PanoEditor extends THREE.EventDispatcher{
         
         //console.log('panoLink',this.panoLink)
     }
-     
     
-     
-    groupChange(pano0, pano1, type){//修改group (type == 'remove'时,pano1可以为空)
-        if(type == 'add'){
-            Common.pushToGroupAuto([pano0, pano1], this.panoGroup  )
-        }else{ 
-            let atGroup = this.panoGroup.find(e=>e.includes(pano0) && (e.includes(pano1) || !pano1));//所在组
-            
-            if(!atGroup){
-                if(pano1){
-                    console.log('这两个pano原本就不在一个组', pano0.id, pano1.id)
-                }else{
-                    console.log('pano0不在任何组', pano0)
-                }
-                return 
-            }
-            
-            //断开连接时,因为组内没有其他成员的连接信息,所以需要清除整组,并将剩余的一个个重新连接
-            this.panoGroup.splice(this.panoGroup.indexOf(atGroup),1) //删除
-            
-            
-            atGroup.forEach(pano=>{//然后再重新生成这两个和组的关系,各自分组
-                if(pano == pano0 || pano == pano1)return
-                for(let id in this.panoLink[pano.id]){
-                    if(this.panoLink[pano.id][id]){
-                        let pano_ = images360.getPano(id)
-                        Common.pushToGroupAuto([pano, pano_], this.panoGroup  )
-                    } 
-                } 
-            })
-            
-            
-            
-        }
-    } 
+    
     
     linkChange(pano0, pano1, type){//修改link  (type == 'remove'时,pano1可以为空)
         
@@ -915,12 +901,13 @@ class PanoEditor extends THREE.EventDispatcher{
         this.selectPano(this.selectedPano, false,true) //更新选中点云显示
     } 
     
+     
     
     
     lineChange(pano0, pano1, type){//修改line
         if(type == 'add'){
             if(this.panoLink[pano0.id][pano1.id].line) return 
-            let line = LineDraw.createFatLine([pano0.position, pano1.position], {material:lineMats.default})
+            let line = LineDraw.createFatLine([pano0.position, pano1.position], {mat:lineMats.default})
             line.name = `${pano0.id}-${pano1.id}`
             line.renderOrder = line.pickOrder = renderOrders.line
             this.lineMeshes.add(line) 
@@ -965,6 +952,39 @@ class PanoEditor extends THREE.EventDispatcher{
     
     
     
+    groupChange(pano0, pano1, type){//修改group (type == 'remove'时,pano1可以为空)
+        if(type == 'add'){
+            Common.pushToGroupAuto([pano0, pano1], this.panoGroup  )
+        }else{ 
+            let atGroup = this.panoGroup.find(e=>e.includes(pano0) && (e.includes(pano1) || !pano1));//所在组
+            
+            if(!atGroup){
+                if(pano1){
+                    console.log('这两个pano原本就不在一个组', pano0.id, pano1.id)
+                }else{
+                    console.log('pano0不在任何组', pano0)
+                }
+                return 
+            }
+            
+            //断开连接时,因为组内没有其他成员的连接信息,所以需要清除整组,并将剩余的一个个重新连接
+            this.panoGroup.splice(this.panoGroup.indexOf(atGroup),1) //删除
+            
+            
+            atGroup.forEach(pano=>{//然后再重新生成这两个和组的关系,各自分组 
+                this.panoGroup.push([pano])
+                for(let id in this.panoLink[pano.id]){
+                    if(this.panoLink[pano.id][id]){
+                        let pano_ = images360.getPano(id)
+                        Common.pushToGroupAuto([pano, pano_], this.panoGroup  )
+                    } 
+                } 
+            }) 
+        }
+    } 
+    
+    
+    
     
     selectLine(line){
         if(this.selectedLine == line)return
@@ -1027,6 +1047,8 @@ class PanoEditor extends THREE.EventDispatcher{
         circleMats.hovered_rtk_off.useDepth = false         
         
         
+         
+        
         
         let setPos = (circle)=>{
              circle.position.copy(circle.pano.position)
@@ -1198,7 +1220,7 @@ class PanoEditor extends THREE.EventDispatcher{
             }
              
             
-            {//自动切换楼层
+            if(this.currentFloor != 'all'){//如果原本不是展示全部楼层的话,自动切换楼层
                
                 let atFloor = SiteModel.entities.find(e=>e.buildType == 'floor' && e.panos.includes(pano))
                 if(!atFloor){
@@ -1237,19 +1259,19 @@ class PanoEditor extends THREE.EventDispatcher{
             this.dispatchEvent({type:'panoSelect', pano })
         } 
         
-         
-        
+       
+        this.updateIntersectEnable()
         viewer.dispatchEvent('content_changed') 
     }
     
     
     
-    updatePointLevels(){
+    /* updatePointLevels(){
         if(this.pauseUpdateLevels)return
         let maxBudget = Potree.config.pointDensity.panoEdit.pointBudget
         let visiCount1 = viewer.scene.pointclouds.filter(e=>e.visible).length
         let visiCount2 = viewer.scene.pointclouds.filter(e=>e.visibleNodes.length>0).length //屏幕范围内可见的个数
-        let maxCount = 200, minCount = 1,  minPer = 0.45/* 0.4 */, maxPer = 1
+        let maxCount = 200, minCount = 1,  minPer = 0.45 , maxPer = 1
         let percent1 = maxPer - ( maxPer - minPer) * THREE.Math.clamp((visiCount1 - minCount)  / (maxCount - minCount),0,1)   
         let percent2 = maxPer - ( maxPer - minPer) * THREE.Math.clamp((visiCount2 - minCount)  / (maxCount - minCount),0,1)   
         let percent = percent1*percent2
@@ -1270,7 +1292,7 @@ class PanoEditor extends THREE.EventDispatcher{
         viewer.setPointLevels() 
         //侧面容易卡顿,但和显示的点数无关,似乎是因加载点云多而卡?为何正面不会
         //console.warn('setPointBudget', Potree.pointBudget, visiCount1,visiCount2,  Potree.settings.UserDensityPercent)
-    }
+    } */
     
     getPanoRtkState(pano){
         return pano.panosData.has_rtk ? pano.rtkState ? 'rtk_on' : 'rtk_off' : 'normal'
@@ -1287,7 +1309,8 @@ class PanoEditor extends THREE.EventDispatcher{
             this.selectedGroup = [this.selectedPano, ...this.selectedGroup.filter(e=>e != this.selectedPano)];//将选中的放第一个,便于旋转时绕其旋转。
         }
         
-        this.selectedClouds = this.selectedPano ? (this.selectedGroup || [this.selectedPano]).map(e=>e.pointcloud) : []
+        //this.selectedClouds = this.selectedPano ? (this.selectedGroup || [this.selectedPano]).map(e=>e.pointcloud) : []
+        this.selectedClouds = this.selectedPano ? this.selectedGroup.map(e=>e.pointcloud) : []
     
         
     }
@@ -1325,7 +1348,68 @@ class PanoEditor extends THREE.EventDispatcher{
         return panos.length == group.length
     }
     
-   
+    
+    
+    
+    getSuggestLinkPanos(){//给出建议连接的点
+        let panos = [];
+        let startTime = Date.now()
+        for(let datasetId in Potree.settings.datasetsPanos ) {
+            if(!this.checkIfAllLinked({datasetId})){ 
+                let groups = this.panoGroup.filter(panos=>panos[0].pointcloud.dataset_id == datasetId )
+                groups = groups.sort((a,b)=>{return b.length - a.length})//找出个数最多的一组来连接其他组
+                 
+                let mainGroup = groups[0].slice(),  subGroup;
+                
+                for(let i=1,len=groups.length;i<len;i++){ 
+                    subGroup = groups[i]
+                    
+                    let minDis = {dis:Infinity, panos:[]}
+                    for(let a=0, len1=mainGroup.length; a<len1; a++){
+                        for(let b=0, len2=subGroup.length; b<len2; b++){
+                            
+                            let dis = mainGroup[a].position.distanceToSquared(subGroup[b].position)
+                            if(dis<minDis.dis){
+                                minDis.dis = dis;  minDis.panos = [mainGroup[a], subGroup[b]]
+                            }
+                        }
+                    }
+                    panos.push(minDis.panos)
+                     
+                    //console.log('第i次',minDis)
+                    mainGroup.push(...subGroup)//连接后,加入集合
+                }
+                 
+            }
+        }
+        //console.log('cost', Date.now() - startTime)
+        return panos  
+        
+    }
+    
+    
+    
+    showSuggestLinkPanos(){
+        let groups = this.getSuggestLinkPanos()
+        let s = 0.7
+        let createCircle = (pano)=>{
+            let circle = new THREE.Mesh(pano.circle.geometry, suggestCircleMat)
+            circle.name = 'suggest-circle'  
+            circle.scale.set(s,s,s)
+            circle.renderOrder = 100
+            pano.circle.add(circle)
+        }
+        groups.forEach(panos=>{
+            createCircle(panos[0])
+            createCircle(panos[1])
+            let line = LineDraw.createFatLine([panos[0].position, panos[1].position], {mat: lineMats.suggestLink})
+            this.suggestLines.push(line)
+            line.renderOrder = renderOrders.line
+            viewer.scene.scene.add(line)
+        })
+        
+    }
+    
     
     getPanoPose(pano){
         let pose = {

+ 35 - 39
src/custom/modules/panos/DepthImageSampler.js

@@ -42,29 +42,32 @@ class DepthImageSampler extends THREE.EventDispatcher{
             //console.log('重复使用',item.pano.id)
             return
         }
-        
-        viewer.addTimeMark('depthSampler','start')
-        this.canvas.width = img.width 
-        this.canvas.height = img.height 
-        this.context.drawImage(img, 0, 0) 
-        let data = this.context.getImageData(0, 0, img.width , img.height ).data;     //getImageData 1px时 : pc chrome 耗时0.01毫秒左右(排除第一次的50) , 但firefox: 4。但换贴图之后就多达5甚至几十  
-        //console.log('changeImg',pano.id ) 
-        //this.img = img
-         
-         
-        if(this.imgDatas.length >= this.maxDataCount){
-            let old = this.imgDatas.find(e=>!this.nearPanos.includes(e.pano))   
-            //console.log('推出',old.pano.id)
-            this.imgDatas.splice(this.imgDatas.indexOf(old), 1)//推出使用时间最早的一个非nearPano
-        } 
-        this.imgDatas.push({pano, data})
-        
-        
-        
-        this.dispatchEvent({type:'changeImg',pano})
-        viewer.addTimeMark('depthSampler','end') //耗时chrome 25ms,firefox: 38ms, iphoneX:33ms
-        
-        
+        try{
+            viewer.addTimeMark('depthSampler','start')
+            this.canvas.width = img.width 
+            this.canvas.height = img.height 
+            this.context.drawImage(img, 0, 0) 
+            let data = this.context.getImageData(0, 0, img.width , img.height ).data;     //getImageData 1px时 : pc chrome 耗时0.01毫秒左右(排除第一次的50) , 但firefox: 4。但换贴图之后就多达5甚至几十  
+            //console.log('changeImg',pano.id ) 
+            //this.img = img
+             
+             
+            if(this.imgDatas.length >= this.maxDataCount){
+                let old = this.imgDatas.find(e=>!this.nearPanos.includes(e.pano))   
+                //console.log('推出',old.pano.id)
+                this.imgDatas.splice(this.imgDatas.indexOf(old), 1)//推出使用时间最早的一个非nearPano
+            } 
+            this.imgDatas.push({pano, data})
+            
+            
+            
+            this.dispatchEvent({type:'changeImg',pano})
+            viewer.addTimeMark('depthSampler','end') //耗时chrome 25ms,firefox: 38ms, iphoneX:33ms
+            
+        }catch(e){
+            console.error(e ) //内存不足  Failed to execute 'getImageData' on 'CanvasRenderingContext2D': Out of memory at ImageData creation
+            return false
+        }
         
          /* pano.depthData = {}
         for(let h=0; h<img.height; h++){
@@ -86,13 +89,9 @@ class DepthImageSampler extends THREE.EventDispatcher{
         
         if (!(x < 0 || y < 0 || x >= this.canvas.width || y >= this.canvas.height)) { 
          
-            /* viewer.addTimeMark('depthSampler','start')
-            
+            /* viewer.addTimeMark('depthSampler','start') 
             var r = this.context.getImageData(x, y, 1, 1).data;     //pc chrome 耗时0.01毫秒左右(排除第一次的50) , 但firefox: 4。但换贴图之后就多达5甚至几十  
-            
-            viewer.addTimeMark('depthSampler','end')
-            
-             
+            viewer.addTimeMark('depthSampler','end') 
             //console.log('color', r, x,y)
             return r[1] + r[0] / 256 */
             let imgData = this.imgDatas.find(p=>p.pano == this.pano)
@@ -116,20 +115,17 @@ class DepthImageSampler extends THREE.EventDispatcher{
         let normal
         currentPano = currentPano || viewer.images360.currentPano
         
-        //let markName 
          
-        
         if(currentPano != this.currentPano){
             if(!currentPano.depthTex/*  || !currentPano.depthTex.image  */) return //未加载
-             
-            /* markName = 'depthSampleChangeTex'
-            viewer.addTimeMark(markName,'start') */
-            this.changeImg(currentPano.depthTex.image, currentPano)
+           
+            if(this.changeImg(currentPano.depthTex.image, currentPano) === false){
+                console.log('失败', currentPano.id)
+                return false //失败
+            }
+            
             this.currentPano = currentPano
-        }/* else{
-            markName = 'depthSampleSame'
-            viewer.addTimeMark(markName,'start')
-        } */
+        } 
         
         let origin = currentPano.position
         let dir = intersect.dir || new THREE.Vector3().subVectors(intersect.point, origin).normalize()

+ 38 - 79
src/custom/modules/panos/Images360.js

@@ -632,7 +632,7 @@ export class Images360 extends THREE.EventDispatcher{
 
 	cancelFlyToPano(toPano){//取消当前已有的飞行准备,前提是相机还未移动 
         if(viewer.mainViewport.view.isFlying() || toPano && this.latestToPano != toPano)return
-         Potree.Log('cancelFlyToPano', this.latestToPano && this.latestToPano.pano.id)
+        //Potree.Log('cancelFlyToPano', this.latestToPano && this.latestToPano.pano.id)
         this.nextPano = null 
         this.latestToPano = null 
     }
@@ -661,13 +661,15 @@ export class Images360 extends THREE.EventDispatcher{
         }
         
         if(!toPano.pano.enabled)return done(false,true);
-         Potree.Log('hope flyToPano: '+toPano.pano.id )
+        //Potree.Log('hope flyToPano: '+toPano.pano.id, toPano.pano.position.toArray() )
         
         
         if(this.latestToPano && this.latestToPano != toPano && this.latestToPano.pano != this.currentPano){//还在飞//如果旧的toPano只是旋转镜头,就直接取消旧的
             return done(false) 
         }
-        //Potree.Log('flyToPano: '+toPano.pano.id,  this.latestToPano && this.latestToPano.pano.id )
+         
+        //Potree.Log('flyToPano: '+toPano.pano.id, toPano.pano.position.toArray()  /* this.latestToPano && this.latestToPano.pano.id */ )
+          
         if(this.currentPano == toPano.pano && this.isAtPano() && !toPano.target && !toPano.quaternion  ){
             this.dispatchEvent({type:'flyToPano', toPano})
             return done(true);
@@ -690,7 +692,7 @@ export class Images360 extends THREE.EventDispatcher{
         {//不飞的话是否不要执行这段?
             
             let wait = (e)=> {
-                console.log('wait done', pano.id)
+                //console.log('wait done', pano.id)
                 if(/* e.pano &&  */this.latestToPano && pano != this.latestToPano.pano)return//loadedDepthImg
                 if(this.latestToPano != toPano)return   Potree.Log('已经取消', pano.id)  //如果取消了
                 setTimeout(()=>{ 
@@ -713,7 +715,7 @@ export class Images360 extends THREE.EventDispatcher{
                 
               
                 if(this.checkAndWaitForPanoLoad(pano, toPano.basePanoSize || this.basePanoSize,  wait )){
-                    console.log('等待贴图加载',pano.id)
+                    //console.log('等待贴图加载',pano.id)
                     return
                 }  
             } 
@@ -1287,7 +1289,7 @@ export class Images360 extends THREE.EventDispatcher{
 
     bump(direction) {//撞墙弹回效果
         if (!this.bumping && !this.latestToPano) {  
-            let distance = Potree.settings.displayMode == 'showPanos' ? 0.3 : 0.2;//感觉点云模式比全景模式更明显,所以降低
+            let distance = Potree.settings.displayMode == 'showPanos' ? 0.15 : 0.12;//感觉点云模式比全景模式更明显,所以降低
             let currentPos = this.position.clone()
             let endPosition = new THREE.Vector3().addVectors(this.position, direction.clone().multiplyScalar(distance)) 
             
@@ -1760,7 +1762,7 @@ export class Images360 extends THREE.EventDispatcher{
         
 		 
 		var g = Common.sortByScore(panos,  require, rank);
-        console.log(g)
+        //console.log(g)
         
 		/* let result1 = g && g.slice(0, 10)
         if(result1){ 
@@ -2086,7 +2088,7 @@ export class Images360 extends THREE.EventDispatcher{
         this.hideHighMap()
     }
     
-    setHighMap(pano){
+    setHighMap(pano){ 
         if(!this.highMapCube)   return 
         this.highMapCube.position.copy(pano.position)
  
@@ -2250,17 +2252,17 @@ Images360.prototype.getNeighbours = function(){ //逐渐自动获取neighbours
         this.depthSampler.updateNearPanos(panos)
         
         let maxWaitDur = browser.isMobile() ? 40 : 60  
-        let changeCount = 0, getCount = 0
+        let changeCount = 0,  maxChangeTex = browser.isMobile() ? 2 : 4,    getCount = 0 
         let changeTexCount = ()=>{
             changeCount ++;
         }
-        let median = Math.max(10, Potree.timeCollect.depthSampler.median)
-        
+        let median = Potree.timeCollect.depthSampler.median 
+          
         
         let ifOverTime = ()=>{ 
-            let is = changeCount * median  +  getCount * 0.01 > maxWaitDur//不换贴图也要一丢丢计算时间 
+            let is = changeCount >= maxChangeTex || changeCount * median  +  getCount * 0.01 > maxWaitDur//不换贴图也要一丢丢计算时间 
             /* if(is){
-                console.log(1)
+                console.log('OverTime, changeCount', changeCount)
             } */  
             return is
         }
@@ -2302,7 +2304,9 @@ Images360.prototype.getNeighbours = function(){ //逐渐自动获取neighbours
             lastIndex = i+1  //这轮结束
         } 
          
-        
+        /* if(changeCount){
+            console.log( 'changeCount', changeCount)
+        } */
         this.depthSampler.removeEventListener('changeImg', changeTexCount)
         
         /* let costTime = Date.now() - startTime
@@ -2454,10 +2458,12 @@ Images360.prototype.updateCube = (function(){//增加细分的版本,且垂直
         }
         
         
-        let getPanoBound = (pano)=>{//因漫游点可能在点云外部,如室外平地,所以需要union进漫游点
+        
+        let getPanoBound = (pano,  dis)=>{//因漫游点可能在点云外部,如室外平地,所以需要union进漫游点
             let panoBound = new THREE.Box3
             panoBound.expandByPoint(pano.position)
-            panoBound.expandByVector(new THREE.Vector3(10,10,10));//give pano a margin
+            let margin = dis ? Math.max(dis * 0.1,  10) : 10
+            panoBound.expandByVector(new THREE.Vector3(margin,margin,margin)); //give pano a margin 。 随着bound扩大,margin要相应扩大,否则当距离很远时看起来就像没有
             return pano.pointcloud.bound.clone().union(panoBound)
         }
         
@@ -2472,33 +2478,23 @@ Images360.prototype.updateCube = (function(){//增加细分的版本,且垂直
             let isNeighbour = this.isNeighbour(pano0, pano1)   
             //console.log(pano0.id, pano1.id,  maxSinAlpha.toFixed(2), sinAlpha.toFixed(2),  score.toFixed(2), isNeighbour)
             
-            //let depthTiming = Potree.timeCollect.depthSampler.median    //pc firefox达到4.  chrome为0.01
-            
             if(sinAlpha>maxSinAlpha || !pano0.pointcloud.hasDepthTex || !pano1.pointcloud.hasDepthTex || (isNeighbour ?  score > 100 : score > 50  ) ){  
-                let bound = getPanoBound(pano0).union(getPanoBound(pano1))
+                let bound = getPanoBound(pano0, dis).union(getPanoBound(pano1, dis))
                 let size = bound.getSize(new THREE.Vector3) 
                 let max = Math.max(size.x, size.y, size.z) 
                 size.set(max,max,max)        //距离太远的数据集,过渡会畸变。所以扩大skybox,且为立方体
                 return useBound(bound, size)
-            }else if(/* depthTiming > 1 || */ (isNeighbour ? score > 70 : score > 15)){
+            }else if( isNeighbour ? score > 70 : score > 15 ){
                 dontAddSides = true //pano间有阻挡时得到的side点可能使通道变窄,所以去掉。
             }
             //俯仰角增大时可能不在同一楼层,算出来的mesh不太好,所以更倾向直接使用cube,或去除side。
              
              
              
-            let half            //6  : (browser.isMobile() ? 2 : 3)  //自行输入  (点云计算的慢,还不准) 
-            {
-                let min = 3,max = 6, minTime = 0, maxTime = 3
-                /* half = math.linearClamp(depthTiming, minTime,maxTime, max,min)
-                half = Math.round(half)   */
-                half = max
-            } 
+            let half =  browser.isMobile() ? 4 : 8   //自行输入  (点云计算的慢,还不准)  
             let count1 = 2*half//偶数个 每个pano向 外dir 个数 
             //奇数个的好处:在窄空间内能探测到最远距离,坏处是前方有尖角。偶数个的坏处就是可能检测距离太近。
-            
-            //let panoIndex = 0
-            
+          
             
             let getDir = (angle_, vec)=>{ //旋转获得水平向量
                 let rotMat = new THREE.Matrix4().makeRotationZ(angle_)
@@ -2518,10 +2514,8 @@ Images360.prototype.updateCube = (function(){//增加细分的版本,且垂直
                     deg = THREE.Math.clamp(deg, 1,  80);
                     return Math.tan(THREE.Math.degToRad(deg))
                 }
-                let dirs_  //注意:角度太大会碰到天花板或地板,越远越容易碰到, 在地下停车场就会伸展不开。 户外时需要更多向上的方向,所以上方向多一个
-                /* if(depthTiming > 2) dirs_ = [35,0,-5]
-                else if(depthTiming > 0.5) dirs_ = [35,10,0,-5] 
-                else  */dirs_ = [35,20,7, 0,-5] 
+                let dirs_  //注意:角度太大会碰到天花板或地板,越远越容易碰到, 在地下停车场就会伸展不开。  更多取接近0度的,否则围墙矮一点就会取到远处。 
+                dirs_ = [15, 8, 3, -1, -5] 
                 dirs_ = dirs_.map(deg=> dir.clone().setZ(getZ(deg)).normalize() )
               
                 
@@ -2549,49 +2543,11 @@ Images360.prototype.updateCube = (function(){//增加细分的版本,且垂直
                 maxZ = pano.getCeilHeight()
                 
                 if(maxZ == Infinity) maxZ = skyHeight;   //maxZ = Math.max(skyHeight, maxZ)
-                
-                
-                   
-            
-                /* if(pano.ceilZ != void 0){
-                    maxZ = pano.ceilZ
-                }else{//天花板高度值
-                    //用三个间隔120度散开,和中心垂直线成一定夹角的三个向量去求 最高高度 (不求平均的原因:万一是0不好算)
-                    let rotMat = new THREE.Matrix4().makeRotationX(THREE.Math.degToRad(40))// 角度不能小于天花板中空的半径,大概就是0.2*Math.PI=36度
-                     
-                    let dirs = [new THREE.Vector3(0,0,1).applyMatrix4(rotMat)];
-                    if(depthTiming < 1){
-                        let rotMat1 = new THREE.Matrix4().makeRotationZ(Math.PI*2 / 3);
-                        dirs.push(dirs[0].clone().applyMatrix4(rotMat1))
-                    }
-                    if(depthTiming < 0.3){
-                        let rotMat2 = new THREE.Matrix4().makeRotationZ(-Math.PI*2 / 3);
-                        dirs.push(dirs[0].clone().applyMatrix4(rotMat2)); 
-                    }
-                    
-                    
-                    let skyHeight = 50
-                    let zs = dirs.map(dir_=>{ 
-                        let intersect = this.getIntersect(pano, dir_) 
-                        let z = intersect ? intersect.location.z : pano.position.z+skyHeight //没有intersect代表可能是天空
-                        return z 
-                    })
-                    zs.sort((a,b)=>{return b-a});//得最大值  (不用中位数的原因:在屋檐处,如果仅有一个intersect是天空,因到了室外所以也用天空高度)
-                    maxZ = zs[0]
-                    
-                    let min = pano.position.z + 1  // 防止意外太低
-                    maxZ = Math.max(min,maxZ)
-                    pano.ceilZ = maxZ
-                     
-                } */
-                //console.log(pano.id, 'maxZ:',maxZ )
-                //console.log(pano.id, 'minZ:',minZ )
+                  
                 [maxZ, minZ ].forEach(z=>{  
                     posArr.push(pano.position.clone().setZ(z))
                 })
-                
-                
-                
+                 
                 //在画面上线条从左往右数
                 const angle = Math.PI/(count1-1)  
                 const dirs = [];  //平分这半边180度
@@ -2704,7 +2660,7 @@ Images360.prototype.updateCube = (function(){//增加细分的版本,且垂直
                         //console.log('dis2d',dis2d,'r',r) 
                          
                         
-                        let angles = (browser.isMobile ? [50] : [35,65]).map(deg=>{ //正的在左边  尽量能够平分中间这段墙体。 (角度为从中心向外)
+                        let angles = ((browser.isMobile()/* || dis2d<4 */)? [60] : [50,70]   /*  [35,65] */).map(deg=>{ //正的在左边  尽量能够平分中间这段墙体。 (角度为从中心向外)
                             let angle = THREE.Math.clamp(deg * r, 5, 80);
                             //console.log('angle',angle)  
                             return THREE.Math.degToRad(angle)
@@ -2717,10 +2673,10 @@ Images360.prototype.updateCube = (function(){//增加细分的版本,且垂直
                                 let dirs = angles.map(angle=>getDir(axis_[index]*angle, vecs[index]))//一侧的若干角度
                                  
                                 dirs.forEach((dir_,i)=>{
-                                    let dis1 = getFar(dir_, pano);
-                                    
+                                    let dis1 = getFar(dir_, pano); 
                                     let disToPano2d = dis1 * Math.cos(angles[i])
-                                    if(disToPano2d<dis2d){//超过的话都到另一半pano的半圆了,不计入
+                                     
+                                    if(disToPano2d<dis2d){//超过的话都到另一半pano的半圆了,不计入。(角度越小越容易超过)
                                         let disToSide = dis1 * Math.sin(angles[i]) 
                                          
                                         if(pano != accordingPano){
@@ -2729,7 +2685,10 @@ Images360.prototype.updateCube = (function(){//增加细分的版本,且垂直
                                         
                                         dir_.multiplyScalar( dis1 );
                                         disToSides.push({disToSide,disToPano2d, pano, dir_})
-                                    }
+                                    }else{
+                                        //console.log('超过',index0,index,i)
+                                    }  
+                                    
                                 }) 
                             })
                            

+ 4 - 1
src/custom/modules/panos/Panorama.js

@@ -102,7 +102,7 @@ class Panorama extends THREE.EventDispatcher{
         
         if(Potree.settings.editType == 'pano'){//漫游点拼合编辑
             this.uuid = o.uuid  //因为有多个数据集 所以会重复
-            this.index = o.index  //下标, 用于visibles
+            this.index = this.originID = o.index  //下标, 用于visibles
             this.pointcloud = viewer.scene.pointclouds.find(e=>e.panoUuid == o.uuid) 
             this.pointcloud.panos.push(this)
             this.sid = this.pointcloud.dataset_id + '|' + this.uuid  //不会更改的标记  用于entity.panos里的标记
@@ -354,6 +354,9 @@ class Panorama extends THREE.EventDispatcher{
     }
     
     
+    /* getRealPos(){//当整体移动以后
+        return this.position.clone().applyMatrix4(viewer.scene.scene.matrix)
+    } */
     
     getMarkerMat(){
         if(!markerTex) {

+ 4 - 4
src/custom/objects/tool/Measure.js

@@ -327,7 +327,7 @@ export class Measure extends ctrlPolygon{
          
         let edge
 		{ // edges 
-            edge = LineDraw.createFatLine( [ ],{material:this.getLineMat('edgeDefault')} ) 
+            edge = LineDraw.createFatLine( [ ],{mat:this.getLineMat('edgeDefault')} ) 
             edge.pickOrder = 0
             Potree.Utils.setObjectLayers(edge, 'measure' ) 
 
@@ -620,18 +620,18 @@ export class Measure extends ctrlPolygon{
      
     
     createGuideLine(){//add 辅助线 
-        var guideLine = LineDraw.createFatLine([ ],{material:this.getLineMat('guide')} )
+        var guideLine = LineDraw.createFatLine([ ],{mat:this.getLineMat('guide')} )
         guideLine.visible = false 
         this.guideLine = guideLine
         this.add(guideLine);
     }
     createHorVerGuideLine(){//创建水平与垂直辅助线,仅距离测量有。
-        var verGuideEdge = LineDraw.createFatLine([ ],{material:this.getLineMat('guide')} )
+        var verGuideEdge = LineDraw.createFatLine([ ],{mat:this.getLineMat('guide')} )
         verGuideEdge.visible = false 
         this.verGuideEdge = verGuideEdge
         verGuideEdge.name = 'verGuideEdge'
         
-        var horGuideEdge = LineDraw.createFatLine([ ],{material:this.getLineMat('guide')} )
+        var horGuideEdge = LineDraw.createFatLine([ ],{mat:this.getLineMat('guide')} )
         horGuideEdge.visible = false 
         horGuideEdge.name = 'horGuideEdge'
         this.horGuideEdge = horGuideEdge

+ 9 - 6
src/custom/objects/tool/TransformControls.js

@@ -648,11 +648,13 @@ var TransformControls = function ( camera, domElement, options ) {
                         rotationAxis.copy( _unit[ axis ] );
                     }
                     let center = new THREE.Vector3//坐标轴位置
-                    if(this.object.boundingBox){ 
-                        center.copy(worldPosition)
-                    }else{
-                        center.copy(worldPositionStart)//boundingBox中心可能变化 这里可能要改成直接获取model的position
-                    }
+                    
+                     
+                    /* if(this.object.boundingBox){  
+                        center.copy(worldPosition)  //center设置为boundingbox的中心。但center一直更改会导致虽然在按某个时针旋转,但v2相对v1可能会时不时逆向,导致闪烁。所以固定住center,虽然这样计算的角度和绕模型中心的感觉偏颇
+                    }else{ */
+                        center.copy(worldPositionStart) 
+                    //}
                      
 
                      
@@ -678,7 +680,8 @@ var TransformControls = function ( camera, domElement, options ) {
                         let v1 = this.rotateStart.v1
                         
                         rotationAngle = math.getAngle(  v1, v2, rotationAxis_) 
-                         
+                        //console.log('rot', rotationAngle,  center.toArray()) 
+                        
                         if (Number.isNaN(rotationAngle)) {
                             return;
                         }

+ 1 - 1
src/custom/potree.shim.js

@@ -1384,7 +1384,7 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 				let dd = sphere.center.distanceToSquared(camObjPos);
 				  
                 
-                let addPow = viewer.mainViewport.view.isFlying() ? 0 : 0.5  //0-0.5,正常原本是0. 数字越大近处加载越快。但会造成远处加载慢甚至因pointBudge限制不加载。  isFlying:漫游时需要尽量加载一下远处的点云
+                let addPow = 0.2//viewer.mainViewport.view.isFlying() ? 0 : 0.5  //0-0.5,正常原本是0. 数字越大近处加载越快。但会造成远处加载慢甚至因pointBudge限制不加载。  isFlying:漫游时需要尽量加载一下远处的点云
                 //addPow *= window.devicePixelRatio    //devicePixelRatio高的手机需要优先加载最近的高级点云,减少远处的中高级点云。
 				let distance = Math.pow(dd,0.5+addPow)//Math.sqrt(dd); //提高距离权重,为了提高近处加载速度。   某些场景近处加载慢优化明显,如SS-t-cqCAL6rJ5i 
 				

+ 6 - 5
src/custom/settings.js

@@ -76,7 +76,7 @@ const config = {//配置参数   不可修改
     },
     
     transitionsTime:{
-        flyMinTime : 300  ,  // 毫秒/米
+        flyMinTime : 500  ,  // 毫秒/米
         flytimeDistanceMultiplier: 135 ,
         panoToPanoMax: 1800 , 
         flyIn:1000,
@@ -121,9 +121,9 @@ const config = {//配置参数   不可修改
         ,
         panoEdit:{
             maxLevelPercent: 1,  //在远处时由于pointBudget限制而展示稀疏,凑近时就变为最高质量了
-            pointBudget :6*1000*1000, //比最高的低一点,避免卡顿
+            pointBudget :4*1000*1000, //要使点云达到200个以上时还不卡
             percentByUser:true,
-            minNodeSize : 50 ,
+            minNodeSize : 80 ,  //点云多的话远处的尽量就不可见吧
         }, 
         low:{//highPerformance
             maxLevelPercent: 0.4, //最小为0
@@ -279,7 +279,7 @@ const config = {//配置参数   不可修改
     ,
     axis : {   'x':{color:'#ea3f3f'/* '#d0021b' */  /* 'red' */}, 'y':{ color:'#86c215' /* '#86c542'  *//* 'green' */},  'z': {color:'#3396f8'/* '#3399c8' */ /* 'blue' */}, 'xyz':{color:'#ccc',}},  
     
-    shelterMargin:0.1,
+    shelterMargin:0.1,  //多少米内不算遮挡
     highQualityMaxZoom: 2,
     ultraHighQualityMaxZoom: 3,
     panoFieldRadius : 10, //当前位置多远范围内可以切全景模式
@@ -435,7 +435,8 @@ let settings = {//设置   可修改
     
     showCompass : isTest,
     showAxis : isTest,
-    //testCube : true,
+    // testCube : true,
+    // moveToCenter:true, //针对数据集间隔很远的场景  dis>5000 容易抖动
     
 }
   

+ 17 - 5
src/custom/start.js

@@ -54,7 +54,7 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
 
     Potree.loadDatasetsCallback = function(data, ifReload){
         if(!data || data.length == 0)return console.error('getDataSet加载的数据为空')
-           
+     
         Potree.datasetData = data
         viewer.transform = null
         var datasetLength = data.length 
@@ -62,7 +62,7 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
         var panosLoaded = 0
         var pointcloudLoadDone = function(){//点云cloud.js加载完毕后 
         }
-        
+         
          
         var panosLoadDone = function(){   
              
@@ -138,6 +138,11 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
             var location = viewer.transform.lonlatToLocal.forward(locationLonLat)  //transform.inverse()
             //初始化位置 
             
+            /* 
+            location[0] = Math.sign(location[0]) * Math.min(7000, Math.abs(location[0]))
+            location[1] = Math.sign(location[1]) * Math.min(7000, Math.abs(location[1]))
+             */
+            
             viewer.sidebar && viewer.sidebar.addAlignmentButton(pointcloud) 
             
             //dataset.orientation = 0
@@ -790,10 +795,17 @@ export function mergeEditStart(dom){
                 MergeEditor.moveBoundCenterTo(model, new THREE.Vector3(0,0,0))  
                 MergeEditor.setModelBtmHeight(model, 0) //初始加载设置离地高度为0
                 
-                if(prop.mode != 'single'){//如果不是模型展示页,模型会随着鼠标位置移动
-                    viewer.addEventListener('global_mousemove', moveModel); 
-                    viewer.addEventListener('global_click', confirmPos, {importance:3});
+                if(prop.mode != 'single'){//如果不是模型展示页,模型会随着鼠标位置移动 
                     modelEditing = model;
+                    if(model.fileType == '3dTiles'){
+                        setTimeout(()=>{
+                            moveModel({pointer:{x:0,y:0}}) //3dTiles的移动会错乱,先默认放在当前视图中间吧 
+                            confirmPos()
+                        },1)
+                    }else{
+                        viewer.addEventListener('global_mousemove', moveModel); 
+                        viewer.addEventListener('global_click', confirmPos, {importance:3});
+                    } 
                 }
                 model.dispatchEvent("position_changed") 
             }else{

+ 2 - 2
src/custom/three.shim.js

@@ -127,9 +127,9 @@ THREE.EventDispatcher.prototype.addEventListener = function(type, listener, {imp
 		if ( listeners[ type ] === undefined ) { 
 			listeners[ type ] = []; 
 		}
-        if(type == 'flyingDone'){
+        /* if(type == 'flyingDone'){
             console.log('addEventListener flyingDone')
-        }
+        } */
 		if ( !listeners[ type ].some(e=>e.listener == listener )  ) {  
             listeners[type].push({ listener, importance, once});
             listeners[type] = listeners[type].sort((e,a)=> a.importance - e.importance)//add

+ 12 - 7
src/custom/utils/Common.js

@@ -225,12 +225,6 @@ var Common = {
         
     } 
     ,
-    replaceAll : function (str, f, e) {
-        //f全部替换成e
-        var reg = new RegExp(f, "g"); //创建正则RegExp对象  
-        return str.replace(reg, e);
-    } 
-    , 
     downloadFile : function(data, filename, cb) {
         var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
         save_link.href = data;
@@ -240,13 +234,24 @@ var Common = {
         save_link.dispatchEvent(event);
         cb && cb();
     }, 
+     
+    replaceAll : function (str, f, e) {
+        //f全部替换成e
+        var reg = new RegExp(f, "g"); //创建正则RegExp对象  
+        return str.replace(reg, e);
+    }, 
       
     dealURL(url){
-        return this.replaceAll(url, "\\+", "%2B");// 浏览器似乎不支持访问带+的地址
+        let urlNew = this.replaceAll(url, "\\+", "%2B");// 浏览器似乎不支持访问带+的地址
+        
+        urlNew = this.replaceAll(urlNew, "/.//", "/") //去除双斜杠(/.//)
+         
+        return urlNew
     },
     
     
     getNameFromURL(url){
+        if(!url)return ''
         let get = (e)=>{
             return e.split('/').pop()
         }

+ 2 - 3
src/custom/utils/DrawUtil.js

@@ -33,8 +33,7 @@ var LineDraw = {
             let prop = Object.assign({
                 lineWidth: o.lineWidth || 1,
                 //windows无效。 似乎mac/ios上粗细有效 ? 
-                color: o.color || defaultColor, 
-                //depthTest : false, 
+                color: o.color || defaultColor   
             },o)
             if(o.deshed ){
                 prop.dashSize = o.dashSize || 0.1,
@@ -110,7 +109,7 @@ var LineDraw = {
 		var geometry = new LineGeometry(); 
 		geometry.setColors( o.color || [1,1,1]);
 
-		var matLine = o.material || this.createFatLineMat(o);
+		var matLine = o.mat || this.createFatLineMat(o);
 		var line = new Line2( geometry, matLine );
 		//line.computeLineDistances();
          

+ 1 - 1
src/custom/utils/transitions.js

@@ -396,7 +396,7 @@ var transitions = {
     },
     update: function(e) {
         this.funcs.forEach(function(t) {
-            if(t.updateCount++ == 0 && t.ignoreFirstFrame) return //add start可能发生在一帧中任意时刻,而每次update的是在一帧中的固定时刻,所以从start到第一次update的时间并不是所传入的delta,该delta 是上一帧的update到这一帧的update的耗时。 故去掉了第一次的update,相当于延迟一帧再update.
+            if(t.updateCount++ == 0 && t.ignoreFirstFrame) return //add start可能发生在一帧中任意时刻,而每次update的是在一帧中的固定时刻,所以从start到第一次update的时间并不是所传入的delta,该delta 是上一帧的update到这一帧的update的耗时。 故去掉了第一次的update,相当于延迟一帧再update.   
             if (!(t.paused || (t.current += 1e3 * e, t.current < 0))){
                 if (t.current >= t.duration && !t.cycling) {
                     var u = t.easing(1, 0, 1, 1);

+ 110 - 41
src/custom/viewer/ViewerNew.js

@@ -762,7 +762,7 @@ export class Viewer extends ViewerBase{
             
         } 
         
-        {
+        /* {
             let setInteract = ()=>{
                 this.interacted = true //标记这一帧用户有操作屏幕
             }
@@ -770,8 +770,36 @@ export class Viewer extends ViewerBase{
             this.addEventListener('global_touchmove', setInteract)
             this.addEventListener('global_mousewheel', setInteract)
               
-        }
-         
+        } 
+        
+        
+        
+        {//针对数据集偏离中心很远后产生的精度损失而抖动
+            this.addEventListener('camera_changed', e => { 
+                if(e.viewport == this.mainViewport && (e.changeInfo.positionChanged)){  
+                    if(Potree.settings.editType != 'merge' && Potree.settings.editType != 'pano'){ 
+                        if(!this.mainViewport.view.isFlying() ){ 
+                            let pos =  this.mainViewport.view.position.clone() // this.mainViewport.camera.getWorldPosition(new THREE.Vector3) 
+                            if(pos.lengthSq() > 25000000){
+                                Common.intervalTool.isWaiting('moveWorldCenter', ()=>{
+                                    pos = this.mainViewport.view.position.clone()
+                                     
+                                    this.mainViewport.view.translateWorld(-pos.x, -pos.y, -pos.z)  
+                                    this.scene.scene.position.sub(pos)
+                                    console.log('变位置', pos)
+                                    
+                                    this.scene.pointclouds.forEach(cloud=>{
+                                        Alignment.setMatrix(cloud)
+                                    }) 
+                                    
+                                },500)
+                            }
+                        }  
+                    }
+                }
+            })
+        }*/
+        
 	}
     
     
@@ -959,7 +987,7 @@ export class Viewer extends ViewerBase{
                     }
                     history.ifShelter = ifShelter
                     byCloud++
-                    console.log('补2',  history.pos3d.toArray()) 
+                    //console.log('补2',  history.pos3d.toArray()) 
                     delete history.waitCompute
                 })
             
@@ -1797,6 +1825,14 @@ export class Viewer extends ViewerBase{
 
 	toggleNavigationCube() {
 		this.navigationCube.visible = !this.navigationCube.visible;
+        
+        /* this.viewports.push({
+            name:'navigationCube',
+            left:0, bottom:0, width:0.2,
+            
+        }) */
+        
+        
 	}
 
 	/* setView(pos, view) {
@@ -2944,11 +2980,7 @@ export class Viewer extends ViewerBase{
 		let pRenderer = this.getPRenderer();
         let viewports = params_.viewports || this.viewports
         
-        /* if(!this.needRender){
-            viewports = viewports.filter(v=>v.needRender) //可以渲染的条件是viewer或viewport的needRender为true
-        }
-        viewports = viewports.filter(v=>v.active) 
-        if(viewports.length == 0)return    */
+         
 		 
         viewer.addTimeMark('renderDefault','start')
         
@@ -3285,9 +3317,7 @@ export class Viewer extends ViewerBase{
         
         Potree.settings.pointEnableRT = this.scene.measurements.length > 0 || !Potree.settings.useRTPoint 
         
-        
-        
-        
+         
         if(vrActive){
             this.renderVR();
         }else{ 
@@ -3797,12 +3827,28 @@ export class Viewer extends ViewerBase{
                     dir,  
                     point : position,
                     bestDistance : 0 , 
-                    checkIntersect: true//o.checkIntersect                    
+                    checkIntersect: o.checkIntersect                    
                 })
-                if(pano){
+                
+                
+                let result = {promise:deferred.promise() }    
+                if(pano && pano.msg){
+                    pano = pano.pano
+                    result.msg = pano.msg 
+                }
+                  
+                if(pano){  
                     viewer.images360.flyToPano({pano, target : target2 || target, duration, deferred, dontMoveMap:true  , basePanoSize:o.basePanoSize})//dontMoveMap不要移动map,否则flytopano会自动在map中focus到漫游点的位置,而非测量线了
+                    if(viewer.images360.currentPano == pano){ 
+                        let dis1 = viewer.images360.currentPano.position.distanceTo(target)
+                        let dis2 = position.distanceTo(target)
+                        //console.log('dis1 / dis2',dis1 / dis2, 'dis1-dis2', dis1-dis2)
+                        return {msg: (dis1 / dis2 > 1.5 && dis1-dis2>10)? 'tooFar' : 'posNoChange',  promise : deferred.promise()  }
+                       
+                    }
                 }
-                if(viewer.images360.currentPano == pano){ 
+                return result
+                /* if(viewer.images360.currentPano == pano){ 
                     let dis1 = viewer.images360.currentPano.position.distanceTo(target)
                     let dis2 = position.distanceTo(target)
                     //console.log('dis1 / dis2',dis1 / dis2, 'dis1-dis2', dis1-dis2)
@@ -3810,7 +3856,7 @@ export class Viewer extends ViewerBase{
                   
                 }else{
                     return {promise : deferred.promise()}
-                }
+                } */
                   
                 //出现过到达位置后测量线标签闪烁的情况
             }
@@ -3894,13 +3940,17 @@ export class Viewer extends ViewerBase{
                     point : position,
                     bestDistance : 0 , 
                 })
-                
+                let result = {promise:deferred.promise() }    
+                if(pano && pano.msg){
+                    pano = pano.pano
+                    result.msg = pano.msg 
+                }
                 pano && viewer.images360.flyToPano({pano, target, duration, deferred, dontMoveMap:true  , basePanoSize:o.basePanoSize})//dontMoveMap不要移动map,否则flytopano会自动在map中focus到漫游点的位置,而非测量线了
                 
                 if(!pano){
                     console.error('no pano')
                 }
-                return {promise:deferred.promise() }
+                return result
                 //出现过到达位置后测量线标签闪烁的情况
             }else{
                /*  if(o.dontChangeCamDir){
@@ -4171,6 +4221,8 @@ export class Viewer extends ViewerBase{
 		}
        
         performance.mark('loop-start') ;// 无论有没有reportTimings都要获取,因为getBestCound需要
+        this.dispatchEvent('loopStart')
+        
         
         this.interacted = false
          
@@ -4523,7 +4575,7 @@ export class Viewer extends ViewerBase{
      */
 
     async loadModel(fileInfo, done, onProgress_, onError){ 
-        console.log('开始加载',  Common.getNameFromURL(fileInfo.name) )
+        console.log('开始加载',  Common.getNameFromURL(fileInfo.url) )
     
         let boundingBox = new THREE.Box3()
         /* if(!Potree.settings.boundAddObjs){
@@ -4579,36 +4631,53 @@ export class Viewer extends ViewerBase{
             
             fileInfo_.loadCostTime = Date.now() - fileInfo_.loadStartTime
             /* let weight = Math.round((total / 1024 / 1024) * 100) / 100;*/
-            console.log( '加载完毕:', Common.getNameFromURL(fileInfo_.name),  '耗时(ms)', fileInfo_.loadCostTime, /* 模型数据量:' + weight + 'M' */)
+            console.log( '加载完毕:', Common.getNameFromURL(fileInfo_.url),  '耗时(ms)', fileInfo_.loadCostTime, /* 模型数据量:' + weight + 'M' */)
              
              
             if(fileInfo_.fileType == '3dTiles'){
                 let tileset = object.runtime.getTileset()
                
                 //TileHeader: tileset.root 
-                //参见另一个工程 TileRenderer.js  preprocessNode
-                //let boundingVolume = tileset.root.boundingVolume //这个坐标位置几万…… let data = boundingVolume.halfAxes  //但这个似乎是premultiply( transform );过后的,可能需还原下
+                //参见另一个工程 TileRenderer.js  preprocessNode //这个坐标位置几万…… let data = boundingVolume.halfAxes  //但这个似乎是premultiply( transform );过后的,可能需还原下
                 
-                let json = tileset.tileset  
+                let json = tileset.tileset   
                 let box = json.root.boundingVolume.box
                 
-                let center = new THREE.Vector3(box[0],box[1],box[2])
-                let boundSize = new THREE.Vector3( )  
-                 
-                // get the extents of the bounds in each axis
-                let vecX = new THREE.Vector3( box[ 3 ], box[ 4 ], box[ 5 ] )
-                let vecY = new THREE.Vector3( box[ 6 ], box[ 7 ], box[ 8 ] );
-                let vecZ = new THREE.Vector3( box[ 9 ], box[ 10 ], box[ 11 ] );
-
-                const scaleX = vecX.length();
-                const scaleY = vecY.length();
-                const scaleZ = vecZ.length();
-                /* boundingBox.expandByPoint(center);
-                boundingBox.expandByVector(new THREE.Vector3(scaleX,scaleY,scaleZ)) */
-                 
-                
-                boundingBox.min.set( - scaleX, - scaleY, - scaleZ );
-                boundingBox.max.set( scaleX, scaleY, scaleZ );
+                if(box){
+                    let center = new THREE.Vector3(box[0],box[1],box[2])
+                    let boundSize = new THREE.Vector3( )  
+                     
+                    // get the extents of the bounds in each axis
+                    let vecX = new THREE.Vector3( box[ 3 ], box[ 4 ], box[ 5 ] )
+                    let vecY = new THREE.Vector3( box[ 6 ], box[ 7 ], box[ 8 ] );
+                    let vecZ = new THREE.Vector3( box[ 9 ], box[ 10 ], box[ 11 ] );
+
+                    const scaleX = vecX.length();
+                    const scaleY = vecY.length();
+                    const scaleZ = vecZ.length();
+                    /* boundingBox.expandByPoint(center);
+                    boundingBox.expandByVector(new THREE.Vector3(scaleX,scaleY,scaleZ)) */
+                     
+                    
+                    boundingBox.min.set( - scaleX, - scaleY, - scaleZ );
+                    boundingBox.max.set( scaleX, scaleY, scaleZ );
+                    
+                }else if(json.root.boundingVolume.sphere){
+                    let sphereData = json.root.boundingVolume.sphere
+                    let center = new THREE.Vector3(...sphereData)
+                    let radius = sphereData[3] / 2
+                    /* let sphere = new THREE.Sphere(center, radius) 
+                    let box = sphere.getBoundingBox()
+                    boundingBox.copy(box) */
+                     
+                    boundingBox.min.set( - radius, - radius, - radius );
+                    boundingBox.max.set( radius, radius, radius );
+                    
+                    
+                    
+                }else{
+                    return console.error('json boundingVolume 缺少信息') 
+                }
                 
                 //中心点居然没用。可能是漏用了什么信息,也许这和LVBADUI_qp是散的有关。
                 console.log('3d tiles json',json)
@@ -4723,7 +4792,7 @@ export class Viewer extends ViewerBase{
                 options: {
                     //dracoDecoderPath: '../utils/loaders/DRACOLoader/draco',
                     //basisTranscoderPath: '../utils/loaders/KTX2Loader/basis',
-                    maximumScreenSpaceError: 50,
+                    maximumScreenSpaceError: 30,  //如果本身tiles很密很小这个值就不能很大。
                     maxDepth: 100, 
                     maximumMemoryUsage: 700, //缓存大小。 若太小,密集的tile反复加载很卡
                     //debug:true,

+ 46 - 31
src/custom/viewer/map/Map.js

@@ -241,6 +241,10 @@ export class TiledMapBase extends THREE.EventDispatcher{
         })
         
         this.computeCount = 0
+        this.maxLoading = 3 
+        this.loadFailCount = 0
+        this.loadingInProgress = 0
+        
     }
     
     get zoomLevel(){
@@ -292,7 +296,7 @@ export class TiledMapBase extends THREE.EventDispatcher{
     setEnable(enable){//add
         if(!this.disabled == enable)return
         if(enable){
-            console.log('setEnable',true)
+            //console.log('setEnable',true)
         }
         this.disabled = !enable
      
@@ -345,9 +349,9 @@ export class TiledMapBase extends THREE.EventDispatcher{
         let lonlat = viewer.transform.lonlatToLocal.inverse(viewport.camera.position.clone()) 
         let cos = Math.cos(THREE.Math.degToRad(lonlat.y)); //越小就在纬度上越高,tile表现越小
         //为什么lonlat.y会超出90?
-        if(lonlat.y>90){
+        /* if(lonlat.y>90){
             console.log('lonlat.y>90',lonlat.y)
-        } 
+        }  */
         
         cos = THREE.Math.clamp(cos, 0,1)
         let lonShift =  Math.abs(viewer.mapViewer.camera.position.x / this.mapSizeM * 16  )  //越大就在经度离中心越远,tile表现越大  。  
@@ -444,11 +448,12 @@ export class TiledMapBase extends THREE.EventDispatcher{
 
 
 
-let maxLoading = 3 
-let loadFailCount = 0
+
 const waitQueue = [] //等待加载的
 const loadDone = (tile, success)=>{
     tile.map.mapLayer.loadingInProgress--
+    tile.map.loadingInProgress--
+    
     tile.loading = false
      
     let next = waitQueue[0]
@@ -462,16 +467,15 @@ const loadDone = (tile, success)=>{
     tile.mesh && (tile.mesh.material.needsUpdate = true)
     
 }
-let lastTile 
+ 
 function addLoadTile(tile){
     
-    if(tile.map.mapLayer.loadingInProgress < maxLoading){
+    if(tile.map.loadingInProgress < tile.map.maxLoading){
         if(!tile.mesh)return;  //有时候会遇到这种情况, 为什么没有被cancelLoad呢?
 
-        
-        tile.map.mapLayer.loadingInProgress ++
-        //console.log('addLoadTile', tile.id, tile.texURL )
-        
+        tile.map.mapLayer.loadingInProgress++ 
+        tile.map.loadingInProgress ++ 
+        //tile.texURL && tile.texURL.includes('testdata') && console.log('addLoadTile',   tile.texURL.split('map_tiles/')[1] )
          
         tile.loading = true
         let index = waitQueue.indexOf(tile);
@@ -486,10 +490,10 @@ function addLoadTile(tile){
                 tile.map.mapLayer.needUpdate = true //表示还要继续update(以removeChildren)
                 
                 if(tile.map instanceof TiledMapOpenStreetMap){
-                    maxLoading = browser.isMobile() ? 5 : 10; 
-                }
-                
+                    tile.map.maxLoading = browser.isMobile() ? 5 : 10; 
+                } 
             }else{
+                //tile.texURL && tile.texURL.includes('testdata') && console.log('loadDone and dispose',   tile.texURL.split('map_tiles/')[1] )
                 tex.dispose()   
             } 
             loadDone(tile, true)
@@ -501,10 +505,10 @@ function addLoadTile(tile){
                 tile.map.mapLayer.viewer.mapChanged = true 
             } 
             loadDone(tile, false)
-            loadFailCount ++ ;
+            tile.map.loadFailCount ++ ;
             
-            if(tile.map instanceof TiledMapOpenStreetMap && Potree.settings.mapCompany == 'google' && loadFailCount > 3){//极有可能没有vpn为了防止影响到其他资源加载,减少加载的个数
-                maxLoading = 2;
+            if(tile.map instanceof TiledMapOpenStreetMap && Potree.settings.mapCompany == 'google' && tile.map.loadFailCount > 3){//极有可能没有vpn为了防止影响到其他资源加载,减少加载的个数
+                tile.map.maxLoading = 2;
             }
             
         }))  
@@ -518,13 +522,15 @@ function addLoadTile(tile){
     }
     
 }
-function cancelLoad(tile){//如果等待加载,但还没开始加载,取消加载
-    ///* tile.texURL.includes('testdata') &&  */console.log('cancelLoad', tile.id, tile.loading)
+function cancelLoad(tile,log){//如果等待加载,但还没开始加载,取消加载
+ 
+    
     if(!tile.loading){ 
         let index = waitQueue.indexOf(tile);
-        index > -1 && waitQueue.splice(index,1) 
-    }
-     
+        index > -1 && waitQueue.splice(index,1)   
+        //index > -1 && tile.texURL && tile.texURL.includes('testdata') && console.log('cancelLoad',   tile.texURL.split('map_tiles/')[1]/* ,  (log && waitQueue.indexOf(tile)>-1) ? log:'' ,  tile.loading */ )
+  
+    } 
 }
 
 
@@ -548,7 +554,7 @@ export class MapTile{
         return t.tilePresenceMap && t.tilePresenceMap.empty
     }
     
-    updateTile(t, e, n, i){ 
+    updateTile(t, e, n, i){ //真正显示mesh的是这一层,最高level, i==0的
         if(!this.mesh){
             this.createTileObject(t, e, n, i)
         }
@@ -556,15 +562,17 @@ export class MapTile{
             this.objectGroup.add(this.mesh) 
             this.meshAdded = !0
         }
-        if(this.textureLoaded){
+        if(this.textureLoaded){//贴图加载完就不需要子集了
             this.removeChildren() 
+        }else{
+            this.cancelChildren() //add 停止加载子集
         }
          
         return this.textureLoaded
     }
     
     updateSubTiles(entity, n, level, o, a, s, c){
-        for (var l = !0, u = [-.25 * o, .25 * o, -.25 * o, .25 * o], d = [.25 * o, .25 * o, -.25 * o, -.25 * o], p = 0; p < 4; ++p){
+        for (var noContent = !0, u = [-.25 * o, .25 * o, -.25 * o, .25 * o], d = [.25 * o, .25 * o, -.25 * o, -.25 * o], p = 0; p < 4; ++p){
             var h = c + p.toString(10);
             //一级(512):0 1 2 3分别为左上、右上、左下、右下。二级(1024)就是把一级的每一块分裂,如00 01 02 03分别是0的左上、右上、左下、右下……
             /* if(entity.name == 'floorplan'){
@@ -582,7 +590,7 @@ export class MapTile{
                 
                 if (entity.isTileVisible(tempVector, .5 * o, n)){ 
                     this.children[p] || (this.children[p] = new MapTile(this.map, this.objectGroup,this.tileColor, this, this.name+p ))
-                    l = this.children[p].update(entity, n, level - 1, .5 * o, f, m, h) && l
+                    noContent = noContent && this.children[p].update(entity, n, level - 1, .5 * o, f, m, h)  
                 } else {
                     if (this.children[p]){
                         this.children[p].remove()
@@ -593,8 +601,8 @@ export class MapTile{
                 
             }
         }
-        return l && this.removeObject3D(),
-        l
+        return noContent && this.removeObject3D(),
+        noContent
 
     }
     
@@ -667,6 +675,7 @@ export class MapTile{
     }
     
     removeObject3D(){
+        let hasMesh = !!this.mesh
         if (this.mesh){
             this.objectGroup.remove(this.mesh)
             if (this.textureLoaded){
@@ -679,11 +688,10 @@ export class MapTile{
             this.mesh.material.dispose() //o.disposeMeshMaterial(this.mesh),
             this.mesh.geometry.dispose() 
             this.mesh = void 0
-            ///* this.texURL && this.texURL.includes('testdata') &&  */console.log('removeObject3D',this.id)
         }
         this.meshAdded = !1,
         this.textureLoaded = !1
-        
+        //this.texURL && this.texURL.includes('testdata') && console.log('removeObject3D', this.id, 'hasMesh',hasMesh, this.texURL.split('map_tiles/')[1] )
     }
     
     removeChildren(){
@@ -694,7 +702,14 @@ export class MapTile{
         }
         this.children.length = 0
     }
-  
+    
+    cancelChildren(){//子集全部停止加载
+        for (var t = 0, e = this.children; t < e.length; t++){
+            var n = e[t];
+            n && (cancelLoad(n, '提前'), n.cancelChildren())   
+        }
+        
+    }
 }
 
 

+ 6 - 6
src/materials/PointCloudMaterial.js

@@ -42,8 +42,8 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {//base
 		this._weighted = false;
 		this._gradient = Gradients.SPECTRAL;
 		this.gradientTexture = PointCloudMaterial.generateGradientTexture(this._gradient);
-		this._matcap = "matcap.jpg";
-		this.matcapTexture = PointCloudMaterial.generateMatcapTexture(this._matcap);
+		//this._matcap = "matcap.jpg";
+		//this.matcapTexture = PointCloudMaterial.generateMatcapTexture(this._matcap);
 		this.lights = false;
 		this.fog = false;
 		this._treeType = treeType;
@@ -148,8 +148,8 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {//base
 			uFilterNumberOfReturnsRange:	{ type: "fv", value: [0, 7]},
 			uFilterGPSTimeClipRange:		{ type: "fv", value: [0, 7]},
 			uFilterPointSourceIDClipRange:		{ type: "fv", value: [0, 65535]},
-			matcapTextureUniform: 	{ type: "t", value: this.matcapTexture },
-			backfaceCulling: { type: "b", value: false },
+			//matcapTextureUniform: 	{ type: "t", value: this.matcapTexture },
+			backfaceCulling: { type: "b", value: false },  
 		};
 
 		this.classification = ClassificationScheme.DEFAULT;
@@ -330,7 +330,7 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {//base
 		}
 	}
 
-	get matcap(){
+	/* get matcap(){
 		return this._matcap;
 	}
 
@@ -340,7 +340,7 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {//base
 			this.matcapTexture = Potree.PointCloudMaterial.generateMatcapTexture(this._matcap);
 			this.uniforms.matcapTextureUniform.value = this.matcapTexture;
 		}
-	}
+	} */
 	get useOrthographicCamera() {
 		return this.uniforms.useOrthographicCamera.value;
 	}

+ 12 - 10
src/materials/shaders/pointcloud_new.vs

@@ -117,6 +117,7 @@ uniform float uNodeSpacing;
 uniform float uOctreeSize;
 uniform vec3 uBBSize;
 uniform float uLevel;
+uniform float levelPercent;//add
 uniform float uVNStart;
 uniform bool uIsLeafNode;
 
@@ -1011,17 +1012,18 @@ void main() {
    
    
     //-------------------        
- 
-    #ifdef attenuated_opacity  
-        //zoom不会改变z 所以这并不是用在分屏时候的
-        //vOpacity = uOpacity * exp(-length(-mvPosition.xyz) / 1000.0);  // e为底的指数函数  opacityAttenuation = 1000
-        vOpacity = uOpacity  * exp(gl_Position.z/50.0); 
-        vOpacity = clamp(vOpacity, 0.001, 1.0);  
-        
-    #else
+  
+    if(uOpacity>=1.0){ 
         vOpacity = uOpacity; 
-         
-    #endif
+    }else{                                              //#ifdef attenuated_opacity      zoom不会改变z 所以这并不是用在分屏时候的
+        float v = -gl_Position.z-1.0 ;   // 范围从-2到0,   e的-2到0次方的范围是0.818到1 
+        //vOpacity = uOpacity * exp(v/ (levelPercent * 20.0 )  );  
+        //近处加深,远处变淡  gl_Position.z似乎朝向屏幕里为正
+        float r = clamp( pow(1.5, v/5.0    ),  0.1, 1.0  );  //除以的数字越大,近高远低的程度越小,范围越长。 程度太高远处单薄的区域看不见  pow的底数越大改变率越大
+        vOpacity = uOpacity * r  ;
+        
+       // vOpacity = clamp(vOpacity, 0.001, 1.0);  
+    }  
     
     vOpacity *= max(0.1,  (1.0 - normalZ));//垂直朝相机时降低透明度 
 

+ 3 - 3
src/navigation/FirstPersonControlsNew.js

@@ -207,7 +207,7 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                         let PanoEditor = window.viewer.modules.PanoEditor
                              
                         if(a && PanoEditor.selectedPano){
-                            if(!PanoEditor.selectedGroup || !PanoEditor.checkIfAllLinked({group:PanoEditor.selectedGroup}) ){
+                            if(/* !PanoEditor.selectedGroup ||  */!PanoEditor.checkIfAllLinked({group:PanoEditor.selectedGroup}) ){
                                 if(handleState == 'translate' && ( e.drag.intersectStart.pointclouds && Common.getMixedSet(PanoEditor.selectedClouds, e.drag.intersectStart.pointclouds).length  || PanoEditor.selectedPano.hovered)//平移时 拖拽到点云上 或 circle。(其中点云只需要intersect的点云中包含选择的点云中之一即可)
                                     || handleState == 'rotate' ) //旋转模式不需要intersect
                                 {                                           
@@ -220,7 +220,7 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                         }
                         
                         if(!pointclouds && e.buttons === Buttons.LEFT && viewport.rotateSide){//侧视图  (有时候会卡顿,是mousemove执行延迟了,一般发生在突然加载很多点云时)
-                            //console.log('rotateSide') 
+                            //console.log('rotateSide', -e.drag.pointerDelta.x ) 
                             return PanoEditor.rotateSideCamera(-e.drag.pointerDelta.x) 
                         }
                     }else if(Potree.settings.editType == 'merge'){ 
@@ -393,7 +393,7 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                     }else{ */
                     direction = this.viewer.inputHandler.getMouseDirection().direction  //定点缩放
                      
-                    if(e.intersect){//和intersect的墙越接近,速度越慢,便于focus细节
+                    if(e.intersect && e.intersect.location){//和intersect的墙越接近,速度越慢,便于focus细节
                         let dis = camera.position.distanceTo(e.intersect.location);
                         
                         speed = THREE.Math.clamp(dis * 0.1,  0.3, speed) 

+ 19 - 13
src/navigation/InputHandlerNew.js

@@ -52,7 +52,7 @@ export class InputHandler extends THREE.EventDispatcher {
         this.lastPointerUpTime = 0
         
         this.touches = []
-
+        this.interactHistory = {move:0} //add
 
         this.hoverViewport = viewer.viewports[0]
         
@@ -94,6 +94,10 @@ export class InputHandler extends THREE.EventDispatcher {
             }) 
         }
         
+        window.viewer.addEventListener('loopStart',()=>{
+            this.interactHistory = {}  //清空
+        })
+        
         
 	}
 
@@ -399,7 +403,7 @@ export class InputHandler extends THREE.EventDispatcher {
       
         
         //if(isTouch || !Potree.settings.intersectWhenHover ){ 
-        if(!this.dragViewport.view.isFlying()){
+        if(!this.dragViewport.view.isFlying() && Potree.settings.intersectWhenHover && Potree.settings.editType != 'pano'){//漫游点编辑如果拖拽前getIntersect旋转会延迟
             this.hoveredElements = this.getHoveredElements();
             this.intersect = this.getIntersect(viewport) //更新intersect,避免在没有mousemove但flyToPano后intersect未更新。
             //this.intersect = this.getWholeIntersect()  
@@ -906,6 +910,10 @@ export class InputHandler extends THREE.EventDispatcher {
         //点云费时:2-15ms
         //深度图费时: 0.1-0.2ms
 
+       /*  
+        intersect && intersect.location && intersect.location.applyMatrix4(viewer.scene.scene.matrix)//add
+         */
+        
         
         
         if(onlyGetIntersect){ 
@@ -942,11 +950,15 @@ export class InputHandler extends THREE.EventDispatcher {
     
     
     
-    onMouseMove (e) { 
+    onMouseMove (e) {  
         return this.dealPointerMove( e )
     }
 
     dealPointerMove(e, isTouch){ 
+    
+        if(this.interactHistory.move) return  //一帧只触发一次
+        this.interactHistory.move = 1
+         
         if(isTouch){
             var  {  camera, viewport  } = this.updateTouchesInfo(e) 
         }else { 
@@ -970,7 +982,7 @@ export class InputHandler extends THREE.EventDispatcher {
                  this.intersect = this.getIntersect(viewport,  e.onlyGetIntersect, e.pickWindowSize, !!dontIntersect, e.whichPointcloud) //数据集多的时候卡顿
             }, 156); */
 	                 
-            //console.log('intersectPoint', intersectPoint)
+            //console.log('intersect', intersect)
         } 
         
         if(e.onlyGetIntersect){ 
@@ -978,17 +990,12 @@ export class InputHandler extends THREE.EventDispatcher {
                 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) {//有拖拽(不一定拖拽了物体, 也不一定按下了鼠标)
@@ -1083,8 +1090,7 @@ export class InputHandler extends THREE.EventDispatcher {
             
             //this.intersect = this.getWholeIntersect()
             
-            
-            
+             
             
             this.viewer.dispatchEvent($.extend(  
                 this.getEventDesc(e,isTouch),

+ 1 - 1
src/utils/TransformationToolNew.js

@@ -300,7 +300,7 @@ export class TransformationTool extends THREE.EventDispatcher{
                 
                 
                 let point = new THREE.Vector3(0,0,length/2)//new THREE.Vector3().copy(alignment).multiplyScalar(length/2)
-                mesh = LineDraw.createFatLine([point, point.clone().negate()],{lineWidth:5, material: new LineDraw.createFatLineMat(matProp)})
+                mesh = LineDraw.createFatLine([point, point.clone().negate()],{lineWidth:5, mat : new LineDraw.createFatLineMat(matProp)})
                 lookAtPoint = alignment 
                 renderOrder = 10; 
                 

+ 1 - 1
src/viewer/EDLRendererNew.js

@@ -284,7 +284,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
                     viewer.pRenderer.render(viewer.scene.scenePointCloud, camera,  rtEDL, {
                         shadowMaps:  lights.length > 0 ? [this.shadowMap] : null,
                         clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
-                        transparent: false,
+                        transparent: true,   //如果点云透明需要透明
                     });
                 } 
                 if(Potree.settings.intersectOnObjs){// model也要渲染到rtEDL

+ 6 - 0
src/viewer/ExtendView.js

@@ -207,6 +207,12 @@ class ExtendView extends View {
         let endPosition = new THREE.Vector3().copy(info.position)
         let startPosition = this.position.clone();
 		let startQuaternion, endQuaternion, endTarget = null ;
+        
+        /* if(info.considerSceneTran){
+            endPosition.applyMatrix4(viewer.scene.scene.matrix)  
+        } 
+         */
+        
         this.restrictPos(endPosition)
         
 		if(info.target ){

+ 32 - 0
改bug的历史.txt

@@ -1,3 +1,35 @@
+疑难杂症 -。-
+
+
+
+
+
+
+
+
+
+2023.4.21
+
+
+SS-t-0lHRLIEqFY 场景的images360.cube抖动,导致整个画面在相机变化时扭曲
+只有在非普通cube创建出后才会,恢复为普通cube后就正常。但数据集的test boundingbox、buildingBox、测量线一直抖动。 
+
+
+三个数据集,前两个无深度图,最后一个有,且位置很远。
+
+也只有第三个数据集会产生抖动。应该是因为数字过大而精度不够。
+
+但为何点云、panoLabel不会抖动,可能因为geo规则。
+
+尝试将整体平移,使当前位置在原点,但特别麻烦,而且测量线正常了但cube总是不正常。放弃。
+
+( 大场景距离很远的话 也抖动,只是抖得不太一样,不会扭曲和撕裂)
+ 
+
+
+
+
+ 
 2023.2.17
 
 现象:转动过程中,面对相同的一块点云,有时候很流畅,有时候反向再转回去超级卡,但numVisiblePoints并无增加。