Browse Source

fix: 写完updateCube了,但是为什么tile出黑快了?之前不会

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

+ 4 - 1
src/PointCloudOctree.js

@@ -307,6 +307,9 @@ export class PointCloudOctree extends PointCloudTree {
         //var visibleNodes1 = this.visibleNodes.map(e=>e.getLevel())
         //var visibleNodes1 = this.visibleNodes.map(e=>e.getLevel())
         //console.log('visibleNodes1',visibleNodes1)
         //console.log('visibleNodes1',visibleNodes1)
         Potree.updatePointClouds([this],  viewer.scene.getActiveCamera(), viewer.mainViewport.resolution );
         Potree.updatePointClouds([this],  viewer.scene.getActiveCamera(), viewer.mainViewport.resolution );
+        //不在camera可视范围内还是加载不出来。即使临时修改位置
+        
+        
         var visibleNodes2 = this.visibleNodes.map(e=>e.getLevel())
         var visibleNodes2 = this.visibleNodes.map(e=>e.getLevel())
         //console.log('visibleNodes2',visibleNodes2) 
         //console.log('visibleNodes2',visibleNodes2) 
         this.maxLevel = old;
         this.maxLevel = old;
@@ -1516,7 +1519,7 @@ export class PointCloudOctree extends PointCloudTree {
 
 
 		performance.mark("pick-start");
 		performance.mark("pick-start");
 
 
-		let getVal = (a, b) => a !== undefined ? a : b;
+		let getVal = (a, b) => a != void 0 ? a : b;
         
         
         
         
         let pickWindowSize_ = THREE.Math.clamp( Math.round((1.1-this.maxLevel/this.nodeMaxLevel)*80),  5, 100)
         let pickWindowSize_ = THREE.Math.clamp( Math.round((1.1-this.maxLevel/this.nodeMaxLevel)*80),  5, 100)

+ 0 - 2
src/Potree.js

@@ -1,7 +1,5 @@
 export {config, settings} from "./settings.js";
 export {config, settings} from "./settings.js";
 export {start, panoEditStart} from "./start.js";
 export {start, panoEditStart} from "./start.js";
-
-
  
  
 
 
 export * from "./Actions.js";
 export * from "./Actions.js";

+ 6 - 1
src/materials/DepthBasicMaterial.js

@@ -40,6 +40,7 @@ export default class DepthBasicMaterial extends THREE.ShaderMaterial{
             defines, 
             defines, 
         } )
         } )
         
         
+       
         if(o.useDepth && Features.EXT_DEPTH.isSupported()) this.useDepth_ = true
         if(o.useDepth && Features.EXT_DEPTH.isSupported()) this.useDepth_ = true
         
         
         
         
@@ -86,7 +87,11 @@ export default class DepthBasicMaterial extends THREE.ShaderMaterial{
         if(this.useDepth){ 
         if(this.useDepth){ 
             var viewport = e.viewport || viewer.mainViewport;
             var viewport = e.viewport || viewer.mainViewport;
             var camera = viewport.camera;
             var camera = viewport.camera;
-            this.uniforms.depthTexture.value = viewer.getPRenderer().getRtEDL(viewport).depthTexture   //其实只赋值一次就行
+            /* if(Potree.settings.displayMode == 'showPanos' && viewer.images360.currentPano.depthTex){
+                this.uniforms.depthTexture.value = viewer.images360.currentPano.depthTex
+            }else{ */
+                this.uniforms.depthTexture.value = viewer.getPRenderer().getRtEDL(viewport).depthTexture   //其实只赋值一次就行
+            //}
             this.uniforms.nearPlane.value = camera.near;
             this.uniforms.nearPlane.value = camera.near;
             this.uniforms.farPlane.value = camera.far;
             this.uniforms.farPlane.value = camera.far;
             
             

+ 402 - 0
src/materials/ModelTextureMaterial.js

@@ -0,0 +1,402 @@
+import * as THREE from "../../libs/three.js/build/three.module.js";
+const prefixVertex ="precision highp float;\nprecision highp int;\n\nuniform mat4 modelMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\n"
+const prefixFragment ="precision highp float;\nprecision highp int;\n\nuniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"
+ 
+let shader = {
+	 
+		uniforms: { 
+			
+			opacity: {
+				type: "f",
+				value: 1
+			},
+			progress: {
+				type: "f",
+				value: 0
+			},
+			
+			pano0Map: {
+				type: "t",
+				value: null
+			}, 
+            pano1Map: {
+				type: "t",
+				value: null
+			}, 
+            depthMap0: {
+				type: "t",
+				value: null
+			},
+            depthMap1: {
+				type: "t",
+				value: null
+			}, 
+			pano0Position: {
+				type: "v3",
+				value: new THREE.Vector3
+			},
+			pano0Matrix: {
+				type: "m4",
+				value: new THREE.Matrix4
+			},
+			
+			pano1Position: {
+				type: "v3",
+				value: new THREE.Vector3
+			},
+			pano1Matrix: {
+				type: "m4",
+				value: new THREE.Matrix4
+            },
+			/* pano1Matrix2: {
+				type: "m4",
+				value: new THREE.Matrix4
+            },
+            */
+            
+            inverseProjectionMatrix: {
+                value: new THREE.Matrix4
+            },  
+            /* projectionMatrix:{//需要再写一遍吗
+                value: new THREE.Matrix4
+            }, */
+            viewport: {
+                value: new THREE.Vector4
+            },
+            //如     {x: 0, y: 0, z: 428, w: 969}  xy应该是offset, zw是宽高 
+            cameraHeight0: {
+				type: "f",
+				value: 1
+			},
+            cameraHeight1: {
+				type: "f",
+				value: 1
+			},
+            
+        },
+       
+        vertexShader: prefixVertex + `
+
+            uniform vec3 pano0Position;
+            uniform mat4 pano0Matrix;
+            
+            uniform vec3 pano1Position;
+            uniform mat4 pano1Matrix;
+            //uniform mat4 pano1Matrix2;
+
+           
+            varying vec2 vUv; 
+            varying vec3 vWorldPosition0;
+            varying vec3 vWorldPosition1;
+            varying vec3 vWorldPosition12;
+            
+            vec3 transformAxis( vec3 direction ) //navvis->4dkk
+            {
+                float y = direction.y;
+                direction.y = direction.z;
+                direction.z = -y;
+                return  direction;
+            }
+             
+            
+            void main() {
+            
+                vUv = uv;
+                vec4 worldPosition = modelMatrix * vec4(position, 1.0);
+                
+                
+            
+                vec3 positionLocalToPanoCenter0 = worldPosition.xyz - pano0Position;
+                vWorldPosition0 = (vec4(positionLocalToPanoCenter0, 1.0) * pano0Matrix).xyz;
+                vWorldPosition0.x *= -1.0;
+                vWorldPosition0 = transformAxis(vWorldPosition0);
+                
+                vec3 positionLocalToPanoCenter1 = worldPosition.xyz - pano1Position;
+                vWorldPosition1 = (vec4(positionLocalToPanoCenter1, 1.0) * pano1Matrix).xyz;
+                vWorldPosition1.x *= -1.0;
+                vWorldPosition1 = transformAxis(vWorldPosition1);
+                
+                /* 
+                vec3 positionLocalToPanoCenter12 = worldPosition.xyz - pano1Position;
+                vWorldPosition12 = (vec4(positionLocalToPanoCenter12, 1.0) * pano1Matrix2).xyz;
+                vWorldPosition12.x *= -1.0;
+                vWorldPosition12 = transformAxis(vWorldPosition12);
+                 */
+                
+                
+                
+                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
+            
+            }
+
+        `,
+        fragmentShader: prefixFragment + `
+             
+            #define PI 3.141592653 
+            
+             
+            uniform float modelAlpha;
+            uniform float opacity;
+            uniform float progress;
+            uniform int blackout;
+            uniform vec3 pano0Position;
+            uniform vec3 pano1Position;
+            uniform float maxDistance;
+            uniform float minDistance;
+            uniform float minOpa;
+            
+            uniform float cameraHeight0;
+            uniform float cameraHeight1;
+
+          
+       
+            /* uniform sampler2D pano0Map;
+            uniform sampler2D pano1Map;    */   
+            uniform samplerCube pano0Map;
+            uniform samplerCube pano1Map;
+          
+            
+            varying vec2 vUv; 
+            varying vec3 vWorldPosition0;
+            varying vec3 vWorldPosition1;
+            //varying vec3 vWorldPosition12;
+          
+            /* vec2 getSamplerCoord( vec3 direction ) 
+            {
+                direction = normalize(direction);
+                float tx=atan(direction.x,-direction.y)/(PI*2.0)+0.5;
+                float ty=acos(direction.z)/PI;
+
+                return vec2(tx,ty);
+            } */
+
+            vec2 getSamplerCoord2( vec3 direction ) 
+            { 
+                direction = normalize(direction);
+                float tx=atan(direction.x,direction.z)/(PI*2.0)+0.5;
+                float ty=acos(direction.y)/PI;
+
+                return vec2(tx,ty); 
+            }
+            
+            #extension GL_EXT_frag_depth : enable
+            #if defined(GL_EXT_frag_depth) && defined(hasDepthTex)  
+                uniform sampler2D depthMap0;
+                uniform sampler2D depthMap1;
+                uniform mat4 inverseProjectionMatrix;
+                uniform mat4 projectionMatrix;
+                uniform vec4 viewport; 
+            
+                vec2 getDepth(vec3 dir, sampler2D depthMap, float height, vec4 eyePos){
+                    vec2 depthValue = vec2(0.0, 0.0);
+                    vec2 uv2 = getSamplerCoord2(/* vWorldPosition12 */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);
+                    //distance *= 255. * .001;           // distance is now in meters
+                    
+                    //更改
+                    float distance = (depth.g + depth.r / 256.) * 255.;  //为什么要乘以255 
+                    
+                    if(distance == 0.0){//漫游点底部识别不到的区域,给一个地板高度 
+                         if(uv2.y > 0.75)distance = height / dir.y; 
+                         else distance = 100000.0;//给个超级远的值
+                    } 
+                    depthValue.x = distance;
+                    
+                   // return  r[1] + r[0] / 256  
+                    distance += .1;          // add a safety margin
+
+                    vec4 eyePos2 = vec4(normalize(eyePos.xyz) * distance, 1.);
+                    vec4 clipPos2 = projectionMatrix * eyePos2;
+                    vec4 ndcPos2 = clipPos2 * 1. / clipPos2.w;
+
+                    
+                    depthValue.y = 0.5 * ((gl_DepthRange.far - gl_DepthRange.near) * ndcPos2.z
+                            + gl_DepthRange.near + gl_DepthRange.far); 
+                    return depthValue;      
+                }
+                //注:未加载好的话,depth为0,导致第一次漫游过去的时候许多mesh会立刻被遮挡,所以要确保加载完
+            #endif
+            
+            void main()
+            {
+                
+                /* 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
+                    colorFromPano0=textureCube(pano0Map,vWorldPosition0.xyz);
+                }
+                vec4 colorFromPano1=textureCube(pano1Map,vWorldPosition1.xyz);
+ 
+                gl_FragColor=mix(colorFromPano0,colorFromPano1,progress);
+              
+              
+                
+              
+                //深度图修改深度
+              
+                #if defined(GL_EXT_frag_depth) && defined(hasDepthTex)  
+                    vec4 ndcPos;
+                    ndcPos.xy = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1.;
+                    ndcPos.z = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) /
+                        (gl_DepthRange.far - gl_DepthRange.near);
+                    ndcPos.w = 1.0;
+
+                    vec4 clipPos = ndcPos / gl_FragCoord.w;
+                    vec4 eyePos = inverseProjectionMatrix * clipPos;
+                    vec2 depth0 = vec2(0.0,0.0); 
+                    if(progress < 1.0){
+                        depth0 = getDepth(vWorldPosition0, depthMap0, cameraHeight0, eyePos);
+                    }
+                    vec2 depth1 = getDepth(vWorldPosition1, depthMap1, cameraHeight1, 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);
+                    //}
+                    
+                    
+
+                #endif
+
+                
+            }
+        `
+    }
+            
+            
+
+export default class ModelTextureMaterial extends THREE.RawShaderMaterial { 
+	constructor( ){ 
+    
+        let defines = {}
+        if(Potree.settings.hasDepthTex){
+            defines.hasDepthTex = '' 
+        } 
+       
+        
+        super({
+            fragmentShader: shader.fragmentShader,
+			vertexShader: shader.vertexShader,
+			uniforms: THREE.UniformsUtils.clone(shader.uniforms),
+            side:THREE.DoubleSide,
+			name: "ModelTextureMaterial",
+            defines
+        })
+        
+        
+        /* var defines = parameters.defines || {}
+        defines.Not_Cube = "";
+        parameters.defines = defines; 
+		
+ 
+		super(Object.assign()({
+			fragmentShader: shaders[matName].fragmentShader,
+			vertexShader: shaders[matName].vertexShader,
+			uniforms: THREE.UniformsUtils.clone(shaders[matName].uniforms),
+			name: "ModelTextureMaterial"
+		}, parameters));*/
+        
+            
+        let setSize = (e)=>{ 
+            let viewport = e.viewport
+            let viewportOffset = viewport.offset || new Vector2()  
+            let resolution = viewport.resolution2 
+            this.uniforms.viewport.value.set(viewportOffset.x, viewportOffset.y, resolution.x, resolution.y) 
+        }
+        let viewport = viewer.mainViewport;
+         
+        setSize({viewport})
+
+
+        viewer.addEventListener('resize',(e)=>{
+            setSize(e)     
+        }) 
+
+        /* if(this.supportExtDepth) */{
+         
+            //add
+            
+            viewer.addEventListener('camera_changed', (e)=>{
+                //this.uniforms.projectionMatrix.value.copy(e.camera.projectionMatrix) 
+                this.uniforms.inverseProjectionMatrix.value.copy(e.camera.projectionMatrixInverse)
+            })   
+     
+        
+            /* viewer.addEventListener("render.begin", (e)=>{//before render  如果有大于两个viewport的话,不同viewport用不同的depthTex
+                if(e.viewport.camera.isPerspectiveCamera) this.updateDepthParams(e)
+            }) */ 
+
+        }
+
+        
+		//-------------------------------------
+	}
+
+	/**
+	 * 
+	 * @param {Panorama} pano0 
+	 * @param {Panorama} pano1 
+	 * @param {boolean} flag 
+     
+     更新全景图的材质uniforms 
+     
+	 */
+     
+      
+     
+	setProjectedPanos(pano0, pano1, progressValue ){
+        
+ 		progressValue!=void 0 && (this.uniforms.progress.value = progressValue);
+		//pano0.ensureSkyboxReadyForRender();
+        
+        
+        if(pano0){
+            this.uniforms.pano0Map.value = pano0.getSkyboxTexture();//pano0.texture
+            this.uniforms.pano0Position.value.copy(pano0.position)
+            this.uniforms.pano0Matrix.value.copy(pano0.panoMatrix/* pano0.mesh.matrixWorld */ );
+            this.uniforms.cameraHeight0.value = pano0.floorPosition.distanceTo(pano0.position)
+            
+            //pano1.ensureSkyboxReadyForRender();
+        }
+        
+		
+		this.uniforms.pano1Map.value = pano1.getSkyboxTexture()//pano1.texture;
+		this.uniforms.pano1Position.value.copy(pano1.position)
+		this.uniforms.pano1Matrix.value.copy(pano1.panoMatrix /* pano1.mesh.matrixWorld */ );
+        this.uniforms.cameraHeight1.value = pano1.floorPosition.distanceTo(pano1.position)
+        this.pano0 = pano0
+        this.pano1 = pano1
+        
+        this.updateDepthTex(pano0)  
+        this.updateDepthTex(pano1)
+        
+        
+        console.log('setProjectedPanos', pano0.id, pano1&&pano1.id)
+        //this.needsUpdate = true;
+ 	}
+    
+    
+    
+    updateDepthTex(pano){
+        if( !Potree.settings.hasDepthTex || !pano || !pano.depthTex || pano!=this.pano0 && pano!=this.pano1)return
+        //console.log('updateDepthTex', pano.id,  this.pano0 && this.pano0.id,  this.pano1 && this.pano1.id)
+        this.uniforms.depthMap0.value = this.pano0 && this.pano0.depthTex 
+        this.uniforms.depthMap1.value = this.pano1 && this.pano1.depthTex 
+       
+    }
+    
+    EnableDepthTex(){//开启DepthTex
+        if(this.defines['hasDepthTex']){
+            return 
+        }
+        this.defines['hasDepthTex'] = ''
+        this.needsUpdate = true;
+    }
+}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 789 - 105
src/modules/Images360/Images360.js


+ 0 - 210
src/modules/Images360/ModelTextureMaterial.js

@@ -1,210 +0,0 @@
-import * as THREE from "../../../libs/three.js/build/three.module.js";
-const prefixVertex ="precision highp float;\nprecision highp int;\n\nuniform mat4 modelMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\n"
-const prefixFragment ="precision highp float;\nprecision highp int;\n\nuniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"
- 
-let shader = {
-	 
-		uniforms: { 
-			
-			opacity: {
-				type: "f",
-				value: 1
-			},
-			progress: {
-				type: "f",
-				value: 0
-			},
-			
-			pano0Map: {
-				type: "t",
-				value: null
-			},
-			pano0Position: {
-				type: "v3",
-				value: new THREE.Vector3
-			},
-			pano0Matrix: {
-				type: "m4",
-				value: new THREE.Matrix4
-			},
-			pano1Map: {
-				type: "t",
-				value: null
-			},
-			pano1Position: {
-				type: "v3",
-				value: new THREE.Vector3
-			},
-			pano1Matrix: {
-				type: "m4",
-				value: new THREE.Matrix4
-            } 
-            
-        },
-       
-        vertexShader: prefixVertex + `
-
-            uniform vec3 pano0Position;
-            uniform mat4 pano0Matrix;
-            
-            uniform vec3 pano1Position;
-            uniform mat4 pano1Matrix;
-
-           
-            varying vec2 vUv;
-            varying vec3 vWorldPosition0;
-            varying vec3 vWorldPosition1;
-            
-            vec3 transformAxis( vec3 direction ) //navvis->4dkk
-            {
-                float y = direction.y;
-                direction.y = direction.z;
-                direction.z = -y;
-                return  direction;
-            }  
-            
-            
-            
-            void main() {
-            
-                vUv = uv;
-                vec4 worldPosition = modelMatrix * vec4(position, 1.0);
-                
-                
-            
-                vec3 positionLocalToPanoCenter0 = worldPosition.xyz - pano0Position;
-                vWorldPosition0 = (vec4(positionLocalToPanoCenter0, 1.0) * pano0Matrix).xyz;
-                vWorldPosition0.x *= -1.0;
-                vWorldPosition0 = transformAxis(vWorldPosition0);
-                
-                vec3 positionLocalToPanoCenter1 = worldPosition.xyz - pano1Position;
-                vWorldPosition1 = (vec4(positionLocalToPanoCenter1, 1.0) * pano1Matrix).xyz;
-                vWorldPosition1.x *= -1.0;
-                vWorldPosition1 = transformAxis(vWorldPosition1);
-                
-                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
-            
-            }
-
-        `,
-        fragmentShader: prefixFragment + `
-
-            #define PI 3.141592653 
-            
-             
-            uniform float modelAlpha;
-            uniform float opacity;
-            uniform float progress;
-            uniform int blackout;
-            uniform vec3 pano0Position;
-            uniform vec3 pano1Position;
-            uniform float maxDistance;
-            uniform float minDistance;
-            uniform float minOpa;
-            
-          
-       
-            /* uniform sampler2D pano0Map;
-            uniform sampler2D pano1Map;    */   
-            uniform samplerCube pano0Map;
-            uniform samplerCube pano1Map;
-          
-            
-            varying vec2 vUv;
-            varying vec3 vWorldPosition0;
-            varying vec3 vWorldPosition1;
-
-          
-            vec2 getSamplerCoord( vec3 direction ) 
-            {
-                direction = normalize(direction);
-                float tx=atan(direction.x,-direction.y)/(PI*2.0)+0.5;
-                float ty=acos(direction.z)/PI;
-
-                return vec2(tx,ty);
-            }  
-            void main()
-            {
-                
-                /* vec2 samplerCoord0 = getSamplerCoord(vWorldPosition0.xyz);
-                vec2 samplerCoord1 = getSamplerCoord(vWorldPosition1.xyz);  
-                vec4 colorFromPano0=texture2D(pano0Map,samplerCoord0);
-                vec4 colorFromPano1=texture2D(pano1Map,samplerCoord1); */
-                
-                vec4 colorFromPano0=textureCube(pano0Map,vWorldPosition0.xyz);
-                vec4 colorFromPano1=textureCube(pano1Map,vWorldPosition1.xyz);
-
-                
-
-
-
-
-                gl_FragColor=mix(colorFromPano0,colorFromPano1,progress);
-              
-                
-            }
-        `
-    }
-            
-            
-
-export default class ModelTextureMaterial extends THREE.RawShaderMaterial { 
-	constructor( ){ 
-        
-        super({
-            fragmentShader: shader.fragmentShader,
-			vertexShader: shader.vertexShader,
-			uniforms: THREE.UniformsUtils.clone(shader.uniforms),
-            side:THREE.DoubleSide,
-			name: "ModelTextureMaterial"
-            
-        })
-        
-        
-        /* var defines = parameters.defines || {}
-        defines.Not_Cube = "";
-        parameters.defines = defines; 
-		
- 
-		super(common.extendObject({
-			fragmentShader: shaders[matName].fragmentShader,
-			vertexShader: shaders[matName].vertexShader,
-			uniforms: THREE.UniformsUtils.clone(shaders[matName].uniforms),
-			name: "ModelTextureMaterial"
-		}, parameters));*/
-        
-        
-		//-------------------------------------
-	}
-
-	/**
-	 * 
-	 * @param {Panorama} pano0 
-	 * @param {Panorama} pano1 
-	 * @param {boolean} flag 
-     
-     更新全景图的材质uniforms 
-     
-	 */
-	setProjectedPanos(pano0, pano1, progressValue ){
-        
- 		progressValue!=void 0 && (this.uniforms.progress.value = progressValue);
-		//pano0.ensureSkyboxReadyForRender();
-        
-        
-        if(pano0){
-            this.uniforms.pano0Map.value = pano0.getSkyboxTexture();//pano0.texture
-            this.uniforms.pano0Position.value.copy(pano0.position)
-            this.uniforms.pano0Matrix.value.copy(pano0.panoMatrix/* pano0.mesh.matrixWorld */ );
-            //pano1.ensureSkyboxReadyForRender();
-        }
-        
-		
-		this.uniforms.pano1Map.value = pano1.getSkyboxTexture()//pano1.texture;
-		this.uniforms.pano1Position.value.copy(pano1.position)
-		this.uniforms.pano1Matrix.value.copy(pano1.panoMatrix /* pano1.mesh.matrixWorld */ );
-        
-        
-        this.needsUpdate = true;
- 	}
-}

+ 76 - 12
src/modules/Images360/Panorama.js

@@ -16,11 +16,23 @@ const labelProp = {
 }
 }
 
 
 let standardMarkerMat 
 let standardMarkerMat 
+let markerTex
 let getMarerMat = function(){
 let getMarerMat = function(){
     if(!standardMarkerMat) {
     if(!standardMarkerMat) {
-        let map = texLoader.load( Potree.resourcePath+'/textures/marker.png' )
-        map.anisotropy = 4 // 各向异性过滤 .防止倾斜模糊
-        standardMarkerMat = new THREE.MeshBasicMaterial({opacity:0.7, side: THREE.DoubleSide , map ,transparent:true, depthTest:false})//总是被点云遮住,所以depthTest:false
+        markerTex = {
+            default:texLoader.load( Potree.resourcePath+'/textures/marker.png' ),
+            ring:texLoader.load( Potree.resourcePath+'/textures/marker2.png' )
+        }
+        markerTex.default.anisotropy = 4 // 各向异性过滤 .防止倾斜模糊
+        markerTex.ring.anisotropy = 4 
+        standardMarkerMat = new THREE.MeshBasicMaterial({opacity:0.7, side: THREE.DoubleSide , map:markerTex.default ,transparent:true, 
+            depthTest: Potree.settings.hasDepthTex ? true : false
+            
+        })
+        //有可能被点云遮住吗。
+        
+        
+        //等深度图出来后,改为depthTest:true, 这样两种模式都可以看到遮挡
     }
     }
     return standardMarkerMat.clone()
     return standardMarkerMat.clone()
 }
 }
@@ -66,8 +78,9 @@ class Panorama extends THREE.EventDispatcher{
             if(e.reason == 'screenshot' || e.visible){
             if(e.reason == 'screenshot' || e.visible){
                 this.label && (this.label.visible = e.visible)//截图时隐藏下
                 this.label && (this.label.visible = e.visible)//截图时隐藏下
             }
             }
+            viewer.updateVisible(this.label2, 'panoVisi', e.visible)
         })
         })
-        /* 
+        /*  
         漫游点可见性:旧
         漫游点可见性:旧
             level       reason                           类型
             level       reason                           类型
             2(最高)buildingChange(不在此楼层)        unvisible   
             2(最高)buildingChange(不在此楼层)        unvisible   
@@ -149,7 +162,7 @@ class Panorama extends THREE.EventDispatcher{
                 qua = [qua[1], qua[2], qua[3], qua[0]] 
                 qua = [qua[1], qua[2], qua[3], qua[0]] 
                 this.quaternion = new THREE.Quaternion().fromArray(qua)
                 this.quaternion = new THREE.Quaternion().fromArray(qua)
                 this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion 
                 this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion 
-                
+                this.quaternion2 = this.quaternion.clone()
                 this.quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion,  rot90);//全景图和Cube的水平采样起始坐标相差90度,cubeTex转90度
                 this.quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion,  rot90);//全景图和Cube的水平采样起始坐标相差90度,cubeTex转90度
                 
                 
                 this.rotation4dkk = new THREE.Euler().setFromQuaternion(this.quaternion4dkk)
                 this.rotation4dkk = new THREE.Euler().setFromQuaternion(this.quaternion4dkk)
@@ -215,7 +228,20 @@ class Panorama extends THREE.EventDispatcher{
     }
     }
 
 
  
  
-
+    loadDepthImg(){ 
+        if(this.depthTex || this.depthTexLoading || !Potree.settings.hasDepthTex)return
+        this.depthTexLoading = true
+        let src = `${Potree.scriptPath}/data/${Potree.settings.number}/depthMap/${this.originID}.png`
+        let texture = texLoader.load( src, ()=>{
+            this.depthTex = texture
+            this.images360.dispatchEvent({type:'loadedDepthImg', pano:this})
+            this.depthTexLoading = false
+        });
+        texture.wrapS = THREE.RepeatWrapping;
+        texture.flipY = false 
+        texture.magFilter = THREE.LinearFilter
+        texture.minFilter = THREE.LinearFilter
+	}
 
 
     
     
     build(){
     build(){
@@ -249,6 +275,10 @@ class Panorama extends THREE.EventDispatcher{
             //quaternion.premultiply(rot90)
             //quaternion.premultiply(rot90)
             this.panoMatrix = new THREE.Matrix4().makeRotationFromQuaternion(this.quaternion) 
             this.panoMatrix = new THREE.Matrix4().makeRotationFromQuaternion(this.quaternion) 
             this.oriPanoMatrix = this.panoMatrix.clone()
             this.oriPanoMatrix = this.panoMatrix.clone()
+            
+            this.oriPanoMatrix2 = new THREE.Matrix4().makeRotationFromQuaternion(this.quaternion2) 
+        
+            
             //console.log(this.quaternion)
             //console.log(this.quaternion)
             //this.quaternion = quaternion
             //this.quaternion = quaternion
         } 
         } 
@@ -259,7 +289,9 @@ class Panorama extends THREE.EventDispatcher{
             marker.up.set(0,0,1)
             marker.up.set(0,0,1)
             marker.lookAt(marker.up) 
             marker.lookAt(marker.up) 
             marker.scale.set(2,2,2) 
             marker.scale.set(2,2,2) 
-            
+        this.addEventListener('changeMarkerTex',(e)=>{
+            marker.material.map = markerTex[e.name]  
+        })    
              
              
         this.marker = marker 
         this.marker = marker 
         if(Potree.settings.editType == 'pano'){
         if(Potree.settings.editType == 'pano'){
@@ -268,7 +300,7 @@ class Panorama extends THREE.EventDispatcher{
         
         
         this.images360.node.add(marker)
         this.images360.node.add(marker)
         Potree.settings.isTest && this.createTextLabel()
         Potree.settings.isTest && this.createTextLabel()
-        
+        this.createTextLabel2() 
         
         
         /* let mouseover = (e)=>{ 
         /* let mouseover = (e)=>{ 
             if(!e.byMap){
             if(!e.byMap){
@@ -301,7 +333,9 @@ class Panorama extends THREE.EventDispatcher{
         this.setPosition(position, floorPosition) 
         this.setPosition(position, floorPosition) 
         this.panoMatrix = new THREE.Matrix4().multiplyMatrices(this.pointcloud.rotateMatrix, this.oriPanoMatrix  ) 
         this.panoMatrix = new THREE.Matrix4().multiplyMatrices(this.pointcloud.rotateMatrix, this.oriPanoMatrix  ) 
         //this.panoMatrix2 =  Potree.Utils.datasetRotTransform({fromDataset:true, pointcloud:this.pointcloud,  matrix:this.oriPanoMatrix, getMatrix:true}) //和上一行结果一样
         //this.panoMatrix2 =  Potree.Utils.datasetRotTransform({fromDataset:true, pointcloud:this.pointcloud,  matrix:this.oriPanoMatrix, getMatrix:true}) //和上一行结果一样
-        //quaternion也变下  
+        //quaternion也变下 
+        this.panoMatrix2 = new THREE.Matrix4().multiplyMatrices(this.pointcloud.rotateMatrix, this.oriPanoMatrix2  )//供DepthImageSampler使用 
+        this.panoMatrix2Inverse = this.panoMatrix2.clone().invert();     
         this.dispatchEvent('rePos')
         this.dispatchEvent('rePos')
     }
     }
     
     
@@ -311,16 +345,25 @@ class Panorama extends THREE.EventDispatcher{
         //this.mesh.position.copy(this.position)
         //this.mesh.position.copy(this.position)
         this.marker.position.copy(this.floorPosition) 
         this.marker.position.copy(this.floorPosition) 
         this.marker.position.z+=0.1//会被点云遮住
         this.marker.position.z+=0.1//会被点云遮住
-        if(this.label){
-             
+        if(this.label){ 
             if(Potree.settings.editType == 'pano'){
             if(Potree.settings.editType == 'pano'){
                 this.label.position.copy(this.position)
                 this.label.position.copy(this.position)
             }else{
             }else{
                 this.label.position.copy(this.floorPosition)
                 this.label.position.copy(this.floorPosition)
-            }
+            } 
             this.label.position.z+=0.2
             this.label.position.z+=0.2
             this.label.update()
             this.label.update()
         }
         }
+        
+        if(this.label2){
+            if(Potree.settings.editType == 'pano'){
+                this.label2.position.copy(this.position)
+            }else{
+                this.label2.position.copy(this.floorPosition)
+            }
+            this.label2.position.copy(this.marker.position)
+            this.label2.update()
+        }
           
           
     }
     }
     
     
@@ -501,6 +544,27 @@ class Panorama extends THREE.EventDispatcher{
         this.floorPosition && this.label.position.copy(this.floorPosition)
         this.floorPosition && this.label.position.copy(this.floorPosition)
     }
     }
     
     
+    createTextLabel2(){ 
+        let labelProp2 = {
+            //sizeInfo: {minSize : 200 ,  maxSize : 250,   nearBound : 0.8, farBound : 10},
+            backgroundColor:{r: 255, g: 255, b: 255, a: 0 },
+            textColor:{r:255 , g: 255, b: 255, a: 1 }, 
+            textBorderColor:{r:30 , g:30, b: 30, a: 1 }, 
+            textBorderThick:3,
+            dontFixOrient:true,
+            renderOrder:10,
+            fontsize:30,
+        } 
+        this.label2 = new TextSprite(Object.assign({},
+           labelProp2, {text: /* this.originID  */   parseInt(this.id)+1   }) //{text: `id:${this.id}, dataset:${this.pointcloud.name}, 4dkkId:${this.originID}`}
+        ); 
+        this.images360.node.add(this.label2);
+        this.floorPosition && this.label2.position.copy(this.floorPosition)
+        let s = 0.4
+        this.label2.scale.set(s,s,s)
+        viewer.updateVisible(this.label2, 'notDisplay', false)
+    }
+    
     removeTextLabel(){
     removeTextLabel(){
         if(this.label){ 
         if(this.label){ 
             this.label.parent.remove(this.label);
             this.label.parent.remove(this.label);

+ 1 - 1
src/modules/Images360/tile/TilePrioritizer.js

@@ -225,7 +225,7 @@ TilePrioritizer.prototype.filterAndPrioritize = function () {//挑选出优先
         //获得视野范围内的邻近点位序列t
         //获得视野范围内的邻近点位序列t
         this.populateScoredPanos(this.priorityCriteria.pano, panos, t, cameraDirLocals , TilePrioritizer.MAX_SCORED_PANOS_TOCONSIDER);
         this.populateScoredPanos(this.priorityCriteria.pano, panos, t, cameraDirLocals , TilePrioritizer.MAX_SCORED_PANOS_TOCONSIDER);
         
         
-        
+        t.forEach(p=>p.loadDepthImg())
         
         
         var s = this.baseSize //512
         var s = this.baseSize //512
             ,
             ,

+ 1 - 0
src/modules/panoEdit/panoEditor.js

@@ -137,6 +137,7 @@ class PanoEditor extends THREE.EventDispatcher{
             
             
             Alignment.bus.addEventListener('switchHandle', this.updateCursor.bind(this))
             Alignment.bus.addEventListener('switchHandle', this.updateCursor.bind(this))
             
             
+            
             viewer.addEventListener('global_click',(e)=>{
             viewer.addEventListener('global_click',(e)=>{
                 if(e.button === THREE.MOUSE.RIGHT){//取消旋转和平移
                 if(e.button === THREE.MOUSE.RIGHT){//取消旋转和平移
                      console.log('right click',e)
                      console.log('right click',e)

+ 1 - 1
src/modules/siteModel/BuildingBox.js

@@ -799,7 +799,7 @@ export class BuildingBox extends ctrlPolygon{//建筑实体,包括building, fl
     
     
     unselect(){
     unselect(){
         if(!this.selected)return
         if(!this.selected)return
-        console.log('unselect '+this.name  )
+        //console.log('unselect '+this.name  )
         if(this.box){
         if(this.box){
             this.box.material = this.mats.boxDefault;
             this.box.material = this.mats.boxDefault;
         }
         }

+ 9 - 6
src/modules/siteModel/SiteModel.js

@@ -63,7 +63,9 @@ var SiteModel = {
         if(Potree.settings.isOfficial){
         if(Potree.settings.isOfficial){
              
              
             viewer.addEventListener('camera_changed', e => {
             viewer.addEventListener('camera_changed', e => {
-                this.updateEntityAt()
+                if(e.changeInfo.positionChanged){
+                    this.updateEntityAt()
+                }
             })
             })
         }
         }
         
         
@@ -98,7 +100,7 @@ var SiteModel = {
         let fun = ()=>{ //延时update,防止卡顿
         let fun = ()=>{ //延时update,防止卡顿
             let currPos = viewer.mainViewport.view.position
             let currPos = viewer.mainViewport.view.position
             
             
-            if(force || !currPos.equals(this.lastPos)){
+            //if(force   || !currPos.equals(this.lastPos) ){
                 //console.log('currPos ', currPos.toArray())
                 //console.log('currPos ', currPos.toArray())
                 this.lastPos.copy(currPos)
                 this.lastPos.copy(currPos)
                 let entity;
                 let entity;
@@ -109,14 +111,14 @@ var SiteModel = {
                 if(force || this.inEntity != entity ){
                 if(force || this.inEntity != entity ){
                     let oldEntity = this.inEntity
                     let oldEntity = this.inEntity
                     this.inEntity = entity 
                     this.inEntity = entity 
-                    console.log('buildingChange', entity) 
+                    //console.log('buildingChange', entity) 
                     this.bus.dispatchEvent({type:'buildingChange',entity}) 
                     this.bus.dispatchEvent({type:'buildingChange',entity}) 
                     //this.updatePanosVisible(oldEntity, this.inEntity) 
                     //this.updatePanosVisible(oldEntity, this.inEntity) 
                       
                       
                     let lastFloor = this.currentFloor   //oldEntity ? oldEntity.buildType == 'floor' ? oldEntity : oldEntity.buildType == 'room' ? oldEntity.buildParent : null : null; //基本只会是floor或room
                     let lastFloor = this.currentFloor   //oldEntity ? oldEntity.buildType == 'floor' ? oldEntity : oldEntity.buildType == 'room' ? oldEntity.buildParent : null : null; //基本只会是floor或room
                     let currentFloor = entity ? entity.buildType == 'floor' ? entity : entity.buildType == 'room' ? entity.buildParent : null : null; //基本只会是floor或room
                     let currentFloor = entity ? entity.buildType == 'floor' ? entity : entity.buildType == 'room' ? entity.buildParent : null : null; //基本只会是floor或room
-                    if(currentFloor != lastFloor || force){
-                        console.log('改变了floor',lastFloor,currentFloor)
+                    if(force || currentFloor != lastFloor){
+                        //console.log('改变了floor',lastFloor,currentFloor)
                         this.currentFloor = currentFloor
                         this.currentFloor = currentFloor
                         this.bus.dispatchEvent({type:'FloorChange',currentFloor}) 
                         this.bus.dispatchEvent({type:'FloorChange',currentFloor}) 
                     }
                     }
@@ -124,7 +126,7 @@ var SiteModel = {
                 }
                 }
                 force = false
                 force = false
                 return true 
                 return true 
-            }
+            //}
         }
         }
         
         
         if(force)fun()
         if(force)fun()
@@ -197,6 +199,7 @@ var SiteModel = {
         this.clear()   
         this.clear()   
         this.editing = false
         this.editing = false
         
         
+        this.updateEntityAt(true)
         viewer.updateFpVisiDatasets()
         viewer.updateFpVisiDatasets()
     } ,
     } ,
     
     

+ 79 - 18
src/navigation/InputHandler.js

@@ -50,7 +50,7 @@ export class InputHandler extends THREE.EventDispatcher {
         this.touches = []
         this.touches = []
 
 
 
 
-        
+        this.hoverViewport = viewer.viewports[0]
         
         
         
         
         
         
@@ -397,7 +397,7 @@ export class InputHandler extends THREE.EventDispatcher {
         if(isTouch){ 
         if(isTouch){ 
             this.hoveredElements = this.getHoveredElements(); 
             this.hoveredElements = this.getHoveredElements(); 
               
               
-            let intersectPoint = this.getIntersect(viewport,camera)
+            let intersectPoint = this.getIntersect(viewport  )
             
             
             
             
         }
         }
@@ -696,17 +696,72 @@ export class InputHandler extends THREE.EventDispatcher {
         }
         }
     }
     }
 
 
-    getIntersect(viewport,camera, onlyGetIntersect, pickWindowSize, dontIntersectPointcloud){
-        //add
-        let intersectPoint = (viewport.noPointcloud || dontIntersectPointcloud)? null : Utils.getMousePointCloudIntersection(
-            viewport,
-            this.mouse,
-            this.pointer, 
-            camera, 
-            this.viewer, 
-            this.viewer.scene.pointclouds,
-            {pickClipped: true, isMeasuring: this.isMeasuring, pickWindowSize}
-        );
+
+    ifBlockedByIntersect(point, margin, usePointcloud, cameraPos, pickWindowSize){//某点是否被遮挡(不允许camera修改位置, 因为depthTex不好置换)
+         
+        if(cameraPos){
+            usePointcloud = true  //只有使用点云才允许换位置
+        }
+         
+        let intersectPoint = this.getIntersect(this.hoverViewport, true, pickWindowSize, null, usePointcloud, {point, cameraPos})
+        if(intersectPoint && intersectPoint.distance+margin <= point.distanceTo(cameraPos||this.hoverViewport.view.position)){
+            return intersectPoint //被遮挡
+        }
+        //点云模式,对没加载出的点云不准确。 尤其是需要修改相机位置时,因临时修改并不能使点云加载。
+    }
+
+    getIntersect(viewport,   onlyGetIntersect, pickWindowSize, dontIntersectPointcloud, usePointcloud, prop={}){
+        let intersectPoint  
+        let camera = viewport.camera
+        
+        if(Potree.settings.hasDepthTex && !usePointcloud && !this.isMeasuring && viewport == viewer.mainViewport && Potree.settings.displayMode == 'showPanos'){
+            let raycaster 
+            /* 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),
+            }  */
+            let intersect
+            if(prop.point){
+                let dir = new THREE.Vector3().subVectors(subPano.position, mainPano.position).normalize();
+                intersect = {dir}
+            }else{
+                intersect = Utils.getIntersect(camera, [viewer.images360.cube], this.pointer, raycaster) 
+            } 
+            intersectPoint = viewer.images360.depthSampler.sample(intersect, null, !!prop.point) 
+             
+        }else{
+            if(prop.point){
+                /* oldView = viewport.view.clone()
+                viewport.view.position.copy(raycaster.ray.origin)
+                viewport.view. */
+                prop.cameraPos && camera.position.copy(prop.cameraPos)
+                camera.lookAt(prop.point)
+                camera.updateMatrixWorld()
+                this.pointer.set(0,0)   //画布中心
+                this.mouse.set(Math.round(viewport.resolution.x/2), Math.round(viewport.resolution.y/2))
+            }
+                
+            intersectPoint = (viewport.noPointcloud || dontIntersectPointcloud)? null : Utils.getMousePointCloudIntersection(
+                viewport,
+                this.mouse,
+                this.pointer, 
+                camera, 
+                this.viewer, 
+                this.viewer.scene.pointclouds,
+                {pickClipped: true, isMeasuring: this.isMeasuring, pickWindowSize, cameraChanged: !!prop.point }  
+                
+            );
+            //恢复
+            if(prop.point){
+                viewport.view.applyToCamera(camera)
+                camera.updateMatrixWorld()
+            }
+        }
+        
+        
+        
+        
         
         
             
             
         //console.log(viewport.name , intersectPoint &&  intersectPoint.location )
         //console.log(viewport.name , intersectPoint &&  intersectPoint.location )
@@ -763,11 +818,10 @@ export class InputHandler extends THREE.EventDispatcher {
     dealPointerMove(e, isTouch){ 
     dealPointerMove(e, isTouch){ 
         if(isTouch){
         if(isTouch){
             var  {  camera, viewport  } = this.updateTouchesInfo(e) 
             var  {  camera, viewport  } = this.updateTouchesInfo(e) 
-        }else{
-            
+        }else { 
             var  {  camera, viewport  } = this.getPointerInViewport(e.clientX, e.clientY,  this.dragViewport) 
             var  {  camera, viewport  } = this.getPointerInViewport(e.clientX, e.clientY,  this.dragViewport) 
         }
         }
-         
+          
 		this.hoverViewport = viewport
 		this.hoverViewport = viewport
         if(!viewport)return//刚变化viewport时会找不到
         if(!viewport)return//刚变化viewport时会找不到
          
          
@@ -779,7 +833,7 @@ export class InputHandler extends THREE.EventDispatcher {
         
         
             let dontIntersectPointcloud =  this.drag && viewport.alignment && Potree.settings.editType == 'pano' || viewer.images360.flying // flying 时可能卡顿
             let dontIntersectPointcloud =  this.drag && viewport.alignment && Potree.settings.editType == 'pano' || viewer.images360.flying // flying 时可能卡顿
             //console.log('dontIntersectPointcloud',dontIntersectPointcloud)
             //console.log('dontIntersectPointcloud',dontIntersectPointcloud)
-            intersectPoint = this.getIntersect(viewport,camera,e.onlyGetIntersect, e.pickWindowSize, dontIntersectPointcloud) //数据集多的时候卡顿
+            intersectPoint = this.getIntersect(viewport,  e.onlyGetIntersect, e.pickWindowSize, dontIntersectPointcloud, e.whichPointcloud) //数据集多的时候卡顿
         } 
         } 
         
         
         if(e.onlyGetIntersect){ 
         if(e.onlyGetIntersect){ 
@@ -1130,7 +1184,14 @@ export class InputHandler extends THREE.EventDispatcher {
         
         
         viewer.dispatchEvent( {type:'raycaster',  viewport: this.hoverViewport})//add
         viewer.dispatchEvent( {type:'raycaster',  viewport: this.hoverViewport})//add
 		let intersections = raycaster.intersectObjects(interactables.filter(o => o.visible), true); //原本是false 检测不到children
 		let intersections = raycaster.intersectObjects(interactables.filter(o => o.visible), true); //原本是false 检测不到children
-         
+        if(this.intersectPoint && this.intersectPoint.distance != void 0){//add
+            intersections = intersections.filter(e=>{
+                let material = e.object.material
+                
+                return (material.depthTest == false || material.depthWrite == false) && !material.depthTestWhenPick
+                 || e.distance < this.intersectPoint.distance
+            }) 
+        }
         intersections = intersections.map(e=>{//add 转化为interactables
         intersections = intersections.map(e=>{//add 转化为interactables
             var object = e.object; 
             var object = e.object; 
             do{ 
             do{ 

+ 1 - 1
src/objects/Magnifier.js

@@ -85,7 +85,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
 			  */ 
 			  */ 
         } )
         } )
         
         
-		this.rtEDL = new THREE.WebGLRenderTarget(this.width, this.height, {
+		this.rtEDL = new THREE.WebGLRenderTarget(this.width, this.height, {  //好像没用到? 因为这里不绘制测量线
 			minFilter: THREE.NearestFilter,
 			minFilter: THREE.NearestFilter,
 			magFilter: THREE.NearestFilter,
 			magFilter: THREE.NearestFilter,
 			format: THREE.RGBAFormat,
 			format: THREE.RGBAFormat,

+ 10 - 4
src/objects/Reticule.js

@@ -210,11 +210,17 @@ export default class Reticule extends THREE.Mesh{
                 location.setZ(0);//低于相机高度即可
                 location.setZ(0);//低于相机高度即可
                 this.direction = normal.clone()
                 this.direction = normal.clone()
             }else{
             }else{
-                //console.log(location) 
-                normal = new THREE.Vector3().fromArray(intersectPoint.point.normal ).applyMatrix4(intersectPoint.pointcloud.rotateMatrix);
+                if(intersectPoint.point){ 
+                    normal = new THREE.Vector3().fromArray(intersectPoint.point.normal ).applyMatrix4(intersectPoint.pointcloud.rotateMatrix);
+                }else{
+                    normal = intersectPoint.normal  //when showPanos
+                }
                 
                 
-                this.direction = this.direction.multiplyScalar(.8); 
-                this.direction.add(normal.clone().multiplyScalar(.2)); 
+                if(normal){
+                    let ratio = Potree.settings.hasDepthTex ? 1 : 0.2;   
+                    this.direction = this.direction.multiplyScalar(1-ratio); 
+                    this.direction.add(normal.clone().multiplyScalar(ratio)); 
+                }
                 //this.direction = normal.clone() //改为瞬间变化,否则刚hover上某个点时看起来不太对
                 //this.direction = normal.clone() //改为瞬间变化,否则刚hover上某个点时看起来不太对
             }
             }
              
              

+ 9 - 5
src/objects/tool/Measure.js

@@ -29,7 +29,11 @@ const lineDepthInfo = {
 const LabelDepthInfo = {
 const LabelDepthInfo = {
     clipDistance : 6,//消失距离
     clipDistance : 6,//消失距离
     occlusionDistance: 2,//变为backColor距离 
     occlusionDistance: 2,//变为backColor距离 
-} 
+}  
+/* const LabelDepthInfo = {
+    clipDistance : 0.1,//消失距离
+    occlusionDistance: 0.1,//变为backColor距离 
+} */
 
 
 const markerSizeInfo = {
 const markerSizeInfo = {
     minSize : 25 ,  maxSize : 65,   nearBound : 0.2, farBound : 4,
     minSize : 25 ,  maxSize : 65,   nearBound : 0.2, farBound : 4,
@@ -626,6 +630,7 @@ export class Measure extends ctrlPolygon{
             })
             })
         }
         }
         edgeLabel.visible = false
         edgeLabel.visible = false
+        edgeLabel.sprite.material.depthTestWhenPick = true
         viewer.setObjectLayers(edgeLabel, 'measure' )
         viewer.setObjectLayers(edgeLabel, 'measure' )
         this.add(edgeLabel)
         this.add(edgeLabel)
         return edgeLabel
         return edgeLabel
@@ -696,9 +701,7 @@ export class Measure extends ctrlPolygon{
         if(!Measure.lineMats){
         if(!Measure.lineMats){
             Measure.lineMats = { 
             Measure.lineMats = { 
                 edgeDefault:  LineDraw.createFatLineMat({
                 edgeDefault:  LineDraw.createFatLineMat({
-                    color: config.measure.default.color,
-                    dashSize: 0.5, 
-                    gapSize: 0.2, 
+                    color: config.measure.default.color, 
                     lineWidth: config.measure.lineWidth,
                     lineWidth: config.measure.lineWidth,
                     useDepth :true,
                     useDepth :true,
                     dashWithDepth :true,  // 只在被遮住的部分显示虚线,因为实线容易挡住label
                     dashWithDepth :true,  // 只在被遮住的部分显示虚线,因为实线容易挡住label
@@ -706,7 +709,8 @@ export class Measure extends ctrlPolygon{
                     dashSize : 0.04,
                     dashSize : 0.04,
                     gapSize: 0.04,    
                     gapSize: 0.04,    
                     transparent: true,
                     transparent: true,
-                    opacity: config.measure.default.opacity
+                    opacity: config.measure.default.opacity,
+                    depthTestWhenPick:true,
                 }),
                 }),
                 edgeSelect:  LineDraw.createFatLineMat({
                 edgeSelect:  LineDraw.createFatLineMat({
                     color: config.measure.highlight.color,//'#f0ff00',
                     color: config.measure.highlight.color,//'#f0ff00',

+ 4 - 2
src/settings.js

@@ -177,7 +177,7 @@ const config = {//配置参数   不可修改
     },
     },
     material:{//初始化
     material:{//初始化
         pointSize: 0.1,  
         pointSize: 0.1,  
-        realPointSize : 0.1,//实际上的ui滑动条默认大小(兼容旧的版本)
+        realPointSize : 0.4,//实际上的ui滑动条默认大小(兼容旧的版本)
         minSize: 0.1,
         minSize: 0.1,
         maxSize: 10000,
         maxSize: 10000,
         pointSizeType: 'ATTENUATED', //'ADAPTIVE'//'ADAPTIVE' \ FIXED //ADAPTIVE的在小房间里大小会不太匹配,但在远景似乎更好
         pointSizeType: 'ATTENUATED', //'ADAPTIVE'//'ADAPTIVE' \ FIXED //ADAPTIVE的在小房间里大小会不太匹配,但在远景似乎更好
@@ -269,7 +269,7 @@ const config = {//配置参数   不可修改
     },
     },
     OrthoCameraLimit:{
     OrthoCameraLimit:{
         standard:{ 
         standard:{ 
-            zoom:{min:0.001, max:100}, //如果camera缩太小,地图会因为数字边界问题而扭曲
+            zoom:{min:0.001, max:500}, //如果camera缩太小,地图会因为数字边界问题而扭曲
             posBound:{ 
             posBound:{ 
                 min: {x:-1e5, y:-1e5,z:-1 / 0},
                 min: {x:-1e5, y:-1e5,z:-1 / 0},
                 max: {x:1e5, y:1e5, z:1 / 0  }
                 max: {x:1e5, y:1e5, z:1 / 0  }
@@ -403,6 +403,8 @@ let settings = {//设置   可修改
     urls  : $.extend({}, config.urls), 
     urls  : $.extend({}, config.urls), 
     
     
     
     
+    //hasDepthTex: true,//SS-t-7DUfWAUZ3V  使用深度贴图,得到的intersect更准确和稳定
+    
     //panoEdit:
     //panoEdit:
     datasetsPanos:{}
     datasetsPanos:{}
 }
 }

+ 6 - 3
src/start.js

@@ -112,14 +112,17 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                     
                     
                     let pano = viewer.images360.findNearestPano(center)
                     let pano = viewer.images360.findNearestPano(center)
                      
                      
-                    pano && viewer.scene.view.setView({ 
+                    /* pano && viewer.scene.view.setView({ 
                         position: pano.position.clone().add(new THREE.Vector3(10,10,10)), 
                         position: pano.position.clone().add(new THREE.Vector3(10,10,10)), 
                         target: pano.position
                         target: pano.position
+                    }) */
+                     
+                    pano && viewer.images360.flyToPano({
+                        pano,  duration:0,
+                        target : viewer.images360.bound.center     
                     })
                     })
                     
                     
                     
                     
-                    
-                    
                 } 
                 } 
             }
             }
             
             

+ 47 - 11
src/utils.js

@@ -401,7 +401,7 @@ export class Utils {
 		return texture;
 		return texture;
 	}
 	}
 
 
-	static getMousePointCloudIntersection (viewport, mouse, pointer, camera, viewer, pointclouds, pickParams = {}) {
+	static getMousePointCloudIntersection (viewport, mouse, pointer, camera, viewer, pointclouds, pickParams = {} ) {
 		if(!pointclouds)return
 		if(!pointclouds)return
         
         
 		let renderer = viewer.renderer;
 		let renderer = viewer.renderer;
@@ -423,10 +423,17 @@ export class Utils {
         //console.log('getMousePointCloudIntersection')
         //console.log('getMousePointCloudIntersection')
 		
 		
 
 
-		let raycaster = new THREE.Raycaster();
-		raycaster.setFromCamera(pointer, camera);
-		let ray = raycaster.ray;
-
+		 
+		
+		/* if(!raycaster){
+            raycaster = new THREE.Raycaster();
+            raycaster.setFromCamera(pointer, camera); 
+        }  */
+        
+        let raycaster = new THREE.Raycaster();
+        raycaster.setFromCamera(pointer, camera); 
+        let ray = raycaster.ray;
+        
 		let selectedPointcloud = null;
 		let selectedPointcloud = null;
 		let closestDistance = Infinity;
 		let closestDistance = Infinity;
 		let closestIntersection = null;
 		let closestIntersection = null;
@@ -435,25 +442,34 @@ export class Utils {
         
         
         let density
         let density
         let sizeType
         let sizeType
+        let size = new Map()  
         if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos'){ //测量或全景模式提高精准度
         if(pickParams.isMeasuring || Potree.settings.displayMode == 'showPanos'){ //测量或全景模式提高精准度
             density = Potree.settings.pointDensity 
             density = Potree.settings.pointDensity 
             Potree.settings.pointDensity = 'magnifier' 
             Potree.settings.pointDensity = 'magnifier' 
-             
+            
             pointclouds.forEach(e=>{//因为全景模式的pointSizeType是fixed所以要还原下
             pointclouds.forEach(e=>{//因为全景模式的pointSizeType是fixed所以要还原下
+                size.set(e, e.temp.pointSize)    
                 sizeType = e.material.pointSizeType  
                 sizeType = e.material.pointSizeType  
-                e.material.pointSizeType = Potree.config.material.pointSizeType  
+                e.material.pointSizeType = Potree.config.material.pointSizeType 
+                 
+                e.changePointSize(Potree.config.material.realPointSize*2, true)//更改点云大小到能铺满为止,否则容易识别不到
             }) 
             }) 
             Potree.updatePointClouds(pointclouds,  camera, viewport.resolution );
             Potree.updatePointClouds(pointclouds,  camera, viewport.resolution );
         }else{
         }else{
-            if(viewer.viewports.filter(e=>!e.noPointcloud).length>1){
+            if(viewer.viewports.filter(e=>!e.noPointcloud && e.active).length>1 || pickParams.cameraChanged){
                 viewport.beforeRender && viewport.beforeRender()
                 viewport.beforeRender && viewport.beforeRender()
                 Potree.updatePointClouds(pointclouds,  camera, viewport.resolution ); //不加这句的话hover久了会不准 因node是错的
                 Potree.updatePointClouds(pointclouds,  camera, viewport.resolution ); //不加这句的话hover久了会不准 因node是错的
-            
+                //但依旧需要camera真的移动到那个位置才能加载出点云
             }
             }
             
             
         }
         }
         
         
         
         
+         
+        
+        
+        
+        
         let allPointclouds = [] 
         let allPointclouds = [] 
 		for(let pointcloud of pointclouds){ 
 		for(let pointcloud of pointclouds){ 
             
             
@@ -483,6 +499,8 @@ export class Utils {
             
             
             pointclouds.forEach(e=>{
             pointclouds.forEach(e=>{
                 e.material.pointSizeType = sizeType
                 e.material.pointSizeType = sizeType
+                e.changePointSize(size.get(e))
+                
             })
             })
         }else{
         }else{
             /* if(viewer.viewports.filter(e=>!e.noPointcloud).length>1){
             /* if(viewer.viewports.filter(e=>!e.noPointcloud).length>1){
@@ -1354,9 +1372,27 @@ Utils.isInsideBox = function(object,  boxMatrixInverse){//object可以是点或
     intersectsSprite: ƒ intersectsSprite( sprite )
     intersectsSprite: ƒ intersectsSprite( sprite )
      */
      */
 
 
-}
- 
+} 
 
 
+ 
+Utils.getIntersect = function (camera, meshes, pointer, raycaster) {
+    //获取鼠标和meshes交点
+    camera.updateMatrixWorld()
+    if(!raycaster){//getMouseIntersect
+        raycaster = new THREE.Raycaster()
+        var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
+        end = new THREE.Vector3(pointer.x, pointer.y, 1).unproject(camera)
+        var dir = end.sub(origin).normalize()
+        raycaster.set(origin, dir)
+    } 
+    
+    meshes.forEach(e=>{ 
+        raycaster.layers.enable(math.getBaseLog(e.layers.mask,2)) 
+    }) 
+    var n = raycaster.intersectObjects(meshes)
+    if (0 === n.length) return null
+    return n[0]
+} 
 
 
 
 
 
 

+ 70 - 4
src/utils/DrawUtil.js

@@ -49,7 +49,7 @@ var LineDraw = {
         if(posArr.length == 0)return
         if(posArr.length == 0)return
         let position = []
         let position = []
         posArr.forEach(e=>position.push(e.x,e.y,e.z))
         posArr.forEach(e=>position.push(e.x,e.y,e.z))
-        line.geometry.setAttribute('position', new THREE.Float32BufferAttribute(new Float32Array(position), 3));
+        line.geometry.setAttribute('position', new THREE.Float32BufferAttribute(/* new Float32Array( */position/* ) */, 3));
       
       
 		line.geometry.attributes.position.needsUpdate = true;
 		line.geometry.attributes.position.needsUpdate = true;
 		line.geometry.computeBoundingSphere();
 		line.geometry.computeBoundingSphere();
@@ -302,13 +302,16 @@ var MeshDraw = {
 	}(), 
 	}(), 
 	getPlaneGeo : function(A,B,C,D){
 	getPlaneGeo : function(A,B,C,D){
 		var geo = this.getUnPosPlaneGeo().clone();
 		var geo = this.getUnPosPlaneGeo().clone();
-		var pos = new Float32Array([
+		var pos = [
 			A.x, A.y, A.z, 
 			A.x, A.y, A.z, 
 			B.x, B.y, B.z, 
 			B.x, B.y, B.z, 
 			C.x, C.y, C.z, 
 			C.x, C.y, C.z, 
 			D.x, D.y, D.z  
 			D.x, D.y, D.z  
-		])
-		geo.addAttribute("position", new THREE.BufferAttribute(pos, 3))  
+		] 
+		//geo.addAttribute("position", new THREE.BufferAttribute(pos, 3)) 
+        geo.setAttribute('position', new THREE.Float32BufferAttribute(pos, 3));
+      
+        
 		geo.computeVertexNormals()
 		geo.computeVertexNormals()
 		geo.computeBoundingSphere() //for raycaster
 		geo.computeBoundingSphere() //for raycaster
 		return geo;
 		return geo;
@@ -329,8 +332,71 @@ var MeshDraw = {
 		mesh.geometry.computeBoundingSphere()//for checkIntersect
 		mesh.geometry.computeBoundingSphere()//for checkIntersect
 	}  
 	}  
     
     
+    ,
+    
+    createGeometry:function(posArr, faceArr, uvArr, normalArr ){//创建复杂mesh.  faceArr:[[0,1,2],[0,2,3]]
+        let geo = new THREE.BufferGeometry;
+        
+        let positions = []; 
+        posArr.forEach(p=>positions.push(p.x,p.y,p.z)); 
+        geo.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
+        
+        if(faceArr){
+            let indice = []
+            faceArr.forEach(f=>indice.push(...f));
+            geo.setIndex(indice) // auto set Uint16BufferAttribute or Uint32BufferAttribute
+        }
+        
+        if(uvArr){
+            let uvs = []
+            uvArr.forEach(uv=>uvs.push(uv.x,uv.y));
+            geo.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2)) 
+        } 
+        
+        if(normalArr){
+            let normals = []
+            normalArr.forEach(n=>normals.push(n.x,n.y,n.z));
+            geo.setAttribute("normal", new THREE.Float32BufferAttribute(normals, 3)) 
+        }
+        /*  
+        geo.computeVertexNormals()
+		geo.computeBoundingSphere() //for raycaster 
+          */
+        return geo
+    },
     
     
     
     
+    updateGeometry:function(geo, posArr, faceArr, uvArr, normalArr ){//创建复杂mesh.  faceArr:[[0,1,2],[0,2,3]]
+        
+        let positions = []; 
+        posArr.forEach(p=>positions.push(p.x,p.y,p.z)); 
+        geo.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
+        geo.attributes.position.needsUpdate = true;
+		 
+        if(faceArr){
+            let indice = []
+            faceArr.forEach(f=>indice.push(...f));
+            geo.setIndex(indice) // auto set Uint16BufferAttribute or Uint32BufferAttribute
+        }
+        
+        if(uvArr){
+            let uvs = []
+            uvArr.forEach(uv=>uvs.push(uv.x,uv.y));
+            geo.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2)) 
+        } 
+        
+        if(normalArr){
+            let normals = []
+            normalArr.forEach(n=>normals.push(n.x,n.y,n.z));
+            geo.setAttribute("normal", new THREE.Float32BufferAttribute(normals, 3)) 
+        }
+        /*  
+        geo.computeVertexNormals()
+		
+          */
+        geo.computeBoundingSphere() //for raycaster and visi
+        return geo
+    }
 } 
 } 
 
 
 export {LineDraw, MeshDraw} ;
 export {LineDraw, MeshDraw} ;

+ 19 - 39
src/utils/math.js

@@ -5,6 +5,10 @@ import searchRings from "./searchRings.js";
 
 
 
 
 var math = {
 var math = {
+    getBaseLog(x, y) {//返回以 x 为底 y 的对数(即 logx y) .  Math.log 返回一个数的自然对数
+        return Math.log(y) / Math.log(x);
+    }
+    ,
     convertVector : {
     convertVector : {
         ZupToYup: function(e){//navvis -> 4dkk
         ZupToYup: function(e){//navvis -> 4dkk
             return new THREE.Vector3(e.x,e.z,-e.y)
             return new THREE.Vector3(e.x,e.z,-e.y)
@@ -459,9 +463,11 @@ var math = {
     },
     },
     getDirFromUV : function(uv){ //获取dir   反向计算 - -  二维转三维比较麻烦 
     getDirFromUV : function(uv){ //获取dir   反向计算 - -  二维转三维比较麻烦 
         var dirB; //所求 单位向量
         var dirB; //所求 单位向量
-
-        var y = Math.cos(uv.y * Math.PI);              //uv中纵向可以直接确定y,  根据上面getUVfromDir的反向计算
-
+        
+        
+        
+        var y = Math.cos(uv.y * Math.PI);              //uv中纵向可以直接确定y,  根据上面getUVfromDir的反向计算 
+                            // 故 uv.y * Math.PI  就是到垂直线(向上)的夹角
         var angle = 2 * Math.PI * uv.x - Math.PI       //x/z代表的是角度
         var angle = 2 * Math.PI * uv.x - Math.PI       //x/z代表的是角度
 
 
         var axisX, axisZ; //axis为1代表是正,-1是负数
         var axisX, axisZ; //axis为1代表是正,-1是负数
@@ -492,7 +498,7 @@ var math = {
         }
         }
 
 
         x *= -1 //计算完成后这里不能漏掉 *= -1	
         x *= -1 //计算完成后这里不能漏掉 *= -1	
-        dirB = new THREE.Vector3(x, y, z)
+        dirB = this.convertVector.YupToZup(new THREE.Vector3(x, y, z))   
 
 
         //理想状态下x和z和anotherDir相同
         //理想状态下x和z和anotherDir相同
         return dirB
         return dirB
@@ -500,45 +506,16 @@ var math = {
 
 
     },
     },
     
     
-    getUVfromDir : function(dir) { //获取UV  同shader里的计算
-        var dir = dir.clone();
+    getUVfromDir : function(dir) { //获取UV  同shader里的计算 
+        var dir = this.convertVector.ZupToYup(dir)
         dir.x *= -1; //计算前这里不能漏掉 *= -1  见shader
         dir.x *= -1; //计算前这里不能漏掉 *= -1  见shader
         var tx = Math.atan2(dir.x, dir.z) / (Math.PI * 2.0) + 0.5; //atan2(y,x) 返回从 X 轴正向逆时针旋转到点 (x,y) 时经过的角度。区间是-PI 到 PI 之间的值
         var tx = Math.atan2(dir.x, dir.z) / (Math.PI * 2.0) + 0.5; //atan2(y,x) 返回从 X 轴正向逆时针旋转到点 (x,y) 时经过的角度。区间是-PI 到 PI 之间的值
         var ty = Math.acos(dir.y) / Math.PI;
         var ty = Math.acos(dir.y) / Math.PI;
-        return { x: tx, y: ty }
+        return new THREE.Vector2(tx,  ty)  
 
 
         //理想状态下tx相同
         //理想状态下tx相同
     },
     },
-    crossRight : function(vec3, matrix) { //向量右乘矩阵,不能用向量的applyMatrix4(左乘)
-         var e = matrix.elements;
-         var v = new THREE.Vector3;
-         v.x = e[0] * vec3.x + e[1] * vec3.y + e[2] * vec3.z + e[3];
-         v.y = e[4] * vec3.x + e[5] * vec3.y + e[6] * vec3.z + e[7];
-         v.z = e[8] * vec3.x + e[9] * vec3.y + e[10] * vec3.z + e[11];
-         //v.w不要 
-         return v; 
-
-     },
-    getNormalDir : function(point,  supportsTiles, currentPano) { //获取A单位法线   
-         /* console.log("lookVector:")
-         console.log(objects.player.cameraControls.activeControl.lookVector) */
-
-         var dir = point.clone().sub(currentPano.position); //OA 
-         /* console.log("A的dir(无matrix转化):")
-         console.log(dir.clone().normalize()); */
-
-         if (supportsTiles) { 
-             var matrixWorld = currentPano.rot90Matrix.clone(); //因为热点求点时所右乘的matrix必须是单张全景照片时用的转90度的matrix才行   
-         } else {
-             var matrixWorld = currentPano.skyboxMesh.matrixWorld.clone();
-         } 
-         dir = this.crossRight(dir, matrixWorld) //右乘matrixWorld 得matrix转化的向量 
-         dir.normalize();
-         /* var b = player.currentPano.skyboxMesh.matrixWorld.clone().getInverse(player.currentPano.skyboxMesh.matrixWorld)
-         console.log(crossRight(dir,b).normalize()) */
-
-         return dir;
-    },
+     
     getDirByLonLat : function(lon,lat){
     getDirByLonLat : function(lon,lat){
         var dir = new THREE.Vector3
         var dir = new THREE.Vector3
         var phi = THREE.Math.degToRad(90 - lat);
         var phi = THREE.Math.degToRad(90 - lat);
@@ -611,11 +588,14 @@ var math = {
             size: bound.getSize(new THREE.Vector3),
             size: bound.getSize(new THREE.Vector3),
             center,
             center,
         }
         }
-    }
+    },
+
+
+
 };
 };
 
 
  
  
-
+Potree.math = math
 
 
 
 
 export default math
 export default math

+ 879 - 0
src/utils/searchRings.js

@@ -0,0 +1,879 @@
+import * as THREE from "../../libs/three.js/build/three.module.js";
+import math from "./math";
+
+var points = [];
+var lines = [];
+var rings = []; 
+ 
+var precision = 0.1 //容错精度 //正常是0.01 但是在编辑时容易出现交错的线看不出来,导致需要getSliceLines 然后多出新增点
+ 
+ 
+var getPoint = function(o, type){
+    var point;
+    if(typeof o == "string" || typeof o == "number")point = points.find(p=> p.ids.includes(o));
+    else{
+        point = points.find(p=> math.closeTo(p.x , o.x, precision) && math.closeTo(p.y , o.y, precision)   ) 
+        if(!point) point = new Point(o.x, o.y,{record:true, id:o.id}, type) 
+        else{ 
+            //console.log('addPoint', point, o)
+            point.addPoint(o.id)
+        }
+    }
+    if(!point){
+        console.log("no point!")
+    }
+    
+    
+    return point
+}
+
+var getLine = function(id){
+    return lines.find(line=> line.ids.includes(id));
+}
+
+
+
+var getAngleInfo = function(points){
+    var info = {}
+    info.angle = points[1].clone().sub(points[0]).angle(); 
+    if(math.closeTo(info.angle, Math.PI*2)){ //如360-0.01  
+        info.angle -= Math.PI*2;    //有可能得到负数-0.001
+    }else if(info.angle > Math.PI || math.closeTo(info.angle, Math.PI)){//如180+-0.01
+        info.angle -= Math.PI;
+        info.reverse = true
+    } 
+    return info  //结果大约是 0 - 3.14
+}
+
+class Point extends THREE.Vector2{
+    constructor(x, y, o={}){
+        super(x, y);
+        
+        if(o.record){   
+            this.id = o.id;
+            if(this.id == void 0) this.id = "add_"+points.length 
+            this.ids =  [this.id] ;//存储拥有该坐标的点原始数据的id
+            points.push(this)  
+        }  
+        
+        this.type = o.type || "" 
+        this.lines = [];
+          
+    }
+    
+    addPoint(id){
+        this.ids.push(id)
+    }
+    
+    searchLineByFactor(dir, type, comeLine){
+        
+        var lines = this.lines.filter(line=>line.searchTime<2)
+        
+        if(lines.length==0)return;
+        else if(lines.length==1)return lines[0];
+        else lines = lines.filter(line=>line!=comeLine)
+        
+        if(lines.length==1)return lines[0];
+        
+        var result; 
+        lines.forEach(line=>{
+            var vec = line.getVector();
+            if(line.points[1] == this) vec.negate();
+            var factor = math.getVec2Angle(dir, vec);
+            
+            if(new THREE.Vector3(dir.x, dir.y, 0).cross(new THREE.Vector3(vec.x, vec.y, 0)).z<0) factor*= -1  /////
+             
+            if(!result){
+                result = {line, factor}
+            } 
+            else{
+                if(type == "min" && factor<result.factor || type == "max" && factor>result.factor) result = {line, factor}
+            }
+        })
+        return result.line;
+    }
+} 
+ 
+var lineLen=0;
+class Line{
+    constructor(o){  
+        if(o.points[0] == o.points[1])return; 
+        this.points = o.points;
+        this.type = o.type || 'line'
+        
+        if(this.type == 'line'){
+            var oldLine = lines.find(line=>line.points.includes(o.points[0]) && line.points.includes(o.points[1]))
+            if(oldLine){
+                o.id != void 0 && oldLine.ids.push(o.id)
+                return oldLine;
+            }
+            this.id = o.id == void 0 ? ("line"+lineLen ++) : o.id
+            this.ids = [this.id]
+           
+            o.dontWriteToPoint || this.points.forEach((point)=>{point.lines.push(this)})
+            o.isChild || lines.push(this);
+            this.searchTime = 0 // 最多两次
+        } 
+         
+        this.children = [];//分割
+        this.parents = [];//分割
+        this.match = [];
+         
+        
+    }
+    
+    
+    getAngleInfo(){ 
+        var angleInfo = getAngleInfo(this.points)
+        this.angle = angleInfo.angle
+        this.reverse = angleInfo.reverse
+    }
+    
+    getIntersectWithLine(line, precision){
+        var joint = line.points.find(point=>this.points.includes(point))
+        if(joint)return {point:joint, type:"joint"};
+        
+        var intersect = math.isLineIntersect( line.points , this.points , false, precision );
+        if(intersect) return {point: intersect, type:"intersect"};
+        
+        
+    } 
+    
+    writeToPoint(){
+        this.points.forEach((point)=>{point.lines.includes(this) || point.lines.push(this)})
+    }
+    
+    checkIfParent(line){ 
+        if(this == line){ 
+            return true;//原因就是slice的点和端点很近  误差导致 
+        }
+        else return this.parents.find(e=>e.checkIfParent(line))
+        
+    }
+    
+    splitByPoint(point){
+        var line1 = new Line({points:[point, this.points[0]],  dontWriteToPoint:true, hasntsure:true})
+        var line2 = new Line({points:[point, this.points[1]],  dontWriteToPoint:true, hasntsure:true})
+        
+        if(!line1.points || !line2.points){//有至少一个是点相同的,没写到group.lines里
+            
+            console.warn('splitByPoint 线有点相同')
+            return;
+        }
+        
+        if(this.checkIfParent(line1)||this.checkIfParent(line2) || line1.checkIfParent(this) || line2.checkIfParent(this)){
+            console.warn("splitByPoint 发现parent和children一样")//,请检查getSliceWalls,尤其 if(math.closeTo(line1.angle,line2.angle)){ 处
+
+            return;
+        }
+        var deal = (line)=>{ 
+            this.children.push(line);
+            line.parents.push(this)  
+             
+            if(!lines.includes(line))lines.push(line)
+            line.writeToPoint()    
+            
+        }
+        deal(line1)
+        deal(line2)
+         
+        var index = this.points[0].lines.indexOf(this);
+        index > -1 && this.points[0].lines.splice(index,1)
+        var index = this.points[1].lines.indexOf(this);
+        index > -1 && this.points[1].lines.splice(index,1)
+         
+        
+        return [line1,line2]
+    }
+    splitByPoints(points){
+        points = points.map(point=>{return {dis:point.distanceTo(this.points[0]), point:point}})
+        points.sort((point1, point2)=>{return point1.dis - point2.dis})
+        var children = [];
+        
+        
+        points.forEach((point, index)=>{
+            var line1 = new Line({points:[point.point, index==0?this.points[0]:points[index-1].point ],group:this.group , dontWriteToPoint:true, hasntsure:true})
+            children.push(line1)  
+        })
+        var line2 = new Line({points:[points[points.length-1].point, this.points[1] ],group:this.group , dontWriteToPoint:true, hasntsure:true})
+        children.push(line2); 
+        
+        
+         
+        var a = children.find(line=> !line.points ||  this.checkIfParent(line) || line.checkIfParent(this))
+        if(a){
+            console.error("splitByPoints  return")
+            return;
+        }
+         
+        
+        children.forEach(line=>{  
+            this.children.push(line);
+            line.parents.push(this)   
+            
+            if(!lines.includes(line))lines.push(line)
+            line.writeToPoint()   
+            line.writeToPoint() 
+        })
+        
+        var index = this.points[0].lines.indexOf(this);
+        index > -1 && this.points[0].lines.splice(index,1)
+        var index = this.points[1].lines.indexOf(this);
+        index > -1 && this.points[1].lines.splice(index,1)
+        
+         
+    }  
+    
+    
+    getAllSlices(){//如果有被分割的片段 就返回片段,否则返回自身
+        var children = [];
+        var traverse = function(elem){
+            if(elem.children.length == 0) children.push(elem) 
+            else elem.children.forEach(traverse)
+        }
+        traverse(this)
+        return children
+    }
+    getVector(){
+        return this.points[1].clone().sub(this.points[0]);
+    }
+    
+    getLength(){
+        return this.points[0].distanceTo(this.points[1])
+    }
+    
+    getCenter(){
+        return this.points[1].clone().add(this.points[0]).multiplyScalar(.5);
+    }
+} 
+var getMixedSet = function(arr1, arr2){//交集
+    return arr1.filter(item=>arr2.includes(item));
+}
+var getUnionSet = function(arr1, arr2){//并集
+    return arr1.concat(arr2.filter(item=>!arr1.includes(item)))
+}
+var getDifferenceSet = function(arr1, arr2){//差集
+    var arr11 = arr1.filter(item=>!arr2.includes(item));
+    var arr22 = arr2.filter(item=>!arr1.includes(item));
+    return arr11.concat(arr22)
+}
+var getDifferenceSetMuti = function(arr){//收集绝对没有重复的元素,也就是判断出现次数=1的
+    var set = [];
+    arr.forEach(arr1=>{
+        arr1.forEach(item=>{
+            var index = set.indexOf(item)
+            if(index>-1){
+                set.splice(index, 1)
+            }else{
+                set.push(item)
+            }
+        })
+    })
+    return set;
+} 
+
+function DoorAtWhichLine(points, lines){
+    var mid = points[0].clone().add(points[1]).multiplyScalar(0.5)
+    lines = lines.filter(line=>math.ifPointAtLineBound(mid, line.points, precision))
+    if(lines.length == 0)return
+    var result = {line:null, dis:Infinity}
+    lines.forEach(line=>{
+        var foot = math.getFootPoint(mid, line.points[0], line.points[1] )
+        var dis = foot.distanceTo(mid)
+        if(dis<result.dis){
+            result.line = line; result.dis = dis
+        }
+    })
+    return result
+    
+}
+
+
+
+
+var ringLen = 0;
+class Ring{
+    constructor(o){
+        this.id = ringLen ++
+        this.type = o.type || 'normal';
+        this.points = o.points;
+        this.lines = o.lines;     
+        rings.push(this); 
+        this.child = []//包含的环
+        this.parent = []//被包含的环
+        this.smallNeibours = []//相邻最小环(存在和它有一个以上的相同边的最小环)
+        
+        var area = math.getArea(this.points);
+        this.area = Math.abs(area)
+        this.isClockwise = area<0//是否逆时针。一般都是逆时针得到的,如果是顺时针,可能是贪吃蛇的情况,可能不是最小环,需要去掉。
+    } 
+    
+}
+var findLine = function(p1,p2){
+    return lines.find(line=>line.points.includes(p1) && line.points.includes(p2)  )
+}
+var ifSamePart = function(checkPart , part){//checkPart中所包含的part片段是否和基准part的顺序一样(逆序也可以, 中间有其他数也可以,起始不同也行。比如 01234和204一样的)
+    var axis, startIndex, newCheckPart=[];
+     
+     
+    for(var j=0,len1 = checkPart.length; j<len1; j++){//将checkPart中比part多的数除去,使两个数组中包含的数完全相同。
+        if(part.indexOf(checkPart[j])>-1)newCheckPart.push(checkPart[j]);
+    }
+
+    for(var i=0,len = part.length; i<len; i++){
+        var index = newCheckPart.indexOf(part[i]);
+        if(index == -1)return false;
+        if(i == 0) startIndex = index;//标记第一个查找点对应的index 
+        else if(i == 1){//标记查找顺序是正还是逆
+            axis = index - startIndex;
+            if(axis == len - 1) axis = -1;//刚好是首和尾
+            else if(axis == 1- len) axis = 1;
+            
+            if(axis != -1 && axis != 1){
+                return false
+            }  
+        }else{//判断是否是按顺序的
+            if(index != ((startIndex+axis * i + len) % len) ) return false;
+        } 
+    }
+    return {sameAxis:axis>0};	//如果一样的话返回正逆是否相同		
+}
+
+//或者判断是否有相同边(但是相同点是可以组成不同环)
+var ifSameRing = function(ring1, ring2){//判断两个环是否相等。 除了可以逆向外顺序要对
+    if(ring1 instanceof Ring)ring1 = ring1.points;
+    if(ring2 instanceof Ring)ring2 = ring2.points;
+    if(ring1.length != ring2.length)return false;
+    if(ring1.lines && ring2.lines){
+        if(getDifferenceSet(ring1.lines , ring2.lines).length == 0)return true;//差集个数为0
+    }else{
+        if(ifSamePart(ring1, ring2))return true 
+    }
+    
+}
+  
+ 
+
+var atWhichChildLine = function(point, line, precision){
+    if(line.children.length == 0){//这里可能要放低精度 保证能找到
+        if(math.ifPointAtLineBound(point, line.points, precision)) return line;
+           
+    }else{
+        for(var i=0;i<line.children.length;i++){
+            var at = atWhichChildLine(point, line.children[i], precision)
+            if(at)return at
+        }
+    }
+}
+
+
+
+function getSliceLines(){
+    var len = lines.length;
+     
+     
+    var deal = function(line1,line2){
+        if(line1 == line2)return;
+        
+        if(line1.angle == void 0) line1.getAngleInfo()
+        if(line2.angle == void 0) line2.getAngleInfo()
+            
+        var intersect = line1.getIntersectWithLine(line2, precision);
+        if(intersect){
+            var point //得到交点
+            if(intersect.type == "intersect"){
+                point = getPoint(intersect.point, "whenGetSliceLines");
+         
+                var line1_ = atWhichChildLine(point, line1)
+                var line2_ = atWhichChildLine(point, line2)
+                //重合的情况还没考虑(平行)
+                if(!line1_) line1_ = atWhichChildLine(point, line1, precision)//降低精度
+                if(!line1_) line1_ = atWhichChildLine(point, line1, precision*2)//降低精度
+                if(!line2_) line2_ = atWhichChildLine(point, line2, precision)
+                if(!line2_) line2_ = atWhichChildLine(point, line2, precision*2)//降低精度
+                //拆分线条:
+                
+                //如果还报错,找不到ChildLine,就直接返回吧  或者搞个循环 逐渐降低精度
+                if(!line1_ || !line2_){
+                    console.warn("atWhichChildLine仍旧找不到 :" + line1.id + ',' + line2.id + ", pointId: "+point.id)
+                    line1_ || console.warn("找不到line1")
+                    line2_ || console.warn("找不到line2")
+                    return;
+                }
+                
+                if(line1_.points.find(p=>p == point) && line2_.points.find(p=>p == point)){//这个点是line1_、 line2_端点,不做处理
+                    //console.log("joint型  "+point.id)
+                }else if(line1_.points.find(p=>p == point)){//T型交叉 
+                    line2_.splitByPoint(point)//加入到母线中,之后还先用母线判断交点
+                    //console.log("T型交叉1 "+point.id)
+                }else if(line2_.points.find(p=>p == point)){//T型交叉 
+                    line1_.splitByPoint(point)
+                    //console.log("T型交叉2 "+point.id)
+                }else{//十字交叉 
+                    line1_.splitByPoint(point)
+                    line2_.splitByPoint(point)
+                }     
+            }else{
+                point = intersect.point//交点是端点 
+                if(math.closeTo(line1.angle,line2.angle)){ //重合一部分
+                    var children1 = line1.getAllSlices()
+                    var children2 = line2.getAllSlices();
+                    if(children1.length>1 || children2.length>1){  //使用最小分割片段来比较
+                        children1.forEach(child1=>{
+                            children2.forEach(child2=>{
+                                deal(child1, child2)
+                            }) 
+                        })
+                        return;
+                    }
+                
+                    var anotherPoint1 = line1.points.find(point_=>point_!=point)
+                    var anotherPoint2 = line2.points.find(point_=>point_!=point)
+                    if(math.ifPointAtLineBound(anotherPoint1, line2.points)){
+                        line2.splitByPoint(anotherPoint1)
+                    }else if(math.ifPointAtLineBound(anotherPoint2, line1.points)){
+                        line1.splitByPoint(anotherPoint2)
+                    }
+                } 
+                
+            }
+            
+        }else if(math.closeTo(line1.angle,line2.angle)){
+            var vec1 = line1.getVector()
+            var vec = line1.points[0].clone().sub(line2.points[0]);
+            var cos = math.getVec2Cos(vec1, vec);
+            if(math.closeTo(cos, -1, 1e-4) || math.closeTo(cos, 1, 1e-4)){ //共线
+            
+                var children1 = line1.getAllSlices()
+                var children2 = line2.getAllSlices();
+                if(children1.length>1 || children2.length>1){  //使用最小分割片段来比较
+                    children1.forEach(child1=>{
+                        children2.forEach(child2=>{
+                            deal(child1, child2)
+                        }) 
+                    })
+                    return;
+                }
+                
+                //判断是否重叠 
+                var A = line1.points[0]; 
+                var C = line1.reverse == line2.reverse ? line2.points[0] : line2.points[1]; 
+                 
+                var B = line1.points[1];
+                var D = line1.reverse == line2.reverse ? line2.points[1] : line2.points[0];
+                 
+                var BC = C.clone().sub(B) 
+                var AD = D.clone().sub(A)
+                if(BC.length()<AD.length()){
+                    var BA = A.clone().sub(B); 
+                    if(math.getVec2Angle(BC, BA) >= 1.57 )return;//没有重叠部分
+                }else{
+                    var AB = B.clone().sub(A)
+                    if(math.getVec2Angle(AD, AB) >= 1.57 )return;
+                }
+            
+            
+            
+                var f = function(line1,line2){
+                    var one = math.ifPointAtLineBound(line1.points[0], line2.points);
+                    var two = math.ifPointAtLineBound(line1.points[1], line2.points);
+                    if(one && two){//line1在line2上
+                        line2.splitByPoints( line1.points )
+                        return true
+                    }else if(one || two){//错开
+                        var point1 = one ? line1.points[0] : line1.points[1];
+                        var anotherPoint1 = one ? line1.points[1] : line1.points[0];
+                        var dis1 = line2.points[0].distanceTo(anotherPoint1);
+                        var dis2 = line2.points[1].distanceTo(anotherPoint1); 
+                        var point2 = dis1 < dis2 ? line2.points[0] : line2.points[1]
+                        line1.splitByPoint(point2) 
+                        line2.splitByPoint(point1)
+                        return true
+                    }
+                }
+                f(line1, line2) || f(line2, line1)
+            }
+        }
+    
+    }
+     
+    for(let i=0;i<len;i++){
+        let line1 = lines[i];
+        for(let j=i+1;j<len;j++){ 
+            let line2 = lines[j];
+            deal(line1,line2)
+           
+        }
+    }
+    
+    //console.log("原有线条个数:"+len)
+    
+    //lines = lines.filter((line)=>{return line.children.length == 0})
+    
+    //console.log("现有线条个数:"+lines.length)
+    
+}
+var bound = new THREE.Box2()
+var build = function(o){
+    //融合了相近点
+    //根据bound 处理precision
+    o.points.forEach(p=>{
+        bound.expandByPoint(new THREE.Vector2(p.x,p.y))
+    })
+     
+    
+    if(o.precision != void 0){
+        precision = o.precision
+    }else{
+        var boundSize = bound.getSize(new THREE.Vector2)
+        precision = THREE.Math.clamp(Math.max(boundSize.x, boundSize.y) / 70, 0.2, 2);
+    }
+    
+    
+    
+    
+    
+    
+    
+    o.points.forEach(point=>getPoint(point))//{x:..,y:..}
+     
+        
+    o.lines.forEach(line=>{ //{p1:id1. p2:id2}
+        new Line({points:[getPoint(line.p1), getPoint(line.p2)], id:line.id })
+    })
+    //注意:不能出现一条线的两个点坐标一致,否则寻路时方向出错。 所以手动融合下相近点。
+}
+  
+ 
+var searchRings = function(o={}){
+    points = [];
+    lines = [];
+    rings = [];
+    lineLen = ringLen = 0
+    o.points = o.points || []
+    o.lines = o.lines || []
+    
+     
+    build(o)
+    
+    if(!o.dontSliceLines){ 
+        getSliceLines()
+    }
+    
+    
+    
+    
+    
+    //查找最小回路:
+    //参考: 引入方向因子的最小回路、最大回路搜索算法.pdf 
+    //方法:  逆时针寻找(标记)最外层大环 -->从走过的点开始逆时针寻找最小环(直到所有可走的路被走过两次)-->逆时针寻找最外层大环(直到所有可走的路被走过两次)-->..
+    //其中找大环时选择方向因子最小的路, 而小环则相反(但只有开始第一条路是一样的, 都是选择最左边的点的因子最小的路)。  
+    //标记方法: 每条线需要被搜索两次才算完毕。搜索完毕的线退出搜索。(依据:搜索完全部最小回路后 , 在无向图中删除搜索过 2 次的边及孤立节点得到退化图 , 恰好构成最大回路。)  
+    var searchTime = 0;
+    var addRingJudgeCount = 0
+    var addRingJudge = function(ring, lines, connectedLines, type){// 处理拣出的片段 
+        addRingJudgeCount++;
+        
+        //console.log("addRingJudge points("+ type+"):"+  ring.map(point=>point.id) )
+        if(o.onlyGetOutRing && type == "small")return
+        
+        if(type == "small" || o.onlyGetOutRing){//挑出回路:
+            var newRings = []
+            while(ring.length){
+                var road = [];
+                var turnBack = false;
+                for(let i=0;i<ring.length;i++){
+                    if(road.includes(ring[i])){//如果走到方才的点,可能形成回路。 无论是不是回路都要摘去这段。
+                        var index = road.indexOf(ring[i])
+                        var pointArr = ring.slice(index, i);
+                        var linesArr = lines.slice(index, i);
+                        ring.splice(index,i-index);
+                        lines.splice(index,i-index);
+                        if(pointArr.length>2){// 如果只有两个数,代表原路返回, 如 1->2(->1) 
+                            if( !rings.find(ring_=>ifSameRing(pointArr, ring_))) newRings.push( new Ring({points: pointArr, lines:linesArr}) )
+                        }
+                        turnBack = true
+                        break;
+                    }else{
+                        road.push(ring[i])
+                        turnBack = false
+                    } 
+                }
+                if(!turnBack){//没有重复的点,那么就直接处理整条。
+                    if(ring.length>2){// 如果只有两个数,代表原路返回, 如 1->2(->1) 
+                        if( !rings.find(ring_=>ifSameRing(ring, ring_))) newRings.push( new Ring({points: ring, lines}) )
+                    }
+                    break;
+                }
+            } 
+            
+            if(type != 'small'){
+                newRings.forEach(e=>e.isOutRing = true)
+            }
+            
+            
+            //console.log(newRings)
+        }else{
+            return ring
+        }
+    }
+
+     
+   
+
+    var search = function(point2d, comeRoad, type, connectedLines){
+        searchTime++
+        var goLine; 
+        var direction;
+        if(type.includes("big")){  
+            if(!comeRoad){
+                if(type.includes("Left")){//逆时针
+                    direction = new THREE.Vector2(1,0);
+                }else{
+                    direction = new THREE.Vector2(-1,0);
+                }
+                goLine = point2d.searchLineByFactor(direction,"min") 
+            }else{
+                var lastPoint = comeRoad.points[comeRoad.points.length-1]
+                direction = point2d.clone().sub(lastPoint);
+                goLine = point2d.searchLineByFactor(direction,"min", findLine(point2d, lastPoint)) 
+            }
+            
+        }else{ 
+            if(!comeRoad){
+                //似乎找最小环时,第一条线也是找最小的因子,这样才能保证逆时针(除非只有顺时针一条路)
+                direction = new THREE.Vector2(1,0);
+                goLine = point2d.searchLineByFactor(direction,"min")  
+                
+            }else{
+                var lastPoint = comeRoad.points[comeRoad.points.length-1]
+                direction = point2d.clone().sub(lastPoint);
+                goLine = point2d.searchLineByFactor(direction,"max", findLine(point2d, lastPoint))
+            } 
+        }
+        if(!goLine)return 
+        
+        
+        goLine.searchTime++;
+        connectedLines.includes(goLine) || connectedLines.push(goLine)
+         
+             
+        var nextPoint = goLine.points.find( point => point2d!=point )
+        
+        //if( comeRoad && comeRoad.points[comeRoad.points.length - 1] == nextPoint ) return;//不能查找来时的方向(反方向)
+        //走不通就原路返回
+        
+        var roadPoints = comeRoad ? comeRoad.points.concat([point2d]) : [point2d];//每个分叉都能构成一条新的road
+        var roadLines = comeRoad ?  comeRoad.lines.concat([goLine]) : [goLine];
+        
+        
+        
+        
+        //走到第一个点就算停止,这时候可能得到一个环、或者一段走了两遍的线、或者一条线上带了些环。 
+        if(nextPoint == roadPoints[0]) return addRingJudge(roadPoints, roadLines, connectedLines, type) //形成环 
+        else{ 
+            /* var len = roadPoints.indexOf(nextPoint);
+            if( len > -1){ //走到走过的路的某一点 构成这段路的回路
+                var points = roadPoints.slice(len, roadPoints.length);
+                var lines = roadLines.slice(len, roadPoints.length);
+                addRingJudge(points, lines)    
+            }else{ */
+                return search(nextPoint,  {lines:roadLines, points:roadPoints}, type, connectedLines);//继续寻路
+            //}  
+        }
+         
+    }
+     
+
+    while(1){//搜寻一次大环
+        var connectedLines = [];//被搜寻过的且searchTime<2的线。一旦全部搜完就说明该连通区域搜寻完毕,继续查下一个连通区域。
+        var startPoint = null
+        points.forEach(point=>{//找出x最小的点
+            if(!point.lines.find(line=>line.searchTime<2))return;
+            if(!startPoint)startPoint = point
+            else if(point.x < startPoint.x)startPoint = point;
+        })
+        if(!startPoint)break; //说明全部找完
+        
+        
+        var ring = search(startPoint, null, "bigLeft", connectedLines)//逆时针  
+        //search(startPoint, null, "bigRight", connectedLines);//顺时针(为了防止最外层不是回路之前写了顺时针,但如果是回路就会走重复。后来发现只要逆时针即可,因为走完后剩下的可以再次找大环)
+        
+        connectedLines = connectedLines.filter(line=>line.searchTime<2)
+        
+        
+        
+        
+        while(connectedLines.length>0){//目标是顺着connectedLines把所有连通的小环都找到
+            
+            let points_ = [];//connectedLines中所有的点
+            connectedLines.forEach(line=>line.points.forEach(point=>{if(!points_.includes(point))points_.push(point) }))
+            var startPoint = null
+            points_.forEach(point=>{//找出x最小的点
+                if(!point.lines.find(line=>line.searchTime<2))return;
+                if(!startPoint)startPoint = point
+                else if(point.x < startPoint.x)startPoint = point;
+            })
+            if(!startPoint)break;
+            
+             
+            search(startPoint, null, "small", connectedLines)
+            
+            connectedLines = connectedLines.filter(line=>line.searchTime<2)
+        }   
+    } 
+    
+    
+    
+    /* if(o.onlyGetOutRing){
+        rings = rings.filter(e=>e.isOutRing)   
+    } */
+    
+    //console.log("searchTime "+searchTime + ", addRingJudgeCount " +addRingJudgeCount)
+    
+    
+   
+    
+    //找出所有的相邻关系,包括公共边 
+    var len = rings.length;
+    for(let i=0; i<len; i++){
+        let ring1 = rings[i] 
+        for(let j=i+1; j<len; j++){
+            let ring2 = rings[j]
+            var bothHasLines = getMixedSet(ring1.lines, ring2.lines) 
+            if(bothHasLines.length){//ring1oíring2?àáú
+                ring1.smallNeibours.push(ring2)
+                ring2.smallNeibours.push(ring1) 
+            }else{ 
+            }  
+        }
+    }
+    rings.forEach(ring1=>{
+        for(let i=0; i<len; i++){
+            var ring2 = rings[i];
+            if(ring1 == ring2 || ring1.smallNeibours.includes(ring2))continue;
+            
+            let inside
+            for(let u=0;u<ring1.points.length;u++){
+                inside = math.isPointInArea(ring2.points, null, ring1.points[u]);
+                if(!inside)break
+                else if(inside && !inside.atLine){
+                    break
+                }
+            } 
+             
+            
+            if(inside){  //只要其中一个点在ring2内,就说明ring1是内环          
+                if(inside.atLine){//(还是会存在点全在线上的情况,这时候判断中心点)  
+                    var center = math.getCenterOfGravityPoint(ring1.points)
+                    let inside1 = math.isPointInArea(ring2.points, null, center);
+                    if(!inside1){
+                        continue
+                    }
+                }
+                
+                ring2.child.push(ring1);
+                ring1.parent.push(ring2)
+            }
+        }
+    })
+    //去除非最小的ring  是否应该检测parent child?
+     /* 
+        like this: 
+        |———————————————————————|
+        |———|———————|———————|   |
+        |   |       |       |   |
+        |   |———————|———————|   |
+        |———————————————————————|
+    */
+    var wiseRings = rings.filter(r=>!r.isClockwise)//一般都是逆时针得到的,如果是顺时针,可能是贪吃蛇的情况,可能不是最小环,需要去掉。 
+    if(wiseRings.length > 0){
+        //console.log('%c存在非最小的ring! 进行处理:',"color:#00f"); 
+        wiseRings.forEach(ring=>{ //(此案例验证出smallNeibours就是它的最小构成,可以再看看别的案例)
+            if(ring.smallNeibours.length>0){//另:如果内部只有一个,说明它是最小环,不需要处理
+                var is = false
+                var difference = getDifferenceSet(ring.lines , getDifferenceSetMuti(ring.smallNeibours.concat(ring.child).map(ring=>ring.lines)))//获取所有smallNeibours和child的边中没有重复过的边(就是outline) 和该ring的线比较
+                 
+                
+                is = difference.every(line=> ring.child.find(r=>r.lines.includes(line))  )  //多出的线只能是child中的线
+                
+                if(is){
+                    console.log('%c删除非最小环 ring'+ring.id,"color:#00f");
+                    console.log(ring)
+                    rings.splice(rings.indexOf(ring), 1) 
+                    ring.child.forEach(c=>{var index = c.parent.indexOf(ring);index>-1 && c.parent.splice(index,1)})
+                    ring.parent.forEach(c=>{var index = c.child.indexOf(ring);index>-1 && c.child.splice(index,1)})
+                    ring.smallNeibours.forEach(c=>{var index = c.smallNeibours.indexOf(ring);index>-1 && c.smallNeibours.splice(index,1)})
+                }
+                
+            }
+            
+        })
+    }
+    
+    
+    
+    /* rings = rings.filter(ring=>{ 
+        rings = rings.filter(ring=>{ 
+            var enoughSize = ring.area > 0.5
+            if(!enoughSize){console.log('因面积过小去除ring '+ring.id + " , area: "+ring.area)}
+            return enoughSize
+        }) 
+        rings.forEach(ring=>{
+            if(ring.closetChilds){
+                ring.closetChilds = ring.closetChilds.filter(e=>rings.includes(e))
+            }
+        })
+        
+        return rings
+        
+    })  */ //在dealRings前不能随意删除rings,因为判断是否是最小环时需要全部的环  
+    
+    rings.forEach(ring=>{ //这里和cad中的不太一样, cad中双数个parent算外环,单数内环; 这里不分内外, 只看有无parent child
+        if(ring.parent.length){
+            ring.closetParent = ring.parent.find(ring_ => ring_.parent.length == ring.parent.length - 1)//最近一层的大环就是比它的parent个数少一的
+            ring.closetParent.closetChilds || (ring.closetParent.closetChilds = [])//内环可能多个
+            ring.closetParent.closetChilds.push(ring)
+        } 
+    })
+    
+    
+    
+    //console.log(rings)
+    
+    
+    
+   
+    
+    var _ring = rings.map(ring=>{ 
+        var data = {
+            id: ring.id,  
+            points: ring.points.map(point=>{return {id: point.ids[0], x:point.x, y:point.y}}),
+            /* doors : o.doors.filter(door=>{
+                if(ring.closetChilds){
+                    var childOutLines = getDifferenceSetMuti(ring.closetChilds.map(ring=>ring.lines)) //最近子环的外边
+                    return ring.lines.concat(childOutLines).includes(door.atLine)   
+                }else{
+                    return ring.lines.includes(door.atLine) 
+                } 
+            }), */ 
+            area:ring.area,
+            closetParent : ring.closetParent && ring.closetParent.id,
+            closetChilds : ring.closetChilds && ring.closetChilds.map(e=>e.id) 
+        } 
+        
+        return data
+    })
+        
+    //console.log(JSON.stringify(_ring))
+
+    return _ring
+    
+    
+    
+    
+    
+}
+
+ 
+export default searchRings

+ 20 - 10
src/viewer/EDLRenderer.js

@@ -189,14 +189,6 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
         //viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
         //viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
 	
 	
 		                                           
 		                                           
-		//const visiblePointClouds = viewer.scene.pointclouds.filter(pc =>  pc.visible );
-		const visiblePointClouds2 = viewer.scene.pointclouds.filter(pc => viewer.getObjVisiByReason(pc,'datasetSelection')  ); 
-		const showPointClouds = viewer.scene.pointclouds.some(e=>e.visible)
-         
-        viewer.scene.pointclouds.forEach(e=>{//为了绘制到depthTexture,先显示(展示全景图时隐藏了点云,所以需要显示下。且放大镜需要绘制点云)
-            e.oldVisi = e.visible
-            if(viewer.getObjVisiByReason(e, 'datasetSelection') ) e.visible = true; 
-        }) 
         
         
          
          
         
         
@@ -236,12 +228,30 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
             
             
         }
         }
         
         
-        //skybox 
+        //skybox  全景图
         if(!params.magnifier){
         if(!params.magnifier){
             viewer.setCameraLayers(camera, ['skybox'])
             viewer.setCameraLayers(camera, ['skybox'])
+            if(Potree.settings.hasDepthTex && Potree.settings.displayMode == 'showPanos' && Features.EXT_DEPTH.isSupported()){//渲染深度图
+                viewer.renderer.setRenderTarget(params.rtEDL || this.getRtEDL(params.viewport))
+                viewer.renderer.render(viewer.scene.scene, camera);
+                viewer.renderer.setRenderTarget(params.target || null);
+            } 
             viewer.renderer.render(viewer.scene.scene, camera);
             viewer.renderer.render(viewer.scene.scene, camera);
+            if(Potree.settings.hasDepthTex && Potree.settings.displayMode == 'showPanos' )return 
         } 
         } 
          
          
+         
+        
+         
+		//const visiblePointClouds = viewer.scene.pointclouds.filter(pc =>  pc.visible );
+		const visiblePointClouds2 = viewer.scene.pointclouds.filter(pc => viewer.getObjVisiByReason(pc,'datasetSelection')  ); 
+		const showPointClouds = viewer.scene.pointclouds.some(e=>e.visible)
+         
+        viewer.scene.pointclouds.forEach(e=>{//为了绘制到depthTexture,先显示(展示全景图时隐藏了点云,所以需要显示下。且放大镜需要绘制点云)
+            e.oldVisi = e.visible
+            if(viewer.getObjVisiByReason(e, 'datasetSelection') ) e.visible = true; 
+        })
+
         
         
         //pointcloud
         //pointcloud
         viewer.setCameraLayers(camera, ['pointcloud'])
         viewer.setCameraLayers(camera, ['pointcloud'])
@@ -275,7 +285,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
                 }else{
                 }else{
                     material.useEDL = false;
                     material.useEDL = false;
                     //material.fakeEDL = true; //add 使也输出深度
                     //material.fakeEDL = true; //add 使也输出深度
-                }  
+                }   
                 
                 
 			}
 			}
             
             

+ 9 - 2
src/viewer/View.js

@@ -234,10 +234,17 @@ export class View extends THREE.EventDispatcher{
             }else if(endQuaternion){
             }else if(endQuaternion){
                 this.rotation = new THREE.Euler().setFromQuaternion(endQuaternion)
                 this.rotation = new THREE.Euler().setFromQuaternion(endQuaternion)
             }
             }
-            setTimeout(()=>{//延迟是为了使isFlying先为false
+             
+            let f = ()=>{
                 info.callback && info.callback()     
                 info.callback && info.callback()     
                 this.dispatchEvent('flyingDone')    
                 this.dispatchEvent('flyingDone')    
-            },1)
+            }
+            if(info.duration){
+                setTimeout(f,1)//延迟是为了使isFlying先为false
+            }else{
+                f()  //有的需要迅速执行回调
+            }
+            
             
             
         }
         }
         
         

+ 14 - 12
src/viewer/Viewport.js

@@ -62,21 +62,23 @@ export default class Viewport{
                 
                 
             }; 
             }; 
         }
         }
-        
-        
-        if (!this.previousState){ 
-            copy()
-            return true//{cameraChanged:!0, changed:!0};
+        let projectionChanged = true
+        let positionChanged = true
+        let quaternionChanged = true
+        let getChanged = ()=>{
+            return {
+                projectionChanged,positionChanged,quaternionChanged, 
+                changed:projectionChanged || positionChanged || quaternionChanged
+            }
         }
         }
-        var cameraChanged =  
-            !this.camera.projectionMatrix.equals(this.previousState.projectionMatrix) ||
-            !this.camera.position.equals(this.previousState.position) ||
-            !this.camera.quaternion.equals(this.previousState.quaternion)
-            
-             
+        if (this.previousState){ 
+            projectionChanged = !this.camera.projectionMatrix.equals(this.previousState.projectionMatrix) 
+            positionChanged = !this.camera.position.equals(this.previousState.position)  
+            quaternionChanged = !this.camera.quaternion.equals(this.previousState.quaternion) 
+        }   
         copy() 
         copy() 
         
         
-        return cameraChanged
+        return getChanged()
 	}
 	}
     
     
     setResolution(w,h, wholeW=0, wholeH=0){
     setResolution(w,h, wholeW=0, wholeH=0){

+ 1 - 1
src/viewer/map/MapViewer.js

@@ -262,7 +262,7 @@ export class MapViewer extends ViewerBase{
             pano.mapMarker = new THREE.Mesh(planeGeo, panoMarkerMats.default);
             pano.mapMarker = new THREE.Mesh(planeGeo, panoMarkerMats.default);
             pano.mapMarker.position.copy(pano.position).setZ(0)   
             pano.mapMarker.position.copy(pano.position).setZ(0)   
             pano.mapMarker.scale.set(markerSize,markerSize,markerSize)
             pano.mapMarker.scale.set(markerSize,markerSize,markerSize)
-            
+            pano.mapMarker.name = 'mapMarker'
             panosGroup.add(pano.mapMarker); 
             panosGroup.add(pano.mapMarker); 
             
             
             
             

+ 72 - 34
src/viewer/viewer.js

@@ -77,7 +77,7 @@ import FXAAShader from "../materials/postprocessing/FXAAShader"
 
 
 
 
 let mapArea; 
 let mapArea; 
-
+let blockedByIntersectHistory = new Map();
 export class Viewer extends ViewerBase{
 export class Viewer extends ViewerBase{
 	
 	
 	constructor(domElement, mapArea_, args = {}){
 	constructor(domElement, mapArea_, args = {}){
@@ -115,7 +115,7 @@ export class Viewer extends ViewerBase{
         this.visible = true
         this.visible = true
         this.fpVisiDatasets = []
         this.fpVisiDatasets = []
         this.atDatasets = []
         this.atDatasets = []
-        this.lastPos = new THREE.Vector3(Infinity,Infinity,Infinity) 
+        //this.lastPos = new THREE.Vector3(Infinity,Infinity,Infinity) 
 		//-------------
 		//-------------
         
         
         var supportExtFragDepth = !!Features.EXT_DEPTH.isSupported() ;//iphoneX居然不支持
         var supportExtFragDepth = !!Features.EXT_DEPTH.isSupported() ;//iphoneX居然不支持
@@ -394,36 +394,37 @@ export class Viewer extends ViewerBase{
             
             
             
             
 
 
-            {
-                this.inputHandler = new InputHandler(this, this.scene.scene);
-                //this.inputHandler.setScene(this.scene);
-                //this.inputHandler.addInputListener(this);//add
-                
+            { 
+            
                 
                 
+                this.mainViewport = new Viewport(  this.scene.view, this.scene.cameraP, {
+                    left:0, bottom:0, width:1, height: 1, name:'MainView' 
+                }) 
+                this.viewports = [this.mainViewport]
                 
                 
-                this.clippingTool = new ClippingTool(this);
-                this.transformationTool = new TransformationTool(this);
-                this.navigationCube = new NavigationCube(this);
-                this.navigationCube.visible = false;
-
                 this.compass = new Compass(this);
                 this.compass = new Compass(this);
-                 
-                //add----------
                 this.magnifier = new Magnifier(this);
                 this.magnifier = new Magnifier(this);
                 this.reticule = new Reticule(this) 
                 this.reticule = new Reticule(this) 
                 this.scene.scene.add(this.magnifier) 
                 this.scene.scene.add(this.magnifier) 
                 this.scene.scene.add(this.reticule)
                 this.scene.scene.add(this.reticule)
-                this.mainViewport = new Viewport(  this.scene.view, this.scene.cameraP, {
-                    left:0, bottom:0, width:1, height: 1, name:'MainView' 
-                }) 
-                this.viewports = [this.mainViewport]
+                
+                
                 if(Potree.settings.editType != "pano"){
                 if(Potree.settings.editType != "pano"){
                     this.mapViewer = new MapViewer(mapArea/* $('#mapGaode')[0] */)
                     this.mapViewer = new MapViewer(mapArea/* $('#mapGaode')[0] */)
                 }
                 }
                 
                 
+                this.inputHandler = new InputHandler(this, this.scene.scene);
+                //this.inputHandler.setScene(this.scene);
+                //this.inputHandler.addInputListener(this);//add
+                
+                this.clippingTool = new ClippingTool(this);
+                this.transformationTool = new TransformationTool(this);
+                this.navigationCube = new NavigationCube(this);
+                this.navigationCube.visible = false;
+
                 
                 
-                //---------------------------
                 
                 
+                 
                 
                 
                 this.createControls();
                 this.createControls();
 
 
@@ -602,7 +603,9 @@ export class Viewer extends ViewerBase{
         }
         }
         
         
         
         
-        this.addEventListener('allLoaded',  this.testPointcloudsMaxLevel.bind(this))
+        this.addEventListener('allLoaded', ()=>{
+            setTimeout(this.testPointcloudsMaxLevel.bind(this), 2000) //延迟一丢丢,等画面出现
+        }) 
         
         
         
         
         
         
@@ -648,20 +651,34 @@ export class Viewer extends ViewerBase{
         { 
         { 
             //更新所在数据集 
             //更新所在数据集 
             this.addEventListener('camera_changed', e => {
             this.addEventListener('camera_changed', e => {
-                this.updateDatasetAt() 
+                if(e.changeInfo.positionChanged){ 
+                    blockedByIntersectHistory.clear() //清空
+                    this.updateDatasetAt() 
+                }
             })  
             })  
         }  
         }  
 	}
 	}
-
-
+    
+    
+    ifPointBlockedByIntersect(pos3d, object){//点是否被遮挡
+        let ifShelter
+        let shelter = blockedByIntersectHistory.get(object || pos3d);
+        if(shelter){
+            ifShelter = shelter.ifShelter
+        }else{
+            ifShelter = viewer.inputHandler.ifBlockedByIntersect(pos3d, 0.3, true)//由于热点都是使用点云得到的位置,所以判断遮挡时也用点云
+            blockedByIntersectHistory.set(object || pos3d, {ifShelter})
+        }
+        return ifShelter 
+    }
     
     
     updateDatasetAt(force){//更新所在数据集
     updateDatasetAt(force){//更新所在数据集
     
     
         let fun = ()=>{   
         let fun = ()=>{   
             let currPos = viewer.mainViewport.view.position
             let currPos = viewer.mainViewport.view.position
          
          
-            if(force || !currPos.equals(this.lastPos)){
-                this.lastPos.copy(currPos)
+            //if(force || !currPos.equals(this.lastPos)){
+                //this.lastPos.copy(currPos)
                 
                 
                 var at = this.scene.pointclouds.filter(e=>e.ifContainsPoint(currPos)) 
                 var at = this.scene.pointclouds.filter(e=>e.ifContainsPoint(currPos)) 
                 
                 
@@ -673,7 +690,7 @@ export class Viewer extends ViewerBase{
                 }
                 }
                 force = false 
                 force = false 
                 return true 
                 return true 
-            }
+            //}
         }            
         }            
         if(force)fun()
         if(force)fun()
         else Common.intervalTool.isWaiting('atWhichDataset', fun , 500)  
         else Common.intervalTool.isWaiting('atWhichDataset', fun , 500)  
@@ -801,8 +818,8 @@ export class Viewer extends ViewerBase{
     }
     }
 
 
 
 
-    //更新所在数据集
-             
+     
+    //促使点云加载出最高级别        
     testPointcloudsMaxLevel(){ //所有点云都无需testMaxNodeLevel 就停止
     testPointcloudsMaxLevel(){ //所有点云都无需testMaxNodeLevel 就停止
         let camera_changed,  count = 0
         let camera_changed,  count = 0
         let test = ()=>{
         let test = ()=>{
@@ -810,7 +827,7 @@ export class Viewer extends ViewerBase{
             
             
             
             
             Common.intervalTool.isWaiting('testPointcloudsMaxLevel', ()=>{  
             Common.intervalTool.isWaiting('testPointcloudsMaxLevel', ()=>{  
-                if(!camera_changed && count>10 )return //只有当camera_changed后才继续循环, 除了最开始几次需要连续加载下
+                if(!camera_changed && count>20 )return //只有当camera_changed后才继续循环, 除了最开始几次需要连续加载下
                 camera_changed = false
                 camera_changed = false
                 count ++;
                 count ++;
                 //console.log('testPointcloudsMaxLevel中')
                 //console.log('testPointcloudsMaxLevel中')
@@ -829,7 +846,7 @@ export class Viewer extends ViewerBase{
                     console.log('testPointcloudsMaxLevel结束')
                     console.log('testPointcloudsMaxLevel结束')
                 }
                 }
                 
                 
-            }, count<5 ? 150 : 500) 
+            }, count<10 ? 150 : 500) 
         }            
         }            
         this.addEventListener('camera_changed',test) 
         this.addEventListener('camera_changed',test) 
         test()
         test()
@@ -2804,6 +2821,7 @@ export class Viewer extends ViewerBase{
                 
                 
             } 
             } 
             
             
+
              
              
             view.render || this.renderOverlay(params) 
             view.render || this.renderOverlay(params) 
            
            
@@ -2866,11 +2884,14 @@ export class Viewer extends ViewerBase{
           
           
         this.dispatchEvent({type: "render.pass.scene", viewer: viewer});
         this.dispatchEvent({type: "render.pass.scene", viewer: viewer});
     
     
+    
+        
+    
         //清除深度 !!!!
         //清除深度 !!!!
         this.renderer.clearDepth(); 
         this.renderer.clearDepth(); 
 
 
         //this.transformationTool.update();
         //this.transformationTool.update();
-       
+        
          
          
         if(!params.magnifier){ 
         if(!params.magnifier){ 
             //测量线 
             //测量线 
@@ -3138,7 +3159,8 @@ export class Viewer extends ViewerBase{
                 this.dispatchEvent({  //update map  and sprite
                 this.dispatchEvent({  //update map  and sprite
                     type: "camera_changed", 
                     type: "camera_changed", 
                     camera: e.camera,
                     camera: e.camera,
-                    viewport : e
+                    viewport : e,
+                    changeInfo:{positionChanged:true,changed:true}
                 })   
                 })   
             })  
             })  
         }
         }
@@ -3506,9 +3528,25 @@ export class Viewer extends ViewerBase{
             
             
             if(Potree.settings.displayMode == 'showPointCloud'){ 
             if(Potree.settings.displayMode == 'showPointCloud'){ 
                 dis = bestDistance
                 dis = bestDistance
-                let dir = o.direction ? o.direction.clone().negate() : new THREE.Vector3().subVectors(camera.position, target).normalize() 
+                let dir = o.direction ? o.direction.clone().negate() : this.mainViewport.view.direction.negate()//new THREE.Vector3().subVectors(camera.position, target).normalize() 
+                  
                 position.copy(target).add(dir.multiplyScalar(dis))
                 position.copy(target).add(dir.multiplyScalar(dis))
             
             
+                if(o.checkIntersect){//识别被点云遮住的话 
+                    let ifShelter 
+                    
+                    while(1){
+                        ifShelter = this.inputHandler.ifBlockedByIntersect(target, o.checkMargin, true, position)  
+                        if(ifShelter){
+                            if(dis > 0.5){ 
+                                dis -- 
+                                dir.dot(ifShelter.normal)>0 ? dir.copy(ifShelter.normal).negate() : dir.copy(ifShelter.normal); 
+                                position.copy(target).add(dir.multiplyScalar(dis))
+                            }
+                        }  
+                    }
+                }
+            
             }else if(Potree.settings.displayMode == 'showPanos'){
             }else if(Potree.settings.displayMode == 'showPanos'){
                 let pano = viewer.images360.fitPanoTowardPoint({
                 let pano = viewer.images360.fitPanoTowardPoint({
                     point : target,
                     point : target,
@@ -3910,7 +3948,7 @@ export class Viewer extends ViewerBase{
             viewer.scene.pointclouds.forEach(e=>{   
             viewer.scene.pointclouds.forEach(e=>{   
                 e.material.activeAttributeName = 'rgba'; 
                 e.material.activeAttributeName = 'rgba'; 
                 e.material.shape = Potree.PointShape['SQUARE']
                 e.material.shape = Potree.PointShape['SQUARE']
-                fitPointsize && e.changePointSize(Potree.config.material.pointSize, true) 
+                fitPointsize && e.changePointSize(Potree.config.material.realPointSize, true) 
                 e.changePointOpacity(1)      
                 e.changePointOpacity(1)      
             })
             })
             
             

+ 11 - 7
src/viewer/viewerBase.js

@@ -265,14 +265,18 @@ export class ViewerBase extends THREE.EventDispatcher{
             return true
             return true
         } */
         } */
         for(let i=0,j=this.viewports.length;i<j;i++){
         for(let i=0,j=this.viewports.length;i<j;i++){
-            let changed_ = this.viewports[i].cameraChanged()
-            if(changed_){
+            let changeInfo = this.viewports[i].cameraChanged()
+            if(changeInfo.changed){
                 changed = true
                 changed = true
-                this.dispatchEvent({
-                    type: "camera_changed", 
-                    camera: this.viewports[i].camera,
-                    viewport : this.viewports[i]
-                })
+                //if(!this.changeTime ||this.changeTime<100){ 
+                    this.dispatchEvent({
+                        type: "camera_changed", 
+                        camera: this.viewports[i].camera,
+                        viewport : this.viewports[i],
+                        changeInfo 
+                    }) 
+                    //this.changeTime = (this.changeTime || 0) +1
+                //} 
             }                
             }                
         }
         }
         return changed
         return changed